From 988db52016f3c5c75289a4db06331e37232323d3 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Thu, 29 Mar 2018 22:49:26 +0200 Subject: [PATCH] rtsp-server: add API to enable retransmission requests "do-retransmission" was previously set when rtx-time != 0, which made no sense as do-retransmission is used to enable the sending of retransmission requests, where as rtx-time is used by the peer to enable storing of buffers in order to respond to retransmission requests. rtsp-media now also provides a callback for the request-aux-receiver signal. https://bugzilla.gnome.org/show_bug.cgi?id=794822 --- docs/libs/gst-rtsp-server-sections.txt | 7 +++ gst/rtsp-server/rtsp-media-factory.c | 53 +++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 7 +++ gst/rtsp-server/rtsp-media.c | 95 ++++++++++++++++++++++++++++++++-- gst/rtsp-server/rtsp-media.h | 7 +++ gst/rtsp-server/rtsp-stream.c | 79 ++++++++++++++++++++++++++++ gst/rtsp-server/rtsp-stream.h | 3 ++ 7 files changed, 246 insertions(+), 5 deletions(-) diff --git a/docs/libs/gst-rtsp-server-sections.txt b/docs/libs/gst-rtsp-server-sections.txt index 103cd4a..956ac0a 100644 --- a/docs/libs/gst-rtsp-server-sections.txt +++ b/docs/libs/gst-rtsp-server-sections.txt @@ -178,6 +178,9 @@ gst_rtsp_media_get_buffer_size gst_rtsp_media_set_retransmission_time gst_rtsp_media_get_retransmission_time +gst_rtsp_media_set_do_retransmission +gst_rtsp_media_get_do_retransmission + gst_rtsp_media_set_latency gst_rtsp_media_get_latency @@ -277,6 +280,9 @@ gst_rtsp_media_factory_set_suspend_mode gst_rtsp_media_factory_set_retransmission_time gst_rtsp_media_factory_get_retransmission_time +gst_rtsp_media_factory_set_do_retransmission +gst_rtsp_media_factory_get_do_retransmission + gst_rtsp_media_factory_set_latency gst_rtsp_media_factory_get_latency @@ -617,6 +623,7 @@ gst_rtsp_stream_update_crypto gst_rtsp_stream_set_pt_map gst_rtsp_stream_request_aux_sender +gst_rtsp_stream_request_aux_receiver gst_rtsp_stream_seekable diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 5987d1b..80208d3 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -65,6 +65,7 @@ struct _GstRTSPMediaFactoryPrivate GstClockTime rtx_time; guint latency; + gboolean do_retransmission; GMutex medias_lock; GHashTable *medias; /* protected by medias_lock */ @@ -87,6 +88,7 @@ struct _GstRTSPMediaFactoryPrivate #define DEFAULT_LATENCY 200 #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE +#define DEFAULT_DO_RETRANSMISSION FALSE enum { @@ -264,6 +266,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory) priv->transport_mode = DEFAULT_TRANSPORT_MODE; priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; + priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; g_mutex_init (&priv->lock); g_mutex_init (&priv->medias_lock); @@ -1086,6 +1089,55 @@ gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory) } /** + * gst_rtsp_media_factory_set_do_retransmission: + * + * Set whether retransmission requests will be sent for + * receiving media + * + * Since: 1.16 + */ +void +gst_rtsp_media_factory_set_do_retransmission (GstRTSPMediaFactory * factory, + gboolean do_retransmission) +{ + GstRTSPMediaFactoryPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); + + priv = factory->priv; + + GST_DEBUG_OBJECT (factory, "Do retransmission %d", do_retransmission); + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + priv->do_retransmission = do_retransmission; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); +} + +/** + * gst_rtsp_media_factory_get_do_retransmission: + * + * Returns: Whether retransmission requests will be sent for receiving media + * + * Since: 1.16 + */ +gboolean +gst_rtsp_media_factory_get_do_retransmission (GstRTSPMediaFactory * factory) +{ + GstRTSPMediaFactoryPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), 0); + + priv = factory->priv; + + GST_RTSP_MEDIA_FACTORY_LOCK (factory); + res = priv->do_retransmission; + GST_RTSP_MEDIA_FACTORY_UNLOCK (factory); + + return res; +} + +/** * gst_rtsp_media_factory_set_latency: * @factory: a #GstRTSPMediaFactory * @latency: latency in milliseconds @@ -1584,6 +1636,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media) gst_rtsp_media_set_profiles (media, profiles); gst_rtsp_media_set_protocols (media, protocols); gst_rtsp_media_set_retransmission_time (media, rtx_time); + gst_rtsp_media_set_do_retransmission (media, priv->do_retransmission); 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); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 350dae8..7fb7fcc 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -199,6 +199,13 @@ GST_RTSP_SERVER_API GstClockTime gst_rtsp_media_factory_get_retransmission_time (GstRTSPMediaFactory * factory); GST_RTSP_SERVER_API +void gst_rtsp_media_factory_set_do_retransmission (GstRTSPMediaFactory * factory, + gboolean do_retransmission); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_factory_get_do_retransmission (GstRTSPMediaFactory * factory); + +GST_RTSP_SERVER_API void gst_rtsp_media_factory_set_latency (GstRTSPMediaFactory * factory, guint latency); diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index a1ab7aa..217dc35 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -139,6 +139,7 @@ struct _GstRTSPMediaPrivate GList *payloads; /* protected by lock */ GstClockTime rtx_time; /* protected by lock */ + gboolean do_retransmission; /* protected by lock */ guint latency; /* protected by lock */ GstClock *clock; /* protected by lock */ GstRTSPPublishClockMode publish_clock_mode; @@ -161,6 +162,8 @@ struct _GstRTSPMediaPrivate #define DEFAULT_TRANSPORT_MODE GST_RTSP_TRANSPORT_MODE_PLAY #define DEFAULT_STOP_ON_DISCONNECT TRUE +#define DEFAULT_DO_RETRANSMISSION FALSE + /* define to dump received RTCP packets */ #undef DUMP_STATS @@ -444,6 +447,7 @@ gst_rtsp_media_init (GstRTSPMedia * media) priv->transport_mode = DEFAULT_TRANSPORT_MODE; priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT; priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK; + priv->do_retransmission = DEFAULT_DO_RETRANSMISSION; } static void @@ -1408,9 +1412,6 @@ gst_rtsp_media_set_retransmission_time (GstRTSPMedia * media, GstClockTime time) gst_rtsp_stream_set_retransmission_time (stream, time); } - - if (priv->rtpbin) - g_object_set (priv->rtpbin, "do-retransmission", time > 0, NULL); g_mutex_unlock (&priv->lock); } @@ -1440,6 +1441,54 @@ gst_rtsp_media_get_retransmission_time (GstRTSPMedia * media) } /** + * gst_rtsp_media_set_do_retransmission: + * + * Set whether retransmission requests will be sent + * + * Since: 1.16 + */ +void +gst_rtsp_media_set_do_retransmission (GstRTSPMedia * media, gboolean do_retransmission) +{ + GstRTSPMediaPrivate *priv; + + g_return_if_fail (GST_IS_RTSP_MEDIA (media)); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + priv->do_retransmission = do_retransmission; + + if (priv->rtpbin) + g_object_set (priv->rtpbin, "do-retransmission", do_retransmission, NULL); + g_mutex_unlock (&priv->lock); +} + +/** + * gst_rtsp_media_get_do_retransmission: + * + * Returns: Whether retransmission requests will be sent + * + * Since: 1.16 + */ +gboolean +gst_rtsp_media_get_do_retransmission (GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv; + gboolean res; + + g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), 0); + + priv = media->priv; + + g_mutex_lock (&priv->lock); + res = priv->do_retransmission; + g_mutex_unlock (&priv->lock); + + return res; +} + +/** * gst_rtsp_media_set_latency: * @media: a #GstRTSPMedia * @latency: latency in milliseconds @@ -2997,6 +3046,32 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) GstRTSPMediaPrivate *priv = media->priv; GstRTSPStream *stream = NULL; guint i; + GstElement *res = NULL; + + g_mutex_lock (&priv->lock); + for (i = 0; i < priv->streams->len; i++) { + stream = g_ptr_array_index (priv->streams, i); + + if (sessid == gst_rtsp_stream_get_index (stream)) + break; + + stream = NULL; + } + g_mutex_unlock (&priv->lock); + + if (stream) + res = gst_rtsp_stream_request_aux_sender (stream, sessid); + + return res; +} + +static GstElement * +request_aux_receiver (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) +{ + GstRTSPMediaPrivate *priv = media->priv; + GstRTSPStream *stream = NULL; + guint i; + GstElement *res = NULL; g_mutex_lock (&priv->lock); for (i = 0; i < priv->streams->len; i++) { @@ -3004,10 +3079,15 @@ request_aux_sender (GstElement * rtpbin, guint sessid, GstRTSPMedia * media) if (sessid == gst_rtsp_stream_get_index (stream)) break; + + stream = NULL; } g_mutex_unlock (&priv->lock); - return gst_rtsp_stream_request_aux_sender (stream, sessid); + if (stream) + res = gst_rtsp_stream_request_aux_receiver (stream, sessid); + + return res; } static gboolean @@ -3034,6 +3114,11 @@ start_prepare (GstRTSPMedia * media) (GCallback) request_aux_sender, media); } + if (priv->do_retransmission) { + g_signal_connect (priv->rtpbin, "request-aux-receiver", + (GCallback) request_aux_receiver, media); + } + if (!gst_rtsp_stream_join_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin, GST_STATE_NULL)) { goto join_bin_failed; @@ -3041,7 +3126,7 @@ start_prepare (GstRTSPMedia * media) } if (priv->rtpbin) - g_object_set (priv->rtpbin, "do-retransmission", priv->rtx_time > 0, NULL); + g_object_set (priv->rtpbin, "do-retransmission", priv->do_retransmission, NULL); for (walk = priv->dynamic; walk; walk = g_list_next (walk)) { GstElement *elem = walk->data; diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 4d47517..84dfb14 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -282,6 +282,13 @@ GST_RTSP_SERVER_API GstClockTime gst_rtsp_media_get_retransmission_time (GstRTSPMedia *media); GST_RTSP_SERVER_API +void gst_rtsp_media_set_do_retransmission (GstRTSPMedia * media, + gboolean do_retransmission); + +GST_RTSP_SERVER_API +gboolean gst_rtsp_media_get_do_retransmission (GstRTSPMedia * media); + +GST_RTSP_SERVER_API void gst_rtsp_media_set_latency (GstRTSPMedia *media, guint latency); GST_RTSP_SERVER_API diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index f640d5a..abc0a56 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -124,6 +124,7 @@ struct _GstRTSPStreamPrivate /* retransmission */ GstElement *rtxsend; + GstElement *rtxreceive; guint rtx_pt; GstClockTime rtx_time; @@ -298,6 +299,8 @@ gst_rtsp_stream_finalize (GObject * obj) g_object_unref (priv->pool); if (priv->rtxsend) g_object_unref (priv->rtxsend); + if (priv->rtxreceive) + g_object_unref (priv->rtxreceive); for (i = 0; i < 2; i++) { if (priv->socket_v4[i]) @@ -2328,6 +2331,81 @@ gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid) return bin; } +static void +add_rtx_pt (gpointer key, GstCaps *caps, GstStructure *pt_map) +{ + guint pt = GPOINTER_TO_INT (key); + const GstStructure *s = gst_caps_get_structure (caps, 0); + const gchar *apt; + + if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "RTX") && + (apt = gst_structure_get_string (s, "apt"))) { + gst_structure_set (pt_map, apt, G_TYPE_UINT, pt, NULL); + } +} + +/* Call with priv->lock taken */ +static void +update_rtx_receive_pt_map (GstRTSPStream * stream) +{ + GstStructure *pt_map; + + if (!stream->priv->rtxreceive) + goto done; + + pt_map = gst_structure_new_empty ("application/x-rtp-pt-map"); + g_hash_table_foreach (stream->priv->ptmap, (GHFunc) add_rtx_pt, pt_map); + g_object_set (stream->priv->rtxreceive, "payload-type-map", pt_map, NULL); + gst_structure_free (pt_map); + +done: + return; +} + +/** + * gst_rtsp_stream_request_aux_receiver: + * @stream: a #GstRTSPStream + * @sessid: the session id + * + * Creating a rtxreceive bin + * + * Returns: (transfer full) (nullable): a #GstElement. + * + * Since: 1.16 + */ +GstElement * +gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid) +{ + GstElement *bin; + GstPad *pad; + gchar *name; + + g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL); + + g_mutex_lock (&stream->priv->lock); + + bin = gst_bin_new (NULL); + stream->priv->rtxreceive = gst_element_factory_make ("rtprtxreceive", NULL); + update_rtx_receive_pt_map (stream); + gst_bin_add (GST_BIN (bin), gst_object_ref (stream->priv->rtxreceive)); + + pad = gst_element_get_static_pad (stream->priv->rtxreceive, "src"); + name = g_strdup_printf ("src_%u", sessid); + gst_element_add_pad (bin, gst_ghost_pad_new (name, pad)); + g_free (name); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (stream->priv->rtxreceive, "sink"); + name = g_strdup_printf ("sink_%u", sessid); + gst_element_add_pad (bin, gst_ghost_pad_new (name, pad)); + g_free (name); + gst_object_unref (pad); + + g_mutex_unlock (&stream->priv->lock); + + return bin; +} + /** * gst_rtsp_stream_set_pt_map: * @stream: a #GstRTSPStream @@ -2346,6 +2424,7 @@ gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps) g_mutex_lock (&priv->lock); g_hash_table_insert (priv->ptmap, GINT_TO_POINTER (pt), gst_caps_ref (caps)); + update_rtx_receive_pt_map (stream); g_mutex_unlock (&priv->lock); } diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 9e3ec54..89839f8 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -280,6 +280,9 @@ GST_RTSP_SERVER_API GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * stream, guint sessid); GST_RTSP_SERVER_API +GstElement * gst_rtsp_stream_request_aux_receiver (GstRTSPStream * stream, guint sessid); + +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family, GstRTSPTransport *transport, gboolean use_client_settings); -- 2.7.4