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