rtpjitterbuffer: Add and expose more stats and increase testing of it
authorHavard Graff <havard.graff@gmail.com>
Thu, 11 Aug 2016 09:02:44 +0000 (11:02 +0200)
committerOlivier CrĂȘte <olivier.crete@collabora.com>
Wed, 14 Sep 2016 23:37:50 +0000 (19:37 -0400)
Add num-pushed and num-lost.
Expose num-late, num-duplicates and avg-jitter.

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

gst/rtpmanager/gstrtpjitterbuffer.c
tests/check/elements/rtpjitterbuffer.c

index 8d300a9..afedd03 100644 (file)
@@ -333,6 +333,8 @@ struct _GstRtpJitterBufferPrivate
   GstBuffer *last_sr;
 
   /* some accounting */
+  guint64 num_pushed;
+  guint64 num_lost;
   guint64 num_late;
   guint64 num_duplicates;
   guint64 num_rtx_requests;
@@ -710,6 +712,34 @@ gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
    * <listitem>
    *   <para>
    *   #guint64
+   *   <classname>&quot;num-pushed&quot;</classname>:
+   *   the number of packets pushed out.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;num-lost&quot;</classname>:
+   *   the number of packets considered lost.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;num-late&quot;</classname>:
+   *   the number of packets arriving too late.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
+   *   <classname>&quot;num-duplicates&quot;</classname>:
+   *   the number of duplicate packets.
+   *   </para>
+   * </listitem>
+   * <listitem>
+   *   <para>
+   *   #guint64
    *   <classname>&quot;rtx-count&quot;</classname>:
    *   the number of retransmissions requested.
    *   </para>
@@ -3165,6 +3195,7 @@ pop_and_push_next (GstRtpJitterBuffer * jitterbuffer, guint seqnum)
           "Pushing buffer %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
           seqnum, GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
           GST_TIME_ARGS (GST_BUFFER_PTS (outbuf)));
+      priv->num_pushed++;
       result = gst_pad_push (priv->srcpad, outbuf);
 
       JBUF_LOCK_CHECK (priv, out_flushing);
