rtsp-media: Add property to decide if sending media should be stopped when a client disconnects without TEARDOWN

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
This commit is contained in:
Sebastian Dröge 2015-12-09 18:24:24 +02:00
parent 5dd1166259
commit c8f179948e
5 changed files with 191 additions and 9 deletions

View file

@ -332,9 +332,38 @@ static GstRTSPFilterResult
filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia, filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia,
gpointer user_data) 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;
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; return GST_RTSP_FILTER_REMOVE;
} else {
*closed = FALSE;
return GST_RTSP_FILTER_KEEP;
}
} }
static void static void
@ -395,11 +424,16 @@ static GstRTSPFilterResult
cleanup_session (GstRTSPClient * client, GstRTSPSession * sess, cleanup_session (GstRTSPClient * client, GstRTSPSession * sess,
gpointer user_data) gpointer user_data)
{ {
gboolean *closed = user_data;
/* unlink all media managed in this session. This needs to happen /* unlink all media managed in this session. This needs to happen
* without the client lock, so we really want to do it here. */ * 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);
if (*closed)
return GST_RTSP_FILTER_REMOVE; return GST_RTSP_FILTER_REMOVE;
else
return GST_RTSP_FILTER_KEEP;
} }
static void static void
@ -3784,11 +3818,13 @@ static void
client_watch_notify (GstRTSPClient * client) client_watch_notify (GstRTSPClient * client)
{ {
GstRTSPClientPrivate *priv = client->priv; GstRTSPClientPrivate *priv = client->priv;
gboolean closed = TRUE;
GST_INFO ("client %p: watch destroyed", client); GST_INFO ("client %p: watch destroyed", client);
priv->watch = NULL; priv->watch = NULL;
/* remove all sessions and so drop the extra client ref */ /* remove all sessions if the media says so and so drop the extra client ref */
gst_rtsp_client_session_filter (client, cleanup_session, NULL); gst_rtsp_client_session_filter (client, cleanup_session, &closed);
if (closed)
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL); g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
g_object_unref (client); g_object_unref (client);
} }

View file

@ -60,6 +60,7 @@ struct _GstRTSPMediaFactoryPrivate
guint buffer_size; guint buffer_size;
GstRTSPAddressPool *pool; GstRTSPAddressPool *pool;
GstRTSPTransportMode transport_mode; GstRTSPTransportMode transport_mode;
gboolean stop_on_disconnect;
GstClockTime rtx_time; GstClockTime rtx_time;
guint latency; guint latency;
@ -80,6 +81,7 @@ struct _GstRTSPMediaFactoryPrivate
#define DEFAULT_BUFFER_SIZE 0x80000 #define DEFAULT_BUFFER_SIZE 0x80000
#define DEFAULT_LATENCY 200 #define DEFAULT_LATENCY 200
#define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY
#define DEFAULT_STOP_ON_DISCONNECT TRUE
enum enum
{ {
@ -93,6 +95,7 @@ enum
PROP_BUFFER_SIZE, PROP_BUFFER_SIZE,
PROP_LATENCY, PROP_LATENCY,
PROP_TRANSPORT_MODE, PROP_TRANSPORT_MODE,
PROP_STOP_ON_DISCONNECT,
PROP_LAST PROP_LAST
}; };
@ -202,6 +205,13 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE, GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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] = gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass), g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass, 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->buffer_size = DEFAULT_BUFFER_SIZE;
priv->latency = DEFAULT_LATENCY; priv->latency = DEFAULT_LATENCY;
priv->transport_mode = DEFAULT_TRANSPORT_MODE; priv->transport_mode = DEFAULT_TRANSPORT_MODE;
priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
g_mutex_init (&priv->lock); g_mutex_init (&priv->lock);
g_mutex_init (&priv->medias_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, g_value_set_flags (value,
gst_rtsp_media_factory_get_transport_mode (factory)); gst_rtsp_media_factory_get_transport_mode (factory));
break; break;
case PROP_STOP_ON_DISCONNECT:
g_value_set_boolean (value,
gst_rtsp_media_factory_is_stop_on_disonnect (factory));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); 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, gst_rtsp_media_factory_set_transport_mode (factory,
g_value_get_flags (value)); g_value_get_flags (value));
break; break;
case PROP_STOP_ON_DISCONNECT:
gst_rtsp_media_factory_set_stop_on_disconnect (factory,
g_value_get_boolean (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
} }
@ -862,6 +881,56 @@ gst_rtsp_media_factory_get_protocols (GstRTSPMediaFactory * factory)
return res; 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: * gst_rtsp_media_factory_set_retransmission_time:
* @factory: a #GstRTSPMediaFactory * @factory: a #GstRTSPMediaFactory
@ -1270,7 +1339,7 @@ static void
default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
{ {
GstRTSPMediaFactoryPrivate *priv = factory->priv; GstRTSPMediaFactoryPrivate *priv = factory->priv;
gboolean shared, eos_shutdown; gboolean shared, eos_shutdown, stop_on_disconnect;
guint size; guint size;
GstRTSPSuspendMode suspend_mode; GstRTSPSuspendMode suspend_mode;
GstRTSPProfile profiles; GstRTSPProfile profiles;
@ -1292,6 +1361,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
rtx_time = priv->rtx_time; rtx_time = priv->rtx_time;
latency = priv->latency; latency = priv->latency;
transport_mode = priv->transport_mode; transport_mode = priv->transport_mode;
stop_on_disconnect = priv->stop_on_disconnect;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
gst_rtsp_media_set_suspend_mode (media, suspend_mode); 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_retransmission_time (media, rtx_time);
gst_rtsp_media_set_latency (media, latency); gst_rtsp_media_set_latency (media, latency);
gst_rtsp_media_set_transport_mode (media, transport_mode); 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))) { if ((pool = gst_rtsp_media_factory_get_address_pool (factory))) {
gst_rtsp_media_set_address_pool (media, pool); gst_rtsp_media_set_address_pool (media, pool);

View file

@ -118,6 +118,10 @@ void gst_rtsp_media_factory_set_shared (GstRTSPMediaFacto
gboolean shared); gboolean shared);
gboolean gst_rtsp_media_factory_is_shared (GstRTSPMediaFactory *factory); 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, void gst_rtsp_media_factory_set_suspend_mode (GstRTSPMediaFactory *factory,
GstRTSPSuspendMode mode); GstRTSPSuspendMode mode);
GstRTSPSuspendMode gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory *factory); GstRTSPSuspendMode gst_rtsp_media_factory_get_suspend_mode (GstRTSPMediaFactory *factory);

View file

@ -102,6 +102,7 @@ struct _GstRTSPMediaPrivate
GstRTSPAddressPool *pool; GstRTSPAddressPool *pool;
gboolean blocked; gboolean blocked;
GstRTSPTransportMode transport_mode; GstRTSPTransportMode transport_mode;
gboolean stop_on_disconnect;
GstElement *element; GstElement *element;
GRecMutex state_lock; /* locking order: state lock, lock */ GRecMutex state_lock; /* locking order: state lock, lock */
@ -151,6 +152,7 @@ struct _GstRTSPMediaPrivate
#define DEFAULT_TIME_PROVIDER FALSE #define DEFAULT_TIME_PROVIDER FALSE
#define DEFAULT_LATENCY 200 #define DEFAULT_LATENCY 200
#define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY
#define DEFAULT_STOP_ON_DISCONNECT TRUE
/* define to dump received RTCP packets */ /* define to dump received RTCP packets */
#undef DUMP_STATS #undef DUMP_STATS
@ -169,6 +171,7 @@ enum
PROP_TIME_PROVIDER, PROP_TIME_PROVIDER,
PROP_LATENCY, PROP_LATENCY,
PROP_TRANSPORT_MODE, PROP_TRANSPORT_MODE,
PROP_STOP_ON_DISCONNECT,
PROP_LAST PROP_LAST
}; };
@ -329,6 +332,13 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE, GST_TYPE_RTSP_TRANSPORT_MODE, DEFAULT_TRANSPORT_MODE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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] = gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL, 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->buffer_size = DEFAULT_BUFFER_SIZE;
priv->time_provider = DEFAULT_TIME_PROVIDER; priv->time_provider = DEFAULT_TIME_PROVIDER;
priv->transport_mode = DEFAULT_TRANSPORT_MODE; priv->transport_mode = DEFAULT_TRANSPORT_MODE;
priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
} }
static void static void
@ -472,6 +483,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
case PROP_TRANSPORT_MODE: case PROP_TRANSPORT_MODE:
g_value_set_flags (value, gst_rtsp_media_get_transport_mode (media)); g_value_set_flags (value, gst_rtsp_media_get_transport_mode (media));
break; break;
case PROP_STOP_ON_DISCONNECT:
g_value_set_boolean (value, gst_rtsp_media_is_stop_on_disconnect (media));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); 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: case PROP_TRANSPORT_MODE:
gst_rtsp_media_set_transport_mode (media, g_value_get_flags (value)); gst_rtsp_media_set_transport_mode (media, g_value_get_flags (value));
break; break;
case PROP_STOP_ON_DISCONNECT:
gst_rtsp_media_set_stop_on_disconnect (media,
g_value_get_boolean (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
} }
@ -1167,6 +1185,56 @@ gst_rtsp_media_get_buffer_size (GstRTSPMedia * media)
return res; 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: * gst_rtsp_media_set_retransmission_time:
* @media: a #GstRTSPMedia * @media: a #GstRTSPMedia

View file

@ -186,6 +186,9 @@ GstRTSPPermissions * gst_rtsp_media_get_permissions (GstRTSPMedia *media);
void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared); void gst_rtsp_media_set_shared (GstRTSPMedia *media, gboolean shared);
gboolean gst_rtsp_media_is_shared (GstRTSPMedia *media); 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); void gst_rtsp_media_set_transport_mode (GstRTSPMedia *media, GstRTSPTransportMode mode);
GstRTSPTransportMode gst_rtsp_media_get_transport_mode (GstRTSPMedia *media); GstRTSPTransportMode gst_rtsp_media_get_transport_mode (GstRTSPMedia *media);