rtpbin: change how NTP time is calculated in RTCP
authorWim Taymans <wim.taymans@collabora.co.uk>
Wed, 20 Jan 2010 16:04:03 +0000 (17:04 +0100)
committerWim Taymans <wim@metal.(none)>
Mon, 15 Feb 2010 20:36:29 +0000 (21:36 +0100)
Don't calculate the NTP time based on the running_time of the pipeline but from
the systemclock. This allows us to generate more accurate NTP timestamps in case
the systemclock is synchronized with NTP or similar.

gst/rtpmanager/gstrtpsession.c
gst/rtpmanager/rtpsession.c
gst/rtpmanager/rtpsession.h
gst/rtpmanager/rtpsource.c
gst/rtpmanager/rtpsource.h

index be749de..3dddf8d 100644 (file)
@@ -713,24 +713,29 @@ gst_rtp_session_get_property (GObject * object, guint prop_id,
 }
 
 static void
-get_current_times (GstRtpSession * rtpsession,
-    GstClockTime * running_time, guint64 * ntpnstime)
+get_current_times (GstRtpSession * rtpsession, GstClockTime * running_time,
+    guint64 * ntpnstime)
 {
   guint64 ntpns;
   GstClock *clock;
-  GstClockTime base_time, ntpnsbase, rt;
+  GstClockTime base_time, rt;
+  GTimeVal current;
 
   GST_OBJECT_LOCK (rtpsession);
   if ((clock = GST_ELEMENT_CLOCK (rtpsession))) {
     base_time = GST_ELEMENT_CAST (rtpsession)->base_time;
-    ntpnsbase = rtpsession->priv->ntpnsbase;
     gst_object_ref (clock);
     GST_OBJECT_UNLOCK (rtpsession);
 
+    /* get current NTP time */
+    g_get_current_time (&current);
+    ntpns = GST_TIMEVAL_TO_TIME (current);
+
+    /* 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 = gst_clock_get_time (clock) - base_time;
-    /* add NTP base offset to get NTP ns time */
-    ntpns = rt + ntpnsbase;
 
     gst_object_unref (clock);
   } else {
@@ -751,6 +756,7 @@ rtcp_thread (GstRtpSession * rtpsession)
   GstClockTime current_time;
   GstClockTime next_timeout;
   guint64 ntpnstime;
+  GstClockTime running_time;
 
   GST_DEBUG_OBJECT (rtpsession, "entering RTCP thread");
 
@@ -789,7 +795,7 @@ rtcp_thread (GstRtpSession * rtpsession)
     current_time = gst_clock_get_time (rtpsession->priv->sysclock);
 
     /* get current NTP time */
-    get_current_times (rtpsession, NULL, &ntpnstime);
+    get_current_times (rtpsession, &running_time, &ntpnstime);
 
     /* we get unlocked because we need to perform reconsideration, don't perform
      * the timeout but get a new reporting estimate. */
@@ -798,7 +804,8 @@ rtcp_thread (GstRtpSession * rtpsession)
 
     /* perform actions, we ignore result. Release lock because it might push. */
     GST_RTP_SESSION_UNLOCK (rtpsession);
-    rtp_session_on_timeout (rtpsession->priv->session, current_time, ntpnstime);
+    rtp_session_on_timeout (rtpsession->priv->session, current_time, ntpnstime,
+        running_time);
     GST_RTP_SESSION_LOCK (rtpsession);
   }
   /* mark the thread as stopped now */
@@ -1602,9 +1609,8 @@ gst_rtp_session_chain_send_rtp_common (GstPad * pad, gpointer data,
   GstRtpSession *rtpsession;
   GstRtpSessionPrivate *priv;
   GstFlowReturn ret;
-  GstClockTime timestamp;
+  GstClockTime timestamp, running_time;
   GstClockTime current_time;
-  guint64 ntpnstime;
 
   rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
   priv = rtpsession->priv;
@@ -1625,23 +1631,20 @@ gst_rtp_session_chain_send_rtp_common (GstPad * pad, gpointer data,
   } else {
     timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (data));
   }
+
   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
     /* convert to running time using the segment start value. */
-    ntpnstime =
+    running_time =
         gst_segment_to_running_time (&rtpsession->send_rtp_seg, GST_FORMAT_TIME,
         timestamp);
-    /* convert to NTP time by adding the NTP base */
-    ntpnstime += priv->ntpnsbase;
   } else {
-    /* no timestamp, we could take the current running_time and convert it to
-     * NTP time. */
-    ntpnstime = -1;
+    /* no timestamp. */
+    running_time = -1;
   }
 
   current_time = gst_clock_get_time (priv->sysclock);
-  ret =
-      rtp_session_send_rtp (priv->session, data, is_list, current_time,
-      ntpnstime);
+  ret = rtp_session_send_rtp (priv->session, data, is_list, current_time,
+      running_time);
   if (ret != GST_FLOW_OK)
     goto push_error;
 
index 7abaf34..ace3dc2 100644 (file)
@@ -1956,9 +1956,9 @@ ignore:
  * rtp_session_send_rtp:
  * @sess: an #RTPSession
  * @data: pointer to either an RTP buffer or a list of RTP buffers
+ * @is_list: TRUE when @data is a buffer list
  * @current_time: the current system time
- * @ntpnstime: the NTP time in nanoseconds of when this buffer was captured.
- * This is the buffer timestamp converted to NTP time.
+ * @running_time: the running time of @data
  *
  * Send the RTP buffer in the session manager. This function takes ownership of
  * @buffer.
@@ -1967,7 +1967,7 @@ ignore:
  */
 GstFlowReturn
 rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list,
-    GstClockTime current_time, guint64 ntpnstime)
+    GstClockTime current_time, GstClockTime running_time)
 {
   GstFlowReturn result;
   RTPSource *source;
@@ -1997,7 +1997,7 @@ rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list,
   prevsender = RTP_SOURCE_IS_SENDER (source);
 
   /* we use our own source to send */
-  result = rtp_source_send_rtp (source, data, is_list, ntpnstime);
+  result = rtp_source_send_rtp (source, data, is_list, running_time);
 
   if (RTP_SOURCE_IS_SENDER (source) && !prevsender)
     sess->stats.sender_sources++;
@@ -2175,6 +2175,7 @@ typedef struct
   GstBuffer *rtcp;
   GstClockTime current_time;
   guint64 ntpnstime;
+  GstClockTime running_time;
   GstClockTime interval;
   GstRTCPPacket packet;
   gboolean is_bye;
@@ -2199,8 +2200,8 @@ session_start_rtcp (RTPSession * sess, ReportData * data)
     gst_rtcp_buffer_add_packet (data->rtcp, GST_RTCP_TYPE_SR, packet);
 
     /* get latest stats */
-    rtp_source_get_new_sr (own, data->ntpnstime, &ntptime, &rtptime,
-        &packet_count, &octet_count);
+    rtp_source_get_new_sr (own, data->ntpnstime, data->running_time,
+        &ntptime, &rtptime, &packet_count, &octet_count);
     /* store stats */
     rtp_source_process_sr (own, data->current_time, ntptime, rtptime,
         packet_count, octet_count);
@@ -2448,6 +2449,7 @@ is_rtcp_time (RTPSession * sess, GstClockTime current_time, ReportData * data)
  * @sess: an #RTPSession
  * @current_time: the current system time
  * @ntpnstime: the current NTP time in nanoseconds
+ * @running_time: the current running_time of the pipeline
  *
  * Perform maintenance actions after the timeout obtained with
  * rtp_session_next_timeout() expired.
@@ -2462,7 +2464,7 @@ is_rtcp_time (RTPSession * sess, GstClockTime current_time, ReportData * data)
  */
 GstFlowReturn
 rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
-    guint64 ntpnstime)
+    guint64 ntpnstime, GstClockTime running_time)
 {
   GstFlowReturn result = GST_FLOW_OK;
   GList *item;
@@ -2481,6 +2483,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
   data.ntpnstime = ntpnstime;
   data.is_bye = FALSE;
   data.has_sdes = FALSE;
+  data.running_time = running_time;
 
   own = sess->source;
 
index 25e228b..5cb38f6 100644 (file)
@@ -292,7 +292,7 @@ GstFlowReturn   rtp_session_process_rtcp           (RTPSession *sess, GstBuffer
 
 /* processing packets for sending */
 GstFlowReturn   rtp_session_send_rtp               (RTPSession *sess, gpointer data, gboolean is_list,
-                                                    GstClockTime current_time, guint64 ntpnstime);
+                                                    GstClockTime current_time, GstClockTime running_time);
 
 /* stopping the session */
 GstFlowReturn   rtp_session_schedule_bye           (RTPSession *sess, const gchar *reason,
@@ -301,6 +301,6 @@ GstFlowReturn   rtp_session_schedule_bye           (RTPSession *sess, const gcha
 /* get interval for next RTCP interval */
 GstClockTime    rtp_session_next_timeout           (RTPSession *sess, GstClockTime current_time);
 GstFlowReturn   rtp_session_on_timeout             (RTPSession *sess, GstClockTime current_time,
-                                                    guint64 ntpnstime);
+                                                    guint64 ntpnstime, GstClockTime running_time);
 
 #endif /* __RTP_SESSION_H__ */
index 6a46873..ed4c433 100644 (file)
@@ -1047,8 +1047,7 @@ set_ssrc (GstBuffer ** buffer, guint group, guint idx, RTPSource * src)
  * @src: an #RTPSource
  * @data: an RTP buffer or a list of RTP buffers
  * @is_list: if @data is a buffer or list
- * @ntpnstime: the NTP time when this buffer was captured in nanoseconds. This
- * is the buffer timestamp converted to NTP time.
+ * @running_time: the running time of @data
  *
  * Send @data (an RTP buffer or list of buffers) originating from @src.
  * This will make @src a sender. This function takes ownership of @data and
@@ -1058,13 +1057,13 @@ set_ssrc (GstBuffer ** buffer, guint group, guint idx, RTPSource * src)
  */
 GstFlowReturn
 rtp_source_send_rtp (RTPSource * src, gpointer data, gboolean is_list,
-    guint64 ntpnstime)
+    GstClockTime running_time)
 {
   GstFlowReturn result;
   guint len;
   guint32 rtptime;
   guint64 ext_rtptime;
-  guint64 ntp_diff, rtp_diff;
+  guint64 rt_diff, rtp_diff;
   guint64 elapsed;
   GstBufferList *list = NULL;
   GstBuffer *buffer = NULL;
@@ -1104,8 +1103,8 @@ rtp_source_send_rtp (RTPSource * src, gpointer data, gboolean is_list,
   src->stats.octets_sent += len;
   src->bytes_sent += len;
 
-  if (src->prev_ntpnstime) {
-    elapsed = ntpnstime - src->prev_ntpnstime;
+  if (src->prev_rtime) {
+    elapsed = running_time - src->prev_rtime;
 
     if (elapsed > (G_GINT64_CONSTANT (1) << 31)) {
       guint64 rate;
@@ -1122,12 +1121,12 @@ rtp_source_send_rtp (RTPSource * src, gpointer data, gboolean is_list,
       else
         src->bitrate = ((src->bitrate * 3) + rate) / 4;
 
-      src->prev_ntpnstime = ntpnstime;
+      src->prev_rtime = running_time;
       src->bytes_sent = 0;
     }
   } else {
     GST_LOG ("Reset bitrate measurement");
-    src->prev_ntpnstime = ntpnstime;
+    src->prev_rtime = running_time;
     src->bitrate = 0;
   }
 
@@ -1139,24 +1138,24 @@ rtp_source_send_rtp (RTPSource * src, gpointer data, gboolean is_list,
   ext_rtptime = src->last_rtptime;
   ext_rtptime = gst_rtp_buffer_ext_timestamp (&ext_rtptime, rtptime);
 
-  GST_LOG ("SSRC %08x, RTP %" G_GUINT64_FORMAT ", NTP %" GST_TIME_FORMAT,
-      src->ssrc, ext_rtptime, GST_TIME_ARGS (ntpnstime));
+  GST_LOG ("SSRC %08x, RTP %" G_GUINT64_FORMAT ", running_time %"
+      GST_TIME_FORMAT, src->ssrc, ext_rtptime, GST_TIME_ARGS (running_time));
 
   if (ext_rtptime > src->last_rtptime) {
     rtp_diff = ext_rtptime - src->last_rtptime;
-    ntp_diff = ntpnstime - src->last_ntpnstime;
+    rt_diff = running_time - src->last_rtime;
 
     /* calc the diff so we can detect drift at the sender. This can also be used
      * to guestimate the clock rate if the NTP time is locked to the RTP
      * timestamps (as is the case when the capture device is providing the clock). */
-    GST_LOG ("SSRC %08x, diff RTP %" G_GUINT64_FORMAT ", diff NTP %"
-        GST_TIME_FORMAT, src->ssrc, rtp_diff, GST_TIME_ARGS (ntp_diff));
+    GST_LOG ("SSRC %08x, diff RTP %" G_GUINT64_FORMAT ", diff running_time %"
+        GST_TIME_FORMAT, src->ssrc, rtp_diff, GST_TIME_ARGS (rt_diff));
   }
 
   /* we keep track of the last received RTP timestamp and the corresponding
-   * NTP timestamp so that we can use this info when constructing SR reports */
+   * buffer running_time so that we can use this info when constructing SR reports */
+  src->last_rtime = running_time;
   src->last_rtptime = ext_rtptime;
-  src->last_ntpnstime = ntpnstime;
 
   /* push packet */
   if (!src->callbacks.push_rtp)
@@ -1312,6 +1311,7 @@ rtp_source_process_rb (RTPSource * src, GstClockTime time, guint8 fractionlost,
  * rtp_source_get_new_sr:
  * @src: an #RTPSource
  * @ntpnstime: the current time in nanoseconds since 1970
+ * @running_time: the current running_time of the pipeline.
  * @ntptime: the NTP time in 32.32 fixed point
  * @rtptime: the RTP time corresponding to @ntptime
  * @packet_count: the packet count
@@ -1319,12 +1319,19 @@ rtp_source_process_rb (RTPSource * src, GstClockTime time, guint8 fractionlost,
  *
  * Get new values to put into a new SR report from this source.
  *
+ * @running_time and @ntpnstime are captured at the same time and represent the
+ * running time of the pipeline clock and the absolute current system time in
+ * nanoseconds respectively. Together with the last running_time and rtp timestamp
+ * we have observed in the source, we can generate @ntptime and @rtptime for an SR
+ * packet. @ntptime is basically the fixed point representation of @ntpnstime
+ * and @rtptime the associated RTP timestamp.
+ *
  * Returns: %TRUE on success.
  */
 gboolean
 rtp_source_get_new_sr (RTPSource * src, guint64 ntpnstime,
-    guint64 * ntptime, guint32 * rtptime, guint32 * packet_count,
-    guint32 * octet_count)
+    GstClockTime running_time, guint64 * ntptime, guint32 * rtptime,
+    guint32 * packet_count, guint32 * octet_count)
 {
   guint64 t_rtp;
   guint64 t_current_ntp;
@@ -1332,30 +1339,36 @@ rtp_source_get_new_sr (RTPSource * src, guint64 ntpnstime,
 
   g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
 
-  /* use the sync params to interpolate the date->time member to rtptime. We
-   * use the last sent timestamp and rtptime as reference points. We assume
-   * that the slope of the rtptime vs timestamp curve is 1, which is certainly
+  /* We last saw a buffer with last_rtptime at last_rtime. Given a running_time
+   * and an NTP time, we can scale the RTP timestamps so that they match the
+   * given NTP time.  for scaling, we assume that the slope of the rtptime vs
+   * running_time vs ntptime curve is close to 1, which is certainly
    * sufficient for the frequency at which we report SR and the rate we send
    * out RTP packets. */
   t_rtp = src->last_rtptime;
 
-  GST_DEBUG ("last_ntpnstime %" GST_TIME_FORMAT ", last_rtptime %"
-      G_GUINT64_FORMAT, GST_TIME_ARGS (src->last_ntpnstime), t_rtp);
+  GST_DEBUG ("last_rtime %" GST_TIME_FORMAT ", last_rtptime %"
+      G_GUINT64_FORMAT, GST_TIME_ARGS (src->last_rtime), t_rtp);
 
   if (src->clock_rate != -1) {
-    /* get the diff with the SR time */
-    diff = GST_CLOCK_DIFF (src->last_ntpnstime, ntpnstime);
+    /* get the diff between the clock running_time and the buffer running_time.
+     * This is the elapsed time, as measured against the pipeline clock, between
+     * when the rtp timestamp was observed and the current running_time.
+     *
+     * We need to apply this diff to the RTP timestamp to get the RTP timestamp
+     * for the given ntpnstime. */
+    diff = GST_CLOCK_DIFF (src->last_rtime, running_time);
 
     /* now translate the diff to RTP time, handle positive and negative cases.
      * If there is no diff, we already set rtptime correctly above. */
     if (diff > 0) {
-      GST_DEBUG ("ntpnstime %" GST_TIME_FORMAT ", diff %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (ntpnstime), GST_TIME_ARGS (diff));
+      GST_DEBUG ("running_time %" GST_TIME_FORMAT ", diff %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (running_time), GST_TIME_ARGS (diff));
       t_rtp += gst_util_uint64_scale_int (diff, src->clock_rate, GST_SECOND);
     } else {
       diff = -diff;
-      GST_DEBUG ("ntpnstime %" GST_TIME_FORMAT ", diff -%" GST_TIME_FORMAT,
-          GST_TIME_ARGS (ntpnstime), GST_TIME_ARGS (diff));
+      GST_DEBUG ("running_time %" GST_TIME_FORMAT ", diff -%" GST_TIME_FORMAT,
+          GST_TIME_ARGS (running_time), GST_TIME_ARGS (diff));
       t_rtp -= gst_util_uint64_scale_int (diff, src->clock_rate, GST_SECOND);
     }
   } else {
index b0c9bd0..6d43a02 100644 (file)
@@ -136,12 +136,12 @@ struct _RTPSource {
   GstClockTime  last_activity;
   GstClockTime  last_rtp_activity;
 
+  GstClockTime  last_rtime;
   GstClockTime  last_rtptime;
-  GstClockTime  last_ntpnstime;
 
   /* for bitrate estimation */
   guint64       bitrate;
-  GstClockTime  prev_ntpnstime;
+  GstClockTime  prev_rtime;
   guint64       bytes_sent;
 
   GQueue       *packets;
@@ -192,8 +192,8 @@ void            rtp_source_set_rtcp_from       (RTPSource *src, GstNetAddress *a
 /* handling RTP */
 GstFlowReturn   rtp_source_process_rtp         (RTPSource *src, GstBuffer *buffer, RTPArrivalStats *arrival);
 
-GstFlowReturn   rtp_source_send_rtp            (RTPSource *src, gpointer data, gboolean is_list, guint64 ntpnstime);
-
+GstFlowReturn   rtp_source_send_rtp            (RTPSource *src, gpointer data, gboolean is_list,
+                                                GstClockTime running_time);
 /* RTCP messages */
 void            rtp_source_process_bye         (RTPSource *src, const gchar *reason);
 void            rtp_source_process_sr          (RTPSource *src, GstClockTime time, guint64 ntptime,
@@ -202,8 +202,8 @@ void            rtp_source_process_rb          (RTPSource *src, GstClockTime tim
                                                 gint32 packetslost, guint32 exthighestseq, guint32 jitter,
                                                 guint32 lsr, guint32 dlsr);
 
-gboolean        rtp_source_get_new_sr          (RTPSource *src, guint64 ntpnstime, guint64 *ntptime,
-                                               guint32 *rtptime, guint32 *packet_count,
+gboolean        rtp_source_get_new_sr          (RTPSource *src, guint64 ntpnstime, GstClockTime running_time,
+                                                guint64 *ntptime, guint32 *rtptime, guint32 *packet_count,
                                                guint32 *octet_count);
 gboolean        rtp_source_get_new_rb          (RTPSource *src, GstClockTime time, guint8 *fractionlost,
                                                 gint32 *packetslost, guint32 *exthighestseq, guint32 *jitter,