diff options
author | Aleix Conchillo Flaque <aleix@oblong.com> | 2012-09-27 12:17:58 -0700 |
---|---|---|
committer | Wim Taymans <wim.taymans@collabora.co.uk> | 2012-12-10 15:48:10 +0100 |
commit | 967fc61715fa854dacaa200069437fe57d4d8390 (patch) | |
tree | a6ee3157307881343f269b94335de5ab43d445fe /gst/rtsp/gstrtspsrc.c | |
parent | a1e38e7a743181f9694fb788371da9d05866d1e4 (diff) |
rtspsrc: do not change state to PLAYING if currently chaning state
* gst/rtsp/gstrtspsrc.c (gst_rtspsrc_play): state change might be
happening in the application thread, so we don't change the state to
PLAYING in the gstrtspsrc thread unless it is safe.
A specific case is when chaning the state to NULL from the application
thread. This will synchronously try to stop the task (with the element
state lock acquired), but we will try a gst_element_set_state from
gstrtspsrc thread which will block on the element state lock causing a
deadlock.
https://bugzilla.gnome.org/show_bug.cgi?id=684312
Diffstat (limited to 'gst/rtsp/gstrtspsrc.c')
-rw-r--r-- | gst/rtsp/gstrtspsrc.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 48698932d..3db2d6905 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -6183,8 +6183,23 @@ gst_rtspsrc_play (GstRTSPSrc * src, GstSegment * segment, gboolean async) * only in async case, since receive elements may not have been affected * by overall state change (e.g. not around yet), * do not mess with state in sync case (e.g. seeking) */ - if (async) - gst_element_set_state (GST_ELEMENT_CAST (src), GST_STATE_PLAYING); + if (async) { + /* state change might be happening in the application thread. A + * specific case is when chaging state to NULL where we will wait + * for this task to finish (gst_rtspsrc_stop). However this task + * will try to change the state to PLAYING causing a deadlock. */ + + /* make sure we are not in the middle of a state change. The + * state lock is a recursive lock so it's safe to lock twice from + * the same thread */ + if (GST_STATE_TRYLOCK (src)) { + gst_element_set_state (GST_ELEMENT_CAST (src), GST_STATE_PLAYING); + GST_STATE_UNLOCK (src); + } else { + res = GST_RTSP_ERROR; + goto changing_state; + } + } /* construct a control url */ if (src->control) @@ -6341,6 +6356,11 @@ was_playing: GST_DEBUG_OBJECT (src, "we were already PLAYING"); goto done; } +changing_state: + { + GST_DEBUG_OBJECT (src, "failed going to PLAYING, already changing state"); + goto done; + } create_request_failed: { gchar *str = gst_rtsp_strresult (res); |