rtspsrc: do not change state to PLAYING if currently chaning state
authorAleix Conchillo Flaque <aleix@oblong.com>
Thu, 27 Sep 2012 19:17:58 +0000 (12:17 -0700)
committerWim Taymans <wim.taymans@collabora.co.uk>
Mon, 10 Dec 2012 14:13:22 +0000 (15:13 +0100)
* 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

gst/rtsp/gstrtspsrc.c

index 03398fc..f8fea02 100644 (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);