diff options
author | Max Kellermann <max@musicpd.org> | 2021-03-10 20:25:20 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2021-03-10 20:38:27 +0100 |
commit | 1fe0c673bc3ead4e99e47e61e7aa3f0ed590bbba (patch) | |
tree | bb986c47f2f31d9e4650cfeb04fb804ac1a7beb9 /src/output | |
parent | 8a045207a72b1fdff161b53ef740be762e7c78f7 (diff) |
output/wasapi: implement Cancel() properly
Calling consume_all() is illegal in the producer thread.
Diffstat (limited to 'src/output')
-rw-r--r-- | src/output/plugins/wasapi/WasapiOutputPlugin.cxx | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/src/output/plugins/wasapi/WasapiOutputPlugin.cxx b/src/output/plugins/wasapi/WasapiOutputPlugin.cxx index ba6b61a80..e7075c0b5 100644 --- a/src/output/plugins/wasapi/WasapiOutputPlugin.cxx +++ b/src/output/plugins/wasapi/WasapiOutputPlugin.cxx @@ -170,7 +170,10 @@ class WasapiOutputThread { bool started = false; + std::atomic_bool cancel = false; + enum class Status : uint32_t { FINISH, PLAY, PAUSE }; + alignas(BOOST_LOCKFREE_CACHELINE_BYTES) std::atomic<Status> status = Status::PAUSE; alignas(BOOST_LOCKFREE_CACHELINE_BYTES) struct { @@ -202,6 +205,24 @@ public: void Pause() noexcept { return SetStatus(Status::PAUSE); } /** + * Instruct the thread to discard the buffer (and wait for + * completion). This needs to be done inside this thread, + * because only the consumer thread is allowed to do that. + */ + void Cancel() noexcept { + cancel.store(true); + event.Set(); + + while (cancel.load() && !error.occur.load()) + Wait(); + + /* not rethrowing the exception here via + CheckException() because this method must be + "noexcept"; the next WasapiOutput::Play() call will + throw */ + } + + /** * Wait for the thread to finish some work (e.g. until some * buffer space becomes available). */ @@ -366,6 +387,12 @@ try { while (true) { event.Wait(); + if (cancel.load()) { + spsc_buffer.consume_all([](auto &&) {}); + cancel.store(false); + InterruptWaiter(); + } + Status current_state = status.load(); switch (current_state) { case Status::FINISH: @@ -707,7 +734,7 @@ WasapiOutput::Cancel() noexcept { assert(thread); - thread->spsc_buffer.consume_all([](auto &&) {}); + thread->Cancel(); } /// run inside COMWorkerThread |