rtpjitterbuffer: Add a faststart-min-packets property
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Thu, 22 Jun 2017 19:34:42 +0000 (15:34 -0400)
committerNicolas Dufresne <nicolas.dufresne@collabora.com>
Wed, 28 Jun 2017 15:51:10 +0000 (11:51 -0400)
When set this property will allow the jitterbuffer to start delivering
packets as soon as N most recent packets have consecutive seqnum. A
faststart-min-packets of zero disables this feature. This heuristic is
also used in rtpsource which implements the probation mechanism and a
similar heuristic is used to handle long gaps.

https://bugzilla.gnome.org/show_bug.cgi?id=769536

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

index 64f05dc..8574f17 100644 (file)
@@ -149,6 +149,7 @@ enum
 #define DEFAULT_MAX_DROPOUT_TIME    60000
 #define DEFAULT_MAX_MISORDER_TIME   2000
 #define DEFAULT_RFC7273_SYNC        FALSE
+#define DEFAULT_FASTSTART_MIN_PACKETS 0
 
 #define DEFAULT_AUTO_RTX_DELAY (20 * GST_MSECOND)
 #define DEFAULT_AUTO_RTX_TIMEOUT (40 * GST_MSECOND)
@@ -177,7 +178,8 @@ enum
   PROP_MAX_RTCP_RTP_TIME_DIFF,
   PROP_MAX_DROPOUT_TIME,
   PROP_MAX_MISORDER_TIME,
-  PROP_RFC7273_SYNC
+  PROP_RFC7273_SYNC,
+  PROP_FASTSTART_MIN_PACKETS
 };
 
 #define JBUF_LOCK(priv)   G_STMT_START {                       \
@@ -294,6 +296,7 @@ struct _GstRtpJitterBufferPrivate
   gint max_rtcp_rtp_time_diff;
   guint32 max_dropout_time;
   guint32 max_misorder_time;
+  guint faststart_min_packets;
 
   /* the last seqnum we pushed out */
   guint32 last_popped_seqnum;
@@ -852,6 +855,23 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   /**
+   * GstRtpJitterBuffer:faststart-min-packets
+   *
+   * The number of consecutive packets needed to start (set to 0 to
+   * disable faststart. The jitterbuffer will by default start after the
+   * latency has elapsed)
+   *
+   * Since: 1.14
+   */
+  g_object_class_install_property (gobject_class, PROP_FASTSTART_MIN_PACKETS,
+      g_param_spec_uint ("faststart-min-packets", "Faststart minimum packets",
+          "The number of consecutive packets needed to start (set to 0 to "
+          "disable faststart. The jitterbuffer will by default start after "
+          "the latency has elapsed)",
+          0, G_MAXUINT, DEFAULT_FASTSTART_MIN_PACKETS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
    * GstRtpJitterBuffer::request-pt-map:
    * @buffer: the object which received the signal
    * @pt: the pt
@@ -975,6 +995,7 @@ gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer)
   priv->max_rtcp_rtp_time_diff = DEFAULT_MAX_RTCP_RTP_TIME_DIFF;
   priv->max_dropout_time = DEFAULT_MAX_DROPOUT_TIME;
   priv->max_misorder_time = DEFAULT_MAX_MISORDER_TIME;
+  priv->faststart_min_packets = DEFAULT_FASTSTART_MIN_PACKETS;
 
   priv->last_dts = -1;
   priv->last_rtptime = -1;
@@ -2784,6 +2805,37 @@ gst_rtp_jitter_buffer_reset (GstRtpJitterBuffer * jitterbuffer,
   return ret;
 }
 
+static gboolean
+gst_rtp_jitter_buffer_fast_start (GstRtpJitterBuffer * jitterbuffer)
+{
+  GstRtpJitterBufferPrivate *priv;
+  RTPJitterBufferItem *item;
+  TimerData *timer;
+
+  priv = jitterbuffer->priv;
+
+  if (priv->faststart_min_packets == 0)
+    return FALSE;
+
+  item = rtp_jitter_buffer_peek (priv->jbuf);
+  if (!item)
+    return FALSE;
+
+  timer = find_timer (jitterbuffer, item->seqnum);
+  if (!timer || timer->type != TIMER_TYPE_DEADLINE)
+    return FALSE;
+
+  if (rtp_jitter_buffer_can_fast_start (priv->jbuf,
+          priv->faststart_min_packets)) {
+    GST_INFO_OBJECT (jitterbuffer, "We found %i consecutive packet, start now",
+        priv->faststart_min_packets);
+    timer->timeout = -1;
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
 static GstFlowReturn
 gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
     GstBuffer * buffer)
@@ -3096,6 +3148,10 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
     goto duplicate;
   }
 
+  /* Trigger fast start if needed */
+  if (gst_rtp_jitter_buffer_fast_start (jitterbuffer))
+    head = TRUE;
+
   /* update timers */
   update_timers (jitterbuffer, seqnum, dts, pts, do_next_seqnum,
       GST_BUFFER_IS_RETRANSMISSION (buffer), timer);
@@ -4514,6 +4570,11 @@ gst_rtp_jitter_buffer_set_property (GObject * object,
           g_value_get_boolean (value));
       JBUF_UNLOCK (priv);
       break;
+    case PROP_FASTSTART_MIN_PACKETS:
+      JBUF_LOCK (priv);
+      priv->faststart_min_packets = g_value_get_uint (value);
+      JBUF_UNLOCK (priv);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -4650,6 +4711,11 @@ gst_rtp_jitter_buffer_get_property (GObject * object,
           rtp_jitter_buffer_get_rfc7273_sync (priv->jbuf));
       JBUF_UNLOCK (priv);
       break;
+    case PROP_FASTSTART_MIN_PACKETS:
+      JBUF_LOCK (priv);
+      g_value_set_uint (value, priv->faststart_min_packets);
+      JBUF_UNLOCK (priv);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index a706d62..f1187e2 100644 (file)
@@ -1257,3 +1257,41 @@ rtp_jitter_buffer_get_sync (RTPJitterBuffer * jbuf, guint64 * rtptime,
   if (last_rtptime)
     *last_rtptime = jbuf->last_rtptime;
 }
+
+/**
+ * rtp_jitter_buffer_can_fast_start:
+ * @jbuf: an #RTPJitterBuffer
+ * @num_packets: Number of consecutive packets needed
+ *
+ * Check if in the queue if there is enough packets with consecutive seqnum in
+ * order to start delivering them.
+ *
+ * Returns: %TRUE if the required number of consecutive packets was found.
+ */
+gboolean
+rtp_jitter_buffer_can_fast_start (RTPJitterBuffer * jbuf, gint num_packet)
+{
+  gboolean ret = TRUE;
+  RTPJitterBufferItem *last_item = NULL, *item;
+  gint i;
+
+  if (rtp_jitter_buffer_num_packets (jbuf) < num_packet)
+    return FALSE;
+
+  item = rtp_jitter_buffer_peek (jbuf);
+  for (i = 0; i < num_packet; i++) {
+    if (G_LIKELY (last_item)) {
+      guint16 expected_seqnum = last_item->seqnum + 1;
+
+      if (expected_seqnum != item->seqnum) {
+        ret = FALSE;
+        break;
+      }
+    }
+
+    last_item = item;
+    item = (RTPJitterBufferItem *) last_item->next;
+  }
+
+  return ret;
+}
index 4d3c6fe..16db644 100644 (file)
@@ -192,4 +192,6 @@ void                  rtp_jitter_buffer_get_sync         (RTPJitterBuffer *jbuf,
 GstClockTime          rtp_jitter_buffer_calculate_pts    (RTPJitterBuffer * jbuf, GstClockTime dts, gboolean estimated_dts,
                                                           guint32 rtptime, GstClockTime base_time);
 
+gboolean              rtp_jitter_buffer_can_fast_start   (RTPJitterBuffer * jbuf, gint num_packet);
+
 #endif /* __RTP_JITTER_BUFFER_H__ */