aboutsummaryrefslogtreecommitdiffstats
path: root/OpenAL32/alSource.c
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2018-02-24 09:24:18 -0800
committerChris Robinson <[email protected]>2018-02-24 09:24:18 -0800
commita1ef5e38b6ee6db718fa7652d7831d2f86ec6b1c (patch)
tree4e857865010f24f010d4b264a5aa71fb8cb2b0a3 /OpenAL32/alSource.c
parent14bdc6c2ef295dd4c7a22faab1e834def125177d (diff)
Handle source state change events
Diffstat (limited to 'OpenAL32/alSource.c')
-rw-r--r--OpenAL32/alSource.c67
1 files changed, 56 insertions, 11 deletions
diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c
index 2323da3e..bb3a62c3 100644
--- a/OpenAL32/alSource.c
+++ b/OpenAL32/alSource.c
@@ -32,6 +32,7 @@
#include "alSource.h"
#include "alBuffer.h"
#include "alAuxEffectSlot.h"
+#include "ringbuffer.h"
#include "backends/base.h"
@@ -232,6 +233,36 @@ static inline bool SourceShouldUpdate(ALsource *source, ALCcontext *context)
IsPlayingOrPaused(source);
}
+
+/** Can only be called while the mixer is locked! */
+static void SendStateChangeEvent(ALCcontext *context, ALuint id, ALenum state)
+{
+ ALbitfieldSOFT enabledevt;
+ AsyncEvent evt;
+
+ enabledevt = ATOMIC_LOAD(&context->EnabledEvts, almemory_order_acquire);
+ if(!(enabledevt&EventType_SourceStateChange)) return;
+
+ evt.EnumType = EventType_SourceStateChange;
+ evt.Type = AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT;
+ evt.ObjectId = id;
+ evt.Param = state;
+ snprintf(evt.Message, sizeof(evt.Message), "Source ID %u state changed to %s", id,
+ (state==AL_INITIAL) ? "AL_INITIAL" :
+ (state==AL_PLAYING) ? "AL_PLAYING" :
+ (state==AL_PAUSED) ? "AL_PAUSED" :
+ (state==AL_STOPPED) ? "AL_STOPPED" : "<unknown>"
+ );
+ /* The mixer may have queued a state change that's not yet been processed,
+ * and we don't want state change messages to occur out of order, so send
+ * it through the async queue to ensure proper ordering.
+ */
+ if(ll_ringbuffer_write_space(context->AsyncEvents) > 0)
+ ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1);
+ alsem_post(&context->EventSem);
+}
+
+
static ALint FloatValsByProp(ALenum prop)
{
if(prop != (ALenum)((SourceProp)prop))
@@ -2396,10 +2427,13 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
/* If the device is disconnected, go right to stopped. */
if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
{
+ /* TODO: Send state change event? */
for(i = 0;i < n;i++)
{
source = LookupSource(context, sources[i]);
ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
+ source->OffsetType = AL_NONE;
+ source->Offset = 0.0;
}
ALCdevice_Unlock(device);
goto done;
@@ -2443,15 +2477,18 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
}
/* If there's nothing to play, go right to stopped. */
- if(!BufferList)
+ if(UNLIKELY(!BufferList))
{
/* NOTE: A source without any playable buffers should not have an
* ALvoice since it shouldn't be in a playing or paused state. So
* there's no need to look up its voice and clear the source.
*/
+ ALenum oldstate = GetSourceState(source, NULL);
ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
source->OffsetType = AL_NONE;
source->Offset = 0.0;
+ if(oldstate != AL_STOPPED)
+ SendStateChangeEvent(context, source->id, AL_STOPPED);
continue;
}
@@ -2471,6 +2508,7 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
/* A source that's paused simply resumes. */
ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
+ SendStateChangeEvent(context, source->id, AL_PLAYING);
continue;
default:
@@ -2543,6 +2581,8 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
ATOMIC_STORE(&voice->Playing, true, almemory_order_release);
ATOMIC_STORE(&source->state, AL_PLAYING, almemory_order_release);
source->VoiceIdx = vidx;
+
+ SendStateChangeEvent(context, source->id, AL_PLAYING);
}
ALCdevice_Unlock(device);
@@ -2581,13 +2621,12 @@ AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
{
source = LookupSource(context, sources[i]);
if((voice=GetSourceVoice(source, context)) != NULL)
- {
ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
- while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
- althrd_yield();
- }
if(GetSourceState(source, voice) == AL_PLAYING)
+ {
ATOMIC_STORE(&source->state, AL_PAUSED, almemory_order_release);
+ SendStateChangeEvent(context, source->id, AL_PAUSED);
+ }
}
ALCdevice_Unlock(device);
@@ -2624,16 +2663,20 @@ AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
ALCdevice_Lock(device);
for(i = 0;i < n;i++)
{
+ ALenum oldstate;
source = LookupSource(context, sources[i]);
if((voice=GetSourceVoice(source, context)) != NULL)
{
ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
- while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
- althrd_yield();
+ voice = NULL;
}
- if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
+ oldstate = GetSourceState(source, voice);
+ if(oldstate != AL_INITIAL && oldstate != AL_STOPPED)
+ {
ATOMIC_STORE(&source->state, AL_STOPPED, almemory_order_relaxed);
+ SendStateChangeEvent(context, source->id, AL_STOPPED);
+ }
source->OffsetType = AL_NONE;
source->Offset = 0.0;
}
@@ -2677,11 +2720,13 @@ AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
{
ATOMIC_STORE(&voice->Source, NULL, almemory_order_relaxed);
ATOMIC_STORE(&voice->Playing, false, almemory_order_release);
- while((ATOMIC_LOAD(&device->MixCount, almemory_order_acquire)&1))
- althrd_yield();
+ voice = NULL;
}
- if(ATOMIC_LOAD(&source->state, almemory_order_acquire) != AL_INITIAL)
+ if(GetSourceState(source, voice) != AL_INITIAL)
+ {
ATOMIC_STORE(&source->state, AL_INITIAL, almemory_order_relaxed);
+ SendStateChangeEvent(context, source->id, AL_INITIAL);
+ }
source->OffsetType = AL_NONE;
source->Offset = 0.0;
}