GstBuffer *last_sr;
/* some accounting */
+ guint64 num_pushed;
+ guint64 num_lost;
guint64 num_late;
guint64 num_duplicates;
guint64 num_rtx_requests;
* <listitem>
* <para>
* #guint64
+ * <classname>"num-pushed"</classname>:
+ * the number of packets pushed out.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * #guint64
+ * <classname>"num-lost"</classname>:
+ * the number of packets considered lost.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * #guint64
+ * <classname>"num-late"</classname>:
+ * the number of packets arriving too late.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * #guint64
+ * <classname>"num-duplicates"</classname>:
+ * the number of duplicate packets.
+ * </para>
+ * </listitem>
+ * <listitem>
+ * <para>
+ * #guint64
* <classname>"rtx-count"</classname>:
* the number of retransmissions requested.
* </para>
"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);
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;
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;
}
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");
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);
}
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);
}
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");
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);
}
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 ());
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);
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);
}
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);
}
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);
}
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);
}
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);