Asynchronously stop and rewind voices

This commit is contained in:
Chris Robinson
2020-02-20 23:53:56 -08:00
parent bdb8ef22b0
commit 9b43327f56
2 changed files with 46 additions and 39 deletions
+44 -36
View File
@@ -523,10 +523,16 @@ VoiceChange *GetVoiceChangers(ALCcontext *ctx, size_t count)
void SendVoiceChangers(ALCcontext *ctx, VoiceChange *tail)
{
ALCdevice *device{ctx->mDevice.get()};
VoiceChange *oldhead{ctx->mCurrentVoiceChange.load(std::memory_order_acquire)};
while(VoiceChange *next{oldhead->mNext.load(std::memory_order_relaxed)})
oldhead = next;
oldhead->mNext.store(tail, std::memory_order_release);
ALuint refcount;
while(((refcount=device->MixCount.load(std::memory_order_acquire))&1))
std::this_thread::yield();
}
@@ -3009,35 +3015,33 @@ START_API_FUNC
++sources;
}
ALCdevice *device{context->mDevice.get()};
BackendLockGuard __{*device->Backend};
auto stop_source = [&context](ALsource *source) -> void
VoiceChange *tail{GetVoiceChangers(context.get(), srchandles.size())};
VoiceChange *cur{tail};
auto stop_source = [&context,&cur](ALsource *source) -> void
{
/* Get the source state before clearing from the voice, so we know what
* state the source+voice was actually in.
*/
ALvoice *voice{GetSourceVoice(source, context.get())};
const ALenum oldstate{GetSourceState(source, voice)};
if(voice != nullptr)
{
voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
voice->mSourceID.store(0u, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
ALvoice::State oldvstate{ALvoice::Playing};
voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
std::memory_order_acq_rel, std::memory_order_acquire);
voice = nullptr;
}
if(oldstate != AL_INITIAL && oldstate != AL_STOPPED)
if(ALvoice *voice{GetSourceVoice(source, context.get())})
{
voice->mPendingStop.store(true, std::memory_order_relaxed);
cur->mVoice = voice;
cur->mSourceID = source->id;
cur->mState = AL_STOPPED;
cur = cur->mNext.load(std::memory_order_relaxed);
source->state = AL_STOPPED;
SendStateChangeEvent(context.get(), source->id, AL_STOPPED);
}
source->OffsetType = AL_NONE;
source->Offset = 0.0;
source->VoiceIdx = INVALID_VOICE_IDX;
};
std::for_each(srchandles.begin(), srchandles.end(), stop_source);
while(cur)
{
cur->mVoice = nullptr;
cur->mSourceID = 0;
cur->mState = AL_NONE;
cur = cur->mNext.load(std::memory_order_relaxed);
}
SendVoiceChangers(context.get(), tail);
}
END_API_FUNC
@@ -3077,31 +3081,35 @@ START_API_FUNC
++sources;
}
ALCdevice *device{context->mDevice.get()};
BackendLockGuard __{*device->Backend};
auto rewind_source = [&context](ALsource *source) -> void
VoiceChange *tail{GetVoiceChangers(context.get(), srchandles.size())};
VoiceChange *cur{tail};
auto rewind_source = [&context,&cur](ALsource *source) -> void
{
ALvoice *voice{GetSourceVoice(source, context.get())};
if(voice != nullptr)
{
voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
voice->mSourceID.store(0u, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
ALvoice::State oldvstate{ALvoice::Playing};
voice->mPlayState.compare_exchange_strong(oldvstate, ALvoice::Stopping,
std::memory_order_acq_rel, std::memory_order_acquire);
voice = nullptr;
}
if(source->state != AL_INITIAL)
{
if(voice != nullptr)
voice->mPendingStop.store(true, std::memory_order_relaxed);
cur->mVoice = voice;
cur->mSourceID = source->id;
cur->mState = AL_INITIAL;
cur = cur->mNext.load(std::memory_order_relaxed);
source->state = AL_INITIAL;
SendStateChangeEvent(context.get(), source->id, AL_INITIAL);
}
source->OffsetType = AL_NONE;
source->Offset = 0.0;
source->VoiceIdx = INVALID_VOICE_IDX;
};
std::for_each(srchandles.begin(), srchandles.end(), rewind_source);
while(cur)
{
cur->mVoice = nullptr;
cur->mSourceID = 0;
cur->mState = AL_NONE;
cur = cur->mNext.load(std::memory_order_relaxed);
}
SendVoiceChangers(context.get(), tail);
}
END_API_FUNC
+2 -3
View File
@@ -1629,10 +1629,9 @@ void ProcessVoiceChanges(ALCcontext *ctx)
cur = next;
bool success{false};
ALvoice *voice{cur->mVoice};
if(cur->mState == AL_INITIAL || cur->mState == AL_STOPPED)
{
if(voice)
if(ALvoice *voice{cur->mVoice})
{
voice->mCurrentBuffer.store(nullptr, std::memory_order_relaxed);
voice->mLoopBuffer.store(nullptr, std::memory_order_relaxed);
@@ -1644,7 +1643,7 @@ void ProcessVoiceChanges(ALCcontext *ctx)
}
success |= (cur->mState == AL_INITIAL);
}
if(success && (enabledevt&EventType_SourceStateChange))
if(success && (enabledevt&EventType_SourceStateChange) && cur->mSourceID != 0)
SendSourceStateEvent(ctx, cur->mSourceID, cur->mState);
} while((next=cur->mNext.load(std::memory_order_acquire)));
ctx->mCurrentVoiceChange.store(cur, std::memory_order_release);