@@ -3446,7 +3477,7 @@ do_lost_timeout (GstRtpJitterBuffer * jitterbuffer, TimerData * timer,
   else
     GST_DEBUG_OBJECT (jitterbuffer, "Packet #%d lost", seqnum);
 
-  priv->num_late += lost_packets;
+  priv->num_lost += lost_packets;
   priv->num_rtx_failed += num_rtx_retry;
 
   next_in_seqnum = (seqnum + lost_packets) & 0xffff;
@@ -4340,15 +4371,21 @@ gst_rtp_jitter_buffer_get_property (GObject * object,
 static GstStructure *
 gst_rtp_jitter_buffer_create_stats (GstRtpJitterBuffer * jbuf)
 {
+  GstRtpJitterBufferPrivate *priv = jbuf->priv;
   GstStructure *s;
 
-  JBUF_LOCK (jbuf->priv);
+  JBUF_LOCK (priv);
   s = gst_structure_new ("application/x-rtp-jitterbuffer-stats",
-      "rtx-count", G_TYPE_UINT64, jbuf->priv->num_rtx_requests,
-      "rtx-success-count", G_TYPE_UINT64, jbuf->priv->num_rtx_success,
-      "rtx-per-packet", G_TYPE_DOUBLE, jbuf->priv->avg_rtx_num,
-      "rtx-rtt", G_TYPE_UINT64, jbuf->priv->avg_rtx_rtt, NULL);
-  JBUF_UNLOCK (jbuf->priv);
+      "num-pushed", G_TYPE_UINT64, priv->num_pushed,
+      "num-lost", G_TYPE_UINT64, priv->num_lost,
+      "num-late", G_TYPE_UINT64, priv->num_late,
+      "num-duplicates", G_TYPE_UINT64, priv->num_duplicates,
+      "avg-jitter", G_TYPE_UINT64, priv->avg_jitter,
+      "rtx-count", G_TYPE_UINT64, priv->num_rtx_requests,
+      "rtx-success-count", G_TYPE_UINT64, priv->num_rtx_success,
+      "rtx-per-packet", G_TYPE_DOUBLE, priv->avg_rtx_num,
+      "rtx-rtt", G_TYPE_UINT64, priv->avg_rtx_rtt, NULL);
+  JBUF_UNLOCK (priv);
 
   return s;
 }
index 10810fa..5cb8510 100644 (file)
@@ -520,6 +520,29 @@ verify_rtx_event (GstEvent * event, guint32 expected_seqnum,
   gst_event_unref (event);
 }
 
+static gboolean
+verify_jb_stats (GstElement * jb, GstStructure * expected)
+{
+  gboolean ret;
+  GstStructure *actual;
+  g_object_get (jb, "stats", &actual, NULL);
+
+  ret = gst_structure_is_subset (actual, expected);
+
+  if (!ret) {
+    gchar *e_str = gst_structure_to_string (expected);
+    gchar *a_str = gst_structure_to_string (actual);
+    fail_unless (ret, "%s is not a subset of %s", e_str, a_str);
+    g_free (e_str);
+    g_free (a_str);
+  }
+
+  gst_structure_free (expected);
+  gst_structure_free (actual);
+
+  return ret;
+}
+
 GST_START_TEST (test_only_one_lost_event_on_large_gaps)
 {
   GstHarness *h = gst_harness_new ("rtpjitterbuffer");
@@ -604,6 +627,10 @@ GST_START_TEST (test_only_one_lost_event_on_large_gaps)
   fail_unless_equals_uint64 (10 * GST_SECOND, GST_BUFFER_PTS (out_buf));
   gst_buffer_unref (out_buf);
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 499, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -688,6 +715,11 @@ GST_START_TEST (test_two_lost_one_arrives_in_time)
   fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
   gst_buffer_unref (out_buf);
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 5,
+              "num-lost", G_TYPE_UINT64, (guint64) 1, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -749,12 +781,76 @@ GST_START_TEST (test_late_packets_still_makes_lost_events)
   fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
   gst_buffer_unref (out_buf);
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 4,
+              "num-lost", G_TYPE_UINT64, (guint64) 2, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
 
 GST_END_TEST;
 
+
+GST_START_TEST (test_num_late_when_considered_lost_arrives)
+{
+  GstHarness *h = gst_harness_new ("rtpjitterbuffer");
+  gboolean do_lost = __i__ != 0;
+
+  gst_harness_set_src_caps (h, generate_caps ());
+  g_object_set (h->element, "do-lost", do_lost, "latency", 100, NULL);
+
+  /* push the first buffer through */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (0)));
+  /* sync on the first packet */
+  gst_harness_crank_single_clock_wait (h);
+
+  /* gap of 1 */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (2)));
+
+  /* crank to output lost-event */
+  gst_harness_crank_single_clock_wait (h);
+
+  if (do_lost) {
+    /* drop GstEventStreamStart & GstEventCaps & GstEventSegment */
+    for (gint i = 0; i < 3; i++)
+      gst_event_unref (gst_harness_pull_event (h));
+
+    /* we should now receive packet-lost-events for buffer 1 */
+    verify_lost_event (gst_harness_pull_event (h),
+        1, 1 * PCMU_BUF_DURATION, PCMU_BUF_DURATION);
+  }
+
+  /* pull out buffers to ensure determinism */
+  gst_buffer_unref (gst_harness_pull (h));
+  gst_buffer_unref (gst_harness_pull (h));
+
+  /* we have one lost packet in the stats */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 0, NULL)));
+
+  /* buffer 1 now arrives (too late) */
+  fail_unless_equals_int (GST_FLOW_OK,
+      gst_harness_push (h, generate_test_buffer (1)));
+
+  /* and this increments num-late */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "num-late", G_TYPE_UINT64, (guint64) 1, NULL)));
+
+  gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
 GST_START_TEST (test_all_packets_are_timestamped_zero)
 {
   GstHarness *h = gst_harness_new ("rtpjitterbuffer");
@@ -809,6 +905,11 @@ GST_START_TEST (test_all_packets_are_timestamped_zero)
   fail_unless_equals_int (5, get_rtp_seq_num (out_buf));
   gst_buffer_unref (out_buf);
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 4,
+              "num-lost", G_TYPE_UINT64, (guint64) 2, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -903,8 +1004,6 @@ GST_START_TEST (test_rtx_two_missing)
   GstEvent *out_event;
   gint jb_latency_ms = 200;
   const GstClockTime rtx_retry_timeout = 40 * GST_MSECOND;
-  GstStructure *rtx_stats;
-  const GValue *rtx_stat;
   gint i;
 
   gst_harness_set_src_caps (h, generate_caps ());
@@ -1010,17 +1109,12 @@ GST_START_TEST (test_rtx_two_missing)
      so no events in the queue */
   fail_unless_equals_int (0, gst_harness_events_in_queue (h));
 
-  g_object_get (h->element, "stats", &rtx_stats, NULL);
-
-  rtx_stat = gst_structure_get_value (rtx_stats, "rtx-count");
-  fail_unless_equals_uint64 (5, g_value_get_uint64 (rtx_stat));
-
-  rtx_stat = gst_structure_get_value (rtx_stats, "rtx-success-count");
-  fail_unless_equals_uint64 (1, g_value_get_uint64 (rtx_stat));
-
-  rtx_stat = gst_structure_get_value (rtx_stats, "rtx-rtt");
-  fail_unless_equals_uint64 (0, g_value_get_uint64 (rtx_stat));
-  gst_structure_free (rtx_stats);
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 1,
+              "rtx-count", G_TYPE_UINT64, (guint64) 5,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 1,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
 
   gst_object_unref (testclock);
   gst_harness_teardown (h);
@@ -1142,6 +1236,13 @@ GST_START_TEST (test_rtx_packet_delay)
   fail_unless_equals_int (0, gst_harness_events_in_queue (h));
   fail_unless_equals_int (20, gst_harness_upstream_events_in_queue (h));
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 7,
+              "rtx-count", G_TYPE_UINT64, (guint64) 26,
+              "rtx-success-count", G_TYPE_UINT64, (guint64) 0,
+              "rtx-rtt", G_TYPE_UINT64, (guint64) 0, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -1274,6 +1375,15 @@ GST_START_TEST (test_gap_exceeds_latency)
   fail_unless_equals_int (0, gst_harness_events_in_queue (h));
   fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 11,
+              "num-lost", G_TYPE_UINT64, (guint64)7,
+              "rtx-count", G_TYPE_UINT64, (guint64)21,
+              "rtx-success-count", G_TYPE_UINT64, (guint64)5,
+              "rtx-rtt", G_TYPE_UINT64, (guint64)0,
+              NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -1360,6 +1470,10 @@ GST_START_TEST (test_dts_gap_larger_than_latency)
     verify_lost_event (out_event, i, i * dur, dur);
   }
 
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-lost", G_TYPE_UINT64, (guint64) 4, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -1488,6 +1602,13 @@ GST_START_TEST (test_considered_lost_packet_in_large_gap_arrives)
   fail_unless_equals_int ((4 + seq_offset) & 0xffff, get_rtp_seq_num (buffer));
   gst_buffer_unref (buffer);
 
+  /* we have lost 3, and one of them arrived eventually, but too late */
+  fail_unless (verify_jb_stats (h->element,
+          gst_structure_new ("application/x-rtp-jitterbuffer-stats",
+              "num-pushed", G_TYPE_UINT64, (guint64) 2,
+              "num-lost", G_TYPE_UINT64, (guint64) 3,
+              "num-late", G_TYPE_UINT64, (guint64) 1, NULL)));
+
   gst_object_unref (testclock);
   gst_harness_teardown (h);
 }
@@ -1510,6 +1631,8 @@ rtpjitterbuffer_suite (void)
   tcase_add_test (tc_chain, test_two_lost_one_arrives_in_time);
   tcase_add_test (tc_chain, test_late_packets_still_makes_lost_events);
   tcase_add_test (tc_chain, test_all_packets_are_timestamped_zero);
+  tcase_add_loop_test (tc_chain, test_num_late_when_considered_lost_arrives, 0,
+      2);
   tcase_add_test (tc_chain, test_rtx_expected_next);
   tcase_add_test (tc_chain, test_rtx_two_missing);
   tcase_add_test (tc_chain, test_rtx_packet_delay);