From 12eaaef210dda959c8a1717914870ef4fcfde69b Mon Sep 17 00:00:00 2001
From: Max Kellermann <max.kellermann@gmail.com>
Date: Mon, 29 Jul 2024 16:44:37 +0200
Subject: [PATCH] output/Thread: allow Delay() to return duration::max()

Eliminate the periodic wakeups while paused in some output plugins.
---
 src/output/Interface.hxx                         | 4 ++++
 src/output/Thread.cxx                            | 5 ++++-
 src/output/plugins/AlsaOutputPlugin.cxx          | 2 +-
 src/output/plugins/JackOutputPlugin.cxx          | 2 +-
 src/output/plugins/PulseOutputPlugin.cxx         | 2 +-
 src/output/plugins/wasapi/WasapiOutputPlugin.cxx | 2 +-
 6 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/src/output/Interface.hxx b/src/output/Interface.hxx
index 8c679f66c..c3aeef2c1 100644
--- a/src/output/Interface.hxx
+++ b/src/output/Interface.hxx
@@ -136,6 +136,10 @@ public:
 	 * instead of doing a sleep inside the plugin, because this
 	 * allows MPD to listen to commands meanwhile.
 	 *
+	 * As a special case, this method is allowed to return
+         * std::chrono::steady_clock::duration::max() which lets MPD
+         * sleep forever until a command is received.
+	 *
 	 * @return the duration to wait
 	 */
 	virtual std::chrono::steady_clock::duration Delay() const noexcept {
diff --git a/src/output/Thread.cxx b/src/output/Thread.cxx
index b8f5e38e3..e1c3ed477 100644
--- a/src/output/Thread.cxx
+++ b/src/output/Thread.cxx
@@ -197,7 +197,10 @@ AudioOutputControl::WaitForDelay(std::unique_lock<Mutex> &lock) noexcept
 		if (delay <= std::chrono::steady_clock::duration::zero())
 			return true;
 
-		(void)wake_cond.wait_for(lock, delay);
+		if (delay >= std::chrono::steady_clock::duration::max())
+			wake_cond.wait(lock);
+		else
+			(void)wake_cond.wait_for(lock, delay);
 
 		if (command != Command::NONE)
 			return false;
diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx
index f6bb22432..c986c787e 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -883,7 +883,7 @@ std::chrono::steady_clock::duration
 AlsaOutput::Delay() const noexcept
 {
 	if (paused)
-		return std::chrono::hours{1};
+		return std::chrono::steady_clock::duration::max();
 
 	return AudioOutput::Delay();
 }
diff --git a/src/output/plugins/JackOutputPlugin.cxx b/src/output/plugins/JackOutputPlugin.cxx
index c393267d4..8b88bdc7f 100644
--- a/src/output/plugins/JackOutputPlugin.cxx
+++ b/src/output/plugins/JackOutputPlugin.cxx
@@ -155,7 +155,7 @@ public:
 
 	std::chrono::steady_clock::duration Delay() const noexcept override {
 		return pause && !LockWasShutdown()
-			? std::chrono::seconds(1)
+			? std::chrono::steady_clock::duration::max()
 			: std::chrono::steady_clock::duration::zero();
 	}
 
diff --git a/src/output/plugins/PulseOutputPlugin.cxx b/src/output/plugins/PulseOutputPlugin.cxx
index 7b35b8271..67e905817 100644
--- a/src/output/plugins/PulseOutputPlugin.cxx
+++ b/src/output/plugins/PulseOutputPlugin.cxx
@@ -762,7 +762,7 @@ PulseOutput::Delay() const noexcept
 	if (pa_stream_is_corked(stream) &&
 	    pa_stream_get_state(stream) == PA_STREAM_READY)
 		/* idle while paused */
-		result = std::chrono::seconds(1);
+		result = std::chrono::steady_clock::duration::max();
 
 	return result;
 }
diff --git a/src/output/plugins/wasapi/WasapiOutputPlugin.cxx b/src/output/plugins/wasapi/WasapiOutputPlugin.cxx
index fcc0d5320..31c9d9544 100644
--- a/src/output/plugins/wasapi/WasapiOutputPlugin.cxx
+++ b/src/output/plugins/wasapi/WasapiOutputPlugin.cxx
@@ -684,7 +684,7 @@ WasapiOutput::Delay() const noexcept
 {
 	if (paused) {
 		// idle while paused
-		return std::chrono::seconds(1);
+		return std::chrono::steady_clock::duration::max();
 	}
 
 	return std::chrono::steady_clock::duration::zero();