From 4484d7a5c2faabd6632e9ca6bc88712781cd4fa6 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 2 Oct 2020 10:55:49 +0200 Subject: [PATCH] output/jack: implement Interrupt() --- NEWS | 2 +- src/output/plugins/JackOutputPlugin.cxx | 36 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 2e8dc14a6..a8d8e763c 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,7 @@ ver 0.22.1 (not yet released) * output - alsa: don't deadlock when the ALSA driver is buggy - - pulse: reduce the delay when stopping or pausing playback + - jack, pulse: reduce the delay when stopping or pausing playback ver 0.22 (2020/09/23) * protocol diff --git a/src/output/plugins/JackOutputPlugin.cxx b/src/output/plugins/JackOutputPlugin.cxx index 8c6da5405..e2f0a63f1 100644 --- a/src/output/plugins/JackOutputPlugin.cxx +++ b/src/output/plugins/JackOutputPlugin.cxx @@ -20,6 +20,7 @@ #include "config.h" #include "JackOutputPlugin.hxx" #include "../OutputAPI.hxx" +#include "../Error.hxx" #include "output/Features.h" #include "thread/Mutex.hxx" #include "util/ScopeExit.hxx" @@ -79,6 +80,15 @@ class JackOutput final : public AudioOutput { */ std::atomic_bool pause; + /** + * Was Interrupt() called? This will unblock Play(). It will + * be reset by Cancel() and Pause(), as documented by the + * #AudioOutput interface. + * + * Only initialized while the output is open. + */ + bool interrupted; + /** * Protects #error. */ @@ -156,6 +166,8 @@ public: Stop(); } + void Interrupt() noexcept override; + std::chrono::steady_clock::duration Delay() const noexcept override { return pause && !LockWasShutdown() ? std::chrono::seconds(1) @@ -164,6 +176,7 @@ public: size_t Play(const void *chunk, size_t size) override; + void Cancel() noexcept override; bool Pause() override; private: @@ -613,9 +626,21 @@ JackOutput::Open(AudioFormat &new_audio_format) new_audio_format.format = SampleFormat::FLOAT; audio_format = new_audio_format; + interrupted = false; + Start(); } +void +JackOutput::Interrupt() noexcept +{ + const std::unique_lock lock(mutex); + + /* the "interrupted" flag will prevent Play() from waiting, + and will instead throw AudioOutputInterrupted */ + interrupted = true; +} + inline size_t JackOutput::WriteSamples(const float *src, size_t n_frames) { @@ -671,6 +696,9 @@ JackOutput::Play(const void *chunk, size_t size) const std::lock_guard lock(mutex); if (error) std::rethrow_exception(error); + + if (interrupted) + throw AudioOutputInterrupted{}; } size_t frames_written = @@ -684,11 +712,19 @@ JackOutput::Play(const void *chunk, size_t size) } } +void +JackOutput::Cancel() noexcept +{ + const std::unique_lock lock(mutex); + interrupted = false; +} + inline bool JackOutput::Pause() { { const std::lock_guard lock(mutex); + interrupted = false; if (error) std::rethrow_exception(error); }