diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 0a33e45321..c7620a89ac 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -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; - return GST_RTSP_FILTER_REMOVE; + 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; + + 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); } diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 087aa8ad35..ac6ce1f0c1 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -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); } @@ -862,6 +881,56 @@ gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory) return res; } +/** + * 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 @@ -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); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 0dc1067e27..e82b64a913 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -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); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index 5a6f758ab0..61e68b2be9 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -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); } @@ -1167,6 +1185,56 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media) return res; } +/** + * 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 @@ -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); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index d554afe769..edf669f296 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -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);