Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <gst/check/gstcheck.h>
24
25 GST_START_TEST (test_cleanup_send)
26 {
27   GstElement *rtpbin;
28   GstPad *rtp_sink, *rtp_src, *rtcp_src;
29   GObject *session;
30   gint count = 2;
31
32   rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
33
34   while (count--) {
35     /* request session 0 */
36     rtp_sink = gst_element_get_request_pad (rtpbin, "send_rtp_sink_0");
37     fail_unless (rtp_sink != NULL);
38     ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
39
40     /* this static pad should be created automatically now */
41     rtp_src = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
42     fail_unless (rtp_src != NULL);
43     ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 2);
44
45     /* we should be able to get an internal session 0 now */
46     g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
47     fail_unless (session != NULL);
48     g_object_unref (session);
49
50     /* get the send RTCP pad too */
51     rtcp_src = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
52     fail_unless (rtcp_src != NULL);
53     ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtcp_src", 2);
54
55     gst_element_release_request_pad (rtpbin, rtp_sink);
56     /* we should only have our refs to the pads now */
57     ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
58     ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
59     ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 2);
60
61     /* the other pad should be gone now */
62     fail_unless (gst_element_get_static_pad (rtpbin, "send_rtp_src_0") == NULL);
63
64     /* internal session should still be there */
65     g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
66     fail_unless (session != NULL);
67     g_object_unref (session);
68
69     /* release the RTCP pad */
70     gst_element_release_request_pad (rtpbin, rtcp_src);
71     /* we should only have our refs to the pads now */
72     ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 1);
73     ASSERT_OBJECT_REFCOUNT (rtp_src, "rtp_src", 1);
74     ASSERT_OBJECT_REFCOUNT (rtcp_src, "rtp_src", 1);
75
76     /* the session should be gone now */
77     g_signal_emit_by_name (rtpbin, "get-internal-session", 0, &session);
78     fail_unless (session == NULL);
79
80     /* unref the request pad and the static pad */
81     gst_object_unref (rtp_sink);
82     gst_object_unref (rtp_src);
83     gst_object_unref (rtcp_src);
84   }
85
86   gst_object_unref (rtpbin);
87 }
88
89 GST_END_TEST;
90
91 typedef struct
92 {
93   guint16 seqnum;
94   gboolean pad_added;
95   GstPad *pad;
96   GMutex *lock;
97   GCond *cond;
98   GstPad *sinkpad;
99   GList *pads;
100 } CleanupData;
101
102 static void
103 init_data (CleanupData * data)
104 {
105   data->seqnum = 10;
106   data->pad_added = FALSE;
107   data->lock = g_mutex_new ();
108   data->cond = g_cond_new ();
109   data->pads = NULL;
110 }
111
112 static void
113 clean_data (CleanupData * data)
114 {
115   g_list_foreach (data->pads, (GFunc) gst_object_unref, NULL);
116   g_list_free (data->pads);
117   g_mutex_free (data->lock);
118   g_cond_free (data->cond);
119 }
120
121 static guint8 rtp_packet[] = { 0x80, 0x60, 0x94, 0xbc, 0x8f, 0x37, 0x4e, 0xb8,
122   0x44, 0xa8, 0xf3, 0x7c, 0x06, 0x6a, 0x0c, 0xce,
123   0x13, 0x25, 0x19, 0x69, 0x1f, 0x93, 0x25, 0x9d,
124   0x2b, 0x82, 0x31, 0x3b, 0x36, 0xc1, 0x3c, 0x13
125 };
126
127 static GstBuffer *
128 make_rtp_packet (CleanupData * data)
129 {
130   static GstCaps *caps = NULL;
131   GstBuffer *result;
132   guint8 *datap;
133
134   if (caps == NULL) {
135     caps = gst_caps_from_string ("application/x-rtp,"
136         "media=(string)audio, clock-rate=(int)44100, "
137         "encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1");
138     data->seqnum = 0;
139   }
140
141   result = gst_buffer_new_and_alloc (sizeof (rtp_packet));
142   datap = GST_BUFFER_DATA (result);
143   memcpy (datap, rtp_packet, sizeof (rtp_packet));
144
145   datap[2] = (data->seqnum >> 8) & 0xff;
146   datap[3] = data->seqnum & 0xff;
147
148   data->seqnum++;
149
150   gst_buffer_set_caps (result, caps);
151
152   return result;
153 }
154
155 static GstFlowReturn
156 dummy_chain (GstPad * pad, GstBuffer * buffer)
157 {
158   gst_buffer_unref (buffer);
159
160   return GST_FLOW_OK;
161 }
162
163 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
164     GST_PAD_SINK,
165     GST_PAD_ALWAYS,
166     GST_STATIC_CAPS ("application/x-rtp"));
167
168
169 static GstPad *
170 make_sinkpad (CleanupData * data)
171 {
172   GstPad *pad;
173
174   pad = gst_pad_new_from_static_template (&sink_factory, "sink");
175
176   gst_pad_set_chain_function (pad, dummy_chain);
177   gst_pad_set_active (pad, TRUE);
178
179   data->pads = g_list_prepend (data->pads, pad);
180
181   return pad;
182 }
183
184 static void
185 pad_added_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
186 {
187   GstPad *sinkpad;
188
189   GST_DEBUG ("pad added %s:%s\n", GST_DEBUG_PAD_NAME (pad));
190
191   if (GST_PAD_IS_SINK (pad))
192     return;
193
194   fail_unless (data->pad_added == FALSE);
195
196   sinkpad = make_sinkpad (data);
197   fail_unless (gst_pad_link (pad, sinkpad) == GST_PAD_LINK_OK);
198
199   g_mutex_lock (data->lock);
200   data->pad_added = TRUE;
201   data->pad = pad;
202   g_cond_signal (data->cond);
203   g_mutex_unlock (data->lock);
204 }
205
206 static void
207 pad_removed_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
208 {
209   GST_DEBUG ("pad removed %s:%s\n", GST_DEBUG_PAD_NAME (pad));
210
211   if (data->pad != pad)
212     return;
213
214   fail_unless (data->pad_added == TRUE);
215
216   g_mutex_lock (data->lock);
217   data->pad_added = FALSE;
218   g_cond_signal (data->cond);
219   g_mutex_unlock (data->lock);
220 }
221
222 GST_START_TEST (test_cleanup_recv)
223 {
224   GstElement *rtpbin;
225   GstPad *rtp_sink;
226   CleanupData data;
227   GstStateChangeReturn ret;
228   GstFlowReturn res;
229   GstBuffer *buffer;
230   gint count = 2;
231
232   init_data (&data);
233
234   rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
235
236   g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
237   g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
238
239   ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
240   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
241
242   while (count--) {
243     /* request session 0 */
244     rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
245     fail_unless (rtp_sink != NULL);
246     ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
247
248     /* no sourcepads are created yet */
249     fail_unless (rtpbin->numsinkpads == 1);
250     fail_unless (rtpbin->numsrcpads == 0);
251
252     buffer = make_rtp_packet (&data);
253     res = gst_pad_chain (rtp_sink, buffer);
254     GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
255     fail_unless (res == GST_FLOW_OK);
256
257     buffer = make_rtp_packet (&data);
258     res = gst_pad_chain (rtp_sink, buffer);
259     GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
260     fail_unless (res == GST_FLOW_OK);
261
262     /* we wait for the new pad to appear now */
263     g_mutex_lock (data.lock);
264     while (!data.pad_added)
265       g_cond_wait (data.cond, data.lock);
266     g_mutex_unlock (data.lock);
267
268     /* sourcepad created now */
269     fail_unless (rtpbin->numsinkpads == 1);
270     fail_unless (rtpbin->numsrcpads == 1);
271
272     /* remove the session */
273     gst_element_release_request_pad (rtpbin, rtp_sink);
274     gst_object_unref (rtp_sink);
275
276     /* pad should be gone now */
277     g_mutex_lock (data.lock);
278     while (data.pad_added)
279       g_cond_wait (data.cond, data.lock);
280     g_mutex_unlock (data.lock);
281
282     /* nothing left anymore now */
283     fail_unless (rtpbin->numsinkpads == 0);
284     fail_unless (rtpbin->numsrcpads == 0);
285   }
286
287   ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
288   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
289
290   gst_object_unref (rtpbin);
291
292   clean_data (&data);
293 }
294
295 GST_END_TEST;
296
297 GST_START_TEST (test_cleanup_recv2)
298 {
299   GstElement *rtpbin;
300   GstPad *rtp_sink;
301   CleanupData data;
302   GstStateChangeReturn ret;
303   GstFlowReturn res;
304   GstBuffer *buffer;
305   gint count = 2;
306
307   init_data (&data);
308
309   rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
310
311   g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
312   g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
313
314   ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
315   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
316
317   /* request session 0 */
318   rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
319   fail_unless (rtp_sink != NULL);
320   ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
321
322   while (count--) {
323     /* no sourcepads are created yet */
324     fail_unless (rtpbin->numsinkpads == 1);
325     fail_unless (rtpbin->numsrcpads == 0);
326
327     buffer = make_rtp_packet (&data);
328     res = gst_pad_chain (rtp_sink, buffer);
329     GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
330     fail_unless (res == GST_FLOW_OK);
331
332     buffer = make_rtp_packet (&data);
333     res = gst_pad_chain (rtp_sink, buffer);
334     GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
335     fail_unless (res == GST_FLOW_OK);
336
337     /* we wait for the new pad to appear now */
338     g_mutex_lock (data.lock);
339     while (!data.pad_added)
340       g_cond_wait (data.cond, data.lock);
341     g_mutex_unlock (data.lock);
342
343     /* sourcepad created now */
344     fail_unless (rtpbin->numsinkpads == 1);
345     fail_unless (rtpbin->numsrcpads == 1);
346
347     /* change state */
348     ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
349     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
350
351     /* pad should be gone now */
352     g_mutex_lock (data.lock);
353     while (data.pad_added)
354       g_cond_wait (data.cond, data.lock);
355     g_mutex_unlock (data.lock);
356
357     /* back to playing for the next round */
358     ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
359     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
360   }
361
362   /* remove the session */
363   gst_element_release_request_pad (rtpbin, rtp_sink);
364   gst_object_unref (rtp_sink);
365
366   /* nothing left anymore now */
367   fail_unless (rtpbin->numsinkpads == 0);
368   fail_unless (rtpbin->numsrcpads == 0);
369
370   ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
371   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
372
373   gst_object_unref (rtpbin);
374
375   clean_data (&data);
376 }
377
378 GST_END_TEST;
379
380 GST_START_TEST (test_request_pad_by_template_name)
381 {
382   GstElement *rtpbin;
383   GstPad *rtp_sink1, *rtp_sink2, *rtp_sink3;
384
385   rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
386   rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
387   fail_unless (rtp_sink1 != NULL);
388   fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "recv_rtp_sink_0");
389   ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
390
391   rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
392   fail_unless (rtp_sink2 != NULL);
393   fail_unless_equals_string (GST_PAD_NAME (rtp_sink2), "recv_rtp_sink_1");
394   ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 2);
395
396   rtp_sink3 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%d");
397   fail_unless (rtp_sink3 != NULL);
398   fail_unless_equals_string (GST_PAD_NAME (rtp_sink3), "recv_rtp_sink_2");
399   ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 2);
400
401
402   gst_element_release_request_pad (rtpbin, rtp_sink2);
403   gst_element_release_request_pad (rtpbin, rtp_sink1);
404   gst_element_release_request_pad (rtpbin, rtp_sink3);
405   ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 1);
406   ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 1);
407   ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink", 1);
408   gst_object_unref (rtp_sink1);
409   gst_object_unref (rtp_sink2);
410   gst_object_unref (rtp_sink3);
411
412   gst_object_unref (rtpbin);
413 }
414
415 GST_END_TEST;
416
417 static Suite *
418 gstrtpbin_suite (void)
419 {
420   Suite *s = suite_create ("gstrtpbin");
421   TCase *tc_chain = tcase_create ("general");
422
423   suite_add_tcase (s, tc_chain);
424   tcase_add_test (tc_chain, test_cleanup_send);
425   tcase_add_test (tc_chain, test_cleanup_recv);
426   tcase_add_test (tc_chain, test_cleanup_recv2);
427   tcase_add_test (tc_chain, test_request_pad_by_template_name);
428
429   return s;
430 }
431
432 int
433 main (int argc, char **argv)
434 {
435   int nf;
436
437   Suite *s = gstrtpbin_suite ();
438   SRunner *sr = srunner_create (s);
439
440   gst_check_init (&argc, &argv);
441
442   srunner_run_all (sr, CK_NORMAL);
443   nf = srunner_ntests_failed (sr);
444   srunner_free (sr);
445
446   return nf;
447 }