aboutsummaryrefslogtreecommitdiffstats
path: root/OpenAL32
diff options
context:
space:
mode:
Diffstat (limited to 'OpenAL32')
-rw-r--r--OpenAL32/Include/alSource.h24
-rw-r--r--OpenAL32/alSource.c191
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;
}