summaryrefslogtreecommitdiff
path: root/src/output
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2021-03-10 20:25:20 +0100
committerMax Kellermann <max@musicpd.org>2021-03-10 20:38:27 +0100
commit1fe0c673bc3ead4e99e47e61e7aa3f0ed590bbba (patch)
treebb986c47f2f31d9e4650cfeb04fb804ac1a7beb9 /src/output
parent8a045207a72b1fdff161b53ef740be762e7c78f7 (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.cxx29
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