mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
tests: add retransmission jitterbuffer test
Store both DTS and PTS on buffers. Make a queue for srcpad events. Activate pads after linking so that we don't get RECONFIGURE events. Add test for retransmission.
This commit is contained in:
parent
fd6c57cf10
commit
ee817363c7
1 changed files with 161 additions and 21 deletions
|
@ -336,8 +336,10 @@ typedef struct
|
|||
GstPad *test_sink_pad, *test_src_pad;
|
||||
GstClock *clock;
|
||||
GAsyncQueue *buf_queue;
|
||||
GAsyncQueue *event_queue;
|
||||
GAsyncQueue *sink_event_queue;
|
||||
GAsyncQueue *src_event_queue;
|
||||
gint lost_event_count;
|
||||
gint rtx_event_count;
|
||||
} TestData;
|
||||
|
||||
static GstCaps *
|
||||
|
@ -361,7 +363,8 @@ generate_test_buffer (GstClockTime gst_ts,
|
|||
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
||||
|
||||
buf = gst_rtp_buffer_new_allocate (payload_size, 0, 0);
|
||||
GST_BUFFER_TIMESTAMP (buf) = gst_ts;
|
||||
GST_BUFFER_DTS (buf) = gst_ts;
|
||||
GST_BUFFER_PTS (buf) = gst_ts;
|
||||
|
||||
gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
|
||||
gst_rtp_buffer_set_payload_type (&rtp, pcmu_payload_type);
|
||||
|
@ -398,7 +401,24 @@ test_sink_pad_event_cb (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
if (strcmp (gst_structure_get_name (structure), "GstRTPPacketLost") == 0)
|
||||
data->lost_event_count++;
|
||||
|
||||
g_async_queue_push (data->event_queue, event);
|
||||
g_async_queue_push (data->sink_event_queue, event);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_src_pad_event_cb (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||
{
|
||||
TestData *data = gst_pad_get_element_private (pad);
|
||||
const GstStructure *structure = gst_event_get_structure (event);
|
||||
|
||||
GST_DEBUG ("got event %" GST_PTR_FORMAT, event);
|
||||
|
||||
if (structure
|
||||
&& strcmp (gst_structure_get_name (structure),
|
||||
"GstRTPRetransmissionRequest") == 0)
|
||||
data->rtx_event_count++;
|
||||
|
||||
g_async_queue_push (data->src_event_queue, event);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -422,33 +442,39 @@ setup_testharness (TestData * data)
|
|||
g_assert_cmpint (gst_element_set_state (data->jitter_buffer,
|
||||
GST_STATE_PLAYING), !=, GST_STATE_CHANGE_FAILURE);
|
||||
|
||||
/* set up the buf and event queues */
|
||||
data->buf_queue =
|
||||
g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
|
||||
data->sink_event_queue =
|
||||
g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
|
||||
data->src_event_queue =
|
||||
g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
|
||||
|
||||
data->lost_event_count = 0;
|
||||
data->rtx_event_count = 0;
|
||||
|
||||
/* link in the test source-pad */
|
||||
data->test_src_pad = gst_pad_new ("src", GST_PAD_SRC);
|
||||
gst_pad_set_element_private (data->test_src_pad, data);
|
||||
gst_pad_set_event_function (data->test_src_pad, test_src_pad_event_cb);
|
||||
jb_sink_pad = gst_element_get_static_pad (data->jitter_buffer, "sink");
|
||||
g_assert_cmpint (gst_pad_link (data->test_src_pad, jb_sink_pad), ==,
|
||||
GST_PAD_LINK_OK);
|
||||
g_assert (gst_pad_set_active (data->test_src_pad, TRUE));
|
||||
gst_object_unref (jb_sink_pad);
|
||||
|
||||
/* link in the test sink-pad */
|
||||
data->test_sink_pad = gst_pad_new ("sink", GST_PAD_SINK);
|
||||
gst_pad_set_element_private (data->test_sink_pad, data);
|
||||
gst_pad_set_caps (data->test_sink_pad, generate_caps ());
|
||||
gst_pad_set_chain_function (data->test_sink_pad, test_sink_pad_chain_cb);
|
||||
gst_pad_set_event_function (data->test_sink_pad, test_sink_pad_event_cb);
|
||||
jb_src_pad = gst_element_get_static_pad (data->jitter_buffer, "src");
|
||||
g_assert_cmpint (gst_pad_link (jb_src_pad, data->test_sink_pad), ==,
|
||||
GST_PAD_LINK_OK);
|
||||
g_assert (gst_pad_set_active (data->test_sink_pad, TRUE));
|
||||
gst_object_unref (jb_src_pad);
|
||||
|
||||
/* set up the buf and event queues */
|
||||
data->buf_queue =
|
||||
g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
|
||||
data->event_queue =
|
||||
g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
|
||||
|
||||
data->lost_event_count = 0;
|
||||
gst_pad_set_element_private (data->test_sink_pad, data);
|
||||
g_assert (gst_pad_set_active (data->test_src_pad, TRUE));
|
||||
g_assert (gst_pad_set_active (data->test_sink_pad, TRUE));
|
||||
|
||||
gst_segment_init (&seg, GST_FORMAT_TIME);
|
||||
|
||||
|
@ -457,7 +483,7 @@ setup_testharness (TestData * data)
|
|||
gst_pad_set_caps (data->test_src_pad, generate_caps ());
|
||||
gst_pad_push_event (data->test_src_pad, gst_event_new_segment (&seg));
|
||||
|
||||
while ((obj = g_async_queue_try_pop (data->event_queue)))
|
||||
while ((obj = g_async_queue_try_pop (data->sink_event_queue)))
|
||||
gst_mini_object_unref (obj);
|
||||
}
|
||||
|
||||
|
@ -482,8 +508,10 @@ destroy_testharness (TestData * data)
|
|||
g_async_queue_unref (data->buf_queue);
|
||||
data->buf_queue = NULL;
|
||||
|
||||
g_async_queue_unref (data->event_queue);
|
||||
data->event_queue = NULL;
|
||||
g_async_queue_unref (data->sink_event_queue);
|
||||
data->sink_event_queue = NULL;
|
||||
g_async_queue_unref (data->src_event_queue);
|
||||
data->src_event_queue = NULL;
|
||||
|
||||
data->lost_event_count = 0;
|
||||
}
|
||||
|
@ -499,6 +527,7 @@ verify_lost_event (GstEvent * event, guint32 expected_seqnum,
|
|||
GstClockTime timestamp;
|
||||
GstClockTime duration;
|
||||
gboolean late;
|
||||
|
||||
g_assert (gst_structure_get_uint (s, "seqnum", &seqnum));
|
||||
|
||||
value = gst_structure_get_value (s, "timestamp");
|
||||
|
@ -517,6 +546,37 @@ verify_lost_event (GstEvent * event, guint32 expected_seqnum,
|
|||
g_assert (late == expected_late);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_rtx_event (GstEvent * event, guint32 expected_seqnum,
|
||||
GstClockTime expected_timestamp, guint expected_delay,
|
||||
GstClockTime expected_spacing)
|
||||
{
|
||||
const GstStructure *s = gst_event_get_structure (event);
|
||||
const GValue *value;
|
||||
guint32 seqnum;
|
||||
GstClockTime timestamp, spacing;
|
||||
guint delay;
|
||||
|
||||
g_assert (gst_structure_get_uint (s, "seqnum", &seqnum));
|
||||
|
||||
value = gst_structure_get_value (s, "running-time");
|
||||
g_assert (value && G_VALUE_HOLDS_UINT64 (value));
|
||||
timestamp = g_value_get_uint64 (value);
|
||||
|
||||
value = gst_structure_get_value (s, "delay");
|
||||
g_assert (value && G_VALUE_HOLDS_UINT (value));
|
||||
delay = g_value_get_uint (value);
|
||||
|
||||
value = gst_structure_get_value (s, "packet-spacing");
|
||||
g_assert (value && G_VALUE_HOLDS_UINT64 (value));
|
||||
spacing = g_value_get_uint64 (value);
|
||||
|
||||
g_assert_cmpint (seqnum, ==, expected_seqnum);
|
||||
g_assert_cmpint (timestamp, ==, expected_timestamp);
|
||||
g_assert_cmpint (delay, ==, expected_delay);
|
||||
g_assert_cmpint (spacing, ==, expected_spacing);
|
||||
}
|
||||
|
||||
GST_START_TEST (test_only_one_lost_event_on_large_gaps)
|
||||
{
|
||||
TestData data;
|
||||
|
@ -578,7 +638,7 @@ GST_START_TEST (test_only_one_lost_event_on_large_gaps)
|
|||
g_assert (id == test_id);
|
||||
|
||||
/* we should now receive a packet-lost-event for buffers 1 through 489 */
|
||||
out_event = g_async_queue_timeout_pop (data.event_queue, timeout);
|
||||
out_event = g_async_queue_timeout_pop (data.sink_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
g_assert_cmpint (data.lost_event_count, ==, 1);
|
||||
verify_lost_event (out_event, 1, 1 * GST_MSECOND * 20, GST_MSECOND * 20 * 490,
|
||||
|
@ -673,7 +733,7 @@ GST_START_TEST (test_two_lost_one_arrives_in_time)
|
|||
== id);
|
||||
|
||||
/* we should now receive a packet-lost-event for buffer 3 */
|
||||
out_event = g_async_queue_timeout_pop (data.event_queue, timeout);
|
||||
out_event = g_async_queue_timeout_pop (data.sink_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
g_assert_cmpint (data.lost_event_count, ==, 1);
|
||||
verify_lost_event (out_event, 3, 3 * GST_MSECOND * 20, GST_MSECOND * 20,
|
||||
|
@ -757,7 +817,7 @@ GST_START_TEST (test_late_packets_still_makes_lost_events)
|
|||
g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);
|
||||
|
||||
/* we should now receive a packet-lost-event for buffer 3 and 4 */
|
||||
out_event = g_async_queue_timeout_pop (data.event_queue, timeout);
|
||||
out_event = g_async_queue_timeout_pop (data.sink_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
g_assert_cmpint (data.lost_event_count, ==, 1);
|
||||
verify_lost_event (out_event, 3, 3 * GST_MSECOND * 20, GST_MSECOND * 20 * 2,
|
||||
|
@ -824,11 +884,11 @@ GST_START_TEST (test_all_packets_are_timestamped_zero)
|
|||
g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);
|
||||
|
||||
/* we should now receive a packet-lost-event for buffer 3 and 4 */
|
||||
out_event = g_async_queue_timeout_pop (data.event_queue, timeout);
|
||||
out_event = g_async_queue_timeout_pop (data.sink_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
verify_lost_event (out_event, 3, 0, 0, FALSE);
|
||||
|
||||
out_event = g_async_queue_timeout_pop (data.event_queue, timeout);
|
||||
out_event = g_async_queue_timeout_pop (data.sink_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
verify_lost_event (out_event, 4, 0, 0, FALSE);
|
||||
|
||||
|
@ -850,6 +910,85 @@ GST_START_TEST (test_all_packets_are_timestamped_zero)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (test_rtx_expected_next)
|
||||
{
|
||||
TestData data;
|
||||
GstClockID id, tid;
|
||||
GstBuffer *in_buf, *out_buf;
|
||||
GstEvent *out_event;
|
||||
gint jb_latency_ms = 200;
|
||||
GstClockTime timeout = 20 * G_USEC_PER_SEC;
|
||||
|
||||
setup_testharness (&data);
|
||||
g_object_set (data.jitter_buffer, "do-retransmission", TRUE, NULL);
|
||||
g_object_set (data.jitter_buffer, "latency", jb_latency_ms, NULL);
|
||||
g_object_set (data.jitter_buffer, "rtx-retry-period", 120, NULL);
|
||||
|
||||
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 0);
|
||||
|
||||
/* push the first buffer in */
|
||||
in_buf = generate_test_buffer (0 * GST_MSECOND, TRUE, 0, 0);
|
||||
g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);
|
||||
|
||||
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 20 * GST_MSECOND);
|
||||
|
||||
/* put second buffer, the jitterbuffer should now know that the packet spacing
|
||||
* is 20ms and should ask for retransmission of seqnum 2 in 20ms */
|
||||
in_buf = generate_test_buffer (20 * GST_MSECOND, TRUE, 1, 160);
|
||||
g_assert_cmpint (gst_pad_push (data.test_src_pad, in_buf), ==, GST_FLOW_OK);
|
||||
|
||||
gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
|
||||
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 60 * GST_MSECOND);
|
||||
g_assert (gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock))
|
||||
== id);
|
||||
|
||||
out_event = g_async_queue_timeout_pop (data.src_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
verify_rtx_event (out_event, 2, 40 * GST_MSECOND, 20, 20 * GST_MSECOND);
|
||||
|
||||
/* now we wait for the next timeout */
|
||||
gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
|
||||
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 100 * GST_MSECOND);
|
||||
tid = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
|
||||
g_assert (id == tid);
|
||||
|
||||
out_event = g_async_queue_timeout_pop (data.src_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
verify_rtx_event (out_event, 2, 40 * GST_MSECOND, 60, 20 * GST_MSECOND);
|
||||
|
||||
gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
|
||||
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 140 * GST_MSECOND);
|
||||
tid = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
|
||||
g_assert (id == tid);
|
||||
|
||||
out_event = g_async_queue_timeout_pop (data.src_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
verify_rtx_event (out_event, 2, 40 * GST_MSECOND, 100, 20 * GST_MSECOND);
|
||||
|
||||
gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
|
||||
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 200 * GST_MSECOND);
|
||||
tid = gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock));
|
||||
g_assert (id == tid);
|
||||
|
||||
out_buf = g_async_queue_timeout_pop (data.buf_queue, timeout);
|
||||
g_assert (out_buf != NULL);
|
||||
|
||||
|
||||
gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
|
||||
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 260 * GST_MSECOND);
|
||||
g_assert (gst_test_clock_process_next_clock_id (GST_TEST_CLOCK (data.clock))
|
||||
== id);
|
||||
|
||||
/* we should now receive a packet-lost-event for buffer 2 */
|
||||
out_event = g_async_queue_timeout_pop (data.sink_event_queue, timeout);
|
||||
g_assert (out_event != NULL);
|
||||
verify_lost_event (out_event, 2, 40 * GST_MSECOND, 20 * GST_MSECOND, FALSE);
|
||||
|
||||
destroy_testharness (&data);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
rtpjitterbuffer_suite (void)
|
||||
{
|
||||
|
@ -865,6 +1004,7 @@ 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_test (tc_chain, test_rtx_expected_next);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue