jitterbuffer: make sure time does not go backwards
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 1 Sep 2009 10:41:36 +0000 (12:41 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 1 Sep 2009 10:48:28 +0000 (12:48 +0200)
When we construct a timestamp that would result in a timestamp that is earlier
than when the packet was received, reset the skew calculation as this is
probably a sign that the sender restarted or paused.

Fixes #593354

gst/rtpmanager/gstrtpjitterbuffer.c
gst/rtpmanager/rtpjitterbuffer.c
gst/rtpmanager/rtpjitterbuffer.h

index e3d6ed0..cb343d9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Farsight Voice+Video library
  *
- *  Copyright 2007 Collabora Ltd, 
+ *  Copyright 2007 Collabora Ltd,
  *  Copyright 2007 Nokia Corporation
  *   @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
  *  Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
  * from a network source. It will also wait for missing packets up to a
  * configurable time limit using the #GstRtpJitterBuffer:latency property.
  * Packets arriving too late are considered to be lost packets.
- * 
+ *
  * This element acts as a live element and so adds #GstRtpJitterBuffer:latency
  * to the pipeline.
- * 
+ *
  * The element needs the clock-rate of the RTP payload in order to estimate the
  * delay. This information is obtained either from the caps on the sink pad or,
  * when no caps are present, from the #GstRtpJitterBuffer::request-pt-map signal.
  * To clear the previous pt-map use the #GstRtpJitterBuffer::clear-pt-map signal.
- * 
+ *
  * This element will automatically be used inside gstrtpbin.
- * 
+ *
  * <refsect2>
  * <title>Example pipelines</title>
  * |[
@@ -300,7 +300,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
 
   /**
    * GstRtpJitterBuffer::latency:
-   * 
+   *
    * The maximum latency of the jitterbuffer. Packets will be kept in the buffer
    * for at most this time.
    */
@@ -310,8 +310,8 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
           G_PARAM_READWRITE));
   /**
    * GstRtpJitterBuffer::drop-on-latency:
-   * 
-   * Drop oldest buffers when the queue is completely filled. 
+   *
+   * Drop oldest buffers when the queue is completely filled.
    */
   g_object_class_install_property (gobject_class, PROP_DROP_ON_LATENCY,
       g_param_spec_boolean ("drop-on-latency",
@@ -320,7 +320,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
           DEFAULT_DROP_ON_LATENCY, G_PARAM_READWRITE));
   /**
    * GstRtpJitterBuffer::ts-offset:
-   * 
+   *
    * Adjust GStreamer output buffer timestamps in the jitterbuffer with offset.
    * This is mainly used to ensure interstream synchronisation.
    */
@@ -332,7 +332,7 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
 
   /**
    * GstRtpJitterBuffer::do-lost:
-   * 
+   *
    * Send out a GstRTPPacketLost event downstream when a packet is considered
    * lost.
    */
@@ -761,7 +761,7 @@ gst_rtp_jitter_buffer_flush_start (GstRtpJitterBuffer * jitterbuffer)
   GST_DEBUG_OBJECT (jitterbuffer, "Disabling pop on queue");
   /* this unblocks any waiting pops on the src pad task */
   JBUF_SIGNAL (priv);
-  /* unlock clock, we just unschedule, the entry will be released by the 
+  /* unlock clock, we just unschedule, the entry will be released by the
    * locking streaming thread. */
   if (priv->clock_id) {
     gst_clock_id_unschedule (priv->clock_id);
@@ -1211,7 +1211,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstBuffer * buffer)
    * FALSE if a packet with the same seqnum was already in the queue, meaning we
    * have a duplicate. */
   if (G_UNLIKELY (!rtp_jitter_buffer_insert (priv->jbuf, buffer, timestamp,
-              priv->clock_rate, &tail)))
+              priv->clock_rate, (priv->latency_ms * GST_MSECOND), &tail)))
     goto duplicate;
 
   /* signal addition of new buffer when the _loop is waiting. */
index a38c214..86629e8 100644 (file)
@@ -183,7 +183,7 @@ rtp_jitter_buffer_resync (RTPJitterBuffer * jbuf, GstClockTime time,
  *
  * Both the window and the weighting used for averaging influence the accuracy
  * of the drift estimation. Finding the correct parameters turns out to be a
- * compromise between accuracy and inertia. 
+ * compromise between accuracy and inertia.
  *
  * We use a 2 second window or up to 512 data points, which is statistically big
  * enough to catch spikes (FIXME, detect spikes).
@@ -195,7 +195,7 @@ rtp_jitter_buffer_resync (RTPJitterBuffer * jbuf, GstClockTime time,
  */
 static GstClockTime
 calculate_skew (RTPJitterBuffer * jbuf, guint32 rtptime, GstClockTime time,
-    guint32 clock_rate)
+    guint32 clock_rate, GstClockTime max_delay)
 {
   guint64 ext_rtptime;
   guint64 send_diff, recv_diff;
@@ -278,7 +278,7 @@ calculate_skew (RTPJitterBuffer * jbuf, guint32 rtptime, GstClockTime time,
    * changed too quickly we have to resync because the server likely restarted
    * its timestamps. */
   if (ABS (delta - jbuf->skew) > GST_SECOND) {
-    GST_WARNING ("delta %" GST_TIME_FORMAT " too big, reset skew",
+    GST_WARNING ("delta - skew: %" GST_TIME_FORMAT " too big, reset skew",
         GST_TIME_ARGS (delta - jbuf->skew));
     rtp_jitter_buffer_resync (jbuf, time, gstrtptime, ext_rtptime, TRUE);
     send_diff = 0;
@@ -386,6 +386,18 @@ no_skew:
         out_time = jbuf->prev_out_time;
       }
     }
+
+    if (out_time + max_delay < time) {
+      /* if we are going to produce a timestamp that is later than the input
+       * timestamp, we need to reset the jitterbuffer. Likely the server paused
+       * temporarily */
+      GST_DEBUG ("out %" GST_TIME_FORMAT " + %" G_GUINT64_FORMAT " < time %"
+          GST_TIME_FORMAT ", reset jitterbuffer", GST_TIME_ARGS (out_time),
+          max_delay, GST_TIME_ARGS (time));
+      rtp_jitter_buffer_resync (jbuf, time, gstrtptime, ext_rtptime, TRUE);
+      out_time = time;
+      send_diff = 0;
+    }
   } else
     out_time = -1;
 
@@ -404,6 +416,7 @@ no_skew:
  * @buf: a buffer
  * @time: a running_time when this buffer was received in nanoseconds
  * @clock_rate: the clock-rate of the payload of @buf
+ * @max_delay: the maximum lateness of @buf
  * @tail: TRUE when the tail element changed.
  *
  * Inserts @buf into the packet queue of @jbuf. The sequence number of the
@@ -415,7 +428,8 @@ no_skew:
  */
 gboolean
 rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
-    GstClockTime time, guint32 clock_rate, gboolean * tail)
+    GstClockTime time, guint32 clock_rate, GstClockTime max_delay,
+    gboolean * tail)
 {
   GList *list;
   guint32 rtptime;
@@ -449,7 +463,7 @@ rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
    * receive time, this function will retimestamp @buf with the skew corrected
    * running time. */
   rtptime = gst_rtp_buffer_get_timestamp (buf);
-  time = calculate_skew (jbuf, rtptime, time, clock_rate);
+  time = calculate_skew (jbuf, rtptime, time, clock_rate, max_delay);
   GST_BUFFER_TIMESTAMP (buf) = time;
 
   /* It's more likely that the packet was inserted in the front of the buffer */
index ff1a16b..9a7232c 100644 (file)
@@ -82,9 +82,10 @@ RTPJitterBuffer*      rtp_jitter_buffer_new              (void);
 void                  rtp_jitter_buffer_reset_skew       (RTPJitterBuffer *jbuf);
 
 gboolean              rtp_jitter_buffer_insert           (RTPJitterBuffer *jbuf, GstBuffer *buf,
-                                                         GstClockTime time,
-                                                         guint32 clock_rate,
-                                                         gboolean *tail);
+                                                          GstClockTime time,
+                                                          guint32 clock_rate,
+                                                          GstClockTime max_delay,
+                                                          gboolean *tail);
 GstBuffer *           rtp_jitter_buffer_peek             (RTPJitterBuffer *jbuf);
 GstBuffer *           rtp_jitter_buffer_pop              (RTPJitterBuffer *jbuf);
 
@@ -95,7 +96,6 @@ guint32               rtp_jitter_buffer_get_ts_diff      (RTPJitterBuffer *jbuf)
 
 void                  rtp_jitter_buffer_get_sync         (RTPJitterBuffer *jbuf, guint64 *rtptime,
                                                           guint64 *timestamp, guint32 *clock_rate,
-                                                         guint64 *last_rtptime);
-
+                                                          guint64 *last_rtptime);
 
 #endif /* __RTP_JITTER_BUFFER_H__ */