diff --git a/src/contrib/directsoundout/DirectSoundOut.cpp b/src/contrib/directsoundout/DirectSoundOut.cpp index f24b47aab..1c4f32a0f 100644 --- a/src/contrib/directsoundout/DirectSoundOut.cpp +++ b/src/contrib/directsoundout/DirectSoundOut.cpp @@ -130,7 +130,7 @@ void DirectSoundOut::SetVolume(double volume) { if (this->secondaryBuffer) { double db = (volume < 0.0001f) ? DSBVOLUME_MIN - : log10f(this->volume) * 6000.f; + : (float) log10f(this->volume) * 6000.f; if (db > DSBVOLUME_MAX) { db = DSBVOLUME_MAX; @@ -236,20 +236,25 @@ void DirectSoundOut::Drain() { return; } - int samples = bufferSize / sizeof(float) / channels; - int sleepMs = ((long long)(samples * 1000) / rate) + 1; - Sleep(sleepMs); + int sleepMs = 0; - /* not sure of a better way to ensure the final buffer is - flushed other than to use this heuristic: given the buffer - size in seconds, sleep for 50 milliseconds at a time while - it's still playing. */ - while (this->state != StateStopped && sleepMs > 0) { - Sleep(50); - if (this->state == StatePlaying) { - sleepMs -= 50; + if (this->state != StateStopped) { + Lock lock(this->stateMutex); + + if (this->secondaryBuffer) { + int pendingBytes = this->bufferSize - getAvailableBytes( + this->secondaryBuffer, this->writeOffset, this->bufferSize); + + int samples = pendingBytes / sizeof(float) / channels; + sleepMs = ((long long)(samples * 1000) / rate); } } + + if (sleepMs > 0) { + Sleep(sleepMs); + } + + this->Stop(); } void DirectSoundOut::Reset() { @@ -296,6 +301,8 @@ bool DirectSoundOut::Configure(IBuffer *buffer) { return true; } + this->Stop(); + HRESULT result; if (!this->outputContext) { diff --git a/src/contrib/directsoundout/DirectSoundOut.h b/src/contrib/directsoundout/DirectSoundOut.h index b12c4beff..35f0c4cf7 100644 --- a/src/contrib/directsoundout/DirectSoundOut.h +++ b/src/contrib/directsoundout/DirectSoundOut.h @@ -78,7 +78,6 @@ class DirectSoundOut : public IOutput { bool Configure(IBuffer *buffer); void Reset(); void ResetBuffers(); - void Drain(IDirectSoundBuffer *buffer); std::atomic state; diff --git a/src/contrib/wasapiout/WasapiOut.cpp b/src/contrib/wasapiout/WasapiOut.cpp index e55bae23a..12b99ac0b 100644 --- a/src/contrib/wasapiout/WasapiOut.cpp +++ b/src/contrib/wasapiout/WasapiOut.cpp @@ -134,37 +134,16 @@ void WasapiOut::Stop() { } void WasapiOut::Drain() { - UINT32 rate = waveFormat.Format.nSamplesPerSec; - REFERENCE_TIME sleepTime = 0; - UINT32 availableFrames = 0; - UINT32 frameOffset = 0; - bool bail = false; + int sleepMs = (int) (round(this->Latency()) * 1000.0f); - while (this->state != StateStopped && !bail) { - { - Lock lock(this->stateMutex); - - if (this->audioClient && rate > 0) { - this->audioClient->GetCurrentPadding(&frameOffset); - availableFrames = (this->outputBufferFrames - frameOffset); - - if (availableFrames < this->outputBufferFrames) { - UINT32 pending = this->outputBufferFrames - availableFrames; - REFERENCE_TIME sleepTime = (pending * 1000 * 1000 * 10) / rate; - } - - if (sleepTime <= 0) { - bail = true; - } - } - else { - bail = true; - } - } - - if (sleepTime > 0) { - std::this_thread::sleep_for( - std::chrono::microseconds(sleepTime)); + /* not sure of a better way to ensure the final buffer is + flushed other than to use this heuristic: given the latency + size in seconds, sleep for 50 milliseconds at a time while + it's still playing. */ + while (this->state != StateStopped && sleepMs > 0) { + Sleep(50); + if (this->state == StatePlaying) { + sleepMs -= 50; } } } diff --git a/src/core/audio/GaplessTransport.cpp b/src/core/audio/GaplessTransport.cpp index 69ada9920..cd02820f9 100644 --- a/src/core/audio/GaplessTransport.cpp +++ b/src/core/audio/GaplessTransport.cpp @@ -163,7 +163,6 @@ void GaplessTransport::StopInternal( LockT lock(this->stateMutex); RESET_NEXT_PLAYER(this); - if (this->activePlayer != exclude) { RESET_ACTIVE_PLAYER(this); } @@ -329,8 +328,17 @@ void GaplessTransport::OnPlayerFinished(Player* player) { } } + /* note we could also call this->Stop() here, but it will shut down the + output and drain any pending buffers. this is a bit of extra overhead + that isn't necessary. */ if (stopped) { - this->Stop(); + { + LockT lock(this->stateMutex); + RESET_NEXT_PLAYER(this); + RESET_ACTIVE_PLAYER(this); + } + + this->SetPlaybackState(PlaybackStopped); } }