diff options
author | Chris Robinson <[email protected]> | 2017-02-27 15:35:15 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2017-02-27 15:35:15 -0800 |
commit | 5c859af24ea44dabbbb31631309bb08a858a523e (patch) | |
tree | 5713cdb318c1d9869e4b2e24d0f415ec0c89fd71 /OpenAL32 | |
parent | 513c18fdc4d0d9184e061570209eb59f4ad0e392 (diff) |
Move the current buffer queue entry and play position to the voice
This has a couple behavioral changes. First and biggest is that querying
AL_BUFFERS_PROCESSED from a source will always return all buffers processed
when in an AL_STOPPED state. Previously all buffers would be set as processed
when first becoming stopped, but newly queued buffers would *not* be indicated
as processed. That old behavior was not compliant with the spec, which
unequivocally states "On a source in the AL_STOPPED state, all buffers are
processed."
Secondly, querying AL_BUFFER on an AL_STREAMING source will now always return
0. Previously it would return the current "active" buffer in the queue, but
there's no basis for that in the spec.
Diffstat (limited to 'OpenAL32')
-rw-r--r-- | OpenAL32/Include/alSource.h | 24 | ||||
-rw-r--r-- | OpenAL32/alSource.c | 191 |
2 files changed, 113 insertions, 102 deletions
diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 6282939e..f8a32f71 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -81,6 +81,17 @@ typedef struct ALvoice { struct ALsource *Source; + /* Current buffer queue item being played. */ + ATOMIC(ALbufferlistitem*) current_buffer; + + /** + * Source offset in samples, relative to the currently playing buffer, NOT + * the whole queue, and the fractional (fixed-point) offset to the next + * sample. + */ + ATOMIC(ALuint) position; + ATOMIC(ALuint) position_fraction; + /** Current target parameters used for mixing. */ ALint Step; @@ -178,18 +189,9 @@ typedef struct ALsource { ATOMIC(ALenum) state; ALenum new_state; - /** Source Buffer Queue info. */ + /** Source Buffer Queue head. */ RWLock queue_lock; ATOMIC(ALbufferlistitem*) queue; - ATOMIC(ALbufferlistitem*) current_buffer; - - /** - * Source offset in samples, relative to the currently playing buffer, NOT - * the whole queue, and the fractional (fixed-point) offset to the next - * sample. - */ - ATOMIC(ALuint) position; - ATOMIC(ALuint) position_fraction; ATOMIC(ALboolean) looping; @@ -222,7 +224,7 @@ inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) void UpdateAllSourceProps(ALCcontext *context); ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); -ALboolean ApplyOffset(ALsource *Source); +ALboolean ApplyOffset(ALsource *Source, ALvoice *voice); inline ALboolean IsPlayingOrPaused(const ALsource *source) { diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 1fc2c5bd..b8345e04 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -51,9 +51,9 @@ extern inline ALboolean IsPlayingOrPaused(const ALsource *source); static void InitSourceParams(ALsource *Source, ALsizei num_sends); static void DeinitSource(ALsource *source, ALsizei num_sends); static void UpdateSourceProps(ALsource *source, ALsizei num_sends); -static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); -static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime); -static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device); +static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); +static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime); +static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context); static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); typedef enum SourceProp { @@ -531,17 +531,20 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(IsPlayingOrPausedSeq(Source) && - !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) + if(!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire) && + IsPlayingOrPausedSeq(Source)) { + ALvoice *voice; + ALCdevice_Lock(Context->Device); /* Double-check that the source is still playing while we have * the lock. */ - if(IsPlayingOrPaused(Source)) + voice = GetSourceVoice(Source, Context); + if(voice) { WriteLock(&Source->queue_lock); - if(ApplyOffset(Source) == AL_FALSE) + if(ApplyOffset(Source, voice) == AL_FALSE) { WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); @@ -714,7 +717,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p newlist = NULL; } oldlist = ATOMIC_EXCHANGE_SEQ(ALbufferlistitem*, &Source->queue, newlist); - ATOMIC_STORE_SEQ(&Source->current_buffer, newlist); WriteUnlock(&Source->queue_lock); UnlockBuffersRead(device); @@ -738,14 +740,17 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p Source->OffsetType = prop; Source->Offset = *values; - if(IsPlayingOrPausedSeq(Source) && - !ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire)) + if(!ATOMIC_LOAD(&Context->DeferUpdates, almemory_order_acquire) && + IsPlayingOrPausedSeq(Source)) { + ALvoice *voice; + ALCdevice_Lock(Context->Device); - if(IsPlayingOrPaused(Source)) + voice = GetSourceVoice(Source, Context); + if(voice) { WriteLock(&Source->queue_lock); - if(ApplyOffset(Source) == AL_FALSE) + if(ApplyOffset(Source, voice) == AL_FALSE) { WriteUnlock(&Source->queue_lock); ALCdevice_Unlock(Context->Device); @@ -1091,7 +1096,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: - *values = GetSourceOffset(Source, prop, device); + *values = GetSourceOffset(Source, prop, Context); return AL_TRUE; case AL_CONE_OUTER_GAINHF: @@ -1144,7 +1149,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp p /* Get the source offset with the clock time first. Then get the * clock time with the device latency. Order is important. */ - values[0] = GetSourceSecOffset(Source, device, &srcclock); + values[0] = GetSourceSecOffset(Source, Context, &srcclock); clocktime = V0(device->Backend,getClockLatency)(); if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = (ALdouble)clocktime.Latency / 1000000000.0; @@ -1235,8 +1240,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p case AL_BUFFER: ReadLock(&Source->queue_lock); BufferList = (Source->SourceType == AL_STATIC) ? - ATOMIC_LOAD_SEQ(&Source->queue) : - ATOMIC_LOAD_SEQ(&Source->current_buffer); + ATOMIC_LOAD_SEQ(&Source->queue) : NULL; *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0; ReadUnlock(&Source->queue_lock); return AL_TRUE; @@ -1326,8 +1330,15 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp p else { const ALbufferlistitem *BufferList = ATOMIC_LOAD_SEQ(&Source->queue); - const ALbufferlistitem *Current = ATOMIC_LOAD_SEQ(&Source->current_buffer); + const ALbufferlistitem *Current = NULL; ALsizei played = 0; + ALvoice *voice; + + if((voice=GetSourceVoice(Source, Context)) != NULL) + Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); + else if(ATOMIC_LOAD_SEQ(&Source->state) == AL_INITIAL) + Current = BufferList; + while(BufferList && BufferList != Current) { played++; @@ -1442,7 +1453,7 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp /* Get the source offset with the clock time first. Then get the * clock time with the device latency. Order is important. */ - values[0] = GetSourceSampleOffset(Source, device, &srcclock); + values[0] = GetSourceSampleOffset(Source, Context, &srcclock); clocktime = V0(device->Backend,getClockLatency)(); if(srcclock == (ALuint64)clocktime.ClockTime) values[1] = clocktime.Latency; @@ -2606,12 +2617,6 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu BufferList = BufferList->next; BufferList->next = BufferListStart; } - /* If the current buffer was at the end (NULL), put it at the start of the newly queued - * buffers. - */ - BufferList = NULL; - ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(ALbufferlistitem*, &source->current_buffer, - &BufferList, BufferListStart); WriteUnlock(&source->queue_lock); done: @@ -2626,11 +2631,9 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint ALbufferlistitem *OldHead; ALbufferlistitem *OldTail; ALbufferlistitem *Current; + ALvoice *voice; ALsizei i = 0; - if(nb == 0) - return; - context = GetContextRef(); if(!context) return; @@ -2641,6 +2644,9 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint if((source=LookupSource(context, src)) == NULL) SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); + /* Nothing to unqueue. */ + if(nb == 0) goto done; + WriteLock(&source->queue_lock); if(ATOMIC_LOAD_SEQ(&source->looping) || source->SourceType != AL_STREAMING) { @@ -2651,7 +2657,11 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint /* Find the new buffer queue head */ OldTail = ATOMIC_LOAD_SEQ(&source->queue); - Current = ATOMIC_LOAD_SEQ(&source->current_buffer); + Current = NULL; + if((voice=GetSourceVoice(source, context)) != NULL) + Current = ATOMIC_LOAD_SEQ(&voice->current_buffer); + else if(ATOMIC_LOAD_SEQ(&source->state) == AL_INITIAL) + Current = OldTail; if(OldTail != Current) { for(i = 1;i < nb;i++) @@ -2782,10 +2792,6 @@ static void InitSourceParams(ALsource *Source, ALsizei num_sends) Source->new_state = AL_NONE; ATOMIC_INIT(&Source->queue, NULL); - ATOMIC_INIT(&Source->current_buffer, NULL); - - ATOMIC_INIT(&Source->position, 0); - ATOMIC_INIT(&Source->position_fraction, 0); ATOMIC_INIT(&Source->looping, AL_FALSE); @@ -2987,29 +2993,22 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) switch(ATOMIC_EXCHANGE(ALenum, &Source->state, AL_PLAYING, almemory_order_acq_rel)) { case AL_PLAYING: + assert(voice != NULL); /* A source that's already playing is restarted. */ - ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); /* fall-through */ case AL_PAUSED: + assert(voice != NULL); /* A source that's paused simply resumes. Make sure it uses the * volume last specified; there's no reason to fade from where * it stopped at. */ - assert(voice != NULL); voice->Moving = AL_FALSE; goto done; default: - /* A source that's not playing or paused has its offset - * applied, and then starts playing. - */ - ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); - ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, 0, almemory_order_release); - if(Source->OffsetType != AL_NONE) - ApplyOffset(Source); break; } @@ -3032,6 +3031,15 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice->Source = Source; } + /* A source that's not playing or paused has any offset applied when it + * starts playing. + */ + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, 0, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, 0, almemory_order_release); + if(Source->OffsetType != AL_NONE) + ApplyOffset(Source, voice); + /* Clear previous samples. */ memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); @@ -3067,10 +3075,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice = GetSourceVoice(Source, Context); if(voice) voice->Source = NULL; if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) - { ATOMIC_STORE(&Source->state, AL_STOPPED, almemory_order_relaxed); - ATOMIC_STORE_SEQ(&Source->current_buffer, NULL); - } Source->OffsetType = AL_NONE; Source->Offset = 0.0; } @@ -3079,13 +3084,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) voice = GetSourceVoice(Source, Context); if(voice) voice->Source = NULL; if(ATOMIC_LOAD(&Source->state, almemory_order_acquire) != AL_INITIAL) - { ATOMIC_STORE(&Source->state, AL_INITIAL, almemory_order_relaxed); - ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD_SEQ(&Source->queue), - almemory_order_relaxed); - ATOMIC_STORE(&Source->position, 0, almemory_order_relaxed); - ATOMIC_STORE_SEQ(&Source->position_fraction, 0); - } Source->OffsetType = AL_NONE; Source->Offset = 0.0; } @@ -3099,42 +3098,49 @@ done: * samples. The offset is relative to the start of the queue (not the start of * the current buffer). */ -static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime) +static ALint64 GetSourceSampleOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) { + ALCdevice *device = context->Device; const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; ALuint64 readPos; ALuint refcount; + ALvoice *voice; ReadLock(&Source->queue_lock); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); do { - BufferList = Current = NULL; + Current = NULL; readPos = 0; while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - if(IsPlayingOrPaused(Source)) + voice = GetSourceVoice(Source, context); + if(voice) { - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << 32; - readPos |= ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed) << + readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << 32; + readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed) << (32-FRACTIONBITS); } ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - while(BufferList && BufferList != Current) + if(voice) { - if(BufferList->buffer) - readPos += (ALuint64)BufferList->buffer->SampleLen << 32; - BufferList = BufferList->next; + while(BufferList && BufferList != Current) + { + if(BufferList->buffer) + readPos += (ALuint64)BufferList->buffer->SampleLen << 32; + BufferList = BufferList->next; + } + readPos = minu64(readPos, U64(0x7fffffffffffffff)); } ReadUnlock(&Source->queue_lock); - return (ALint64)minu64(readPos, U64(0x7fffffffffffffff)); + return (ALint64)readPos; } /* GetSourceSecOffset @@ -3142,37 +3148,39 @@ static ALint64 GetSourceSampleOffset(ALsource *Source, ALCdevice *device, ALuint * Gets the current read offset for the given Source, in seconds. The offset is * relative to the start of the queue (not the start of the current buffer). */ -static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 *clocktime) +static ALdouble GetSourceSecOffset(ALsource *Source, ALCcontext *context, ALuint64 *clocktime) { + ALCdevice *device = context->Device; const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; ALuint64 readPos; ALuint refcount; ALdouble offset; + ALvoice *voice; ReadLock(&Source->queue_lock); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); do { - BufferList = Current = NULL; + Current = NULL; readPos = 0; while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); *clocktime = GetDeviceClockTime(device); - if(IsPlayingOrPaused(Source)) + voice = GetSourceVoice(Source, context); + if(voice) { - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - readPos = (ALuint64)ATOMIC_LOAD(&Source->position, almemory_order_relaxed) << + readPos = (ALuint64)ATOMIC_LOAD(&voice->position, almemory_order_relaxed) << FRACTIONBITS; - readPos |= ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + readPos |= ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); } ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - if(!Current) - offset = 0.0; - else + offset = 0.0; + if(voice) { const ALbuffer *Buffer = NULL; while(BufferList && BufferList != Current) @@ -3207,8 +3215,9 @@ static ALdouble GetSourceSecOffset(ALsource *Source, ALCdevice *device, ALuint64 * (Bytes, Samples or Seconds). The offset is relative to the start of the * queue (not the start of the current buffer). */ -static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device) +static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCcontext *context) { + ALCdevice *device = context->Device; const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; const ALbuffer *Buffer = NULL; @@ -3218,25 +3227,26 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device ALboolean looping; ALuint refcount; ALdouble offset; - ALenum state; + ALvoice *voice; ReadLock(&Source->queue_lock); + BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); + looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); do { while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1)) althrd_yield(); - state = ATOMIC_LOAD(&Source->state, almemory_order_relaxed); - - BufferList = ATOMIC_LOAD(&Source->queue, almemory_order_relaxed); - Current = ATOMIC_LOAD(&Source->current_buffer, almemory_order_relaxed); - - readPos = ATOMIC_LOAD(&Source->position, almemory_order_relaxed); - readPosFrac = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed); + voice = GetSourceVoice(Source, context); + if(voice) + { + Current = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed); - looping = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed); + readPos = ATOMIC_LOAD(&voice->position, almemory_order_relaxed); + readPosFrac = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed); + } ATOMIC_THREAD_FENCE(almemory_order_acquire); } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed)); - if(state != AL_PLAYING && state != AL_PAUSED) + if(!voice) { ReadUnlock(&Source->queue_lock); return 0.0; @@ -3314,7 +3324,7 @@ static ALdouble GetSourceOffset(ALsource *Source, ALenum name, ALCdevice *device * Apply the stored playback offset to the Source. This function will update * the number of buffers "played" given the stored offset. */ -ALboolean ApplyOffset(ALsource *Source) +ALboolean ApplyOffset(ALsource *Source, ALvoice *voice) { ALbufferlistitem *BufferList; const ALbuffer *Buffer; @@ -3335,10 +3345,9 @@ ALboolean ApplyOffset(ALsource *Source) if(bufferLen > offset-totalBufferLen) { /* Offset is in this buffer */ - ATOMIC_STORE(&Source->current_buffer, BufferList, almemory_order_relaxed); - - ATOMIC_STORE(&Source->position, offset - totalBufferLen, almemory_order_relaxed); - ATOMIC_STORE(&Source->position_fraction, frac, almemory_order_release); + ATOMIC_STORE(&voice->current_buffer, BufferList, almemory_order_relaxed); + ATOMIC_STORE(&voice->position, offset - totalBufferLen, almemory_order_relaxed); + ATOMIC_STORE(&voice->position_fraction, frac, almemory_order_release); return AL_TRUE; } |