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