From 105a72457ec1c5bf7c0ddc3b58e8b52141966237 Mon Sep 17 00:00:00 2001 From: casey langen Date: Sun, 25 Dec 2016 11:06:23 -0800 Subject: [PATCH] Sane implementation of DirectSoundOut::Drain() -- just write silence to the playback buffer until it's full. --- src/contrib/directsoundout/DirectSoundOut.cpp | 65 +++++++++++++++---- src/core/audio/GaplessTransport.cpp | 11 +--- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/contrib/directsoundout/DirectSoundOut.cpp b/src/contrib/directsoundout/DirectSoundOut.cpp index 1c4f32a0f..8f7b5c112 100644 --- a/src/contrib/directsoundout/DirectSoundOut.cpp +++ b/src/contrib/directsoundout/DirectSoundOut.cpp @@ -41,6 +41,41 @@ #include #include +class DrainBuffer : + public musik::core::sdk::IBuffer, + public musik::core::sdk::IBufferProvider +{ + public: + DrainBuffer() { + this->buffer = nullptr; + this->channels = this->samples = this->rate = 0; + } + + virtual ~DrainBuffer() { + delete[] buffer; + } + + void Init() { + delete[] buffer; + this->buffer = new float[this->samples]; + memset(this->buffer, 0, this->Bytes()); + } + + virtual long SampleRate() const { return this->rate; } + virtual void SetSampleRate(long sampleRate) { this->rate = sampleRate; } + virtual int Channels() const { return this->channels; } + virtual void SetChannels(int channels) { this->channels = channels; } + virtual float* BufferPointer() const { return this->buffer; } + virtual long Samples() const { return this->samples; } + virtual void SetSamples(long samples) { this->samples = samples; } + virtual long Bytes() const { return this->samples * sizeof(float); } + virtual void OnBufferProcessed(IBuffer *buffer) { } + + private: + int channels, samples, rate; + float *buffer; +}; + #define MAX_BUFFERS_PER_OUTPUT 8 #define BUFFER_SIZE_BYTES_PER_CHANNEL \ @@ -228,6 +263,8 @@ bool DirectSoundOut::Play(IBuffer *buffer, IBufferProvider *provider) { } void DirectSoundOut::Drain() { + static const int drainCount = 4; + int channels = this->channels; int rate = this->rate; int bufferSize = this->bufferSize; @@ -236,22 +273,24 @@ void DirectSoundOut::Drain() { return; } - int sleepMs = 0; + int totalSamples = bufferSize / sizeof(float) / channels; - if (this->state != StateStopped) { - Lock lock(this->stateMutex); + DrainBuffer buffer; + buffer.SetChannels(channels); + buffer.SetSampleRate(rate); + buffer.SetSamples(totalSamples / drainCount); + buffer.Init(); - 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); + /* fill the rest of the buffer with silence to ensure all + real samples get played! */ + int count = drainCount + 1; + while (count > 0 && this->state != StateStopped) { + if (!this->Play(&buffer, &buffer)) { + Sleep(250); /* eh */ + } + else { + --count; } - } - - if (sleepMs > 0) { - Sleep(sleepMs); } this->Stop(); diff --git a/src/core/audio/GaplessTransport.cpp b/src/core/audio/GaplessTransport.cpp index cd02820f9..b90d7394d 100644 --- a/src/core/audio/GaplessTransport.cpp +++ b/src/core/audio/GaplessTransport.cpp @@ -328,17 +328,8 @@ 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) { - { - LockT lock(this->stateMutex); - RESET_NEXT_PLAYER(this); - RESET_ACTIVE_PLAYER(this); - } - - this->SetPlaybackState(PlaybackStopped); + this->Stop(); } }