summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleix Conchillo Flaque <aleix@oblong.com>2012-09-27 12:17:58 -0700
committerWim Taymans <wim.taymans@collabora.co.uk>2012-12-10 15:48:10 +0100
commit967fc61715fa854dacaa200069437fe57d4d8390 (patch)
treea6ee3157307881343f269b94335de5ab43d445fe
parenta1e38e7a743181f9694fb788371da9d05866d1e4 (diff)
downloadgstreamer-plugins-good-967fc61715fa854dacaa200069437fe57d4d8390.tar.gz
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
-rw-r--r--gst/rtsp/gstrtspsrc.c24
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);