From 25b01940369d746debd0240bcab617b3451aa8c3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 10 Mar 2021 20:47:15 +0100 Subject: [PATCH] output/wasapi: implement Drain() --- .../plugins/wasapi/WasapiOutputPlugin.cxx | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/output/plugins/wasapi/WasapiOutputPlugin.cxx b/src/output/plugins/wasapi/WasapiOutputPlugin.cxx index 203896c7a..fed16fbee 100644 --- a/src/output/plugins/wasapi/WasapiOutputPlugin.cxx +++ b/src/output/plugins/wasapi/WasapiOutputPlugin.cxx @@ -181,6 +181,8 @@ class WasapiOutputThread { std::atomic_bool cancel = false; + std::atomic_bool empty = true; + enum class Status : uint32_t { FINISH, PLAY, PAUSE }; alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic status = @@ -224,6 +226,8 @@ public: } std::size_t Push(ConstBuffer input) noexcept { + empty.store(false); + std::size_t consumed = spsc_buffer.push(static_cast(input.data), input.size); @@ -236,6 +240,24 @@ public: return consumed; } + /** + * Check if the buffer is empty, and if not, wait a bit. + * + * Throws on error. + * + * @return true if the buffer is now empty + */ + bool Drain() { + if (empty) + return true; + + CheckException(); + Wait(); + CheckException(); + + return empty; + } + /** * Instruct the thread to discard the buffer (and wait for * completion). This needs to be done inside this thread, @@ -417,6 +439,7 @@ try { if (cancel.load()) { spsc_buffer.consume_all([](auto &&) {}); cancel.store(false); + empty.store(true); InterruptWaiter(); } @@ -475,6 +498,9 @@ try { const UINT32 write_size = write_in_frames * frame_size; UINT32 new_data_size = 0; new_data_size = spsc_buffer.pop(data, write_size); + if (new_data_size == 0) + empty.store(true); + std::fill_n(data + new_data_size, write_size - new_data_size, 0); InterruptWaiter(); @@ -741,9 +767,15 @@ WasapiOutput::Drain() { assert(thread); - // TODO implement + not_interrupted.test_and_set(); - thread->CheckException(); + while (!thread->Drain()) { + if (!not_interrupted.test_and_set()) + throw AudioOutputInterrupted{}; + } + + /* TODO: this needs to wait until the hardware has really + finished playing */ } void