• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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