rtpmanager: Take into account packet rate for max-dropout and max-misorder calculations
authorMiguel París Díaz <mparisdiaz@gmail.com>
Wed, 7 Oct 2015 11:03:02 +0000 (13:03 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Wed, 7 Oct 2015 11:07:18 +0000 (12:07 +0100)
https://bugzilla.gnome.org/show_bug.cgi?id=751311

gst/rtpmanager/gstrtpjitterbuffer.c
gst/rtpmanager/rtpsource.c
gst/rtpmanager/rtpsource.h
gst/rtpmanager/rtpstats.c
gst/rtpmanager/rtpstats.h

index 7fcb729..c5026da 100644 (file)
@@ -5,6 +5,8 @@
  *  Copyright 2007 Nokia Corporation
  *   @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
  *  Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
+ *  Copyright 2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -327,6 +329,7 @@ struct _GstRtpJitterBufferPrivate
   guint64 num_rtx_failed;
   gdouble avg_rtx_num;
   guint64 avg_rtx_rtt;
+  RTPPacketRateCtx packet_rate_ctx;
 
   /* for the jitter */
   GstClockTime last_dts;
@@ -2304,7 +2307,8 @@ compare_buffer_seqnum (GstBuffer * a, GstBuffer * b, gpointer user_data)
 
 static gboolean
 handle_big_gap_buffer (GstRtpJitterBuffer * jitterbuffer, gboolean future,
-    GstBuffer * buffer, guint8 pt, guint16 seqnum, gint gap)
+    GstBuffer * buffer, guint8 pt, guint16 seqnum, gint gap, guint max_dropout,
+    guint max_misorder)
 {
   GstRtpJitterBufferPrivate *priv;
   guint gap_packets_length;
@@ -2346,7 +2350,7 @@ handle_big_gap_buffer (GstRtpJitterBuffer * jitterbuffer, gboolean future,
       GST_DEBUG_OBJECT (jitterbuffer,
           "buffer too %s %d < %d, got 5 consecutive ones - reset",
           (future ? "new" : "old"), gap,
-          (future ? RTP_MAX_DROPOUT : -RTP_MAX_MISORDER));
+          (future ? max_dropout : -max_misorder));
       reset = TRUE;
     } else if (!all_consecutive) {
       g_queue_foreach (&priv->gap_packets, (GFunc) gst_buffer_unref, NULL);
@@ -2354,20 +2358,19 @@ handle_big_gap_buffer (GstRtpJitterBuffer * jitterbuffer, gboolean future,
       GST_DEBUG_OBJECT (jitterbuffer,
           "buffer too %s %d < %d, got no 5 consecutive ones - dropping",
           (future ? "new" : "old"), gap,
-          (future ? RTP_MAX_DROPOUT : -RTP_MAX_MISORDER));
+          (future ? max_dropout : -max_misorder));
       buffer = NULL;
     } else {
       GST_DEBUG_OBJECT (jitterbuffer,
           "buffer too %s %d < %d, got %u consecutive ones - waiting",
           (future ? "new" : "old"), gap,
-          (future ? RTP_MAX_DROPOUT : -RTP_MAX_MISORDER),
-          gap_packets_length + 1);
+          (future ? max_dropout : -max_misorder), gap_packets_length + 1);
       buffer = NULL;
     }
   } else {
     GST_DEBUG_OBJECT (jitterbuffer,
         "buffer too %s %d < %d, first one - waiting", (future ? "new" : "old"),
-        gap, -RTP_MAX_MISORDER);
+        gap, -max_misorder);
     g_queue_push_tail (&priv->gap_packets, buffer);
     buffer = NULL;
   }
@@ -2416,6 +2419,7 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
   RTPJitterBufferItem *item;
   GstMessage *msg = NULL;
   gboolean estimated_dts = FALSE;
+  guint32 packet_rate, max_dropout, max_misorder;
 
   jitterbuffer = GST_RTP_JITTER_BUFFER_CAST (parent);
 
@@ -2520,6 +2524,18 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
 
   expected = priv->next_in_seqnum;
 
