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