diff --git a/src/output/plugins/snapcast/Client.cxx b/src/output/plugins/snapcast/Client.cxx index 8434258b2..08cb737dc 100644 --- a/src/output/plugins/snapcast/Client.cxx +++ b/src/output/plugins/snapcast/Client.cxx @@ -76,6 +76,10 @@ SnapcastClient::LockPopQueue() noexcept auto chunk = std::move(chunks.front()); chunks.pop(); + + if (chunks.empty()) + output.drain_cond.notify_one(); + return chunk; } diff --git a/src/output/plugins/snapcast/Client.hxx b/src/output/plugins/snapcast/Client.hxx index d62e73a82..f46f425ae 100644 --- a/src/output/plugins/snapcast/Client.hxx +++ b/src/output/plugins/snapcast/Client.hxx @@ -65,6 +65,13 @@ public: */ void Push(SnapcastChunkPtr chunk) noexcept; + /** + * Caller must lock the mutex. + */ + bool IsDrained() const noexcept { + return chunks.empty(); + } + /** * Caller must lock the mutex. */ diff --git a/src/output/plugins/snapcast/Internal.hxx b/src/output/plugins/snapcast/Internal.hxx index a9bbd1684..672221e3d 100644 --- a/src/output/plugins/snapcast/Internal.hxx +++ b/src/output/plugins/snapcast/Internal.hxx @@ -24,6 +24,7 @@ #include "output/Interface.hxx" #include "output/Timer.hxx" #include "thread/Mutex.hxx" +#include "thread/Cond.hxx" #include "event/ServerSocket.hxx" #include "event/InjectEvent.hxx" #include "util/AllocatedArray.hxx" @@ -82,6 +83,12 @@ public: */ mutable Mutex mutex; + /** + * This cond is signalled when a #SnapcastClient has an empty + * queue. + */ + Cond drain_cond; + SnapcastOutput(EventLoop &_loop, const ConfigBlock &block); ~SnapcastOutput() noexcept override; @@ -162,13 +169,19 @@ public: size_t Play(const void *chunk, size_t size) override; - // TODO: void Drain() override; + void Drain() override; void Cancel() noexcept override; bool Pause() override; private: void OnInject() noexcept; + /** + * Caller must lock the mutex. + */ + [[gnu::pure]] + bool IsDrained() const noexcept; + /* virtual methods from class ServerSocket */ void OnAccept(UniqueSocketDescriptor fd, SocketAddress address, int uid) noexcept override; diff --git a/src/output/plugins/snapcast/SnapcastOutputPlugin.cxx b/src/output/plugins/snapcast/SnapcastOutputPlugin.cxx index 82b5846e3..8d7f35358 100644 --- a/src/output/plugins/snapcast/SnapcastOutputPlugin.cxx +++ b/src/output/plugins/snapcast/SnapcastOutputPlugin.cxx @@ -181,6 +181,9 @@ SnapcastOutput::RemoveClient(SnapcastClient &client) noexcept client.unlink(); delete &client; + + if (clients.empty()) + drain_cond.notify_one(); } std::chrono::steady_clock::duration @@ -261,6 +264,26 @@ SnapcastOutput::Pause() return true; } +inline bool +SnapcastOutput::IsDrained() const noexcept +{ + if (!chunks.empty()) + return false; + + for (const auto &client : clients) + if (!client.IsDrained()) + return false; + + return true; +} + +void +SnapcastOutput::Drain() +{ + std::unique_lock protect(mutex); + drain_cond.wait(protect, [this]{ return IsDrained(); }); +} + void SnapcastOutput::Cancel() noexcept {