From b3df4dc2c92d27034eaf9cef52e97a6e39c77d2e Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Tue, 23 Aug 2011 22:43:08 +0200
Subject: [PATCH] output/pulse: fix deadlock when the stream was suspended

Check if the stream is suspended; wake up the main loop when it
becomes suspended.
---
 NEWS                             |  1 +
 src/output/pulse_output_plugin.c | 31 +++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/NEWS b/NEWS
index eaa8d194e..b23c4a087 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ ver 0.16.4 (2011/??/??)
   - alsa: fix SIGFPE when alsa announces a period size of 0
   - httpd: don't warn on client disconnect
   - pulse: fix deadlock when resuming the stream
+  - pulse: fix deadlock when the stream was suspended
 
 
 ver 0.16.3 (2011/06/04)
diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c
index c0633b9fb..babb8e221 100644
--- a/src/output/pulse_output_plugin.c
+++ b/src/output/pulse_output_plugin.c
@@ -412,6 +412,23 @@ pulse_output_wait_connection(struct pulse_output *po, GError **error_r)
 	}
 }
 
+#if PA_CHECK_VERSION(0,9,8)
+
+static void
+pulse_output_stream_suspended_cb(G_GNUC_UNUSED pa_stream *stream, void *userdata)
+{
+	struct pulse_output *po = userdata;
+
+	assert(stream == po->stream || po->stream == NULL);
+	assert(po->mainloop != NULL);
+
+	/* wake up the main loop to break out of the loop in
+	   pulse_output_play() */
+	pa_threaded_mainloop_signal(po->mainloop, 0);
+}
+
+#endif
+
 static void
 pulse_output_stream_state_cb(pa_stream *stream, void *userdata)
 {
@@ -508,6 +525,11 @@ pulse_output_open(void *data, struct audio_format *audio_format,
 		return false;
 	}
 
+#if PA_CHECK_VERSION(0,9,8)
+	pa_stream_set_suspended_callback(po->stream,
+					 pulse_output_stream_suspended_cb, po);
+#endif
+
 	pa_stream_set_state_callback(po->stream,
 				     pulse_output_stream_state_cb, po);
 	pa_stream_set_write_callback(po->stream,
@@ -719,6 +741,15 @@ pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r)
 	/* wait until the server allows us to write */
 
 	while (po->writable == 0) {
+#if PA_CHECK_VERSION(0,9,8)
+		if (pa_stream_is_suspended(po->stream)) {
+			pa_threaded_mainloop_unlock(po->mainloop);
+			g_set_error(error_r, pulse_output_quark(), 0,
+				    "suspended");
+			return 0;
+		}
+#endif
+
 		pa_threaded_mainloop_wait(po->mainloop);
 
 		if (pa_stream_get_state(po->stream) != PA_STREAM_READY) {