aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2014-05-10 05:07:13 -0700
committerChris Robinson <[email protected]>2014-05-10 05:07:13 -0700
commita45570414847a359fab317e2ff4929c41a4af431 (patch)
tree9473e57c11708107ac5aafd3adbfd284d1f95d91
parenteebde08e65ea8f2c3200308d8db1e031a0d80273 (diff)
Use a RWLock to help protect the source's buffer queue
In some instances this allows to to remove the device/mixer lock, or reduce how long it's held.
-rw-r--r--OpenAL32/Include/alSource.h1
-rw-r--r--OpenAL32/alSource.c91
-rw-r--r--OpenAL32/alState.c4
3 files changed, 61 insertions, 35 deletions
diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h
index d49120b8..85a7a838 100644
--- a/OpenAL32/Include/alSource.h
+++ b/OpenAL32/Include/alSource.h
@@ -98,6 +98,7 @@ typedef struct ALsource {
/** Source Buffer Queue info. */
ALbufferlistitem *queue;
ALbufferlistitem *current_buffer;
+ RWLock queue_lock;
/** Current buffer sample info. */
ALuint NumChannels;
diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c
index 1e221c73..8a578a5e 100644
--- a/OpenAL32/alSource.c
+++ b/OpenAL32/alSource.c
@@ -152,9 +152,9 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp
static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
-static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
-static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
-static ALboolean GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
+static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
+static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
+static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
static ALint FloatValsByProp(ALenum prop)
{
@@ -572,10 +572,10 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
case AL_BUFFER:
CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL);
- LockContext(Context);
+ WriteLock(&Source->queue_lock);
if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL))
{
- UnlockContext(Context);
+ WriteUnlock(&Source->queue_lock);
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
}
@@ -606,6 +606,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
}
Source->current_buffer = Source->queue;
+ WriteUnlock(&Source->queue_lock);
/* Delete all elements in the previous queue */
while(oldlist != NULL)
@@ -617,7 +618,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
DecrementRef(&temp->buffer->ref);
free(temp);
}
- UnlockContext(Context);
return AL_TRUE;
case siSourceState:
@@ -853,7 +853,7 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp
#undef CHECKVAL
-static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
+static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
{
ALdouble offsets[2];
ALdouble updateLen;
@@ -905,11 +905,11 @@ static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFlo
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
+ ReadLock(&Source->queue_lock);
LockContext(Context);
- updateLen = (ALdouble)Context->Device->UpdateSize /
- Context->Device->Frequency;
- GetSourceOffsets(Source, prop, offsets, updateLen);
+ GetSourceOffsets(Source, prop, offsets, 0.0);
UnlockContext(Context);
+ ReadUnlock(&Source->queue_lock);
*values = offsets[0];
return AL_TRUE;
@@ -931,19 +931,23 @@ static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFlo
case AL_SAMPLE_RW_OFFSETS_SOFT:
case AL_BYTE_RW_OFFSETS_SOFT:
+ ReadLock(&Source->queue_lock);
LockContext(Context);
updateLen = (ALdouble)Context->Device->UpdateSize /
Context->Device->Frequency;
GetSourceOffsets(Source, prop, values, updateLen);
UnlockContext(Context);
+ ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_SEC_OFFSET_LATENCY_SOFT:
+ ReadLock(&Source->queue_lock);
LockContext(Context);
values[0] = GetSourceSecOffset(Source);
values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
1000000000.0;
UnlockContext(Context);
+ ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_POSITION:
@@ -991,7 +995,7 @@ static ALboolean GetSourcedv(const ALsource *Source, ALCcontext *Context, SrcFlo
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
+static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
{
ALbufferlistitem *BufferList;
ALdouble dvals[3];
@@ -1008,11 +1012,11 @@ static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcInt
return AL_TRUE;
case AL_BUFFER:
- LockContext(Context);
+ ReadLock(&Source->queue_lock);
BufferList = (Source->SourceType == AL_STATIC) ? Source->queue :
Source->current_buffer;
*values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
- UnlockContext(Context);
+ ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_SOURCE_STATE:
@@ -1020,7 +1024,7 @@ static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcInt
return AL_TRUE;
case AL_BUFFERS_QUEUED:
- LockContext(Context);
+ ReadLock(&Source->queue_lock);
if(!(BufferList=Source->queue))
*values = 0;
else
@@ -1031,11 +1035,11 @@ static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcInt
} while((BufferList=BufferList->next) != NULL);
*values = count;
}
- UnlockContext(Context);
+ ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_BUFFERS_PROCESSED:
- LockContext(Context);
+ ReadLock(&Source->queue_lock);
if(Source->Looping || Source->SourceType != AL_STREAMING)
{
/* Buffers on a looping source are in a perpetual state of
@@ -1053,7 +1057,7 @@ static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcInt
}
*values = played;
}
- UnlockContext(Context);
+ ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_SOURCE_TYPE:
@@ -1127,7 +1131,7 @@ static ALboolean GetSourceiv(const ALsource *Source, ALCcontext *Context, SrcInt
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALboolean GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
+static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
{
ALdouble dvals[3];
ALint ivals[3];
@@ -1136,10 +1140,12 @@ static ALboolean GetSourcei64v(const ALsource *Source, ALCcontext *Context, SrcI
switch(prop)
{
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ ReadLock(&Source->queue_lock);
LockContext(Context);
values[0] = GetSourceOffset(Source);
values[1] = ALCdevice_GetLatency(Context->Device);
UnlockContext(Context);
+ ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_MAX_DISTANCE:
@@ -2064,10 +2070,10 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu
if((source=LookupSource(context, src)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- LockContext(context);
+ WriteLock(&source->queue_lock);
if(source->SourceType == AL_STATIC)
{
- UnlockContext(context);
+ WriteUnlock(&source->queue_lock);
/* Can't queue on a Static Source */
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
@@ -2084,12 +2090,14 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu
BufferList = BufferList->next;
}
+ LockContext(context);
for(i = 0;i < nb;i++)
{
ALbuffer *buffer = NULL;
if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL)
{
UnlockContext(context);
+ WriteUnlock(&source->queue_lock);
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
}
@@ -2126,6 +2134,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu
{
ReadUnlock(&buffer->lock);
UnlockContext(context);
+ WriteUnlock(&source->queue_lock);
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
ReadUnlock(&buffer->lock);
@@ -2151,6 +2160,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu
BufferListStart = NULL;
UnlockContext(context);
+ WriteUnlock(&source->queue_lock);
done:
while(BufferListStart)
@@ -2185,7 +2195,8 @@ 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);
- LockContext(context);
+ WriteLock(&source->queue_lock);
+ /* Find the new buffer queue head */
BufferList = source->queue;
for(i = 0;i < nb && BufferList;i++)
{
@@ -2195,29 +2206,37 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint
}
if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
{
- UnlockContext(context);
+ WriteUnlock(&source->queue_lock);
/* Trying to unqueue pending buffers, or a buffer that wasn't queued. */
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
}
- for(i = 0;i < nb;i++)
+ /* Swap it, and cut the new head from the old. */
+ BufferList = ExchangePtr((XchgPtr*)&source->queue, BufferList);
+ if(source->queue)
{
- BufferList = source->queue;
- source->queue = BufferList->next;
+ LockContext(context);
+ source->queue->prev->next = NULL;
+ source->queue->prev = NULL;
+ UnlockContext(context);
+ }
+ WriteUnlock(&source->queue_lock);
- if(BufferList->buffer)
+ for(i = 0;BufferList != NULL;i++)
+ {
+ ALbufferlistitem *next = BufferList->next;
+
+ if(!BufferList->buffer)
+ buffers[i] = 0;
+ else
{
buffers[i] = BufferList->buffer->id;
DecrementRef(&BufferList->buffer->ref);
}
- else
- buffers[i] = 0;
free(BufferList);
+ BufferList = next;
}
- if(source->queue)
- source->queue->prev = NULL;
- UnlockContext(context);
done:
ALCcontext_DecRef(context);
@@ -2228,6 +2247,8 @@ static ALvoid InitSourceParams(ALsource *Source)
{
ALuint i;
+ RWLockInit(&Source->queue_lock);
+
Source->InnerAngle = 360.0f;
Source->OuterAngle = 360.0f;
Source->Pitch = 1.0f;
@@ -2285,6 +2306,7 @@ static ALvoid InitSourceParams(ALsource *Source)
*/
ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
{
+ ReadLock(&Source->queue_lock);
if(state == AL_PLAYING)
{
ALCdevice *device = Context->Device;
@@ -2320,10 +2342,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
/* If there's nothing to play, or device is disconnected, go right to
* stopped */
if(!BufferList || !device->Connected)
- {
- SetSourceState(Source, Context, AL_STOPPED);
- return;
- }
+ goto do_stop;
for(j = 0;j < Context->ActiveSourceCount;j++)
{
@@ -2381,6 +2400,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
}
else if(state == AL_STOPPED)
{
+ do_stop:
if(Source->state != AL_INITIAL)
{
Source->state = AL_STOPPED;
@@ -2399,6 +2419,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
}
Source->Offset = -1.0;
}
+ ReadUnlock(&Source->queue_lock);
}
/* GetSourceOffset
diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c
index c6deda46..d499fcd1 100644
--- a/OpenAL32/alState.c
+++ b/OpenAL32/alState.c
@@ -784,7 +784,11 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
Source->Offset >= 0.0)
+ {
+ ReadLock(&Source->queue_lock);
ApplyOffset(Source);
+ ReadUnlock(&Source->queue_lock);
+ }
new_state = ExchangeInt(&Source->new_state, AL_NONE);
if(new_state)