rtsp-media: Add property to decide if sending media should be stopped when a client...
authorSebastian Dröge <sebastian@centricular.com>
Wed, 9 Dec 2015 16:24:24 +0000 (18:24 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Mon, 28 Dec 2015 08:51:56 +0000 (10:51 +0200)
Without TEARDOWN it might be desireable to keep the media running and continue
sending data to the client, even if the RTSP connection itself is
disconnected.

Only do this for session medias that have only UDP transports. If there's at
least on TCP transport, it will stop working and cause problems when the
connection is disconnected.

https://bugzilla.gnome.org/show_bug.cgi?id=758999

gst/rtsp-server/rtsp-client.c
gst/rtsp-server/rtsp-media-factory.c
gst/rtsp-server/rtsp-media-factory.h
gst/rtsp-server/rtsp-media.c
gst/rtsp-server/rtsp-media.h

index 0a33e45..c7620a8 100644 (file)
@@ -332,9 +332,38 @@ static GstRTSPFilterResult
 filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia,
     gpointer user_data)
 {
-  gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
+  gboolean *closed = user_data;
+  GstRTSPMedia *media;
+  guint i, n_streams;
+  gboolean is_all_udp = TRUE;
+
+  media = gst_rtsp_session_media_get_media (sessmedia);
+  n_streams = gst_rtsp_media_n_streams (media);
+
+  for (i = 0; i < n_streams; i++) {
+    GstRTSPStreamTransport *transport =
+        gst_rtsp_session_media_get_transport (sessmedia, i);
+    const GstRTSPTransport *rtsp_transport;
 
-  return GST_RTSP_FILTER_REMOVE;
+    if (!transport)
+      continue;
+
+    rtsp_transport = gst_rtsp_stream_transport_get_transport (transport);
+    if (rtsp_transport
+        && rtsp_transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP
+        && rtsp_transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP_MCAST) {
+      is_all_udp = FALSE;
+      break;
+    }
+  }
+
+  if (!is_all_udp || gst_rtsp_media_is_stop_on_disconnect (media)) {
+    gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
+    return GST_RTSP_FILTER_REMOVE;
+  } else {
+    *closed = FALSE;
+    return GST_RTSP_FILTER_KEEP;
+  }
 }
 
 static void
@@ -395,11 +424,16 @@ static GstRTSPFilterResult
 cleanup_session (GstRTSPClient * client, GstRTSPSession * sess,
     gpointer user_data)
 {
+  gboolean *closed = user_data;
+
   /* unlink all media managed in this session. This needs to happen
    * without the client lock, so we really want to do it here. */
-  gst_rtsp_session_filter (sess, filter_session_media, client);
+  gst_rtsp_session_filter (sess, filter_session_media, user_data);
 
-  return GST_RTSP_FILTER_REMOVE;
+  if (*closed)
+    return GST_RTSP_FILTER_REMOVE;
+  else
+    return GST_RTSP_FILTER_KEEP;
 }
 
 static void
@@ -3784,12 +3818,14 @@ static void
 client_watch_notify (GstRTSPClient * client)
 {
   GstRTSPClientPrivate *priv = client->priv;
+  gboolean closed = TRUE;
 
   GST_INFO ("client %p: watch destroyed", client);
   priv->watch = NULL;
-  /* remove all sessions and so drop the extra client ref */
-  gst_rtsp_client_session_filter (client, cleanup_session, NULL);
-  g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
+  /* remove all sessions if the media says so and so drop the extra client ref */
+  gst_rtsp_client_session_filter (client, cleanup_session, &closed);
+  if (closed)
+    g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
   g_object_unref (client);
 }
 
index 087aa8a..ac6ce1f 100644 (file)
@@ -60,6 +60,7 @@ struct _GstRTSPMediaFactoryPrivate
   guint buffer_size;
   GstRTSPAddressPool *pool;
   GstRTSPTransportMode transport_mode;
+  gboolean stop_on_disconnect;
 
   GstClockTime rtx_time;
   guint latency;
@@ -80,6 +81,7 @@ struct _GstRTSPMediaFactoryPrivate
 #define DEFAULT_BUFFER_SIZE     0x80000
 #define DEFAULT_LATENCY         200
 #define DEFAULT_TRANSPORT_MODE  GST_RTSP_TRANSPORT_MODE_PLAY
+#define DEFAULT_STOP_ON_DISCONNECT TRUE
 
 enum
 {
@@ -93,6 +95,7 @@ enum
   PROP_BUFFER_SIZE,
   PROP_LATENCY,
   PROP_TRANSPORT_MODE,
+  PROP_STOP_ON_DISCONNECT,
   PROP_LAST
 };
 
@@ -202,6 +205,13 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
           GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_STOP_ON_DISCONNECT,
