Browse Source

queueData now returns success state, couple bug fixes

success state return added to queueData functions
queueable source is now seekable while stopped
fixed bug with creating queueable source with invalid format silently crashing LOVE
fixed bug with stopped queueable source reported as not queueable

--HG--
branch : minor
raidho36 8 years ago
parent
commit
10710d3428

+ 1 - 1
src/modules/audio/Source.h

@@ -103,7 +103,7 @@ public:
 	virtual int getChannels() const = 0;
 	virtual int getChannels() const = 0;
 	
 	
 	virtual bool isQueueable() const = 0;
 	virtual bool isQueueable() const = 0;
-	virtual void queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels) = 0;
+	virtual bool queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels) = 0;
 	
 	
 	virtual Type getType() const;
 	virtual Type getType() const;
 
 

+ 2 - 2
src/modules/audio/null/Source.cpp

@@ -222,9 +222,9 @@ bool Source::isQueueable() const
 	return false;
 	return false;
 }
 }
 
 
-void Source::queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels)
+bool Source::queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels)
 {
 {
-	return;
+	return false;
 }
 }
 
 
 
 

+ 1 - 1
src/modules/audio/null/Source.h

@@ -77,7 +77,7 @@ public:
 	virtual int getChannels() const;
 	virtual int getChannels() const;
 
 
 	virtual bool isQueueable() const;
 	virtual bool isQueueable() const;
-	virtual void queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels);
+	virtual bool queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels);
 
 
 private:
 private:
 
 

+ 2 - 2
src/modules/audio/openal/Pool.cpp

@@ -283,10 +283,10 @@ double Pool::getDuration(Source *source, void *unit)
 	return source->getDurationAtomic(unit);
 	return source->getDurationAtomic(unit);
 }
 }
 
 
-void Pool::queueData(Source *source, void *data, ALsizei length)
+bool Pool::queueData(Source *source, void *data, ALsizei length)
 {
 {
 	thread::Lock lock(mutex);
 	thread::Lock lock(mutex);
-	source->queueDataAtomic(data, length);
+	return source->queueDataAtomic(data, length);
 }
 }
 
 
 ALuint Pool::findi(const Source *source) const
 ALuint Pool::findi(const Source *source) const

+ 1 - 1
src/modules/audio/openal/Pool.h

@@ -91,7 +91,7 @@ public:
 	void seek(Source *source, float offset, void *unit);
 	void seek(Source *source, float offset, void *unit);
 	float tell(Source *source, void *unit);
 	float tell(Source *source, void *unit);
 	double getDuration(Source *source, void *unit);
 	double getDuration(Source *source, void *unit);
-	void queueData(Source *source, void *data, ALsizei length);
+	bool queueData(Source *source, void *data, ALsizei length);
 
 
 	bool play(const std::vector<love::audio::Source*> &sources);
 	bool play(const std::vector<love::audio::Source*> &sources);
 	void stop(const std::vector<love::audio::Source*> &sources);
 	void stop(const std::vector<love::audio::Source*> &sources);

+ 70 - 30
src/modules/audio/openal/Source.cpp

@@ -390,7 +390,6 @@ bool Source::update()
 				bufferedBytes -= size;
 				bufferedBytes -= size;
 				unusedBufferPush(buffers[i]);
 				unusedBufferPush(buffers[i]);
 			}
 			}
-			
 			return !isFinished();
 			return !isFinished();
 		}
 		}
 	}
 	}
