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
This commit is contained in:
raidho36
2016-10-12 18:53:49 +03:00
parent 7934bfaf7f
commit 10710d3428
9 changed files with 91 additions and 45 deletions
+1 -1
View File
@@ -103,7 +103,7 @@ public:
virtual int getChannels() 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;
+2 -2
View File
@@ -222,9 +222,9 @@ bool Source::isQueueable() const
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
View File
@@ -77,7 +77,7 @@ public:
virtual int getChannels() 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:
+2 -2
View File
@@ -283,10 +283,10 @@ double Pool::getDuration(Source *source, void *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);
source->queueDataAtomic(data, length);
return source->queueDataAtomic(data, length);
}
ALuint Pool::findi(const Source *source) const
+1 -1
View File
@@ -91,7 +91,7 @@ public:
void seek(Source *source, float offset, void *unit);
float tell(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);
void stop(const std::vector<love::audio::Source*> &sources);
+70 -30
View File
@@ -390,7 +390,6 @@ bool Source::update()
bufferedBytes -= size;
unusedBufferPush(buffers[i]);
}
return !isFinished();
}
}
@@ -442,12 +441,6 @@ float Source::getVolume() const
void Source::seekAtomic(float offset, void *unit)
{
bool wasPlaying = isPlaying();
// To drain all buffers
if (valid && type == TYPE_STREAM)
stopAtomic();
switch (*((Source::Unit *) unit))
{
case Source::UNIT_SAMPLES:
@@ -460,17 +453,58 @@ void Source::seekAtomic(float offset, void *unit)
offsetSamples = offset * sampleRate;
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)
@@ -673,7 +707,7 @@ bool Source::isLooping() const
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)
throw QueueTypeMismatchException();
@@ -688,41 +722,39 @@ void Source::queueData(void *data, int length, int dataSampleRate, int dataBitDe
throw QueueMalformedLengthException(bitDepth / 8 * channels);
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)
{
ALuint buffer = unusedBufferPeek();
if (buffer == AL_NONE)
return; //FIXME: out of buffer space handling?
return false;
alBufferData(buffer, getFormat(channels, bitDepth), data, length, sampleRate);
alSourceQueueBuffers(source, 1, &buffer);
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);
//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;
return true;
}
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 true;
}
@@ -811,6 +843,7 @@ void Source::teardownAtomic()
alSourceUnqueueBuffers(source, 1, &buffer);
unusedBufferPush(buffer);
}
// put unused buffers at the end of stack
for (unsigned int i = 0; i < unused; i++)
unusedBuffers[unusedBufferTop + 1 + i] = buffers[i];
@@ -1013,6 +1046,13 @@ void Source::unusedBufferPush(ALuint 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)
{
// Get more sound data.
+3 -2
View File
@@ -132,8 +132,8 @@ public:
virtual int getChannels() 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 teardownAtomic();
@@ -167,6 +167,7 @@ private:
ALuint unusedBufferPeek();
ALuint *unusedBufferPop();
void unusedBufferPush(ALuint buffer);
void unusedBufferQueue(ALuint buffer);
Pool *pool;
ALuint source;
+6 -4
View File
@@ -47,18 +47,20 @@ int w_newSource(lua_State *L)
Source *t = 0;
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
{
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;
const char *stypestr = lua_isnoneornil(L, 2) ? 0 : lua_tostring(L, 2);
if (stypestr && !Source::getConstant(stypestr, stype))
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))
luax_convobj(L, 1, "sound", "newSoundData");
+5 -2
View File
@@ -340,22 +340,25 @@ int w_Source_isQueueable(lua_State *L)
int w_Source_queueData(lua_State *L)
{
Source *t = luax_checksource(L, 1);
bool success;
luax_catchexcept(L, [&]() {
if (luax_istype(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))
{
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
return luaL_error(L, "No format specified.");
}
else
return luaL_error(L, "Invalid data type.");
});
luax_pushboolean(L, success);
return 1;
}