diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 03398fcade..f8fea023b8 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -6144,8 +6144,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) @@ -6308,6 +6323,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);