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);
40 /* this static pad should be created automatically now */
41 rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
42 fail_unless (rtp_src != NULL);
43 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 2);
45 /* we should be able to get an internal session 0 now */
46 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
47 fail_unless (session != NULL);
48 g_object_unref (session);
50 /* get the send RTCP pad too */
51 rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
52 fail_unless (rtcp_src != NULL);
53 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtcp_src", 2);
55 gst_element_release_request_pad (rtpbin, rtp_sink);
56 /* we should only have our refs to the pads now */
57 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
58 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
59 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 2);
61 /* the other pad should be gone now */
62 fail_unless (gst_element_get_static_pad (rtpbin, "send_rtp_src_0") == NULL);
64 /* internal session should still be there */
65 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
66 fail_unless (session != NULL);
67 g_object_unref (session);
69 /* release the RTCP pad */
70 gst_element_release_request_pad (rtpbin, rtcp_src);
71 /* we should only have our refs to the pads now */
72 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
73 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
74 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 1);
76 /* the session should be gone now */
77 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
78 fail_unless (session == NULL);
80 /* unref the request pad and the static pad */
81 gst_object_unref (rtp_sink);
82 gst_object_unref (rtp_src);
83 gst_object_unref (rtcp_src);
86 gst_object_unref (rtpbin);
103 init_data (CleanupData * data)
106 data->pad_added = FALSE;
107 data->lock = g_mutex_new ();
108 data->cond = g_cond_new ();
113 clean_data (CleanupData * data)
115 g_list_foreach (data->pads, (GFunc) gst_object_unref, NULL);
116 g_list_free (data->pads);
117 g_mutex_free (data->lock);
118 g_cond_free (data->cond);
121 static guint8 rtp_packet[] = { 0x80, 0x60, 0x94, 0xbc, 0x8f, 0x37, 0x4e, 0xb8,
122 0x44, 0xa8, 0xf3, 0x7c, 0x06, 0x6a, 0x0c, 0xce,
123 0x13, 0x25, 0x19, 0x69, 0x1f, 0x93, 0x25, 0x9d,
124 0x2b, 0x82, 0x31, 0x3b, 0x36, 0xc1, 0x3c, 0x13
128 make_rtp_packet (CleanupData * data)
130 static GstCaps *caps = NULL;
135 caps = gst_caps_from_string ("application/x-rtp,"
136 "media=(string)audio, clock-rate=(int)44100, "
137 "encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1");
141 result = gst_buffer_new_and_alloc (sizeof (rtp_packet));
142 datap = GST_BUFFER_DATA (result);
143 memcpy (datap, rtp_packet, sizeof (rtp_packet));
145 datap[2] = (data->seqnum >> 8) & 0xff;
146 datap[3] = data->seqnum & 0xff;
150 gst_buffer_set_caps (result, caps);
156 dummy_chain (GstPad * pad, GstBuffer * buffer)
158 gst_buffer_unref (buffer);
163 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
166 GST_STATIC_CAPS ("application/x-rtp"));
170 make_sinkpad (CleanupData * data)
174 pad = gst_pad_new_from_static_template (&sink_factory, "sink");
176 gst_pad_set_chain_function (pad, dummy_chain);
177 gst_pad_set_active (pad, TRUE);
179 data->pads = g_list_prepend (data->pads, pad);
185 pad_added_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
189 GST_DEBUG ("pad added %s:%s\n", GST_DEBUG_PAD_NAME (pad));
191 if (GST_PAD_IS_SINK (pad))
194 fail_unless (data->pad_added == FALSE);
196 sinkpad = make_sinkpad (data);
197 fail_unless (gst_pad_link (pad, sinkpad) == GST_PAD_LINK_OK);
199 g_mutex_lock (data->lock);
200 data->pad_added = TRUE;
202 g_cond_signal (data->cond);
203 g_mutex_unlock (data->lock);
207 pad_removed_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
209 GST_DEBUG ("pad removed %s:%s\n", GST_DEBUG_PAD_NAME (pad));
211 if (data->pad != pad)
214 fail_unless (data->pad_added == TRUE);
216 g_mutex_lock (data->lock);
217 data->pad_added = FALSE;
218 g_cond_signal (data->cond);
219 g_mutex_unlock (data->lock);
222 GST_START_TEST (test_cleanup_recv)
227 GstStateChangeReturn ret;
234 rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
236 g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
237 g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
239 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
240 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
243 /* request session 0 */
244 rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
245 fail_unless (rtp_sink != NULL);
246 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
248 /* no sourcepads are created yet */
249 fail_unless (rtpbin->numsinkpads == 1);
250 fail_unless (rtpbin->numsrcpads == 0);
252 buffer = make_rtp_packet (&data);
253 res = gst_pad_chain (rtp_sink, buffer);
254 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
255 fail_unless (res == GST_FLOW_OK);
257 buffer = make_rtp_packet (&data);
258 res = gst_pad_chain (rtp_sink, buffer);
259 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
260 fail_unless (res == GST_FLOW_OK);
262 /* we wait for the new pad to appear now */
263 g_mutex_lock (data.lock);
264 while (!data.pad_added)
265 g_cond_wait (data.cond, data.lock);
266 g_mutex_unlock (data.lock);
268 /* sourcepad created now */
269 fail_unless (rtpbin->numsinkpads == 1);
270 fail_unless (rtpbin->numsrcpads == 1);
272 /* remove the session */
273 gst_element_release_request_pad (rtpbin, rtp_sink);
274 gst_object_unref (rtp_sink);
276 /* pad should be gone now */
277 g_mutex_lock (data.lock);
278 while (data.pad_added)
279 g_cond_wait (data.cond, data.lock);
280 g_mutex_unlock (data.lock);
282 /* nothing left anymore now */
283 fail_unless (rtpbin->numsinkpads == 0);
284 fail_unless (rtpbin->numsrcpads == 0);
287 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
288 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
290 gst_object_unref (rtpbin);
297 GST_START_TEST (test_cleanup_recv2)
302 GstStateChangeReturn ret;
309 rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
311 g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
312 g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
314 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
315 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
317 /* request session 0 */
318 rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
319 fail_unless (rtp_sink != NULL);
320 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
323 /* no sourcepads are created yet */
324 fail_unless (rtpbin->numsinkpads == 1);
325 fail_unless (rtpbin->numsrcpads == 0);
327 buffer = make_rtp_packet (&data);
328 res = gst_pad_chain (rtp_sink, buffer);
329 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
330 fail_unless (res == GST_FLOW_OK);
332 buffer = make_rtp_packet (&data);
333 res = gst_pad_chain (rtp_sink, buffer);
334 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
335 fail_unless (res == GST_FLOW_OK);
337 /* we wait for the new pad to appear now */
338 g_mutex_lock (data.lock);
339 while (!data.pad_added)
340 g_cond_wait (data.cond, data.lock);
341 g_mutex_unlock (data.lock);
343 /* sourcepad created now */
344 fail_unless (rtpbin->numsinkpads == 1);
345 fail_unless (rtpbin->numsrcpads == 1);
348 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
349 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
351 /* pad should be gone now */
352 g_mutex_lock (data.lock);
353 while (data.pad_added)
354 g_cond_wait (data.cond, data.lock);
355 g_mutex_unlock (data.lock);
357 /* back to playing for the next round */
358 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
359 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
362 /* remove the session */
363 gst_element_release_request_pad (rtpbin, rtp_sink);
364 gst_object_unref (rtp_sink);
366 /* nothing left anymore now */
367 fail_unless (rtpbin->numsinkpads == 0);
368 fail_unless (rtpbin->numsrcpads == 0);
370 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
371 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
373 gst_object_unref (rtpbin);
380 GST_START_TEST (test_request_pad_by_template_name)
383 GstPad *rtp_sink1, *rtp_sink2, *rtp_sink3;
385 rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
386 rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
387 fail_unless (rtp_sink1 != NULL);
388 fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "recv_rtp_sink_0");
389 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
391 rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
392 fail_unless (rtp_sink2 != NULL);
393 fail_unless_equals_string (GST_PAD_NAME (rtp_sink2), "recv_rtp_sink_1");
394 ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 2);
396 rtp_sink3 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
397 fail_unless (rtp_sink3 != NULL);
398 fail_unless_equals_string (GST_PAD_NAME (rtp_sink3), "recv_rtp_sink_2");
399 ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 2);
402 gst_element_release_request_pad (rtpbin, rtp_sink2);
403 gst_element_release_request_pad (rtpbin, rtp_sink1);
404 gst_element_release_request_pad (rtpbin, rtp_sink3);
405 ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 1);
406 ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 1);
407 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink", 1);
408 gst_object_unref (rtp_sink1);
409 gst_object_unref (rtp_sink2);
410 gst_object_unref (rtp_sink3);
412 gst_object_unref (rtpbin);
418 gstrtpbin_suite (void)
420 Suite *s = suite_create ("gstrtpbin");
421 TCase *tc_chain = tcase_create ("general");
423 suite_add_tcase (s, tc_chain);
424 tcase_add_test (tc_chain, test_cleanup_send);
425 tcase_add_test (tc_chain, test_cleanup_recv);
426 tcase_add_test (tc_chain, test_cleanup_recv2);
427 tcase_add_test (tc_chain, test_request_pad_by_template_name);
433 main (int argc, char **argv)
437 Suite *s = gstrtpbin_suite ();
438 SRunner *sr = srunner_create (s);
440 gst_check_init (&argc, &argv);
442 srunner_run_all (sr, CK_NORMAL);
443 nf = srunner_ntests_failed (sr);