+      g_param_spec_boolean ("stop-on-disconnect", "Stop On Disconnect",
+          "If media from this factory should be stopped "
+          "when a client disconnects without TEARDOWN",
+          DEFAULT_STOP_ON_DISCONNECT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
       g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
@@ -240,6 +250,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
   priv->buffer_size = DEFAULT_BUFFER_SIZE;
   priv->latency = DEFAULT_LATENCY;
   priv->transport_mode = DEFAULT_TRANSPORT_MODE;
+  priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
 
   g_mutex_init (&priv->lock);
   g_mutex_init (&priv->medias_lock);
@@ -304,6 +315,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid,
       g_value_set_flags (value,
           gst_rtsp_media_factory_get_transport_mode (factory));
       break;
+    case PROP_STOP_ON_DISCONNECT:
+      g_value_set_boolean (value,
+          gst_rtsp_media_factory_is_stop_on_disonnect (factory));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
   }
@@ -347,6 +362,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid,
       gst_rtsp_media_factory_set_transport_mode (factory,
           g_value_get_flags (value));
       break;
+    case PROP_STOP_ON_DISCONNECT:
+      gst_rtsp_media_factory_set_stop_on_disconnect (factory,
+          g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
   }
@@ -863,6 +882,56 @@ gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory)
 }
 
 /**
+ * gst_rtsp_media_factory_set_stop_on_disconnect:
+ * @factory: a #GstRTSPMediaFactory
+ * @stop_on_disconnect: the new value
+ *
+ * Configure if media created from this factory should be stopped
+ * when a client disconnects without sending TEARDOWN.
+ */
+void
+gst_rtsp_media_factory_set_stop_on_disconnect (GstRTSPMediaFactory * factory,
+    gboolean stop_on_disconnect)
+{
+  GstRTSPMediaFactoryPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+
+  priv = factory->priv;
+
+  GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+  priv->stop_on_disconnect = stop_on_disconnect;
+  GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+}
+
+/**
+ * gst_rtsp_media_factory_is_stop_on_disconnect:
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Get if media created from this factory should be stopped when a client
+ * disconnects without sending TEARDOWN.
+ *
+ * Returns: %TRUE if the media will be stopped when a client disconnects
+ *     without sending TEARDOWN.
+ */
+gboolean
+gst_rtsp_media_factory_is_stop_on_disonnect (GstRTSPMediaFactory * factory)
+{
+  GstRTSPMediaFactoryPrivate *priv;
+  gboolean result;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), TRUE);
+
+  priv = factory->priv;
+
+  GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+  result = priv->stop_on_disconnect;
+  GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+
+  return result;
+}
+
+/**
  * gst_rtsp_media_factory_set_retransmission_time:
  * @factory: a #GstRTSPMediaFactory
  * @time: a #GstClockTime
@@ -1270,7 +1339,7 @@ static void
 default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
 {
   GstRTSPMediaFactoryPrivate *priv = factory->priv;
-  gboolean shared, eos_shutdown;
+  gboolean shared, eos_shutdown, stop_on_disconnect;
   guint size;
   GstRTSPSuspendMode suspend_mode;
   GstRTSPProfile profiles;
@@ -1292,6 +1361,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
   rtx_time = priv->rtx_time;
   latency = priv->latency;
   transport_mode = priv->transport_mode;
+  stop_on_disconnect = priv->stop_on_disconnect;
   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
 
   gst_rtsp_media_set_suspend_mode (media, suspend_mode);
@@ -1303,6 +1373,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
   gst_rtsp_media_set_retransmission_time (media, rtx_time);
   gst_rtsp_media_set_latency (media, latency);
   gst_rtsp_media_set_transport_mode (media, transport_mode);
+  gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect);
 
   if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) {
     gst_rtsp_media_set_address_pool (media, pool);
index 0dc1067..e82b64a 100644 (file)
@@ -118,6 +118,10 @@ void                  gst_rtsp_media_factory_set_shared       (GstRTSPMediaFacto
                                                                gboolean shared);
 gboolean              gst_rtsp_media_factory_is_shared        (GstRTSPMediaFactory *factory);
 
+void                  gst_rtsp_media_factory_set_stop_on_disconnect       (GstRTSPMediaFactory *factory,
+                                                                           gboolean stop_on_disconnect);
+gboolean              gst_rtsp_media_factory_is_stop_on_disonnect        (GstRTSPMediaFactory *factory);
+
 void                  gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory *factory,
                                                                GstRTSPSuspendMode mode);
 GstRTSPSuspendMode    gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory *factory);
index 5a6f758..61e68b2 100644 (file)
@@ -102,6 +102,7 @@ struct _GstRTSPMediaPrivate
   GstRTSPAddressPool *pool;
   gboolean blocked;
   GstRTSPTransportMode transport_mode;
+  gboolean stop_on_disconnect;
 
   GstElement *element;
   GRecMutex state_lock;         /* locking order: state lock, lock */
@@ -151,6 +152,7 @@ struct _GstRTSPMediaPrivate
 #define DEFAULT_TIME_PROVIDER   FALSE
 #define DEFAULT_LATENCY         200
 #define DEFAULT_TRANSPORT_MODE  GST_RTSP_TRANSPORT_MODE_PLAY
+#define DEFAULT_STOP_ON_DISCONNECT TRUE
 
 /* define to dump received RTCP packets */
 #undef DUMP_STATS
@@ -169,6 +171,7 @@ enum
   PROP_TIME_PROVIDER,
   PROP_LATENCY,
   PROP_TRANSPORT_MODE,
+  PROP_STOP_ON_DISCONNECT,
   PROP_LAST
 };
 
@@ -329,6 +332,13 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
           GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_STOP_ON_DISCONNECT,
+      g_param_spec_boolean ("stop-on-disconnect", "Stop On Disconnect",
+          "If this media pipeline should be stopped "
+          "when a client disconnects without TEARDOWN",
+          DEFAULT_STOP_ON_DISCONNECT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
       g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
       G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
@@ -396,6 +406,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
   priv->buffer_size = DEFAULT_BUFFER_SIZE;
   priv->time_provider = DEFAULT_TIME_PROVIDER;
   priv->transport_mode = DEFAULT_TRANSPORT_MODE;
+  priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
 }
 
 static void
@@ -472,6 +483,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
     case PROP_TRANSPORT_MODE:
       g_value_set_flags (value, gst_rtsp_media_get_transport_mode (media));
       break;
+    case PROP_STOP_ON_DISCONNECT:
+      g_value_set_boolean (value, gst_rtsp_media_is_stop_on_disconnect (media));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
   }
@@ -518,6 +532,10 @@ gst_rtsp_media_set_property (GObject * object, guint propid,
     case PROP_TRANSPORT_MODE:
       gst_rtsp_media_set_transport_mode (media, g_value_get_flags (value));
       break;
+    case PROP_STOP_ON_DISCONNECT:
+      gst_rtsp_media_set_stop_on_disconnect (media,
+          g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
   }
@@ -1168,6 +1186,56 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
 }
 
 /**
+ * gst_rtsp_media_set_stop_on_disconnect:
+ * @media: a #GstRTSPMedia
+ * @stop_on_disconnect: the new value
+ *
+ * Set or unset if the pipeline for @media should be stopped when a
+ * client disconnects without sending TEARDOWN.
+ */
+void
+gst_rtsp_media_set_stop_on_disconnect (GstRTSPMedia * media,
+    gboolean stop_on_disconnect)
+{
+  GstRTSPMediaPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  priv->stop_on_disconnect = stop_on_disconnect;
+  g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_media_is_stop_on_disconnect:
+ * @media: a #GstRTSPMedia
+ *
+ * Check if the pipeline for @media will be stopped when a client disconnects
+ * without sending TEARDOWN.
+ *
+ * Returns: %TRUE if the media will be stopped when a client disconnects
+ *     without sending TEARDOWN.
+ */
+gboolean
+gst_rtsp_media_is_stop_on_disconnect (GstRTSPMedia * media)
+{
+  GstRTSPMediaPrivate *priv;
+  gboolean res;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), TRUE);
+
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  res = priv->stop_on_disconnect;
+  g_mutex_unlock (&priv->lock);
+
+  return res;
+}
+
+/**
  * gst_rtsp_media_set_retransmission_time:
  * @media: a #GstRTSPMedia
  * @time: the new value
@@ -2604,7 +2672,7 @@ default_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
   /* do remainder in context */
   source = g_idle_source_new ();
   g_source_set_callback (source, (GSourceFunc) start_prepare,
-    g_object_ref (media), (GDestroyNotify) g_object_unref);
+      g_object_ref (media), (GDestroyNotify) g_object_unref);
   g_source_attach (source, context);
   g_source_unref (source);
 
index d554afe..edf669f 100644 (file)
@@ -186,6 +186,9 @@ GstRTSPPermissions *  gst_rtsp_media_get_permissions  (GstRTSPMedia *media);
 void                  gst_rtsp_media_set_shared       (GstRTSPMedia *media, gboolean shared);
 gboolean              gst_rtsp_media_is_shared        (GstRTSPMedia *media);
 
+void                  gst_rtsp_media_set_stop_on_disconnect (GstRTSPMedia *media, gboolean stop_on_disconnect);
+gboolean              gst_rtsp_media_is_stop_on_disconnect  (GstRTSPMedia *media);
+
 void                  gst_rtsp_media_set_transport_mode  (GstRTSPMedia *media, GstRTSPTransportMode mode);
 GstRTSPTransportMode  gst_rtsp_media_get_transport_mode  (GstRTSPMedia *media);