@@ -442,12 +441,6 @@ float Source::getVolume() const
 
 
 void Source::seekAtomic(float offset, void *unit)
 void Source::seekAtomic(float offset, void *unit)
 {
 {
-	bool wasPlaying = isPlaying();
-
-	// To drain all buffers
-	if (valid && type == TYPE_STREAM)
-		stopAtomic();
-
 	switch (*((Source::Unit *) unit))
 	switch (*((Source::Unit *) unit))
 	{
 	{
 	case Source::UNIT_SAMPLES:
 	case Source::UNIT_SAMPLES:
@@ -460,17 +453,58 @@ void Source::seekAtomic(float offset, void *unit)
 		offsetSamples = offset * sampleRate;
 		offsetSamples = offset * sampleRate;
 		break;
 		break;
 	}
 	}
-
-	if (type == TYPE_STREAM)
-		decoder->seek(offsetSeconds);
-	else if (valid) // Playing static or queue
+	
+	switch (type)
 	{
 	{
-		alSourcef(source, AL_SAMPLE_OFFSET, offsetSamples);
-		offsetSamples = offsetSeconds = 0;
-	}
+		case TYPE_STATIC:
+			alSourcef(source, AL_SAMPLE_OFFSET, offsetSamples);
+			offsetSamples = offsetSeconds = 0;
+			break;
+		case TYPE_STREAM:
+		{
+			bool wasPlaying = isPlaying();
 
 
-	if (wasPlaying && type == TYPE_STREAM)
-		playAtomic(source);
+			// To drain all buffers
+			if (valid)
+				stopAtomic();
+			
+			decoder->seek(offsetSeconds);
+
+			if (wasPlaying)
+				playAtomic(source);
+				
+			break;
+		}
+		case TYPE_QUEUE:
+			if (valid)
+			{
+				alSourcef(source, AL_SAMPLE_OFFSET, offsetSamples);
+				offsetSamples = offsetSeconds = 0;
+			}
+			else
+			{
+				ALint size;
+				ALuint buffer = unusedBufferPeek();
+				
+				//emulate AL behavior, discarding buffer once playback head is past one
+				while (buffer != AL_NONE)
+				{
+					alGetBufferi(buffer, AL_SIZE, &size);
+					
+					if (offsetSamples < size / (bitDepth / 8 * channels))
+						break;
+
+					unusedBufferPop();
+					buffer = unusedBufferPeek();
+					bufferedBytes -= size;
+					offsetSamples -= size / (bitDepth / 8 * channels);
+				}
+				if (buffer == AL_NONE)
+					offsetSamples = 0;
+				offsetSeconds = offsetSamples / sampleRate;
+			}
+			break;
+	}
 }
 }
 
 
 void Source::seek(float offset, Source::Unit unit)
 void Source::seek(float offset, Source::Unit unit)
@@ -673,7 +707,7 @@ bool Source::isLooping() const
 	return looping;
 	return looping;
 }
 }
 
 
-void Source::queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels)
+bool Source::queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels)
 {
 {
 	if (type != TYPE_QUEUE)
 	if (type != TYPE_QUEUE)
 		throw QueueTypeMismatchException();
 		throw QueueTypeMismatchException();
@@ -688,41 +722,39 @@ void Source::queueData(void *data, int length, int dataSampleRate, int dataBitDe
 		throw QueueMalformedLengthException(bitDepth / 8 * channels);
 		throw QueueMalformedLengthException(bitDepth / 8 * channels);
 	
 	
 	if (length > 0)
 	if (length > 0)
-		pool->queueData(this, data, (ALsizei)length);
+		return pool->queueData(this, data, (ALsizei)length);
 }
 }
 
 
-void Source::queueDataAtomic(void *data, ALsizei length)
+bool Source::queueDataAtomic(void *data, ALsizei length)
 {
 {
 	if (valid)
 	if (valid)
 	{
 	{
 		ALuint buffer = unusedBufferPeek();
 		ALuint buffer = unusedBufferPeek();
 		if (buffer == AL_NONE)
 		if (buffer == AL_NONE)
-			return; //FIXME: out of buffer space handling?
+			return false;
 			
 			
 		alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate);
 		alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate);
 		alSourceQueueBuffers(source, 1, &buffer);
 		alSourceQueueBuffers(source, 1, &buffer);
 		unusedBufferPop();
 		unusedBufferPop();
 	}
 	}
-	else //in not valid state, queue stack is "reversed"
+	else
 	{
 	{
-		//remaining buffers are stored beyond the tip of unused stack
-		if (unusedBufferTop == MAX_BUFFERS - 1)
-			return;
+		//remaining buffers are stored beyond the tail of unused stack
+		if (unusedBufferTop >= (int)MAX_BUFFERS - 1)
+			return false;
 		
 		
-		ALuint buffer = unusedBuffers[++unusedBufferTop];
+		ALuint buffer = unusedBuffers[unusedBufferTop + 1];
 		alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate);
 		alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate);
 		//new buffer must go last, so it goes to the base of the stack
 		//new buffer must go last, so it goes to the base of the stack
-		for (unsigned int i = unusedBufferTop; i > 0; i--)
-			unusedBuffers[i] = unusedBuffers[i - 1];
-		unusedBuffers[0] = buffer;
+		unusedBufferQueue(buffer);
 	}
 	}
 	bufferedBytes += length;
 	bufferedBytes += length;
+	return true;
 }
 }
 
 
 bool Source::isQueueable() const
 bool Source::isQueueable() const
 {
 {
-	//in not valid state, queue stack is "reversed"
-	if (type != TYPE_QUEUE || (valid && unusedBufferTop < 0) || (!valid && unusedBufferTop == MAX_BUFFERS - 1))
+	if (type != TYPE_QUEUE || (valid && unusedBufferTop < 0) || (!valid && unusedBufferTop >= (int)MAX_BUFFERS - 1))
 		return false;
 		return false;
 	return true;
 	return true;
 }
 }
@@ -811,6 +843,7 @@ void Source::teardownAtomic()
 				alSourceUnqueueBuffers(source, 1, &buffer);
 				alSourceUnqueueBuffers(source, 1, &buffer);
 				unusedBufferPush(buffer);
 				unusedBufferPush(buffer);
 			}
 			}
+			
 			// put unused buffers at the end of stack
 			// put unused buffers at the end of stack
 			for (unsigned int i = 0; i < unused; i++)
 			for (unsigned int i = 0; i < unused; i++)
 				unusedBuffers[unusedBufferTop + 1 + i] = buffers[i];
 				unusedBuffers[unusedBufferTop + 1 + i] = buffers[i];
@@ -1013,6 +1046,13 @@ void Source::unusedBufferPush(ALuint buffer)
 	unusedBuffers[++unusedBufferTop] = buffer;
 	unusedBuffers[++unusedBufferTop] = buffer;
 }
 }
 
 
+void Source::unusedBufferQueue(ALuint buffer)
+{
+	for (unsigned int i = ++unusedBufferTop; i > 0; i--)
+		unusedBuffers[i] = unusedBuffers[i - 1];
+	unusedBuffers[0] = buffer;
+}
+
 int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d)
 int Source::streamAtomic(ALuint buffer, love::sound::Decoder *d)
 {
 {
 	// Get more sound data.
 	// Get more sound data.

+ 3 - 2
src/modules/audio/openal/Source.h

@@ -132,8 +132,8 @@ public:
 	virtual int getChannels() const;
 	virtual int getChannels() const;
 
 
 	virtual bool isQueueable() const;
 	virtual bool isQueueable() const;
-	virtual void queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels);
-	virtual void queueDataAtomic(void *data, ALsizei length);
+	virtual bool queueData(void *data, int length, int dataSampleRate, int dataBitDepth, int dataChannels);
+	virtual bool queueDataAtomic(void *data, ALsizei length);
 
 
 	void prepareAtomic();
 	void prepareAtomic();
 	void teardownAtomic();
 	void teardownAtomic();
@@ -167,6 +167,7 @@ private:
 	ALuint unusedBufferPeek();
 	ALuint unusedBufferPeek();
 	ALuint *unusedBufferPop();
 	ALuint *unusedBufferPop();
 	void unusedBufferPush(ALuint buffer);
 	void unusedBufferPush(ALuint buffer);
+	void unusedBufferQueue(ALuint buffer);
 	
 	
 	Pool *pool;
 	Pool *pool;
 	ALuint source;
 	ALuint source;

+ 6 - 4
src/modules/audio/wrap_Audio.cpp

@@ -47,18 +47,20 @@ int w_newSource(lua_State *L)
 	Source *t = 0;
 	Source *t = 0;
 	
 	
 	if (lua_isnumber(L, 1) && lua_isnumber(L, 2) && lua_isnumber(L, 3))
 	if (lua_isnumber(L, 1) && lua_isnumber(L, 2) && lua_isnumber(L, 3))
-		t = instance()->newSource((int)lua_tonumber(L, 1), (int)lua_tonumber(L, 2), (int)lua_tonumber(L, 3));
+		luax_catchexcept(L, [&]() {
+			t = instance()->newSource((int)lua_tonumber(L, 1), (int)lua_tonumber(L, 2), (int)lua_tonumber(L, 3));
+		});
 	else
 	else
 	{
 	{
-		if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_ID) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_ID))
-			luax_convobj(L, 1, "sound", "newDecoder");
-
 		Source::Type stype = Source::TYPE_STREAM;
 		Source::Type stype = Source::TYPE_STREAM;
 
 
 		const char *stypestr = lua_isnoneornil(L, 2) ? 0 : lua_tostring(L, 2);
 		const char *stypestr = lua_isnoneornil(L, 2) ? 0 : lua_tostring(L, 2);
 		if (stypestr && !Source::getConstant(stypestr, stype))
 		if (stypestr && !Source::getConstant(stypestr, stype))
 			return luaL_error(L, "Invalid source type: %s", stypestr);
 			return luaL_error(L, "Invalid source type: %s", stypestr);
 
 
