1 /* GStreamer
2 *
3 * unit test for gstrtpbin
4 *
5 * Copyright (C) <2009> Wim Taymans <wim.taymans@gmail.com>
6 *
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.
11 *
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.
16 *
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., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <gst/check/gstcheck.h>
24 #include <gst/check/gsttestclock.h>
25
26 #include <gst/rtp/gstrtpbuffer.h>
27 #include <gst/rtp/gstrtcpbuffer.h>
28
GST_START_TEST(test_pads)29 GST_START_TEST (test_pads)
30 {
31 GstElement *element;
32 GstPad *pad;
33
34 element = gst_element_factory_make ("rtpsession", NULL);
35
36 pad = gst_element_get_request_pad (element, "recv_rtcp_sink");
37 gst_object_unref (pad);
38 gst_object_unref (element);
39 }
40
41 GST_END_TEST;
42
GST_START_TEST(test_cleanup_send)43 GST_START_TEST (test_cleanup_send)
44 {
45 GstElement *rtpbin;
46 GstPad *rtp_sink, *rtp_src, *rtcp_src;
47 GObject *session;
48 gint count = 2;
49
50 rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
51
52 while (count--) {
53 /* request session 0 */
54 rtp_sink = gst_element_get_request_pad (rtpbin, "send_rtp_sink_0");
55 fail_unless (rtp_sink != NULL);
56 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
57
58 /* this static pad should be created automatically now */
59 rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
60 fail_unless (rtp_src != NULL);
61 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 2);
62
63 /* we should be able to get an internal session 0 now */
64 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
65 fail_unless (session != NULL);
66 g_object_unref (session);
67
68 /* get the send RTCP pad too */
69 rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
70 fail_unless (rtcp_src != NULL);
71 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtcp_src", 2);
72
73 gst_element_release_request_pad (rtpbin, rtp_sink);
74 /* we should only have our refs to the pads now */
75 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
76 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
77 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 2);
78
79 /* the other pad should be gone now */
80 fail_unless (gst_element_get_static_pad (rtpbin, "send_rtp_src_0") == NULL);
81
82 /* internal session should still be there */
83 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
84 fail_unless (session != NULL);
85 g_object_unref (session);
86
87 /* release the RTCP pad */
88 gst_element_release_request_pad (rtpbin, rtcp_src);
89 /* we should only have our refs to the pads now */
90 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
91 ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
92 ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 1);
93
94 /* the session should be gone now */
95 g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
96 fail_unless (session == NULL);
97
98 /* unref the request pad and the static pad */
99 gst_object_unref (rtp_sink);
100 gst_object_unref (rtp_src);
101 gst_object_unref (rtcp_src);
102 }
103
104 gst_object_unref (rtpbin);
105 }
106
107 GST_END_TEST;
108
109 typedef struct
110 {
111 guint16 seqnum;
112 gboolean pad_added;
113 GstPad *pad;
114 GMutex lock;
115 GCond cond;
116 GstPad *sinkpad;
117 GList *pads;
118 GstCaps *caps;
119 } CleanupData;
120
121 static void
init_data(CleanupData * data)122 init_data (CleanupData * data)
123 {
124 data->seqnum = 10;
125 data->pad_added = FALSE;
126 g_mutex_init (&data->lock);
127 g_cond_init (&data->cond);
128 data->pads = NULL;
129 data->caps = NULL;
130 }
131
132 static void
clean_data(CleanupData * data)133 clean_data (CleanupData * data)
134 {
135 g_list_foreach (data->pads, (GFunc) gst_object_unref, NULL);
136 g_list_free (data->pads);
137 g_mutex_clear (&data->lock);
138 g_cond_clear (&data->cond);
139 if (data->caps)
140 gst_caps_unref (data->caps);
141 }
142
143 static guint8 rtp_packet[] = { 0x80, 0x60, 0x94, 0xbc, 0x8f, 0x37, 0x4e, 0xb8,
144 0x44, 0xa8, 0xf3, 0x7c, 0x06, 0x6a, 0x0c, 0xce,
145 0x13, 0x25, 0x19, 0x69, 0x1f, 0x93, 0x25, 0x9d,
146 0x2b, 0x82, 0x31, 0x3b, 0x36, 0xc1, 0x3c, 0x13
147 };
148
149 static GstFlowReturn
chain_rtp_packet(GstPad * pad,CleanupData * data)150 chain_rtp_packet (GstPad * pad, CleanupData * data)
151 {
152 GstFlowReturn res;
153 GstSegment segment;
154 GstBuffer *buffer;
155 GstMapInfo map;
156
157 if (data->caps == NULL) {
158 data->caps = gst_caps_from_string ("application/x-rtp,"
159 "media=(string)audio, clock-rate=(int)44100, "
160 "encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1");
161 data->seqnum = 0;
162 }
163
164 gst_pad_send_event (pad, gst_event_new_stream_start (GST_OBJECT_NAME (pad)));
165 gst_pad_send_event (pad, gst_event_new_caps (data->caps));
166 gst_segment_init (&segment, GST_FORMAT_TIME);
167 gst_pad_send_event (pad, gst_event_new_segment (&segment));
168
169 buffer = gst_buffer_new_and_alloc (sizeof (rtp_packet));
170 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
171 memcpy (map.data, rtp_packet, sizeof (rtp_packet));
172
173 map.data[2] = (data->seqnum >> 8) & 0xff;
174 map.data[3] = data->seqnum & 0xff;
175
176 data->seqnum++;
177 gst_buffer_unmap (buffer, &map);
178
179 res = gst_pad_chain (pad, buffer);
180
181 return res;
182 }
183
184 static GstFlowReturn
dummy_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)185 dummy_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
186 {
187 gst_buffer_unref (buffer);
188
189 return GST_FLOW_OK;
190 }
191
192 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
193 GST_PAD_SINK,
194 GST_PAD_ALWAYS,
195 GST_STATIC_CAPS ("application/x-rtp"));
196
197
198 static GstPad *
make_sinkpad(CleanupData * data)199 make_sinkpad (CleanupData * data)
200 {
201 GstPad *pad;
202
203 pad = gst_pad_new_from_static_template (&sink_factory, "sink");
204
205 gst_pad_set_chain_function (pad, dummy_chain);
206 gst_pad_set_active (pad, TRUE);
207
208 data->pads = g_list_prepend (data->pads, pad);
209
210 return pad;
211 }
212
213 static void
pad_added_cb(GstElement * rtpbin,GstPad * pad,CleanupData * data)214 pad_added_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
215 {
216 GstPad *sinkpad;
217
218 GST_DEBUG ("pad added %s:%s\n", GST_DEBUG_PAD_NAME (pad));
219
220 if (GST_PAD_IS_SINK (pad))
221 return;
222
223 fail_unless (data->pad_added == FALSE);
224
225 sinkpad = make_sinkpad (data);
226 fail_unless (gst_pad_link (pad, sinkpad) == GST_PAD_LINK_OK);
227
228 g_mutex_lock (&data->lock);
229 data->pad_added = TRUE;
230 data->pad = pad;
231 g_cond_signal (&data->cond);
232 g_mutex_unlock (&data->lock);
233 }
234
235 static void
pad_removed_cb(GstElement * rtpbin,GstPad * pad,CleanupData * data)236 pad_removed_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
237 {
238 GST_DEBUG ("pad removed %s:%s\n", GST_DEBUG_PAD_NAME (pad));
239
240 if (data->pad != pad)
241 return;
242
243 fail_unless (data->pad_added == TRUE);
244
245 g_mutex_lock (&data->lock);
246 data->pad_added = FALSE;
247 g_cond_signal (&data->cond);
248 g_mutex_unlock (&data->lock);
249 }
250
GST_START_TEST(test_cleanup_recv)251 GST_START_TEST (test_cleanup_recv)
252 {
253 GstElement *rtpbin;
254 GstPad *rtp_sink;
255 CleanupData data;
256 GstStateChangeReturn ret;
257 GstFlowReturn res;
258 gint count = 2;
259
260 init_data (&data);
261
262 rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
263
264 g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
265 g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
266
267 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
268 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
269
270 while (count--) {
271 /* request session 0 */
272 rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
273 fail_unless (rtp_sink != NULL);
274 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
275
276 /* no sourcepads are created yet */
277 fail_unless (rtpbin->numsinkpads == 1);
278 fail_unless (rtpbin->numsrcpads == 0);
279
280 res = chain_rtp_packet (rtp_sink, &data);
281 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
282 fail_unless (res == GST_FLOW_OK);
283
284 res = chain_rtp_packet (rtp_sink, &data);
285 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
286 fail_unless (res == GST_FLOW_OK);
287
288 /* we wait for the new pad to appear 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);
293
294 /* sourcepad created now */
295 fail_unless (rtpbin->numsinkpads == 1);
296 fail_unless (rtpbin->numsrcpads == 1);
297
298 /* remove the session */
299 gst_element_release_request_pad (rtpbin, rtp_sink);
300 gst_object_unref (rtp_sink);
301
302 /* pad should be gone now */
303 g_mutex_lock (&data.lock);
304 while (data.pad_added)
305 g_cond_wait (&data.cond, &data.lock);
306 g_mutex_unlock (&data.lock);
307
308 /* nothing left anymore now */
309 fail_unless (rtpbin->numsinkpads == 0);
310 fail_unless (rtpbin->numsrcpads == 0);
311 }
312
313 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
314 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
315
316 gst_object_unref (rtpbin);
317
318 clean_data (&data);
319 }
320
321 GST_END_TEST;
322
GST_START_TEST(test_cleanup_recv2)323 GST_START_TEST (test_cleanup_recv2)
324 {
325 GstElement *rtpbin;
326 GstPad *rtp_sink;
327 CleanupData data;
328 GstStateChangeReturn ret;
329 GstFlowReturn res;
330 gint count = 2;
331
332 init_data (&data);
333
334 rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
335
336 g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
337 g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
338
339 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
340 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
341
342 /* request session 0 */
343 rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
344 fail_unless (rtp_sink != NULL);
345 ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
346
347 while (count--) {
348 /* no sourcepads are created yet */
349 fail_unless (rtpbin->numsinkpads == 1);
350 fail_unless (rtpbin->numsrcpads == 0);
351
352 res = chain_rtp_packet (rtp_sink, &data);
353 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
354 fail_unless (res == GST_FLOW_OK);
355
356 res = chain_rtp_packet (rtp_sink, &data);
357 GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
358 fail_unless (res == GST_FLOW_OK);
359
360 /* we wait for the new pad to appear now */
361 g_mutex_lock (&data.lock);
362 while (!data.pad_added)
363 g_cond_wait (&data.cond, &data.lock);
364 g_mutex_unlock (&data.lock);
365
366 /* sourcepad created now */
367 fail_unless (rtpbin->numsinkpads == 1);
368 fail_unless (rtpbin->numsrcpads == 1);
369
370 /* change state */
371 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
372 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
373
374 /* pad should be gone now */
375 g_mutex_lock (&data.lock);
376 while (data.pad_added)
377 g_cond_wait (&data.cond, &data.lock);
378 g_mutex_unlock (&data.lock);
379
380 /* back to playing for the next round */
381 ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
382 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
383 }
384
385 /* remove the session */
386 gst_element_release_request_pad (rtpbin, rtp_sink);
387 gst_object_unref (rtp_sink);
388
389 /* nothing left anymore now */
390 fail_unless (rtpbin->numsinkpads == 0);
391 fail_unless (rtpbin->numsrcpads == 0);
392
393 ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
394 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
395
396 gst_object_unref (rtpbin);
397
398 clean_data (&data);
399 }
400
401 GST_END_TEST;
402
GST_START_TEST(test_request_pad_by_template_name)403 GST_START_TEST (test_request_pad_by_template_name)
404 {
405 GstElement *rtpbin;
406 GstPad *rtp_sink1, *rtp_sink2, *rtp_sink3;
407
408 rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
409 rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
410 fail_unless (rtp_sink1 != NULL);
411 fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "recv_rtp_sink_0");
412 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
413
414 rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
415 fail_unless (rtp_sink2 != NULL);
416 fail_unless_equals_string (GST_PAD_NAME (rtp_sink2), "recv_rtp_sink_1");
417 ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 2);
418
419 rtp_sink3 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
420 fail_unless (rtp_sink3 != NULL);
421 fail_unless_equals_string (GST_PAD_NAME (rtp_sink3), "recv_rtp_sink_2");
422 ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 2);
423
424
425 gst_element_release_request_pad (rtpbin, rtp_sink2);
426 gst_element_release_request_pad (rtpbin, rtp_sink1);
427 gst_element_release_request_pad (rtpbin, rtp_sink3);
428 ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 1);
429 ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 1);
430 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink", 1);
431 gst_object_unref (rtp_sink1);
432 gst_object_unref (rtp_sink2);
433 gst_object_unref (rtp_sink3);
434
435 gst_object_unref (rtpbin);
436 }
437
438 GST_END_TEST;
439
440 static GstElement *
encoder_cb(GstElement * rtpbin,guint sessid,GstElement * bin)441 encoder_cb (GstElement * rtpbin, guint sessid, GstElement * bin)
442 {
443 GstPad *srcpad, *sinkpad;
444
445 fail_unless (sessid == 2);
446
447 GST_DEBUG ("making encoder");
448 sinkpad = gst_ghost_pad_new_no_target ("rtp_sink_2", GST_PAD_SINK);
449 srcpad = gst_ghost_pad_new_no_target ("rtp_src_2", GST_PAD_SRC);
450
451 gst_element_add_pad (bin, sinkpad);
452 gst_element_add_pad (bin, srcpad);
453
454 return gst_object_ref (bin);
455 }
456
457 static GstElement *
encoder_cb2(GstElement * rtpbin,guint sessid,GstElement * bin)458 encoder_cb2 (GstElement * rtpbin, guint sessid, GstElement * bin)
459 {
460 GstPad *srcpad, *sinkpad;
461
462 fail_unless (sessid == 3);
463
464 GST_DEBUG ("making encoder");
465 sinkpad = gst_ghost_pad_new_no_target ("rtp_sink_3", GST_PAD_SINK);
466 srcpad = gst_ghost_pad_new_no_target ("rtp_src_3", GST_PAD_SRC);
467
468 gst_element_add_pad (bin, sinkpad);
469 gst_element_add_pad (bin, srcpad);
470
471 return gst_object_ref (bin);
472 }
473
GST_START_TEST(test_encoder)474 GST_START_TEST (test_encoder)
475 {
476 GstElement *rtpbin, *bin;
477 GstPad *rtp_sink1, *rtp_sink2;
478 gulong id;
479
480 bin = gst_bin_new ("rtpenc");
481
482 rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
483
484 id = g_signal_connect (rtpbin, "request-rtp-encoder", (GCallback) encoder_cb,
485 bin);
486
487 rtp_sink1 = gst_element_get_request_pad (rtpbin, "send_rtp_sink_2");
488 fail_unless (rtp_sink1 != NULL);
489 fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "send_rtp_sink_2");
490 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
491
492 g_signal_handler_disconnect (rtpbin, id);
493
494 id = g_signal_connect (rtpbin, "request-rtp-encoder", (GCallback) encoder_cb2,
495 bin);
496
497 rtp_sink2 = gst_element_get_request_pad (rtpbin, "send_rtp_sink_3");
498 fail_unless (rtp_sink2 != NULL);
499
500 /* remove the session */
501 gst_element_release_request_pad (rtpbin, rtp_sink1);
502 gst_object_unref (rtp_sink1);
503
504 gst_element_release_request_pad (rtpbin, rtp_sink2);
505 gst_object_unref (rtp_sink2);
506
507 /* nothing left anymore now */
508 fail_unless (rtpbin->numsinkpads == 0);
509 fail_unless (rtpbin->numsrcpads == 0);
510
511 gst_object_unref (rtpbin);
512 gst_object_unref (bin);
513 }
514
515 GST_END_TEST;
516
517 static GstElement *
decoder_cb(GstElement * rtpbin,guint sessid,gpointer user_data)518 decoder_cb (GstElement * rtpbin, guint sessid, gpointer user_data)
519 {
520 GstElement *bin;
521 GstPad *srcpad, *sinkpad;
522
523 bin = gst_bin_new (NULL);
524
525 GST_DEBUG ("making decoder");
526 sinkpad = gst_ghost_pad_new_no_target ("rtp_sink", GST_PAD_SINK);
527 srcpad = gst_ghost_pad_new_no_target ("rtp_src", GST_PAD_SRC);
528
529 gst_element_add_pad (bin, sinkpad);
530 gst_element_add_pad (bin, srcpad);
531
532 return bin;
533 }
534
GST_START_TEST(test_decoder)535 GST_START_TEST (test_decoder)
536 {
537 GstElement *rtpbin;
538 GstPad *rtp_sink1, *rtp_sink2;
539 gulong id;
540
541
542 rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
543
544 id = g_signal_connect (rtpbin, "request-rtp-decoder", (GCallback) decoder_cb,
545 NULL);
546
547 rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_2");
548 fail_unless (rtp_sink1 != NULL);
549 fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "recv_rtp_sink_2");
550 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
551
552 rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_3");
553 fail_unless (rtp_sink2 != NULL);
554
555 g_signal_handler_disconnect (rtpbin, id);
556
557 /* remove the session */
558 gst_element_release_request_pad (rtpbin, rtp_sink1);
559 gst_object_unref (rtp_sink1);
560
561 gst_element_release_request_pad (rtpbin, rtp_sink2);
562 gst_object_unref (rtp_sink2);
563
564 /* nothing left anymore now */
565 fail_unless (rtpbin->numsinkpads == 0);
566 fail_unless (rtpbin->numsrcpads == 0);
567
568 gst_object_unref (rtpbin);
569 }
570
571 GST_END_TEST;
572
573 static GstElement *
aux_sender_cb(GstElement * rtpbin,guint sessid,gpointer user_data)574 aux_sender_cb (GstElement * rtpbin, guint sessid, gpointer user_data)
575 {
576 GstElement *bin;
577 GstPad *srcpad, *sinkpad;
578
579 bin = (GstElement *) user_data;
580
581 GST_DEBUG ("making AUX sender");
582 sinkpad = gst_ghost_pad_new_no_target ("sink_2", GST_PAD_SINK);
583 gst_element_add_pad (bin, sinkpad);
584
585 srcpad = gst_ghost_pad_new_no_target ("src_2", GST_PAD_SRC);
586 gst_element_add_pad (bin, srcpad);
587 srcpad = gst_ghost_pad_new_no_target ("src_1", GST_PAD_SRC);
588 gst_element_add_pad (bin, srcpad);
589 srcpad = gst_ghost_pad_new_no_target ("src_3", GST_PAD_SRC);
590 gst_element_add_pad (bin, srcpad);
591
592 return bin;
593 }
594
GST_START_TEST(test_aux_sender)595 GST_START_TEST (test_aux_sender)
596 {
597 GstElement *rtpbin;
598 GstPad *rtp_sink1, *rtp_src, *rtcp_src;
599 gulong id;
600 GstElement *aux_sender = gst_object_ref_sink (gst_bin_new ("aux-sender"));
601
602 gst_object_ref (aux_sender);
603
604 rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
605
606 id = g_signal_connect (rtpbin, "request-aux-sender",
607 (GCallback) aux_sender_cb, aux_sender);
608
609 rtp_sink1 = gst_element_get_request_pad (rtpbin, "send_rtp_sink_2");
610 fail_unless (rtp_sink1 != NULL);
611 fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "send_rtp_sink_2");
612 ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
613
614 g_signal_handler_disconnect (rtpbin, id);
615
616 rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_2");
617 fail_unless (rtp_src != NULL);
618 gst_object_unref (rtp_src);
619
620 rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_1");
621 fail_unless (rtp_src != NULL);
622 gst_object_unref (rtp_src);
623
624 rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_1");
625 fail_unless (rtcp_src != NULL);
626 gst_element_release_request_pad (rtpbin, rtcp_src);
627 gst_object_unref (rtcp_src);
628
629 rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_3");
630 fail_unless (rtp_src != NULL);
631 gst_object_unref (rtp_src);
632
633 /* remove the session */
634 gst_element_release_request_pad (rtpbin, rtp_sink1);
635 gst_object_unref (rtp_sink1);
636
637 /* We have sinked the initial reference before returning it
638 * in the request callback, the ref count should now be 1 because
639 * the return of the signal is transfer full, and rtpbin should
640 * have released that reference by now, but we had taken an
641 * extra reference to perform this check
642 */
643 ASSERT_OBJECT_REFCOUNT (aux_sender, "aux-sender", 1);
644
645 gst_object_unref (aux_sender);
646 gst_object_unref (rtpbin);
647 }
648
649 GST_END_TEST;
650
651 static GstElement *
aux_receiver_cb(GstElement * rtpbin,guint sessid,gpointer user_data)652 aux_receiver_cb (GstElement * rtpbin, guint sessid, gpointer user_data)
653 {
654 GstElement *bin;
655 GstPad *srcpad, *sinkpad;
656
657 bin = gst_bin_new (NULL);
658
659 GST_DEBUG ("making AUX receiver");
660 srcpad = gst_ghost_pad_new_no_target ("src_2", GST_PAD_SRC);
661 gst_element_add_pad (bin, srcpad);
662
663 sinkpad = gst_ghost_pad_new_no_target ("sink_2", GST_PAD_SINK);
664 gst_element_add_pad (bin, sinkpad);
665 sinkpad = gst_ghost_pad_new_no_target ("sink_1", GST_PAD_SINK);
666 gst_element_add_pad (bin, sinkpad);
667 sinkpad = gst_ghost_pad_new_no_target ("sink_3", GST_PAD_SINK);
668 gst_element_add_pad (bin, sinkpad);
669
670 return bin;
671 }
672
GST_START_TEST(test_aux_receiver)673 GST_START_TEST (test_aux_receiver)
674 {
675 GstElement *rtpbin;
676 GstPad *rtp_sink1, *rtp_sink2, *rtcp_sink;
677 gulong id;
678
679 rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
680
681 id = g_signal_connect (rtpbin, "request-aux-receiver",
682 (GCallback) aux_receiver_cb, NULL);
683
684 rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_2");
685 fail_unless (rtp_sink1 != NULL);
686
687 rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_1");
688 fail_unless (rtp_sink2 != NULL);
689
690 g_signal_handler_disconnect (rtpbin, id);
691
692 rtcp_sink = gst_element_get_request_pad (rtpbin, "recv_rtcp_sink_1");
693 fail_unless (rtcp_sink != NULL);
694 gst_element_release_request_pad (rtpbin, rtcp_sink);
695 gst_object_unref (rtcp_sink);
696
697 /* remove the session */
698 gst_element_release_request_pad (rtpbin, rtp_sink1);
699 gst_object_unref (rtp_sink1);
700 gst_element_release_request_pad (rtpbin, rtp_sink2);
701 gst_object_unref (rtp_sink2);
702
703 gst_object_unref (rtpbin);
704 }
705
706 GST_END_TEST;
707
GST_START_TEST(test_sender_eos)708 GST_START_TEST (test_sender_eos)
709 {
710 GstElement *rtpsession;
711 GstBuffer *rtp_buffer;
712 GstBuffer *rtcp_buffer;
713 GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
714 GstRTCPBuffer rtcpbuf = GST_RTCP_BUFFER_INIT;
715 GstRTCPPacket rtcppacket;
716 static GstStaticPadTemplate recv_tmpl =
717 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
718 GST_STATIC_CAPS ("ANY"));
719 GstPad *send_rtp_sink;
720 GstPad *recv_rtcp_sink;
721 GstCaps *caps;
722 GstSegment segment;
723 GstPad *rtp_sink, *rtcp_sink;
724 GstClock *clock;
725 GstTestClock *tclock;
726 GstStructure *s;
727 guint ssrc = 1;
728 guint32 ssrc_in, packet_count, octet_count;
729 gboolean got_bye = FALSE;
730
731 clock = gst_test_clock_new ();
732 gst_system_clock_set_default (clock);
733 tclock = GST_TEST_CLOCK (clock);
734 gst_test_clock_set_time (tclock, 0);
735
736 rtpsession = gst_element_factory_make ("rtpsession", NULL);
737 send_rtp_sink = gst_element_get_request_pad (rtpsession, "send_rtp_sink");
738 recv_rtcp_sink = gst_element_get_request_pad (rtpsession, "recv_rtcp_sink");
739
740
741 rtp_sink = gst_check_setup_sink_pad_by_name (rtpsession, &recv_tmpl,
742 "send_rtp_src");
743 rtcp_sink = gst_check_setup_sink_pad_by_name (rtpsession, &recv_tmpl,
744 "send_rtcp_src");
745
746 gst_pad_set_active (rtp_sink, TRUE);
747 gst_pad_set_active (rtcp_sink, TRUE);
748
749 gst_element_set_state (rtpsession, GST_STATE_PLAYING);
750
751 /* Send initial events */
752
753 gst_segment_init (&segment, GST_FORMAT_TIME);
754 fail_unless (gst_pad_send_event (send_rtp_sink,
755 gst_event_new_stream_start ("id")));
756 fail_unless (gst_pad_send_event (send_rtp_sink,
757 gst_event_new_segment (&segment)));
758
759 fail_unless (gst_pad_send_event (recv_rtcp_sink,
760 gst_event_new_stream_start ("id")));
761 fail_unless (gst_pad_send_event (recv_rtcp_sink,
762 gst_event_new_segment (&segment)));
763
764 /* Get the suggested SSRC from the rtpsession */
765
766 caps = gst_pad_query_caps (send_rtp_sink, NULL);
767 s = gst_caps_get_structure (caps, 0);
768 gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL);
769 gst_caps_unref (caps);
770
771 /* Send a RTP packet */
772
773 rtp_buffer = gst_rtp_buffer_new_allocate (10, 0, 0);
774 gst_rtp_buffer_map (rtp_buffer, GST_MAP_READWRITE, &rtpbuf);
775 gst_rtp_buffer_set_ssrc (&rtpbuf, 1);
776 gst_rtp_buffer_set_seq (&rtpbuf, 0);
777 gst_rtp_buffer_unmap (&rtpbuf);
778
779 fail_unless (gst_pad_chain (send_rtp_sink, rtp_buffer) == GST_FLOW_OK);
780
781 /* Make sure it went through */
782 fail_unless_equals_int (g_list_length (buffers), 1);
783 fail_unless_equals_pointer (buffers->data, rtp_buffer);
784 gst_check_drop_buffers ();
785
786 /* Advance time and send a packet to prevent source sender timeout */
787 gst_test_clock_set_time (tclock, 1 * GST_SECOND);
788
789 /* Just send a send packet to prevent timeout */
790 rtp_buffer = gst_rtp_buffer_new_allocate (10, 0, 0);
791 gst_rtp_buffer_map (rtp_buffer, GST_MAP_READWRITE, &rtpbuf);
792 gst_rtp_buffer_set_ssrc (&rtpbuf, 1);
793 gst_rtp_buffer_set_seq (&rtpbuf, 1);
794 gst_rtp_buffer_set_timestamp (&rtpbuf, 10);
795 gst_rtp_buffer_unmap (&rtpbuf);
796
797 fail_unless (gst_pad_chain (send_rtp_sink, rtp_buffer) == GST_FLOW_OK);
798
799 /* Make sure it went through */
800 fail_unless_equals_int (g_list_length (buffers), 1);
801 fail_unless_equals_pointer (buffers->data, rtp_buffer);
802 gst_check_drop_buffers ();
803
804 /* Advance clock twice and we shoudl have one RTCP packet at least */
805 gst_test_clock_crank (tclock);
806 gst_test_clock_crank (tclock);
807
808 g_mutex_lock (&check_mutex);
809 while (buffers == NULL)
810 g_cond_wait (&check_cond, &check_mutex);
811
812 fail_unless (gst_rtcp_buffer_map (buffers->data, GST_MAP_READ, &rtcpbuf));
813
814 fail_unless (gst_rtcp_buffer_get_first_packet (&rtcpbuf, &rtcppacket));
815
816 fail_unless_equals_int (gst_rtcp_packet_get_type (&rtcppacket),
817 GST_RTCP_TYPE_SR);
818 gst_rtcp_packet_sr_get_sender_info (&rtcppacket, &ssrc_in, NULL, NULL,
819 &packet_count, &octet_count);
820 fail_unless_equals_int (packet_count, 2);
821 fail_unless_equals_int (octet_count, 20);
822
823 fail_unless (gst_rtcp_packet_move_to_next (&rtcppacket));
824 fail_unless_equals_int (gst_rtcp_packet_get_type (&rtcppacket),
825 GST_RTCP_TYPE_SDES);
826
827 gst_rtcp_buffer_unmap (&rtcpbuf);
828 gst_check_drop_buffers ();
829
830 g_mutex_unlock (&check_mutex);
831
832
833 /* Create and send a valid RTCP reply packet */
834 rtcp_buffer = gst_rtcp_buffer_new (1500);
835 gst_rtcp_buffer_map (rtcp_buffer, GST_MAP_READWRITE, &rtcpbuf);
836 gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_RR, &rtcppacket);
837 gst_rtcp_packet_rr_set_ssrc (&rtcppacket, ssrc + 1);
838 gst_rtcp_packet_add_rb (&rtcppacket, ssrc, 0, 0, 0, 0, 0, 0);
839 gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_SDES, &rtcppacket);
840 gst_rtcp_packet_sdes_add_item (&rtcppacket, ssrc + 1);
841 gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_CNAME, 3,
842 (guint8 *) "a@a");
843 gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_NAME, 2,
844 (guint8 *) "aa");
845 gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_END, 0,
846 (guint8 *) "");
847 gst_rtcp_buffer_unmap (&rtcpbuf);
848 fail_unless (gst_pad_chain (recv_rtcp_sink, rtcp_buffer) == GST_FLOW_OK);
849
850
851 /* Send a EOS to trigger sending a BYE message */
852 fail_unless (gst_pad_send_event (send_rtp_sink, gst_event_new_eos ()));
853
854 /* Crank to process EOS and wait for BYE */
855 for (;;) {
856 gst_test_clock_crank (tclock);
857 g_mutex_lock (&check_mutex);
858 while (buffers == NULL)
859 g_cond_wait (&check_cond, &check_mutex);
860
861 fail_unless (gst_rtcp_buffer_map (g_list_last (buffers)->data, GST_MAP_READ,
862 &rtcpbuf));
863 fail_unless (gst_rtcp_buffer_get_first_packet (&rtcpbuf, &rtcppacket));
864
865 while (gst_rtcp_packet_move_to_next (&rtcppacket)) {
866 if (gst_rtcp_packet_get_type (&rtcppacket) == GST_RTCP_TYPE_BYE) {
867 got_bye = TRUE;
868 break;
869 }
870 }
871 g_mutex_unlock (&check_mutex);
872 gst_rtcp_buffer_unmap (&rtcpbuf);
873
874 if (got_bye)
875 break;
876 }
877
878 gst_check_drop_buffers ();
879
880
881 fail_unless (GST_PAD_IS_EOS (rtp_sink));
882 fail_unless (GST_PAD_IS_EOS (rtcp_sink));
883
884 gst_pad_set_active (rtp_sink, FALSE);
885 gst_pad_set_active (rtcp_sink, FALSE);
886
887 gst_check_teardown_pad_by_name (rtpsession, "send_rtp_src");
888 gst_check_teardown_pad_by_name (rtpsession, "send_rtcp_src");
889 gst_element_release_request_pad (rtpsession, send_rtp_sink);
890 gst_object_unref (send_rtp_sink);
891 gst_element_release_request_pad (rtpsession, recv_rtcp_sink);
892 gst_object_unref (recv_rtcp_sink);
893
894 gst_check_teardown_element (rtpsession);
895
896 gst_system_clock_set_default (NULL);
897 gst_object_unref (clock);
898
899 }
900
901 GST_END_TEST;
902
903 static Suite *
rtpbin_suite(void)904 rtpbin_suite (void)
905 {
906 Suite *s = suite_create ("rtpbin");
907 TCase *tc_chain = tcase_create ("general");
908
909 suite_add_tcase (s, tc_chain);
910 tcase_add_test (tc_chain, test_pads);
911 tcase_add_test (tc_chain, test_cleanup_send);
912 tcase_add_test (tc_chain, test_cleanup_recv);
913 tcase_add_test (tc_chain, test_cleanup_recv2);
914 tcase_add_test (tc_chain, test_request_pad_by_template_name);
915 tcase_add_test (tc_chain, test_encoder);
916 tcase_add_test (tc_chain, test_decoder);
917 tcase_add_test (tc_chain, test_aux_sender);
918 tcase_add_test (tc_chain, test_aux_receiver);
919 tcase_add_test (tc_chain, test_sender_eos);
920
921 return s;
922 }
923
924 GST_CHECK_MAIN (rtpbin);
925