From ca7f66f9b527ccc6f7309237af2fe53debd2e846 Mon Sep 17 00:00:00 2001 From: Matt Crane Date: Tue, 22 Nov 2022 11:32:57 -0500 Subject: [PATCH] rtpsession: Support disabling late adjustment of ntp-64 header ext Currently in rtp_session_send_rtp(), the existing ntp-64 RTP header extension timestamp is updated with the actual NTP time before sending the packet. However, there are some circumstances where we would like to preserve the original timestamp obtained from reference timestamp buffer metadata. This commit provides the ability to configure whether or not to update the ntp-64 header extension timestamp with the actual NTP time via the update-ntp64-header-ext boolean property. The property is also exposed via rtpbin. Default property value of TRUE will preserve existing behavior (update ntp-64 header ext with actual NTP time). Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1580 Part-of: --- .../docs/gst_plugins_cache.json | 36 +++++++++++++++++++ .../gst/rtpmanager/gstrtpbin.c | 33 +++++++++++++++++ .../gst/rtpmanager/gstrtpbin.h | 2 ++ .../gst/rtpmanager/gstrtpsession.c | 28 ++++++++++++++- .../gst/rtpmanager/rtpsession.c | 29 ++++++++++++++- .../gst/rtpmanager/rtpsession.h | 2 ++ 6 files changed, 128 insertions(+), 2 deletions(-) diff --git a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json index 0b03c5bd5d..86e530d79c 100644 --- a/subprojects/gst-plugins-good/docs/gst_plugins_cache.json +++ b/subprojects/gst-plugins-good/docs/gst_plugins_cache.json @@ -17401,6 +17401,18 @@ "type": "guint", "writable": true }, + "update-ntp64-header-ext": { + "blurb": "Whether RTP NTP header extension should be updated with actual NTP time", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, "use-pipeline-clock": { "blurb": "Use the pipeline running-time to set the NTP time in the RTCP SR messages (DEPRECATED: Use ntp-time-source property)", "conditionally-available": false, @@ -19318,6 +19330,18 @@ "type": "GstStructure", "writable": false }, + "update-ntp64-header-ext": { + "blurb": "Whether RTP NTP header extension should be updated with actual NTP time", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true + }, "use-pipeline-clock": { "blurb": "Use the pipeline running-time to set the NTP time in the RTCP SR messages (DEPRECATED: Use ntp-time-source property)", "conditionally-available": false, @@ -20083,6 +20107,18 @@ "readable": true, "type": "guint64", "writable": true + }, + "update-ntp64-header-ext": { + "blurb": "Whether RTP NTP header extension should be updated with actual NTP time", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "true", + "mutable": "null", + "readable": true, + "type": "gboolean", + "writable": true } }, "signals": { diff --git a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.c b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.c index bee500eeef..0fbf0820c1 100644 --- a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.c +++ b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.c @@ -357,6 +357,7 @@ enum #define DEFAULT_MAX_TS_OFFSET G_GINT64_CONSTANT(3000000000) #define DEFAULT_MIN_TS_OFFSET MIN_TS_OFFSET_ROUND_OFF_COMP #define DEFAULT_TS_OFFSET_SMOOTHING_FACTOR 0 +#define DEFAULT_UPDATE_NTP64_HEADER_EXT TRUE enum { @@ -389,6 +390,7 @@ enum PROP_TS_OFFSET_SMOOTHING_FACTOR, PROP_FEC_DECODERS, PROP_FEC_ENCODERS, + PROP_UPDATE_NTP64_HEADER_EXT, }; #define GST_RTP_BIN_RTCP_SYNC_TYPE (gst_rtp_bin_rtcp_sync_get_type()) @@ -777,6 +779,10 @@ create_session (GstRtpBin * rtpbin, gint id) g_object_set (session, "max-dropout-time", rtpbin->max_dropout_time, "max-misorder-time", rtpbin->max_misorder_time, NULL); + + g_object_set (session, "update-ntp64-header-ext", + rtpbin->update_ntp64_header_ext, NULL); + GST_OBJECT_UNLOCK (rtpbin); /* provide clock_rate to the session manager when needed */ @@ -2980,6 +2986,22 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass) "fec-encoders='fec,0=\"rtpst2022-1-fecenc\\ rows\\=5\\ columns\\=5\";'", GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRtpBin:update-ntp64-header-ext: + * + * Whether RTP NTP header extension should be updated with actual + * NTP time. If not, use the NTP time from buffer timestamp metadata + * + * Since: 1.22 + */ + g_object_class_install_property (gobject_class, + PROP_UPDATE_NTP64_HEADER_EXT, + g_param_spec_boolean ("update-ntp64-header-ext", + "Update NTP-64 RTP Header Extension", + "Whether RTP NTP header extension should be updated with actual NTP time", + DEFAULT_UPDATE_NTP64_HEADER_EXT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_bin_change_state); gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_rtp_bin_request_new_pad); @@ -3070,6 +3092,7 @@ gst_rtp_bin_init (GstRtpBin * rtpbin) rtpbin->min_ts_offset = DEFAULT_MIN_TS_OFFSET; rtpbin->min_ts_offset_is_set = FALSE; rtpbin->ts_offset_smoothing_factor = DEFAULT_TS_OFFSET_SMOOTHING_FACTOR; + rtpbin->update_ntp64_header_ext = DEFAULT_UPDATE_NTP64_HEADER_EXT; /* some default SDES entries */ cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ()); @@ -3409,6 +3432,13 @@ gst_rtp_bin_set_property (GObject * object, guint prop_id, case PROP_FEC_ENCODERS: gst_rtp_bin_set_fec_encoders_struct (rtpbin, g_value_get_boxed (value)); break; + case PROP_UPDATE_NTP64_HEADER_EXT: + GST_RTP_BIN_LOCK (rtpbin); + rtpbin->update_ntp64_header_ext = g_value_get_boolean (value); + GST_RTP_BIN_UNLOCK (rtpbin); + gst_rtp_bin_propagate_property_to_session (rtpbin, + "update-ntp64-header-ext", value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3518,6 +3548,9 @@ gst_rtp_bin_get_property (GObject * object, guint prop_id, case PROP_FEC_ENCODERS: g_value_take_boxed (value, gst_rtp_bin_get_fec_encoders_struct (rtpbin)); break; + case PROP_UPDATE_NTP64_HEADER_EXT: + g_value_set_boolean (value, rtpbin->update_ntp64_header_ext); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.h b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.h index afb322ac2e..eb98eb28e8 100644 --- a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.h +++ b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpbin.h @@ -98,6 +98,8 @@ struct _GstRtpBin { /* the default FEC encoder factories for sessions */ GstStructure *fec_encoders; + gboolean update_ntp64_header_ext; + /*< private >*/ GstRtpBinPrivate *priv; }; diff --git a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpsession.c b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpsession.c index 3d38e14736..b131e77611 100644 --- a/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpsession.c +++ b/subprojects/gst-plugins-good/gst/rtpmanager/gstrtpsession.c @@ -223,6 +223,7 @@ enum #define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP #define DEFAULT_NTP_TIME_SOURCE GST_RTP_NTP_TIME_SOURCE_NTP #define DEFAULT_RTCP_SYNC_SEND_TIME TRUE +#define DEFAULT_UPDATE_NTP64_HEADER_EXT TRUE enum { @@ -244,7 +245,8 @@ enum PROP_TWCC_STATS, PROP_RTP_PROFILE, PROP_NTP_TIME_SOURCE, - PROP_RTCP_SYNC_SEND_TIME + PROP_RTCP_SYNC_SEND_TIME, + PROP_UPDATE_NTP64_HEADER_EXT }; #define GST_RTP_SESSION_LOCK(sess) g_mutex_lock (&(sess)->priv->lock) @@ -810,6 +812,22 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass) DEFAULT_RTCP_SYNC_SEND_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRtpSession:update-ntp64-header-ext: + * + * Whether RTP NTP header extension should be updated with actual + * NTP time. If not, use the NTP time from buffer timestamp metadata + * + * Since: 1.22 + */ + g_object_class_install_property (gobject_class, + PROP_UPDATE_NTP64_HEADER_EXT, + g_param_spec_boolean ("update-ntp64-header-ext", + "Update NTP-64 RTP Header Extension", + "Whether RTP NTP header extension should be updated with actual NTP time", + DEFAULT_UPDATE_NTP64_HEADER_EXT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_session_change_state); gstelement_class->request_new_pad = @@ -982,6 +1000,10 @@ gst_rtp_session_set_property (GObject * object, guint prop_id, case PROP_RTCP_SYNC_SEND_TIME: priv->rtcp_sync_send_time = g_value_get_boolean (value); break; + case PROP_UPDATE_NTP64_HEADER_EXT: + g_object_set_property (G_OBJECT (priv->session), + "update-ntp64-header-ext", value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1061,6 +1083,10 @@ gst_rtp_session_get_property (GObject * object, guint prop_id, case PROP_RTCP_SYNC_SEND_TIME: g_value_set_boolean (value, priv->rtcp_sync_send_time); break; + case PROP_UPDATE_NTP64_HEADER_EXT: + g_object_get_property (G_OBJECT (priv->session), + "update-ntp64-header-ext", value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/subprojects/gst-plugins-good/gst/rtpmanager/rtpsession.c b/subprojects/gst-plugins-good/gst/rtpmanager/rtpsession.c index 838c24c4bf..294bcf0c17 100644 --- a/subprojects/gst-plugins-good/gst/rtpmanager/rtpsession.c +++ b/subprojects/gst-plugins-good/gst/rtpmanager/rtpsession.c @@ -81,6 +81,7 @@ enum #define DEFAULT_RTCP_DISABLE_SR_TIMESTAMP FALSE #define DEFAULT_FAVOR_NEW FALSE #define DEFAULT_TWCC_FEEDBACK_INTERVAL GST_CLOCK_TIME_NONE +#define DEFAULT_UPDATE_NTP64_HEADER_EXT TRUE enum { @@ -108,6 +109,7 @@ enum PROP_RTCP_REDUCED_SIZE, PROP_RTCP_DISABLE_SR_TIMESTAMP, PROP_TWCC_FEEDBACK_INTERVAL, + PROP_UPDATE_NTP64_HEADER_EXT, PROP_LAST, }; @@ -643,6 +645,21 @@ rtp_session_class_init (RTPSessionClass * klass) 0, G_MAXUINT64, DEFAULT_TWCC_FEEDBACK_INTERVAL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * RTPSession:update-ntp64-header-ext: + * + * Whether RTP NTP header extension should be updated with actual + * NTP time. If not, use the NTP time from buffer timestamp metadata + * + * Since: 1.22 + */ + properties[PROP_UPDATE_NTP64_HEADER_EXT] = + g_param_spec_boolean ("update-ntp64-header-ext", + "Update NTP-64 RTP Header Extension", + "Whether RTP NTP header extension should be updated with actual NTP time", + DEFAULT_UPDATE_NTP64_HEADER_EXT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, PROP_LAST, properties); klass->get_source_by_ssrc = @@ -688,6 +705,8 @@ rtp_session_init (RTPSession * sess) sess->header_len = UDP_IP_HEADER_OVERHEAD; sess->mtu = DEFAULT_RTCP_MTU; + sess->update_ntp64_header_ext = DEFAULT_UPDATE_NTP64_HEADER_EXT; + sess->probation = DEFAULT_PROBATION; sess->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME; sess->max_misorder_time = DEFAULT_MAX_MISORDER_TIME; @@ -928,6 +947,9 @@ rtp_session_set_property (GObject * object, guint prop_id, rtp_twcc_manager_set_feedback_interval (sess->twcc, g_value_get_uint64 (value)); break; + case PROP_UPDATE_NTP64_HEADER_EXT: + sess->update_ntp64_header_ext = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1014,6 +1036,9 @@ rtp_session_get_property (GObject * object, guint prop_id, g_value_set_uint64 (value, rtp_twcc_manager_get_feedback_interval (sess->twcc)); break; + case PROP_UPDATE_NTP64_HEADER_EXT: + g_value_set_boolean (value, sess->update_ntp64_header_ext); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3422,7 +3447,9 @@ rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list, goto invalid_packet; /* Update any 64-bit NTP header extensions with the actual NTP time here */ - update_ntp64_header_ext (&pinfo); + if (sess->update_ntp64_header_ext) + update_ntp64_header_ext (&pinfo); + rtp_twcc_manager_send_packet (sess->twcc, &pinfo); source = obtain_internal_source (sess, pinfo.ssrc, &created, current_time); diff --git a/subprojects/gst-plugins-good/gst/rtpmanager/rtpsession.h b/subprojects/gst-plugins-good/gst/rtpmanager/rtpsession.h index eb512c78f3..84b2948dc4 100644 --- a/subprojects/gst-plugins-good/gst/rtpmanager/rtpsession.h +++ b/subprojects/gst-plugins-good/gst/rtpmanager/rtpsession.h @@ -313,6 +313,8 @@ struct _RTPSession { /* RFC6051 64-bit NTP header extension */ guint8 send_ntp64_ext_id; + gboolean update_ntp64_header_ext; + /* Transport-wide cc-extension */ RTPTWCCManager *twcc; RTPTWCCStats *twcc_stats;