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
This commit is contained in:
Aleix Conchillo Flaque 2012-09-27 12:17:58 -07:00 committed by Wim Taymans
parent d4622c974f
commit 3503aef946

View file

@ -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);