mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user