aboutsummaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2019-03-09 16:48:07 -0800
committerChris Robinson <[email protected]>2019-03-09 16:48:07 -0800
commitef0f3351321a7488e60faa838a4628cfecf230b8 (patch)
treea28d31d1eb4fdf785a6f2fceeaa7cface4a02973 /Alc
parentcde4500e24a8f5067d87711bf778cde99f26d990 (diff)
Add a Stopping state for voices
This currently doesn't do much, except have the mixer progress it to Stopped. It's valid to have without a source or buffers, and in the future will allow fading out when a source is paused or stopped.
Diffstat (limited to 'Alc')
-rw-r--r--Alc/alc.cpp10
-rw-r--r--Alc/alu.cpp19
-rw-r--r--Alc/mixvoice.cpp55
3 files changed, 58 insertions, 26 deletions
diff --git a/Alc/alc.cpp b/Alc/alc.cpp
index 9bba1b52..9891fec5 100644
--- a/Alc/alc.cpp
+++ b/Alc/alc.cpp
@@ -2148,7 +2148,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
{
delete voice->Update.exchange(nullptr, std::memory_order_acq_rel);
- if(voice->SourceID.load(std::memory_order_acquire) == 0u)
+ /* Force the voice to stopped if it was stopping. */
+ ALvoice::State vstate{ALvoice::Stopping};
+ voice->PlayState.compare_exchange_strong(vstate, ALvoice::Stopped,
+ std::memory_order_acquire, std::memory_order_acquire);
+ if(voice->SourceID.load(std::memory_order_relaxed) == 0u)
return;
if(device->AvgSpeakerDist > 0.0f)
@@ -2625,8 +2629,8 @@ void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends)
voice->SourceID.store(old_voice->SourceID.load(std::memory_order_relaxed),
std::memory_order_relaxed);
- voice->Playing.store(old_voice->Playing.load(std::memory_order_relaxed),
- std::memory_order_relaxed);
+ voice->PlayState.store(old_voice->PlayState.load(std::memory_order_relaxed),
+ std::memory_order_relaxed);
voice->Props = old_voice->Props;
/* Clear extraneous property set sends. */
diff --git a/Alc/alu.cpp b/Alc/alu.cpp
index 28f6346e..bf401638 100644
--- a/Alc/alu.cpp
+++ b/Alc/alu.cpp
@@ -1451,18 +1451,12 @@ void ProcessContext(ALCcontext *ctx, const ALsizei SamplesToDo)
std::for_each(ctx->Voices, ctx->Voices+ctx->VoiceCount.load(std::memory_order_acquire),
[SamplesToDo,ctx](ALvoice *voice) -> void
{
- if(!voice->Playing.load(std::memory_order_acquire)) return;
+ if(voice->PlayState.load(std::memory_order_acquire) == ALvoice::Stopped)
+ return;
ALuint sid{voice->SourceID.load(std::memory_order_relaxed)};
- if(!sid || voice->Step < 1) return;
+ if(voice->Step < 1) return;
- if(!MixSource(voice, sid, ctx, SamplesToDo))
- {
- voice->current_buffer.store(nullptr, std::memory_order_relaxed);
- voice->loop_buffer.store(nullptr, std::memory_order_relaxed);
- voice->SourceID.store(0u, std::memory_order_relaxed);
- voice->Playing.store(false, std::memory_order_release);
- SendSourceStoppedEvent(ctx, sid);
- }
+ MixSource(voice, sid, ctx, SamplesToDo);
}
);
@@ -1814,14 +1808,15 @@ void aluHandleDisconnect(ALCdevice *device, const char *msg, ...)
auto stop_voice = [ctx](ALvoice *voice) -> void
{
- if(!voice->Playing.load(std::memory_order_acquire)) return;
+ if(voice->PlayState.load(std::memory_order_acquire) == ALvoice::Playing)
+ return;
ALuint sid{voice->SourceID.load(std::memory_order_relaxed)};
if(!sid) return;
voice->current_buffer.store(nullptr, std::memory_order_relaxed);
voice->loop_buffer.store(nullptr, std::memory_order_relaxed);
voice->SourceID.store(0u, std::memory_order_relaxed);
- voice->Playing.store(false, std::memory_order_release);
+ voice->PlayState.store(ALvoice::Stopped, std::memory_order_release);
/* If the source's voice was playing, it's now effectively stopped
* (the source state will be updated the next time it's checked).
*/
diff --git a/Alc/mixvoice.cpp b/Alc/mixvoice.cpp
index 2cc26d7b..9602ac72 100644
--- a/Alc/mixvoice.cpp
+++ b/Alc/mixvoice.cpp
@@ -198,6 +198,23 @@ void aluInitMixer()
namespace {
+void SendSourceStoppedEvent(ALCcontext *context, ALuint id)
+{
+ ALbitfieldSOFT enabledevt{context->EnabledEvts.load(std::memory_order_acquire)};
+ if(!(enabledevt&EventType_SourceStateChange)) return;
+
+ RingBuffer *ring{context->AsyncEvents.get()};
+ auto evt_vec = ring->getWriteVector();
+ if(evt_vec.first.len < 1) return;
+
+ AsyncEvent *evt{new (evt_vec.first.buf) AsyncEvent{EventType_SourceStateChange}};
+ evt->u.srcstate.id = id;
+ evt->u.srcstate.state = AL_STOPPED;
+
+ ring->writeAdvance(1);
+ context->EventSem.post();
+}
+
/* Base template left undefined. Should be marked =delete, but Clang 3.8.1
* chokes on that given the inline specializations.
*/
@@ -283,20 +300,20 @@ const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter,
} // namespace
-ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo)
+void MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context, const ALsizei SamplesToDo)
{
ASSUME(SamplesToDo > 0);
/* Get source info */
- bool isplaying{true}; /* Will only be called while playing. */
- bool isstatic{(voice->Flags&VOICE_IS_STATIC) != 0};
- ALsizei DataPosInt{static_cast<ALsizei>(voice->position.load(std::memory_order_acquire))};
+ ALvoice::State vstate{voice->PlayState.load(std::memory_order_acquire)};
+ const bool isstatic{(voice->Flags&VOICE_IS_STATIC) != 0};
+ ALsizei DataPosInt{static_cast<ALsizei>(voice->position.load(std::memory_order_relaxed))};
ALsizei DataPosFrac{voice->position_fraction.load(std::memory_order_relaxed)};
ALbufferlistitem *BufferListItem{voice->current_buffer.load(std::memory_order_relaxed)};
ALbufferlistitem *BufferLoopItem{voice->loop_buffer.load(std::memory_order_relaxed)};
- ALsizei NumChannels{voice->NumChannels};
- ALsizei SampleSize{voice->SampleSize};
- ALint increment{voice->Step};
+ const ALsizei NumChannels{voice->NumChannels};
+ const ALsizei SampleSize{voice->SampleSize};
+ const ALint increment{voice->Step};
ASSUME(DataPosInt >= 0);
ASSUME(DataPosFrac >= 0);
@@ -304,6 +321,15 @@ ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context,
ASSUME(SampleSize > 0);
ASSUME(increment > 0);
+ /* TODO: Use stored previous samples to fade out without incrementing when
+ * stopping (buffers may not be available).
+ */
+ if(UNLIKELY(vstate == ALvoice::Stopping))
+ {
+ voice->PlayState.store(ALvoice::Stopped, std::memory_order_release);
+ return;
+ }
+
ALCdevice *Device{Context->Device};
const ALsizei IrSize{Device->mHrtf ? Device->mHrtf->irSize : 0};
const int OutLIdx{GetChannelIdxByName(Device->RealOut, FrontLeft)};
@@ -704,7 +730,7 @@ ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context,
/* Handle non-looping static source */
if(DataPosInt >= BufferListItem->max_samples)
{
- isplaying = false;
+ vstate = ALvoice::Stopped;
BufferListItem = nullptr;
DataPosInt = 0;
DataPosFrac = 0;
@@ -724,13 +750,13 @@ ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context,
BufferListItem = BufferListItem->next.load(std::memory_order_relaxed);
if(!BufferListItem && !(BufferListItem=BufferLoopItem))
{
- isplaying = false;
+ vstate = ALvoice::Stopped;
DataPosInt = 0;
DataPosFrac = 0;
break;
}
}
- } while(isplaying && OutPos < SamplesToDo);
+ } while(vstate != ALvoice::Stopped && OutPos < SamplesToDo);
voice->Flags |= VOICE_IS_FADING;
@@ -755,5 +781,12 @@ ALboolean MixSource(ALvoice *voice, const ALuint SourceID, ALCcontext *Context,
}
}
- return isplaying;
+ if(vstate == ALvoice::Stopped)
+ {
+ voice->current_buffer.store(nullptr, std::memory_order_relaxed);
+ voice->loop_buffer.store(nullptr, std::memory_order_relaxed);
+ voice->SourceID.store(0u, std::memory_order_relaxed);
+ voice->PlayState.store(ALvoice::Stopped, std::memory_order_release);
+ SendSourceStoppedEvent(Context, SourceID);
+ }
}