From dc513eb9498a7d3d482ccafa874486fc88419654 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 12 Jun 2015 23:29:19 +0200 Subject: [PATCH] rtpbin/session: Add new ntp-time-source property and deprecate use-pipeline-clock property The new property allows to select the time source that should be used for the NTP time in RTCP packets. By default it will continue to calculate the NTP timestamp (1900 epoch) based on the realtime clock. Alternatively it can use the UNIX timestamp (1970 epoch), the pipeline's running time or the pipeline's clock time. The latter is especially useful for synchronizing multiple receivers if all of them share the same clock. If use-pipeline-clock is set to TRUE, it will override the ntp-time-source setting and continue to use the running time plus 70 years. This is only kept for backwards compatibility. --- gst/rtpmanager/gstrtpbin.c | 83 +++++++++++++++++++++++++++++++++--------- gst/rtpmanager/gstrtpbin.h | 2 + gst/rtpmanager/gstrtpsession.c | 78 +++++++++++++++++++++++++++++++++------ gst/rtpmanager/gstrtpsession.h | 9 +++++ 4 files changed, 144 insertions(+), 28 deletions(-) diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index cf324e3..6face86 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -289,6 +289,7 @@ enum #define DEFAULT_DO_SYNC_EVENT FALSE #define DEFAULT_DO_RETRANSMISSION FALSE #define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVPF +#define DEFAULT_NTP_TIME_SOURCE GST_RTP_NTP_TIME_SOURCE_NTP enum { @@ -306,7 +307,8 @@ enum PROP_USE_PIPELINE_CLOCK, PROP_DO_SYNC_EVENT, PROP_DO_RETRANSMISSION, - PROP_RTP_PROFILE + PROP_RTP_PROFILE, + PROP_NTP_TIME_SOURCE }; #define GST_RTP_BIN_RTCP_SYNC_TYPE (gst_rtp_bin_rtcp_sync_get_type()) @@ -622,8 +624,13 @@ create_session (GstRtpBin * rtpbin, gint id) /* configure SDES items */ GST_OBJECT_LOCK (rtpbin); - g_object_set (session, "sdes", rtpbin->sdes, "use-pipeline-clock", - rtpbin->use_pipeline_clock, "rtp-profile", rtpbin->rtp_profile, NULL); + g_object_set (session, "sdes", rtpbin->sdes, "rtp-profile", + rtpbin->rtp_profile, NULL); + if (rtpbin->use_pipeline_clock) + g_object_set (session, "use-pipeline-clock", rtpbin->use_pipeline_clock, + NULL); + else + g_object_set (session, "ntp-time-source", rtpbin->ntp_time_source, NULL); GST_OBJECT_UNLOCK (rtpbin); /* provide clock_rate to the session manager when needed */ @@ -1004,24 +1011,41 @@ get_current_times (GstRtpBin * bin, GstClockTime * running_time, gst_object_ref (clock); GST_OBJECT_UNLOCK (bin); + /* get current clock time and convert to running time */ clock_time = gst_clock_get_time (clock); + rt = clock_time - base_time; if (bin->use_pipeline_clock) { - ntpns = clock_time - base_time; + ntpns = rt; + /* add constant to convert from 1970 based time to 1900 based time */ + ntpns += (2208988800LL * GST_SECOND); } else { - GTimeVal current; - - /* get current NTP time */ - g_get_current_time (¤t); - ntpns = GST_TIMEVAL_TO_TIME (current); + switch (bin->ntp_time_source) { + case GST_RTP_NTP_TIME_SOURCE_NTP: + case GST_RTP_NTP_TIME_SOURCE_UNIX:{ + GTimeVal current; + + /* get current NTP time */ + g_get_current_time (¤t); + ntpns = GST_TIMEVAL_TO_TIME (current); + + /* add constant to convert from 1970 based time to 1900 based time */ + if (bin->ntp_time_source == GST_RTP_NTP_TIME_SOURCE_NTP) + ntpns += (2208988800LL * GST_SECOND); + break; + } + case GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME: + ntpns = rt; + break; + case GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME: + ntpns = clock_time; + break; + default: + g_assert_not_reached (); + break; + } } - /* add constant to convert from 1970 based time to 1900 based time */ - ntpns += (2208988800LL * GST_SECOND); - - /* get current clock time and convert to running time */ - rt = clock_time - base_time; - gst_object_unref (clock); } else { GST_OBJECT_UNLOCK (bin); @@ -2061,9 +2085,10 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass) g_object_class_install_property (gobject_class, PROP_USE_PIPELINE_CLOCK, g_param_spec_boolean ("use-pipeline-clock", "Use pipeline clock", - "Use the pipeline running-time to set the NTP time in the RTCP SR messages", + "Use the pipeline running-time to set the NTP time in the RTCP SR messages " + "(DEPRECATED: Use ntp-source property)", DEFAULT_USE_PIPELINE_CLOCK, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED)); /** * GstRtpBin:buffer-mode: * @@ -2140,6 +2165,12 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass) GST_TYPE_RTP_PROFILE, DEFAULT_RTP_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_NTP_TIME_SOURCE, + g_param_spec_enum ("ntp-time-source", "NTP Time Source", + "NTP time source for RTCP packets", + gst_rtp_ntp_time_source_get_type (), DEFAULT_NTP_TIME_SOURCE, + 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); @@ -2203,6 +2234,7 @@ gst_rtp_bin_init (GstRtpBin * rtpbin) rtpbin->send_sync_event = DEFAULT_DO_SYNC_EVENT; rtpbin->do_retransmission = DEFAULT_DO_RETRANSMISSION; rtpbin->rtp_profile = DEFAULT_RTP_PROFILE; + rtpbin->ntp_time_source = DEFAULT_NTP_TIME_SOURCE; /* some default SDES entries */ cname = g_strdup_printf ("user%u@host-%x", g_random_int (), g_random_int ()); @@ -2366,6 +2398,20 @@ gst_rtp_bin_set_property (GObject * object, guint prop_id, case PROP_RTP_PROFILE: rtpbin->rtp_profile = g_value_get_enum (value); break; + case PROP_NTP_TIME_SOURCE:{ + GSList *sessions; + GST_RTP_BIN_LOCK (rtpbin); + rtpbin->ntp_time_source = g_value_get_enum (value); + for (sessions = rtpbin->sessions; sessions; + sessions = g_slist_next (sessions)) { + GstRtpBinSession *session = (GstRtpBinSession *) sessions->data; + + g_object_set (G_OBJECT (session->session), + "ntp-time-source", rtpbin->ntp_time_source, NULL); + } + GST_RTP_BIN_UNLOCK (rtpbin); + break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2431,6 +2477,9 @@ gst_rtp_bin_get_property (GObject * object, guint prop_id, case PROP_RTP_PROFILE: g_value_set_enum (value, rtpbin->rtp_profile); break; + case PROP_NTP_TIME_SOURCE: + g_value_set_enum (value, rtpbin->ntp_time_source); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/gst/rtpmanager/gstrtpbin.h b/gst/rtpmanager/gstrtpbin.h index 61cf5dd..87c1fad 100644 --- a/gst/rtpmanager/gstrtpbin.h +++ b/gst/rtpmanager/gstrtpbin.h @@ -23,6 +23,7 @@ #include #include "rtpsession.h" +#include "gstrtpsession.h" #include "rtpjitterbuffer.h" #define GST_TYPE_RTP_BIN \ @@ -63,6 +64,7 @@ struct _GstRtpBin { RTPJitterBufferMode buffer_mode; gboolean buffering; gboolean use_pipeline_clock; + GstRtpNtpTimeSource ntp_time_source; gboolean send_sync_event; GstClockTime buffer_start; gboolean do_retransmission; diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c index 5051d68..b1ebcea 100644 --- a/gst/rtpmanager/gstrtpsession.c +++ b/gst/rtpmanager/gstrtpsession.c @@ -122,6 +122,26 @@ GST_DEBUG_CATEGORY_STATIC (gst_rtp_session_debug); #define GST_CAT_DEFAULT gst_rtp_session_debug +GType +gst_rtp_ntp_time_source_get_type (void) +{ + static GType type = 0; + static const GEnumValue values[] = { + {GST_RTP_NTP_TIME_SOURCE_NTP, "NTP time based on realtime clock", "ntp"}, + {GST_RTP_NTP_TIME_SOURCE_UNIX, "UNIX time based on realtime clock", "unix"}, + {GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME, + "Running time based on pipeline clock", + "running-time"}, + {GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME, "Pipeline clock time", "clock-time"}, + {0, NULL, NULL}, + }; + + if (!type) { + type = g_enum_register_static ("GstRtpNtpTimeSource", values); + } + return type; +} + /* sink pads */ static GstStaticPadTemplate rtpsession_recv_rtp_sink_template = GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink", @@ -202,6 +222,7 @@ enum #define DEFAULT_RTCP_MIN_INTERVAL (RTP_STATS_MIN_INTERVAL * GST_SECOND) #define DEFAULT_PROBATION RTP_DEFAULT_PROBATION #define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP +#define DEFAULT_NTP_TIME_SOURCE GST_RTP_NTP_TIME_SOURCE_NTP enum { @@ -218,7 +239,8 @@ enum PROP_RTCP_MIN_INTERVAL, PROP_PROBATION, PROP_STATS, - PROP_RTP_PROFILE + PROP_RTP_PROFILE, + PROP_NTP_TIME_SOURCE }; #define GST_RTP_SESSION_GET_PRIVATE(obj) \ @@ -251,6 +273,7 @@ struct _GstRtpSessionPrivate GstClockTime send_latency; gboolean use_pipeline_clock; + GstRtpNtpTimeSource ntp_time_source; guint rtx_count; }; @@ -611,9 +634,10 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass) g_object_class_install_property (gobject_class, PROP_USE_PIPELINE_CLOCK, g_param_spec_boolean ("use-pipeline-clock", "Use pipeline clock", - "Use the pipeline running-time to set the NTP time in the RTCP SR messages", + "Use the pipeline running-time to set the NTP time in the RTCP SR messages " + "(DEPRECATED: Use ntp-source property)", DEFAULT_USE_PIPELINE_CLOCK, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED)); g_object_class_install_property (gobject_class, PROP_RTCP_MIN_INTERVAL, g_param_spec_uint64 ("rtcp-min-interval", "Minimum RTCP interval", @@ -652,6 +676,12 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass) "RTP profile to use", GST_TYPE_RTP_PROFILE, DEFAULT_RTP_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_NTP_TIME_SOURCE, + g_param_spec_enum ("ntp-time-source", "NTP Time Source", + "NTP time source for RTCP packets", + gst_rtp_ntp_time_source_get_type (), DEFAULT_NTP_TIME_SOURCE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_session_change_state); gstelement_class->request_new_pad = @@ -727,6 +757,8 @@ gst_rtp_session_init (GstRtpSession * rtpsession) rtpsession->priv->thread_stopped = TRUE; rtpsession->priv->rtx_count = 0; + + rtpsession->priv->ntp_time_source = DEFAULT_NTP_TIME_SOURCE; } static void @@ -786,6 +818,9 @@ gst_rtp_session_set_property (GObject * object, guint prop_id, case PROP_RTP_PROFILE: g_object_set_property (G_OBJECT (priv->session), "rtp-profile", value); break; + case PROP_NTP_TIME_SOURCE: + priv->ntp_time_source = g_value_get_enum (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -846,6 +881,9 @@ gst_rtp_session_get_property (GObject * object, guint prop_id, case PROP_RTP_PROFILE: g_object_get_property (G_OBJECT (priv->session), "rtp-profile", value); break; + case PROP_NTP_TIME_SOURCE: + g_value_set_enum (value, priv->ntp_time_source); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -884,17 +922,35 @@ get_current_times (GstRtpSession * rtpsession, GstClockTime * running_time, if (rtpsession->priv->use_pipeline_clock) { ntpns = rt; + /* add constant to convert from 1970 based time to 1900 based time */ + ntpns += (2208988800LL * GST_SECOND); } else { - GTimeVal current; - - /* get current NTP time */ - g_get_current_time (¤t); - ntpns = GST_TIMEVAL_TO_TIME (current); + switch (rtpsession->priv->ntp_time_source) { + case GST_RTP_NTP_TIME_SOURCE_NTP: + case GST_RTP_NTP_TIME_SOURCE_UNIX:{ + GTimeVal current; + + /* get current NTP time */ + g_get_current_time (¤t); + ntpns = GST_TIMEVAL_TO_TIME (current); + + /* add constant to convert from 1970 based time to 1900 based time */ + if (rtpsession->priv->ntp_time_source == GST_RTP_NTP_TIME_SOURCE_NTP) + ntpns += (2208988800LL * GST_SECOND); + break; + } + case GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME: + ntpns = rt; + break; + case GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME: + ntpns = clock_time; + break; + default: + g_assert_not_reached (); + break; + } } - /* add constant to convert from 1970 based time to 1900 based time */ - ntpns += (2208988800LL * GST_SECOND); - gst_object_unref (clock); } else { GST_OBJECT_UNLOCK (rtpsession); diff --git a/gst/rtpmanager/gstrtpsession.h b/gst/rtpmanager/gstrtpsession.h index bbaafa6..a144c28 100644 --- a/gst/rtpmanager/gstrtpsession.h +++ b/gst/rtpmanager/gstrtpsession.h @@ -76,4 +76,13 @@ struct _GstRtpSessionClass { GType gst_rtp_session_get_type (void); +typedef enum { + GST_RTP_NTP_TIME_SOURCE_NTP, + GST_RTP_NTP_TIME_SOURCE_UNIX, + GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME, + GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME +} GstRtpNtpTimeSource; + +GType gst_rtp_ntp_time_source_get_type (void); + #endif /* __GST_RTP_SESSION_H__ */ -- 2.7.4