+		if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_ID) || luax_istype(L, 1, FILESYSTEM_FILE_DATA_ID))
+			luax_convobj(L, 1, "sound", "newDecoder");
+
 		if (stype == Source::TYPE_STATIC && luax_istype(L, 1, SOUND_DECODER_ID))
 		if (stype == Source::TYPE_STATIC && luax_istype(L, 1, SOUND_DECODER_ID))
 			luax_convobj(L, 1, "sound", "newSoundData");
 			luax_convobj(L, 1, "sound", "newSoundData");
 			
 			

+ 5 - 2
src/modules/audio/wrap_Source.cpp

@@ -340,22 +340,25 @@ int w_Source_isQueueable(lua_State *L)
 int w_Source_queueData(lua_State *L)
 int w_Source_queueData(lua_State *L)
 {
 {
 	Source *t = luax_checksource(L, 1);
 	Source *t = luax_checksource(L, 1);
+	bool success;
+	
 	luax_catchexcept(L, [&]() {
 	luax_catchexcept(L, [&]() {
 		if (luax_istype(L, 2, SOUND_SOUND_DATA_ID))
 		if (luax_istype(L, 2, SOUND_SOUND_DATA_ID))
 		{
 		{
 			love::sound::SoundData *s = luax_totype<love::sound::SoundData>(L, 2, SOUND_SOUND_DATA_ID);
 			love::sound::SoundData *s = luax_totype<love::sound::SoundData>(L, 2, SOUND_SOUND_DATA_ID);
-			t->queueData(s->getData(), lua_isnumber(L, 3) ? (int)lua_tonumber(L, 3) : s->getSize(), s->getSampleRate(), s->getBitDepth(), s->getChannels());
+			success = t->queueData(s->getData(), lua_isnumber(L, 3) ? (int)lua_tonumber(L, 3) : s->getSize(), s->getSampleRate(), s->getBitDepth(), s->getChannels());
 		}
 		}
 		else if (lua_islightuserdata(L, 2))
 		else if (lua_islightuserdata(L, 2))
 		{
 		{
 			if (lua_isnumber(L, 4) && lua_isnumber(L, 5) && lua_isnumber(L, 6))
 			if (lua_isnumber(L, 4) && lua_isnumber(L, 5) && lua_isnumber(L, 6))
-				t->queueData(lua_touserdata(L, 2), (int)lua_tonumber(L, 3), (int)lua_tonumber(L, 4), (int)lua_tonumber(L, 5), (int)lua_tonumber(L, 6));
+				success = t->queueData(lua_touserdata(L, 2), (int)lua_tonumber(L, 3), (int)lua_tonumber(L, 4), (int)lua_tonumber(L, 5), (int)lua_tonumber(L, 6));
 			else
 			else
 				return luaL_error(L, "No format specified.");
 				return luaL_error(L, "No format specified.");
 		}
 		}
 		else
 		else
 			return luaL_error(L, "Invalid data type.");
 			return luaL_error(L, "Invalid data type.");
 	});
 	});
+	luax_pushboolean(L, success);
 	return 1;
 	return 1;
 }
 }