mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
tests/check: add an rtpsession unit test to verify all RBs are included in all SRs, roundrobin
This test checks that when we have multiple internal sender sources in rtpsession, SRs contain RBs for every other sender source, and that they are included roundrobin when they exceed ST_RTCP_MAX_RB_COUNT, which is the max number of RBs that can fit in a SR.
This commit is contained in:
parent
b4ebf8ca50
commit
f9b7f44938
1 changed files with 146 additions and 4 deletions
|
@ -3,6 +3,7 @@
|
||||||
* unit test for gstrtpsession
|
* unit test for gstrtpsession
|
||||||
*
|
*
|
||||||
* Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
|
* Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
* Copyright (C) 2013 Collabora Ltd.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -115,7 +116,7 @@ destroy_testharness (TestData * data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
setup_testharness (TestData * data)
|
setup_testharness (TestData * data, gboolean session_as_sender)
|
||||||
{
|
{
|
||||||
GstPad *rtp_sink_pad, *rtcp_src_pad, *rtp_src_pad;
|
GstPad *rtp_sink_pad, *rtcp_src_pad, *rtp_src_pad;
|
||||||
GstSegment seg;
|
GstSegment seg;
|
||||||
|
@ -141,14 +142,16 @@ setup_testharness (TestData * data)
|
||||||
/* link in the test source-pad */
|
/* link in the test source-pad */
|
||||||
data->src = gst_pad_new ("src", GST_PAD_SRC);
|
data->src = gst_pad_new ("src", GST_PAD_SRC);
|
||||||
g_assert (data->src);
|
g_assert (data->src);
|
||||||
rtp_sink_pad = gst_element_get_request_pad (data->session, "recv_rtp_sink");
|
rtp_sink_pad = gst_element_get_request_pad (data->session,
|
||||||
|
session_as_sender ? "send_rtp_sink" : "recv_rtp_sink");
|
||||||
g_assert (rtp_sink_pad);
|
g_assert (rtp_sink_pad);
|
||||||
g_assert_cmpint (gst_pad_link (data->src, rtp_sink_pad), ==, GST_PAD_LINK_OK);
|
g_assert_cmpint (gst_pad_link (data->src, rtp_sink_pad), ==, GST_PAD_LINK_OK);
|
||||||
gst_object_unref (rtp_sink_pad);
|
gst_object_unref (rtp_sink_pad);
|
||||||
|
|
||||||
data->rtpsrc = gst_pad_new ("sink", GST_PAD_SINK);
|
data->rtpsrc = gst_pad_new ("sink", GST_PAD_SINK);
|
||||||
g_assert (data->rtpsrc);
|
g_assert (data->rtpsrc);
|
||||||
rtp_src_pad = gst_element_get_static_pad (data->session, "recv_rtp_src");
|
rtp_src_pad = gst_element_get_static_pad (data->session,
|
||||||
|
session_as_sender ? "send_rtp_src" : "recv_rtp_src");
|
||||||
g_assert (rtp_src_pad);
|
g_assert (rtp_src_pad);
|
||||||
g_assert_cmpint (gst_pad_link (rtp_src_pad, data->rtpsrc), ==,
|
g_assert_cmpint (gst_pad_link (rtp_src_pad, data->rtpsrc), ==,
|
||||||
GST_PAD_LINK_OK);
|
GST_PAD_LINK_OK);
|
||||||
|
@ -191,7 +194,7 @@ GST_START_TEST (test_multiple_ssrc_rr)
|
||||||
gint32 packetslost;
|
gint32 packetslost;
|
||||||
guint8 fractionlost;
|
guint8 fractionlost;
|
||||||
|
|
||||||
setup_testharness (&data);
|
setup_testharness (&data, FALSE);
|
||||||
|
|
||||||
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 10 * GST_MSECOND);
|
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), 10 * GST_MSECOND);
|
||||||
|
|
||||||
|
@ -247,6 +250,144 @@ GST_START_TEST (test_multiple_ssrc_rr)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
/* This verifies that rtpsession will correctly place RBs round-robin
|
||||||
|
* across multiple SRs when there are too many senders that their RBs
|
||||||
|
* do not fit in one SR */
|
||||||
|
GST_START_TEST (test_multiple_senders_roundrobin_rbs)
|
||||||
|
{
|
||||||
|
TestData data;
|
||||||
|
GstFlowReturn res;
|
||||||
|
GstClockID id;
|
||||||
|
GstBuffer *buf;
|
||||||
|
GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
|
||||||
|
GstRTCPPacket rtcp_packet;
|
||||||
|
GstClockTime time;
|
||||||
|
gint queue_length;
|
||||||
|
gint i, j, k;
|
||||||
|
guint32 ssrc;
|
||||||
|
GHashTable *sr_ssrcs, *rb_ssrcs, *tmp_set;
|
||||||
|
|
||||||
|
setup_testharness (&data, TRUE);
|
||||||
|
|
||||||
|
/* only the RTCP thread waits on the clock */
|
||||||
|
gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock), &id);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) { /* cycles between SR reports */
|
||||||
|
for (j = 0; j < 5; j++) { /* packets per ssrc */
|
||||||
|
gint seq = (i * 5) + j;
|
||||||
|
GST_DEBUG ("Push %i", seq);
|
||||||
|
|
||||||
|
gst_test_clock_advance_time (GST_TEST_CLOCK (data.clock),
|
||||||
|
200 * GST_MSECOND);
|
||||||
|
|
||||||
|
for (k = 0; k < 35; k++) { /* number of ssrcs */
|
||||||
|
buf =
|
||||||
|
generate_test_buffer (seq * 200 * GST_MSECOND, FALSE, seq,
|
||||||
|
seq * 200, 10000 + k);
|
||||||
|
res = gst_pad_push (data.src, buf);
|
||||||
|
fail_unless (res == GST_FLOW_OK || res == GST_FLOW_FLUSHING);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG ("pushed %i", seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_length = g_async_queue_length (data.rtcp_queue);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* crank the RTCP pad thread */
|
||||||
|
time = gst_clock_id_get_time (id);
|
||||||
|
GST_DEBUG ("Advancing time to %" GST_TIME_FORMAT, GST_TIME_ARGS (time));
|
||||||
|
gst_test_clock_set_time (GST_TEST_CLOCK (data.clock), time);
|
||||||
|
fail_unless_equals_pointer (gst_test_clock_process_next_clock_id
|
||||||
|
(GST_TEST_CLOCK (data.clock)), id);
|
||||||
|
|
||||||
|
/* wait for the RTCP pad thread to output its data
|
||||||
|
* and start waiting on the next timeout */
|
||||||
|
gst_test_clock_wait_for_next_pending_id (GST_TEST_CLOCK (data.clock),
|
||||||
|
&id);
|
||||||
|
|
||||||
|
/* and retry as long as there are no new RTCP packets out,
|
||||||
|
* because the RTCP thread may randomly decide to reschedule
|
||||||
|
* the RTCP timeout for later */
|
||||||
|
} while (g_async_queue_length (data.rtcp_queue) == queue_length);
|
||||||
|
|
||||||
|
GST_DEBUG ("RTCP timeout processed");
|
||||||
|
}
|
||||||
|
|
||||||
|
sr_ssrcs = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||||
|
rb_ssrcs = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
|
||||||
|
(GDestroyNotify) g_hash_table_unref);
|
||||||
|
|
||||||
|
/* verify the rtcp packets */
|
||||||
|
for (i = 0; i < 2 * 35; i++) {
|
||||||
|
guint expected_rb_count = (i < 35) ? GST_RTCP_MAX_RB_COUNT :
|
||||||
|
(35 - GST_RTCP_MAX_RB_COUNT - 1);
|
||||||
|
|
||||||
|
GST_DEBUG ("pop %d", i);
|
||||||
|
|
||||||
|
buf = g_async_queue_pop (data.rtcp_queue);
|
||||||
|
g_assert (buf != NULL);
|
||||||
|
g_assert (gst_rtcp_buffer_validate (buf));
|
||||||
|
|
||||||
|
gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
|
||||||
|
g_assert (gst_rtcp_buffer_get_first_packet (&rtcp, &rtcp_packet));
|
||||||
|
g_assert_cmpint (gst_rtcp_packet_get_type (&rtcp_packet), ==,
|
||||||
|
GST_RTCP_TYPE_SR);
|
||||||
|
|
||||||
|
gst_rtcp_packet_sr_get_sender_info (&rtcp_packet, &ssrc, NULL, NULL, NULL,
|
||||||
|
NULL);
|
||||||
|
g_assert_cmpint (ssrc, >=, 10000);
|
||||||
|
g_assert_cmpint (ssrc, <=, 10035);
|
||||||
|
g_hash_table_add (sr_ssrcs, GUINT_TO_POINTER (ssrc));
|
||||||
|
|
||||||
|
/* inspect the RBs */
|
||||||
|
g_assert_cmpint (gst_rtcp_packet_get_rb_count (&rtcp_packet), ==,
|
||||||
|
expected_rb_count);
|
||||||
|
|
||||||
|
if (i < 35) {
|
||||||
|
tmp_set = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||||
|
g_hash_table_insert (rb_ssrcs, GUINT_TO_POINTER (ssrc), tmp_set);
|
||||||
|
} else {
|
||||||
|
tmp_set = g_hash_table_lookup (rb_ssrcs, GUINT_TO_POINTER (ssrc));
|
||||||
|
g_assert (tmp_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < expected_rb_count; j++) {
|
||||||
|
gst_rtcp_packet_get_rb (&rtcp_packet, j, &ssrc, NULL, NULL,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
g_assert_cmpint (ssrc, >=, 10000);
|
||||||
|
g_assert_cmpint (ssrc, <=, 10035);
|
||||||
|
g_hash_table_add (tmp_set, GUINT_TO_POINTER (ssrc));
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_rtcp_buffer_unmap (&rtcp);
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
|
||||||
|
/* cycle done, verify all ssrcs have issued SR reports */
|
||||||
|
if ((i + 1) == 35 || (i + 1) == (2 * 35)) {
|
||||||
|
g_assert_cmpint (g_hash_table_size (sr_ssrcs), ==, 35);
|
||||||
|
g_hash_table_remove_all (sr_ssrcs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now verify all other ssrcs have been reported on each ssrc's SR */
|
||||||
|
g_assert_cmpint (g_hash_table_size (rb_ssrcs), ==, 35);
|
||||||
|
for (i = 10000; i < 10035; i++) {
|
||||||
|
tmp_set = g_hash_table_lookup (rb_ssrcs, GUINT_TO_POINTER (i));
|
||||||
|
g_assert (tmp_set);
|
||||||
|
/* SR contains RBs for each other ssrc except the ssrc of the SR */
|
||||||
|
g_assert_cmpint (g_hash_table_size (tmp_set), ==, 34);
|
||||||
|
g_assert (!g_hash_table_contains (tmp_set, GUINT_TO_POINTER (i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_unref (sr_ssrcs);
|
||||||
|
g_hash_table_unref (rb_ssrcs);
|
||||||
|
|
||||||
|
destroy_testharness (&data);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
gstrtpsession_suite (void)
|
gstrtpsession_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -255,6 +396,7 @@ gstrtpsession_suite (void)
|
||||||
|
|
||||||
suite_add_tcase (s, tc_chain);
|
suite_add_tcase (s, tc_chain);
|
||||||
tcase_add_test (tc_chain, test_multiple_ssrc_rr);
|
tcase_add_test (tc_chain, test_multiple_ssrc_rr);
|
||||||
|
tcase_add_test (tc_chain, test_multiple_senders_roundrobin_rbs);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue