From 9b75398f448af1a15a8e2859d0d115875e3b6fef Mon Sep 17 00:00:00 2001 From: Federico Mena-Quintero Date: Sun, 19 Apr 2009 03:24:53 +0200 Subject: pulse: don't hang when operation gets canceled Handle properly when a sample play operation gets canceled. http://bugs.freedesktop.org/show_bug.cgi?id=21263 --- src/canberra.h | 3 ++- src/common.c | 3 ++- src/pulse.c | 25 +++++++++++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/canberra.h b/src/canberra.h index 9664ef2..b4ceb27 100644 --- a/src/canberra.h +++ b/src/canberra.h @@ -415,7 +415,8 @@ enum { CA_ERROR_INTERNAL = -15, CA_ERROR_DISABLED = -16, CA_ERROR_FORKED = -17, - _CA_ERROR_MAX = -18 + CA_ERROR_DISCONNECTED = -18, + _CA_ERROR_MAX = -19 }; /** diff --git a/src/common.c b/src/common.c index ac8b982..e2548ec 100644 --- a/src/common.c +++ b/src/common.c @@ -663,7 +663,8 @@ const char *ca_strerror(int code) { [-CA_ERROR_IO] = "IO error", [-CA_ERROR_INTERNAL] = "Internal error", [-CA_ERROR_DISABLED] = "Sound disabled", - [-CA_ERROR_FORKED] = "Process forked" + [-CA_ERROR_FORKED] = "Process forked", + [-CA_ERROR_DISCONNECTED] = "Disconnected" }; ca_return_val_if_fail(code <= 0, NULL); diff --git a/src/pulse.c b/src/pulse.c index 3cd4b2a..c959719 100644 --- a/src/pulse.c +++ b/src/pulse.c @@ -770,6 +770,8 @@ int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_cal /* Ok, this sample has an event id, let's try to play it from the cache */ for (;;) { + ca_bool_t canceled; + pa_threaded_mainloop_lock(p->mainloop); /* Let's try to play the sample */ @@ -779,16 +781,35 @@ int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_cal goto finish; } - while (pa_operation_get_state(o) != PA_OPERATION_DONE) + 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) { + canceled = TRUE; + break; + } + pa_threaded_mainloop_wait(p->mainloop); + } pa_operation_unref(o); pa_threaded_mainloop_unlock(p->mainloop); + /* The operation might have been canceled due to connection termination */ + if (canceled) { + ret = CA_ERROR_DISCONNECTED; + goto finish; + } + /* Did we manage to play the sample or did some other error occur? */ - if (out->error != CA_ERROR_NOTFOUND) + if (out->error != CA_ERROR_NOTFOUND) { + ret = out->error; goto finish; + } /* Hmm, we need to play it directly */ if (cache_control != CA_CACHE_CONTROL_PERMANENT) -- cgit