summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2020-10-02 10:39:55 +0200
committerMax Kellermann <max@musicpd.org>2020-10-02 10:52:25 +0200
commitb80a135cf3cab19dfaef2ddc95a72e67d6c55f2a (patch)
treedde24d7bf1aa03c3eeeb69fda490d1489162b1ef /src
parent4ad525d939397933f1785a0ae8635a073c202950 (diff)
output/pulse: implement Interrupt()
Diffstat (limited to 'src')
-rw-r--r--src/output/plugins/PulseOutputPlugin.cxx36
1 files changed, 36 insertions, 0 deletions
diff --git a/src/output/plugins/PulseOutputPlugin.cxx b/src/output/plugins/PulseOutputPlugin.cxx
index 6558232d0..c2e691b76 100644
--- a/src/output/plugins/PulseOutputPlugin.cxx
+++ b/src/output/plugins/PulseOutputPlugin.cxx
@@ -22,6 +22,7 @@
#include "lib/pulse/LogError.hxx"
#include "lib/pulse/LockGuard.hxx"
#include "../OutputAPI.hxx"
+#include "../Error.hxx"
#include "mixer/MixerList.hxx"
#include "mixer/plugins/PulseMixerPlugin.hxx"
#include "util/ScopeExit.hxx"
@@ -57,6 +58,15 @@ class PulseOutput final : AudioOutput {
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;
+
explicit PulseOutput(const ConfigBlock &block);
public:
@@ -99,6 +109,8 @@ public:
void Open(AudioFormat &audio_format) override;
void Close() noexcept override;
+ void Interrupt() noexcept override;
+
[[nodiscard]] std::chrono::steady_clock::duration Delay() const noexcept override;
size_t Play(const void *chunk, size_t size) override;
void Cancel() noexcept override;
@@ -677,6 +689,7 @@ PulseOutput::Open(AudioFormat &audio_format)
}
pause = false;
+ interrupted = false;
}
void
@@ -705,6 +718,21 @@ PulseOutput::Close() noexcept
}
void
+PulseOutput::Interrupt() noexcept
+{
+ if (mainloop == nullptr)
+ return;
+
+ const Pulse::LockGuard lock(mainloop);
+
+ /* the "interrupted" flag will prevent Play() from blocking,
+ and will instead throw AudioOutputInterrupted */
+ interrupted = true;
+
+ Signal();
+}
+
+void
PulseOutput::WaitStream()
{
while (true) {
@@ -719,6 +747,9 @@ PulseOutput::WaitStream()
"failed to connect the stream");
case PA_STREAM_CREATING:
+ if (interrupted)
+ throw AudioOutputInterrupted{};
+
pa_threaded_mainloop_wait(mainloop);
break;
}
@@ -784,6 +815,9 @@ PulseOutput::Play(const void *chunk, size_t size)
if (pa_stream_is_suspended(stream))
throw std::runtime_error("suspended");
+ if (interrupted)
+ throw AudioOutputInterrupted{};
+
pa_threaded_mainloop_wait(mainloop);
if (pa_stream_get_state(stream) != PA_STREAM_READY)
@@ -813,6 +847,7 @@ PulseOutput::Cancel() noexcept
assert(stream != nullptr);
Pulse::LockGuard lock(mainloop);
+ interrupted = false;
if (pa_stream_get_state(stream) != PA_STREAM_READY) {
/* no need to flush when the stream isn't connected
@@ -842,6 +877,7 @@ PulseOutput::Pause()
Pulse::LockGuard lock(mainloop);
pause = true;
+ interrupted = false;
/* check if the stream is (already/still) connected */