diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c
index 8d300a9288..afedd03e1d 100644
--- a/gst/rtpmanager/gstrtpjitterbuffer.c
+++ b/gst/rtpmanager/gstrtpjitterbuffer.c
@@ -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)
*
*
* #guint64
+ * "num-pushed":
+ * the number of packets pushed out.
+ *
+ *
+ *
+ *
+ * #guint64
+ * "num-lost":
+ * the number of packets considered lost.
+ *
+ *
+ *
+ *
+ * #guint64
+ * "num-late":
+ * the number of packets arriving too late.
+ *
+ *
+ *
+ *
+ * #guint64
+ * "num-duplicates":
+ * the number of duplicate packets.
+ *
+ *
+ *
+ *
+ * #guint64
* "rtx-count":
* the number of retransmissions requested.
*
@@ -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;
}
diff --git a/tests/check/elements/rtpjitterbuffer.c b/tests/check/elements/rtpjitterbuffer.c
index 10810fa39f..5cb8510c82 100644
--- a/tests/check/elements/rtpjitterbuffer.c
+++ b/tests/check/elements/rtpjitterbuffer.c
@@ -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);