1 /* GStreamer
2  *
3  * unit test for rtpfunnel
4  *
5  * Copyright (C) <2017> Pexip.
6  *   Contact: Havard Graff <havard@pexip.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 #include <gst/check/gstcheck.h>
24 #include <gst/check/gstharness.h>
25 
GST_START_TEST(rtpfunnel_ssrc_demuxing)26 GST_START_TEST (rtpfunnel_ssrc_demuxing)
27 {
28   GstHarness *h = gst_harness_new_with_padnames ("rtpfunnel", NULL, "src");
29   GstHarness *h0 = gst_harness_new_with_element (h->element, "sink_0", NULL);
30   GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
31 
32   gst_harness_set_src_caps_str (h0, "application/x-rtp, ssrc=(uint)123");
33   gst_harness_set_src_caps_str (h1, "application/x-rtp, ssrc=(uint)321");
34 
35   /* unref latency events */
36   gst_event_unref (gst_harness_pull_upstream_event (h0));
37   gst_event_unref (gst_harness_pull_upstream_event (h1));
38   fail_unless_equals_int (1, gst_harness_upstream_events_received (h0));
39   fail_unless_equals_int (1, gst_harness_upstream_events_received (h1));
40 
41   /* send to pad 0 */
42   gst_harness_push_upstream_event (h,
43       gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
44           gst_structure_new ("GstForceKeyUnit",
45               "ssrc", G_TYPE_UINT, 123, NULL)));
46   fail_unless_equals_int (2, gst_harness_upstream_events_received (h0));
47   fail_unless_equals_int (1, gst_harness_upstream_events_received (h1));
48 
49   /* send to pad 1 */
50   gst_harness_push_upstream_event (h,
51       gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
52           gst_structure_new ("GstForceKeyUnit",
53               "ssrc", G_TYPE_UINT, 321, NULL)));
54   fail_unless_equals_int (2, gst_harness_upstream_events_received (h0));
55   fail_unless_equals_int (2, gst_harness_upstream_events_received (h1));
56 
57   /* unknown ssrc, we drop it */
58   gst_harness_push_upstream_event (h,
59       gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
60           gst_structure_new ("GstForceKeyUnit",
61               "ssrc", G_TYPE_UINT, 666, NULL)));
62   fail_unless_equals_int (2, gst_harness_upstream_events_received (h0));
63   fail_unless_equals_int (2, gst_harness_upstream_events_received (h1));
64 
65   /* no ssrc, we send to all */
66   gst_harness_push_upstream_event (h,
67       gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
68           gst_structure_new_empty ("GstForceKeyUnit")));
69   fail_unless_equals_int (3, gst_harness_upstream_events_received (h0));
70   fail_unless_equals_int (3, gst_harness_upstream_events_received (h1));
71 
72   /* remove pad 0, and send an event referencing the now dead ssrc */
73   gst_harness_teardown (h0);
74   gst_harness_push_upstream_event (h,
75       gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
76           gst_structure_new ("GstForceKeyUnit",
77               "ssrc", G_TYPE_UINT, 123, NULL)));
78   fail_unless_equals_int (3, gst_harness_upstream_events_received (h1));
79 
80   gst_harness_teardown (h);
81   gst_harness_teardown (h1);
82 }
83 
84 GST_END_TEST
GST_START_TEST(rtpfunnel_ssrc_downstream_not_leaking_through)85 GST_START_TEST (rtpfunnel_ssrc_downstream_not_leaking_through)
86 {
87   GstHarness *h = gst_harness_new_with_padnames ("rtpfunnel",
88       "sink_0", "src");
89   GstCaps *caps;
90   const GstStructure *s;
91 
92   gst_harness_set_sink_caps_str (h, "application/x-rtp, ssrc=(uint)123");
93 
94   caps = gst_pad_peer_query_caps (h->srcpad, NULL);
95   s = gst_caps_get_structure (caps, 0);
96 
97   fail_unless (!gst_structure_has_field (s, "ssrc"));
98 
99   gst_caps_unref (caps);
100   gst_harness_teardown (h);
101 }
102 
103 GST_END_TEST
GST_START_TEST(rtpfunnel_common_ts_offset)104 GST_START_TEST (rtpfunnel_common_ts_offset)
105 {
106   GstHarness *h = gst_harness_new_with_padnames ("rtpfunnel",
107       "sink_0", "src");
108   GstCaps *caps;
109   const GstStructure *s;
110   const guint expected_ts_offset = 12345;
111   guint ts_offset;
112 
113   g_object_set (h->element, "common-ts-offset", expected_ts_offset, NULL);
114 
115   caps = gst_pad_peer_query_caps (h->srcpad, NULL);
116   s = gst_caps_get_structure (caps, 0);
117 
118   fail_unless (gst_structure_get_uint (s, "timestamp-offset", &ts_offset));
119   fail_unless_equals_int (expected_ts_offset, ts_offset);
120 
121   gst_caps_unref (caps);
122   gst_harness_teardown (h);
123 }
124 
125 GST_END_TEST
GST_START_TEST(rtpfunnel_stress)126 GST_START_TEST (rtpfunnel_stress)
127 {
128   GstHarness *h = gst_harness_new_with_padnames ("rtpfunnel",
129       "sink_0", "src");
130   GstHarness *h1 = gst_harness_new_with_element (h->element, "sink_1", NULL);
131 
132   GstPadTemplate *templ =
133       gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (h->element),
134       "sink_%u");
135   GstCaps *caps = gst_caps_from_string ("application/x-rtp, ssrc=(uint)123");
136   GstBuffer *buf = gst_buffer_new_allocate (NULL, 0, NULL);
137   GstSegment segment;
138   GstHarnessThread *statechange, *push, *req, *push1;
139 
140   gst_check_add_log_filter ("GStreamer", G_LOG_LEVEL_WARNING,
141       g_regex_new ("Got data flow before (stream-start|segment) event",
142           (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL),
143       NULL, NULL, NULL);
144   gst_check_add_log_filter ("GStreamer", G_LOG_LEVEL_WARNING,
145       g_regex_new ("Sticky event misordering",
146           (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL),
147       NULL, NULL, NULL);
148 
149 
150   gst_segment_init (&segment, GST_FORMAT_TIME);
151 
152   statechange = gst_harness_stress_statechange_start (h);
153   push = gst_harness_stress_push_buffer_start (h, caps, &segment, buf);
154   req = gst_harness_stress_requestpad_start (h, templ, NULL, NULL, TRUE);
155   push1 = gst_harness_stress_push_buffer_start (h1, caps, &segment, buf);
156 
157   gst_caps_unref (caps);
158   gst_buffer_unref (buf);
159 
160   /* test-length */
161   g_usleep (G_USEC_PER_SEC * 1);
162 
163   gst_harness_stress_thread_stop (push1);
164   gst_harness_stress_thread_stop (req);
165   gst_harness_stress_thread_stop (push);
166   gst_harness_stress_thread_stop (statechange);
167 
168   gst_harness_teardown (h1);
169   gst_harness_teardown (h);
170 
171   gst_check_clear_log_filter ();
172 }
173 
174 GST_END_TEST;
175 
176 static Suite *
rtpfunnel_suite(void)177 rtpfunnel_suite (void)
178 {
179   Suite *s = suite_create ("rtpfunnel");
180   TCase *tc_chain = tcase_create ("general");
181 
182   suite_add_tcase (s, tc_chain);
183 
184   tcase_add_test (tc_chain, rtpfunnel_ssrc_demuxing);
185   tcase_add_test (tc_chain, rtpfunnel_ssrc_downstream_not_leaking_through);
186   tcase_add_test (tc_chain, rtpfunnel_common_ts_offset);
187 
188   tcase_add_test (tc_chain, rtpfunnel_stress);
189 
190   return s;
191 }
192 
193 GST_CHECK_MAIN (rtpfunnel)
194