+  packet_rate =
+      gst_rtp_packet_rate_ctx_update (&priv->packet_rate_ctx, seqnum, rtptime);
+  max_dropout =
+      gst_rtp_packet_rate_ctx_get_max_dropout (&priv->packet_rate_ctx,
+      priv->max_dropout_time);
+  max_misorder =
+      gst_rtp_packet_rate_ctx_get_max_misorder (&priv->packet_rate_ctx,
+      priv->max_misorder_time);
+  GST_TRACE_OBJECT (jitterbuffer,
+      "packet_rate: %d, max_dropout: %d, max_misorder: %d", packet_rate,
+      max_dropout, max_misorder);
+
   /* now check against our expected seqnum */
   if (G_LIKELY (expected != -1)) {
     gint gap;
@@ -2539,17 +2555,17 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
 
       if (gap < 0) {
         /* we received an old packet */
-        if (G_UNLIKELY (gap != -1 && gap < -RTP_MAX_MISORDER)) {
+        if (G_UNLIKELY (gap != -1 && gap < -max_misorder)) {
           reset =
               handle_big_gap_buffer (jitterbuffer, FALSE, buffer, pt, seqnum,
-              gap);
+              gap, max_dropout, max_misorder);
           buffer = NULL;
         } else {
           GST_DEBUG_OBJECT (jitterbuffer, "old packet received");
         }
       } else {
         /* new packet, we are missing some packets */
-        if (G_UNLIKELY (priv->timers->len >= RTP_MAX_DROPOUT)) {
+        if (G_UNLIKELY (priv->timers->len >= max_dropout)) {
           /* If we have timers for more than RTP_MAX_DROPOUT packets
            * pending this means that we have a huge gap overall. We can
            * reset the jitterbuffer at this point because there's
@@ -2558,14 +2574,14 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
            * next packet */
           GST_WARNING_OBJECT (jitterbuffer,
               "%d pending timers > %d - resetting", priv->timers->len,
-              RTP_MAX_DROPOUT);
+              max_dropout);
           reset = TRUE;
           gst_buffer_unref (buffer);
           buffer = NULL;
-        } else if (G_UNLIKELY (gap >= RTP_MAX_DROPOUT)) {
+        } else if (G_UNLIKELY (gap >= max_dropout)) {
           reset =
               handle_big_gap_buffer (jitterbuffer, TRUE, buffer, pt, seqnum,
-              gap);
+              gap, max_dropout, max_misorder);
           buffer = NULL;
         } else {
           GST_DEBUG_OBJECT (jitterbuffer, "%d missing packets", gap);
@@ -3372,10 +3388,11 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer)
     GstClockTime timer_timeout = -1;
     gint i, len;
 
-    /* If we have a clock, update "now" now with the very latest running time
-     * we have. It is used below when timeouts are triggered to calculate
-     * any next possible timeout. If we only update it after waiting for the
-     * clock, we would give a too old time to the timeout functions.
+    /* If we have a clock, update "now" now with the very
+     * latest running time we have. If timers are unscheduled below we
+     * otherwise wouldn't update now (it's only updated when timers
+     * expire), and also for the very first loop iteration now would
+     * otherwise always be 0
      */
     GST_OBJECT_LOCK (jitterbuffer);
     if (GST_ELEMENT_CLOCK (jitterbuffer)) {
@@ -3478,6 +3495,7 @@ wait_next_timeout (GstRtpJitterBuffer * jitterbuffer)
       }
 
       if (ret != GST_CLOCK_UNSCHEDULED) {
+        now = timer_timeout + MAX (clock_jitter, 0);
         GST_DEBUG_OBJECT (jitterbuffer, "sync done, %d, #%d, %" G_GINT64_FORMAT,
             ret, priv->timer_seqnum, clock_jitter);
       } else {
index 202bc3b..f1ecc30 100644 (file)
@@ -1,5 +1,7 @@
 /* GStreamer
  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C)  2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -908,6 +910,7 @@ get_clock_rate (RTPSource * src, guint8 payload)
     GST_DEBUG ("got clock-rate %d", clock_rate);
 
     src->clock_rate = clock_rate;
+    gst_rtp_packet_rate_ctx_reset (&src->packet_rate_ctx, clock_rate);
   }
   return src->clock_rate;
 }
@@ -1041,11 +1044,24 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
   guint16 seqnr, expected;
   RTPSourceStats *stats;
   gint16 delta;
+  gint32 packet_rate, max_dropout, max_misorder;
 
   stats = &src->stats;
 
   seqnr = pinfo->seqnum;
 
+  packet_rate =
+      gst_rtp_packet_rate_ctx_update (&src->packet_rate_ctx, pinfo->seqnum,
+      pinfo->rtptime);
+  max_dropout =
+      gst_rtp_packet_rate_ctx_get_max_dropout (&src->packet_rate_ctx,
+      src->max_dropout_time);
+  max_misorder =
+      gst_rtp_packet_rate_ctx_get_max_misorder (&src->packet_rate_ctx,
+      src->max_misorder_time);
+  GST_TRACE ("SSRC %08x, packet_rate: %d, max_dropout: %d, max_misorder: %d",
+      src->ssrc, packet_rate, max_dropout, max_misorder);
+
   if (stats->cycles == -1) {
     GST_DEBUG ("received first packet");
     /* first time we heard of this source */
@@ -1092,7 +1108,7 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
         /* unexpected seqnum in probation */
         goto probation_seqnum;
       }
-    } else if (delta >= 0 && delta < RTP_MAX_DROPOUT) {
+    } else if (delta >= 0 && delta < max_dropout) {
       /* Clear bad packets */
       stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
       g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
@@ -1104,7 +1120,7 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
         stats->cycles += RTP_SEQ_MOD;
       }
       stats->max_seq = seqnr;
-    } else if (delta < -RTP_MAX_MISORDER || delta >= RTP_MAX_DROPOUT) {
+    } else if (delta < -max_misorder || delta >= max_dropout) {
       /* the sequence number made a very large jump */
       if (seqnr == stats->bad_seq && src->packets->head) {
         /* two sequential packets -- assume that the other side
@@ -1120,7 +1136,7 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
         pinfo->data = NULL;
         goto bad_sequence;
       }
-    } else {                    /* delta < 0 && delta >= -RTP_MAX_MISORDER */
+    } else {                    /* delta < 0 && delta >= -max_misorder */
       /* Clear bad packets */
       stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
       g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
@@ -1150,7 +1166,9 @@ done:
   }
 bad_sequence:
   {
-    GST_WARNING ("unacceptable seqnum received");
+    GST_WARNING
+        ("unacceptable seqnum received (seqnr %u, delta %d, packet_rate: %d, max_dropout: %d, max_misorder: %d)",
+        seqnr, delta, packet_rate, max_dropout, max_misorder);
     return FALSE;
   }
 probation_seqnum:
index f24e25b..941c7d6 100644 (file)
@@ -1,5 +1,7 @@
 /* GStreamer
  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C)  2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -174,6 +176,7 @@ struct _RTPSource {
   guint64       bytes_received;
 
   GQueue       *packets;
+  RTPPacketRateCtx packet_rate_ctx;
   guint32       max_dropout_time;
   guint32       max_misorder_time;
 
index d47578d..984bc9f 100644 (file)
@@ -1,5 +1,7 @@
 /* GStreamer
  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C)  2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -81,6 +83,27 @@ gst_rtp_packet_rate_ctx_get (RTPPacketRateCtx * ctx)
   return ctx->avg_packet_rate;
 }
 
+guint32
+gst_rtp_packet_rate_ctx_get_max_dropout (RTPPacketRateCtx * ctx, gint32 time_ms)
+{
+  if (time_ms <= 0 || !ctx->probed) {
+    return RTP_DEF_DROPOUT;
+  }
+
+  return MAX (RTP_MIN_DROPOUT, ctx->avg_packet_rate * time_ms / 1000);
+}
+
+guint32
+gst_rtp_packet_rate_ctx_get_max_misorder (RTPPacketRateCtx * ctx,
+    gint32 time_ms)
+{
+  if (time_ms <= 0 || !ctx->probed) {
+    return RTP_DEF_MISORDER;
+  }
+
+  return MAX (RTP_MIN_MISORDER, ctx->avg_packet_rate * time_ms / 1000);
+}
+
 /**
  * rtp_stats_init_defaults:
  * @stats: an #RTPSessionStats struct
index 9c74039..14ba9da 100644 (file)
@@ -1,5 +1,7 @@
 /* GStreamer
  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C)  2015 Kurento (http://kurento.org/)
+ *   @author: Miguel París <mparisdiaz@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -183,15 +185,18 @@ typedef struct {
 #define RTP_STATS_BYE_TIMEOUT           (2 * GST_SECOND)
 
 /*
- * The maximum number of missing packets we tolerate. These are packets with a
- * sequence number bigger than the last seen packet.
+ * The default and minimum values of the maximum number of missing packets we tolerate.
+ * These are packets with asequence number bigger than the last seen packet.
  */
-#define RTP_MAX_DROPOUT      3000
+#define RTP_DEF_DROPOUT      3000
+#define RTP_MIN_DROPOUT      30
+
 /*
- * The maximum number of misordered packets we tolerate. These are packets with
- * a sequence number smaller than the last seen packet.
+ * The default and minimum values of the maximum number of misordered packets we tolerate.
+ * These are packets with a sequence number smaller than the last seen packet.
  */
-#define RTP_MAX_MISORDER     100
+#define RTP_DEF_MISORDER     100
+#define RTP_MIN_MISORDER     10
 
 /**
  * RTPPacketRateCtx:
@@ -209,6 +214,8 @@ typedef struct {
 void gst_rtp_packet_rate_ctx_reset (RTPPacketRateCtx * ctx, guint32 clock_rate);
 guint32 gst_rtp_packet_rate_ctx_update (RTPPacketRateCtx *ctx, guint16 seqnum, guint32 ts);
 guint32 gst_rtp_packet_rate_ctx_get (RTPPacketRateCtx *ctx);
+guint32 gst_rtp_packet_rate_ctx_get_max_dropout (RTPPacketRateCtx *ctx, gint32 time_ms);
+guint32 gst_rtp_packet_rate_ctx_get_max_misorder (RTPPacketRateCtx *ctx, gint32 time_ms);
 
 /**
  * RTPSessionStats: