On Tue, 2012-12-04 at 03:47 +0200, Tanu Kaskinen wrote:
> Hmm... I checked when the operation state is set to DONE, and it's not
> done until after calling the callback. So, if the kernel schedules the
> main thread after the pa_threaded_mainloop_signal() call, but before the
> operation state is set to DONE, the main thread will get stuck. It's a
> bug in libcanberra. I'll try to come up with a patch for that.

I've attached a patch. Henrik, could you test it? libcanberra source
code can be retrieved with

    git clone git://git.0pointer.de/libcanberra

-- 
Tanu
>From 1bf93f589dde287525d3dc194b2d7d8912b623e7 Mon Sep 17 00:00:00 2001
From: Tanu Kaskinen <[email protected]>
Date: Tue, 4 Dec 2012 05:18:06 +0200
Subject: [PATCH] pulse: Fix incorrect operation state monitoring.

This should fix gnome-shell hanging in certain situations:
http://thread.gmane.org/gmane.comp.audio.pulseaudio.general/14335/focus=15208
---
 src/pulse.c |   28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/src/pulse.c b/src/pulse.c
index e28a517..bcd5d04 100644
--- a/src/pulse.c
+++ b/src/pulse.c
@@ -65,6 +65,7 @@ struct outstanding {
         ca_sound_file *file;
         int error;
         unsigned clean_up:1; /* Handler needs to clean up the outstanding struct */
+        unsigned play_request_processed:1;
         unsigned finished:1; /* finished playing */
 };
 
@@ -587,6 +588,8 @@ static void play_sample_cb(pa_context *c, uint32_t idx, void *userdata) {
         } else
                 out->error = translate_error(pa_context_errno(c));
 
+        out->play_request_processed = TRUE;
+
         pa_threaded_mainloop_signal(p->mainloop, FALSE);
 }
 
@@ -944,13 +947,30 @@ int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_cal
                         for (;;) {
                                 pa_operation_state_t state = pa_operation_get_state(o);
 
-                                if (state == PA_OPERATION_DONE) {
-                                        canceled = FALSE;
-                                        break;
-                                } else if (state == PA_OPERATION_CANCELED) {
+                                /* We'll wait until we get a reply to the "play
+                                 * sample" request. The context might
+                                 * disconnect while waiting, so that case
+                                 * needs to be handled too.
+                                 *
+                                 * The easiest way to check for disconnection
+                                 * is to check the operation state. The
+                                 * operation will get canceled iff a
+                                 * disconnection happens. It would be nice to
+                                 * use PA_OPERATION_DONE to check if we have
+                                 * received a reply, but unfortunately
+                                 * play_sample_cb() will get called before the
+                                 * operation state is updated. Therefore, we
+                                 * need to store in the outstanding struct a
+                                 * flag that tells whether the play request has
+                                 * been processed. */
+                                if (state == PA_OPERATION_CANCELED) {
                                         canceled = TRUE;
                                         break;
                                 }
+                                if (out->play_request_processed) {
+                                        canceled = FALSE;
+                                        break;
+                                }
 
                                 pa_threaded_mainloop_wait(p->mainloop);
                         }
-- 
1.7.10.4

_______________________________________________
pulseaudio-discuss mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss

Reply via email to