diff --git a/src/output/plugins/PipeWireOutputPlugin.cxx b/src/output/plugins/PipeWireOutputPlugin.cxx index 2d26e3ba9..58bc8dc8e 100644 --- a/src/output/plugins/PipeWireOutputPlugin.cxx +++ b/src/output/plugins/PipeWireOutputPlugin.cxx @@ -58,6 +58,7 @@ class PipeWireOutput final : AudioOutput { bool disconnected; bool interrupted; + bool drained; explicit PipeWireOutput(const ConfigBlock &block); @@ -74,6 +75,7 @@ public: events.version = PW_VERSION_STREAM_EVENTS; events.state_changed = StateChanged; events.process = Process; + events.drained = Drained; return events; } @@ -107,6 +109,16 @@ private: o.Process(); } + void Drained() noexcept { + drained = true; + pw_thread_loop_signal(thread_loop, false); + } + + static void Drained(void *data) noexcept { + auto &o = *(PipeWireOutput *)data; + o.Drained(); + } + /* virtual methods from class AudioOutput */ void Enable() override; void Disable() noexcept override; @@ -125,8 +137,8 @@ private: size_t Play(const void *chunk, size_t size) override; - // TODO: void Drain() override; - void Cancel() noexcept override; + void Drain() override; + void Cancel() noexcept override; // TODO: bool Pause() noexcept override; }; @@ -211,6 +223,7 @@ void PipeWireOutput::Open(AudioFormat &audio_format) { disconnected = false; + drained = true; auto props = pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio", PW_KEY_MEDIA_CATEGORY, "Playback", @@ -307,8 +320,10 @@ PipeWireOutput::Play(const void *chunk, size_t size) std::size_t bytes_written = ring_buffer->push((const std::byte *)chunk, size); - if (bytes_written > 0) + if (bytes_written > 0) { + drained = false; return bytes_written; + } if (interrupted) throw AudioOutputInterrupted{}; @@ -317,6 +332,17 @@ PipeWireOutput::Play(const void *chunk, size_t size) } } +void +PipeWireOutput::Drain() +{ + const PipeWire::ThreadLoopLock lock(thread_loop); + + while (!drained && !interrupted) { + CheckThrowError(); + pw_thread_loop_wait(thread_loop); + } +} + void PipeWireOutput::Cancel() noexcept {