3 * unit test for gstrtpbin
5 * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include <gst/check/gstcheck.h>
25 GST_START_TEST (test_cleanup_send)
28 GstPad *rtp_sink, *rtp_src, *rtcp_src;
32 rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
35 /* request session 0 */
36 rtp_sink = gst_element_get_request_pad (rtpbin, "send_rtp_sink_0");
37 fail_unless (rtp_sink != NULL);
38 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
41 rtp_sink = gst_element_get_request_pad (rtpbin, "send_rtp_sink_0");
42 fail_unless (rtp_sink != NULL);
43 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 3);
44 gst_object_unref (rtp_sink);
46 /* this static pad should be created automatically now */
47 rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
48 fail_unless (rtp_src != NULL);
49 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 2);
51 /* we should be able to get an internal session 0 now */
52 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
53 fail_unless (session != NULL);
54 g_object_unref (session);
56 /* get the send RTCP pad too */
57 rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
58 fail_unless (rtcp_src != NULL);
59 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtcp_src", 2);
62 rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
63 fail_unless (rtcp_src != NULL);
64 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtcp_src", 3);
65 gst_object_unref (rtcp_src);
67 gst_element_release_request_pad (rtpbin, rtp_sink);
68 /* we should only have our refs to the pads now */
69 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
70 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
71 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 2);
73 /* the other pad should be gone now */
74 fail_unless (gst_element_get_static_pad (rtpbin, "send_rtp_src_0") == NULL);
76 /* internal session should still be there */
77 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
78 fail_unless (session != NULL);
79 g_object_unref (session);
81 /* release the RTCP pad */
82 gst_element_release_request_pad (rtpbin, rtcp_src);
83 /* we should only have our refs to the pads now */
84 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
85 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
86 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 1);
88 /* the session should be gone now */
89 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
90 fail_unless (session == NULL);
92 /* unref the request pad and the static pad */
93 gst_object_unref (rtp_sink);
94 gst_object_unref (rtp_src);
95 gst_object_unref (rtcp_src);
98 gst_object_unref (rtpbin);
115 init_data (CleanupData * data)
118 data->pad_added = FALSE;
119 data->lock = g_mutex_new ();
120 data->cond = g_cond_new ();
125 clean_data (CleanupData * data)
127 g_list_foreach (data->pads, (GFunc) gst_object_unref, NULL);
128 g_list_free (data->pads);
129 g_mutex_free (data->lock);
130 g_cond_free (data->cond);
133 static guint8 rtp_packet[] = { 0x80, 0x60, 0x94, 0xbc, 0x8f, 0x37, 0x4e, 0xb8,
134 0x44, 0xa8, 0xf3, 0x7c, 0x06, 0x6a, 0x0c, 0xce,
135 0x13, 0x25, 0x19, 0x69, 0x1f, 0x93, 0x25, 0x9d,
136 0x2b, 0x82, 0x31, 0x3b, 0x36, 0xc1, 0x3c, 0x13
140 make_rtp_packet (CleanupData * data)
142 static GstCaps *caps = NULL;
147 caps = gst_caps_from_string ("application/x-rtp,"
148 "media=(string)audio, clock-rate=(int)44100, "
149 "encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1");
153 result = gst_buffer_new_and_alloc (sizeof (rtp_packet));
154 datap = GST_BUFFER_DATA (result);
155 memcpy (datap, rtp_packet, sizeof (rtp_packet));
157 datap[2] = (data->seqnum >> 8) & 0xff;
158 datap[3] = data->seqnum & 0xff;
162 gst_buffer_set_caps (result, caps);
168 dummy_chain (GstPad * pad, GstBuffer * buffer)
170 gst_buffer_unref (buffer);
175 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
178 GST_STATIC_CAPS ("application/x-rtp"));
182 make_sinkpad (CleanupData * data)
186 pad = gst_pad_new_from_static_template (&sink_factory, "sink");
188 gst_pad_set_chain_function (pad, dummy_chain);
189 gst_pad_set_active (pad, TRUE);
191 data->pads = g_list_prepend (data->pads, pad);
197 pad_added_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
201 GST_DEBUG ("pad added %s:%s\n", GST_DEBUG_PAD_NAME (pad));
203 if (GST_PAD_IS_SINK (pad))
206 fail_unless (data->pad_added == FALSE);
208 sinkpad = make_sinkpad (data);
209 fail_unless (gst_pad_link (pad, sinkpad) == GST_PAD_LINK_OK);
211 g_mutex_lock (data->lock);
212 data->pad_added = TRUE;
214 g_cond_signal (data->cond);
215 g_mutex_unlock (data->lock);
219 pad_removed_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
221 GST_DEBUG ("pad removed %s:%s\n", GST_DEBUG_PAD_NAME (pad));
223 if (data->pad != pad)
226 fail_unless (data->pad_added == TRUE);
228 g_mutex_lock (data->lock);
229 data->pad_added = FALSE;
230 g_cond_signal (data->cond);
231 g_mutex_unlock (data->lock);
234 GST_START_TEST (test_cleanup_recv)
239 GstStateChangeReturn ret;
246 rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
248 g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
249 g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
251 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
252 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
255 /* request session 0 */
256 rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
257 fail_unless (rtp_sink != NULL);
258 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
260 /* no sourcepads are created yet */
261 fail_unless (rtpbin->numsinkpads == 1);
262 fail_unless (rtpbin->numsrcpads == 0);
264 buffer = make_rtp_packet (&data);
265 res = gst_pad_chain (rtp_sink, buffer);
266 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
267 fail_unless (res == GST_FLOW_OK);
269 buffer = make_rtp_packet (&data);
270 res = gst_pad_chain (rtp_sink, buffer);
271 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
272 fail_unless (res == GST_FLOW_OK);
274 /* we wait for the new pad to appear now */
275 g_mutex_lock (data.lock);
276 while (!data.pad_added)
277 g_cond_wait (data.cond, data.lock);
278 g_mutex_unlock (data.lock);
280 /* sourcepad created now */
281 fail_unless (rtpbin->numsinkpads == 1);
282 fail_unless (rtpbin->numsrcpads == 1);
284 /* remove the session */
285 gst_element_release_request_pad (rtpbin, rtp_sink);
286 gst_object_unref (rtp_sink);
288 /* pad should be gone now */
289 g_mutex_lock (data.lock);
290 while (data.pad_added)
291 g_cond_wait (data.cond, data.lock);
292 g_mutex_unlock (data.lock);
294 /* nothing left anymore now */
295 fail_unless (rtpbin->numsinkpads == 0);
296 fail_unless (rtpbin->numsrcpads == 0);
299 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
300 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
302 gst_object_unref (rtpbin);
309 GST_START_TEST (test_cleanup_recv2)
314 GstStateChangeReturn ret;
321 rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
323 g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
324 g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
326 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
327 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
329 /* request session 0 */
330 rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
331 fail_unless (rtp_sink != NULL);
332 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
335 /* no sourcepads are created yet */
336 fail_unless (rtpbin->numsinkpads == 1);
337 fail_unless (rtpbin->numsrcpads == 0);
339 buffer = make_rtp_packet (&data);
340 res = gst_pad_chain (rtp_sink, buffer);
341 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
342 fail_unless (res == GST_FLOW_OK);
344 buffer = make_rtp_packet (&data);
345 res = gst_pad_chain (rtp_sink, buffer);
346 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
347 fail_unless (res == GST_FLOW_OK);
349 /* we wait for the new pad to appear now */
350 g_mutex_lock (data.lock);
351 while (!data.pad_added)
352 g_cond_wait (data.cond, data.lock);
353 g_mutex_unlock (data.lock);
355 /* sourcepad created now */
356 fail_unless (rtpbin->numsinkpads == 1);
357 fail_unless (rtpbin->numsrcpads == 1);
360 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
361 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
363 /* pad should be gone now */
364 g_mutex_lock (data.lock);
365 while (data.pad_added)
366 g_cond_wait (data.cond, data.lock);
367 g_mutex_unlock (data.lock);
369 /* back to playing for the next round */
370 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
371 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
374 /* remove the session */
375 gst_element_release_request_pad (rtpbin, rtp_sink);
376 gst_object_unref (rtp_sink);
378 /* nothing left anymore now */
379 fail_unless (rtpbin->numsinkpads == 0);
380 fail_unless (rtpbin->numsrcpads == 0);
382 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
383 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
385 gst_object_unref (rtpbin);
392 GST_START_TEST (test_request_pad_by_template_name)
395 GstPad *rtp_sink1, *rtp_sink2, *rtp_sink3;
397 rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
398 rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
399 fail_unless (rtp_sink1 != NULL);
400 fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "recv_rtp_sink_0");
401 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
403 rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
404 fail_unless (rtp_sink2 != NULL);
405 fail_unless_equals_string (GST_PAD_NAME (rtp_sink2), "recv_rtp_sink_1");
406 ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 2);
408 rtp_sink3 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
409 fail_unless (rtp_sink3 != NULL);
410 fail_unless_equals_string (GST_PAD_NAME (rtp_sink3), "recv_rtp_sink_2");
411 ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 2);
414 gst_element_release_request_pad (rtpbin, rtp_sink2);
415 gst_element_release_request_pad (rtpbin, rtp_sink1);
416 gst_element_release_request_pad (rtpbin, rtp_sink3);
417 ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 1);
418 ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 1);
419 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink", 1);
420 gst_object_unref (rtp_sink1);
421 gst_object_unref (rtp_sink2);
422 gst_object_unref (rtp_sink3);
424 gst_object_unref (rtpbin);
430 gstrtpbin_suite (void)
432 Suite *s = suite_create ("gstrtpbin");
433 TCase *tc_chain = tcase_create ("general");
435 suite_add_tcase (s, tc_chain);
436 tcase_add_test (tc_chain, test_cleanup_send);
437 tcase_add_test (tc_chain, test_cleanup_recv);
438 tcase_add_test (tc_chain, test_cleanup_recv2);
439 tcase_add_test (tc_chain, test_request_pad_by_template_name);
445 main (int argc, char **argv)
449 Suite *s = gstrtpbin_suite ();
450 SRunner *sr = srunner_create (s);
452 gst_check_init (&argc, &argv);
454 srunner_run_all (sr, CK_NORMAL);
455 nf = srunner_ntests_failed (sr);