Fix usage of C99
[platform/upstream/gstreamer.git] / tests / check / elements / rtpbin.c
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
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_get_request_pad (element, "recv_rtcp_sink");
38   gst_object_unref (pad);
39   gst_object_unref (element);
40 }
41
42 GST_END_TEST;
43
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_get_request_pad (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_get_request_pad (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
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
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
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
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 *
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
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
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
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_get_request_pad (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
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_get_request_pad (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
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_get_request_pad (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_get_request_pad (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_get_request_pad (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 *
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 *
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
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_get_request_pad (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_get_request_pad (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 *
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
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_get_request_pad (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_get_request_pad (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 *
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
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_get_request_pad (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_get_request_pad (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 *
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
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_get_request_pad (rtpbin, "recv_rtp_sink_2");
688   fail_unless (rtp_sink1 != NULL);
689
690   rtp_sink2 = gst_element_get_request_pad (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_get_request_pad (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
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_get_request_pad (rtpsession, "send_rtp_sink");
741   recv_rtcp_sink = gst_element_get_request_pad (rtpsession, "recv_rtcp_sink");
742
743
744   rtp_sink = gst_check_setup_sink_pad_by_name (rtpsession, &recv_tmpl,
745       "send_rtp_src");
746   rtcp_sink = gst_check_setup_sink_pad_by_name (rtpsession, &recv_tmpl,
747       "send_rtcp_src");
748
749   gst_pad_set_active (rtp_sink, TRUE);
750   gst_pad_set_active (rtcp_sink, TRUE);
751
752   gst_element_set_state (rtpsession, GST_STATE_PLAYING);
753
754   /* Send initial events */
755
756   gst_segment_init (&segment, GST_FORMAT_TIME);
757   fail_unless (gst_pad_send_event (send_rtp_sink,
758           gst_event_new_stream_start ("id")));
759   fail_unless (gst_pad_send_event (send_rtp_sink,
760           gst_event_new_segment (&segment)));
761
762   fail_unless (gst_pad_send_event (recv_rtcp_sink,
763           gst_event_new_stream_start ("id")));
764   fail_unless (gst_pad_send_event (recv_rtcp_sink,
765           gst_event_new_segment (&segment)));
766
767   /* Get the suggested SSRC from the rtpsession */
768
769   caps = gst_pad_query_caps (send_rtp_sink, NULL);
770   s = gst_caps_get_structure (caps, 0);
771   gst_structure_get (s, "ssrc", G_TYPE_UINT, &ssrc, NULL);
772   gst_caps_unref (caps);
773
774   /* Send a RTP packet */
775
776   rtp_buffer = gst_rtp_buffer_new_allocate (10, 0, 0);
777   gst_rtp_buffer_map (rtp_buffer, GST_MAP_READWRITE, &rtpbuf);
778   gst_rtp_buffer_set_ssrc (&rtpbuf, 1);
779   gst_rtp_buffer_set_seq (&rtpbuf, 0);
780   gst_rtp_buffer_unmap (&rtpbuf);
781
782   fail_unless (gst_pad_chain (send_rtp_sink, rtp_buffer) == GST_FLOW_OK);
783
784   /* Make sure it went through */
785   fail_unless_equals_int (g_list_length (buffers), 1);
786   fail_unless_equals_pointer (buffers->data, rtp_buffer);
787   gst_check_drop_buffers ();
788
789   /* Advance time and send a packet to prevent source sender timeout */
790   gst_test_clock_set_time (tclock, 1 * GST_SECOND);
791
792   /* Just send a send packet to prevent timeout */
793   rtp_buffer = gst_rtp_buffer_new_allocate (10, 0, 0);
794   gst_rtp_buffer_map (rtp_buffer, GST_MAP_READWRITE, &rtpbuf);
795   gst_rtp_buffer_set_ssrc (&rtpbuf, 1);
796   gst_rtp_buffer_set_seq (&rtpbuf, 1);
797   gst_rtp_buffer_set_timestamp (&rtpbuf, 10);
798   gst_rtp_buffer_unmap (&rtpbuf);
799
800   fail_unless (gst_pad_chain (send_rtp_sink, rtp_buffer) == GST_FLOW_OK);
801
802   /* Make sure it went through */
803   fail_unless_equals_int (g_list_length (buffers), 1);
804   fail_unless_equals_pointer (buffers->data, rtp_buffer);
805   gst_check_drop_buffers ();
806
807   /* Advance clock twice and we should have one RTCP packet at least */
808   gst_test_clock_crank (tclock);
809   gst_test_clock_crank (tclock);
810
811   g_mutex_lock (&check_mutex);
812   while (buffers == NULL)
813     g_cond_wait (&check_cond, &check_mutex);
814
815   fail_unless (gst_rtcp_buffer_map (buffers->data, GST_MAP_READ, &rtcpbuf));
816
817   fail_unless (gst_rtcp_buffer_get_first_packet (&rtcpbuf, &rtcppacket));
818
819   fail_unless_equals_int (gst_rtcp_packet_get_type (&rtcppacket),
820       GST_RTCP_TYPE_SR);
821   gst_rtcp_packet_sr_get_sender_info (&rtcppacket, &ssrc_in, NULL, NULL,
822       &packet_count, &octet_count);
823   fail_unless_equals_int (packet_count, 2);
824   fail_unless_equals_int (octet_count, 20);
825
826   fail_unless (gst_rtcp_packet_move_to_next (&rtcppacket));
827   fail_unless_equals_int (gst_rtcp_packet_get_type (&rtcppacket),
828       GST_RTCP_TYPE_SDES);
829
830   gst_rtcp_buffer_unmap (&rtcpbuf);
831   gst_check_drop_buffers ();
832
833   g_mutex_unlock (&check_mutex);
834
835
836   /* Create and send a valid RTCP reply packet */
837   rtcp_buffer = gst_rtcp_buffer_new (1500);
838   gst_rtcp_buffer_map (rtcp_buffer, GST_MAP_READWRITE, &rtcpbuf);
839   gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_RR, &rtcppacket);
840   gst_rtcp_packet_rr_set_ssrc (&rtcppacket, ssrc + 1);
841   gst_rtcp_packet_add_rb (&rtcppacket, ssrc, 0, 0, 0, 0, 0, 0);
842   gst_rtcp_buffer_add_packet (&rtcpbuf, GST_RTCP_TYPE_SDES, &rtcppacket);
843   gst_rtcp_packet_sdes_add_item (&rtcppacket, ssrc + 1);
844   gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_CNAME, 3,
845       (guint8 *) "a@a");
846   gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_NAME, 2,
847       (guint8 *) "aa");
848   gst_rtcp_packet_sdes_add_entry (&rtcppacket, GST_RTCP_SDES_END, 0,
849       (guint8 *) "");
850   gst_rtcp_buffer_unmap (&rtcpbuf);
851   fail_unless (gst_pad_chain (recv_rtcp_sink, rtcp_buffer) == GST_FLOW_OK);
852
853
854   /* Send a EOS to trigger sending a BYE message */
855   fail_unless (gst_pad_send_event (send_rtp_sink, gst_event_new_eos ()));
856
857   /* Crank to process EOS and wait for BYE */
858   for (;;) {
859     gst_test_clock_crank (tclock);
860     g_mutex_lock (&check_mutex);
861     while (buffers == NULL)
862       g_cond_wait (&check_cond, &check_mutex);
863
864     fail_unless (gst_rtcp_buffer_map (g_list_last (buffers)->data, GST_MAP_READ,
865             &rtcpbuf));
866     fail_unless (gst_rtcp_buffer_get_first_packet (&rtcpbuf, &rtcppacket));
867
868     while (gst_rtcp_packet_move_to_next (&rtcppacket)) {
869       if (gst_rtcp_packet_get_type (&rtcppacket) == GST_RTCP_TYPE_BYE) {
870         got_bye = TRUE;
871         break;
872       }
873     }
874     g_mutex_unlock (&check_mutex);
875     gst_rtcp_buffer_unmap (&rtcpbuf);
876
877     if (got_bye)
878       break;
879   }
880
881   gst_check_drop_buffers ();
882
883
884   fail_unless (GST_PAD_IS_EOS (rtp_sink));
885   fail_unless (GST_PAD_IS_EOS (rtcp_sink));
886
887   gst_pad_set_active (rtp_sink, FALSE);
888   gst_pad_set_active (rtcp_sink, FALSE);
889
890   gst_check_teardown_pad_by_name (rtpsession, "send_rtp_src");
891   gst_check_teardown_pad_by_name (rtpsession, "send_rtcp_src");
892   gst_element_release_request_pad (rtpsession, send_rtp_sink);
893   gst_object_unref (send_rtp_sink);
894   gst_element_release_request_pad (rtpsession, recv_rtcp_sink);
895   gst_object_unref (recv_rtcp_sink);
896
897   gst_check_teardown_element (rtpsession);
898
899   gst_system_clock_set_default (NULL);
900   gst_object_unref (clock);
901
902 }
903
904 GST_END_TEST;
905
906 static GstBuffer *
907 generate_rtp_buffer (GstClockTime ts,
908     guint seqnum, guint32 rtp_ts, guint pt, guint ssrc)
909 {
910   GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
911   GstBuffer *buf = gst_rtp_buffer_new_allocate (0, 0, 0);
912   GST_BUFFER_PTS (buf) = ts;
913   GST_BUFFER_DTS (buf) = ts;
914
915   gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
916   gst_rtp_buffer_set_payload_type (&rtp, pt);
917   gst_rtp_buffer_set_seq (&rtp, seqnum);
918   gst_rtp_buffer_set_timestamp (&rtp, rtp_ts);
919   gst_rtp_buffer_set_ssrc (&rtp, ssrc);
920
921   gst_rtp_buffer_unmap (&rtp);
922
923   return buf;
924 }
925
926 static GstCaps *
927 _request_pt_map (G_GNUC_UNUSED GstElement * rtpbin,
928     G_GNUC_UNUSED guint session_id, G_GNUC_UNUSED guint pt,
929     const GstCaps * caps)
930 {
931   return gst_caps_copy (caps);
932 }
933
934 static void
935 _pad_added (G_GNUC_UNUSED GstElement * rtpbin, GstPad * pad, GstHarness * h)
936 {
937   gst_harness_add_element_src_pad (h, pad);
938 }
939
940 GST_START_TEST (test_quick_shutdown)
941 {
942   guint r;
943
944   for (r = 0; r < 1000; r++) {
945     guint i;
946     GstHarness *h = gst_harness_new_with_padnames ("rtpbin",
947         "recv_rtp_sink_0", NULL);
948     GstCaps *caps = gst_caps_new_simple ("application/x-rtp",
949         "clock-rate", G_TYPE_INT, 8000,
950         "payload", G_TYPE_INT, 100, NULL);
951
952     g_signal_connect (h->element, "request-pt-map",
953         G_CALLBACK (_request_pt_map), caps);
954     g_signal_connect (h->element, "pad-added", G_CALLBACK (_pad_added), h);
955
956     gst_harness_set_src_caps (h, gst_caps_copy (caps));
957
958     for (i = 0; i < 50; i++) {
959       gst_harness_push (h,
960           generate_rtp_buffer (i * GST_MSECOND * 20, i, i * 160, 100, 1234));
961     }
962     gst_harness_crank_single_clock_wait (h);
963
964     gst_caps_unref (caps);
965     gst_harness_teardown (h);
966   }
967 }
968
969 GST_END_TEST;
970
971 static Suite *
972 rtpbin_suite (void)
973 {
974   Suite *s = suite_create ("rtpbin");
975   TCase *tc_chain = tcase_create ("general");
976
977   suite_add_tcase (s, tc_chain);
978   tcase_add_test (tc_chain, test_pads);
979   tcase_add_test (tc_chain, test_cleanup_send);
980   tcase_add_test (tc_chain, test_cleanup_recv);
981   tcase_add_test (tc_chain, test_cleanup_recv2);
982   tcase_add_test (tc_chain, test_request_pad_by_template_name);
983   tcase_add_test (tc_chain, test_encoder);
984   tcase_add_test (tc_chain, test_decoder);
985   tcase_add_test (tc_chain, test_aux_sender);
986   tcase_add_test (tc_chain, test_aux_receiver);
987   tcase_add_test (tc_chain, test_sender_eos);
988   tcase_add_test (tc_chain, test_quick_shutdown);
989
990   return s;
991 }
992
993 GST_CHECK_MAIN (rtpbin);