tests: rtp: misc compatibiliy fixes
[platform/upstream/gst-plugins-good.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 ("rtpbin", "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 GstFlowReturn
128 chain_rtp_packet (GstPad * pad, CleanupData * data)
129 {
130   GstFlowReturn res;
131   static GstCaps *caps = NULL;
132   GstBuffer *buffer;
133   GstMapInfo map;
134
135   if (caps == NULL) {
136     caps = gst_caps_from_string ("application/x-rtp,"
137         "media=(string)audio, clock-rate=(int)44100, "
138         "encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1");
139     data->seqnum = 0;
140   }
141
142   gst_pad_set_caps (pad, caps);
143
144   buffer = gst_buffer_new_and_alloc (sizeof (rtp_packet));
145   gst_buffer_map (buffer, &map, GST_MAP_WRITE);
146   memcpy (map.data, rtp_packet, sizeof (rtp_packet));
147
148   map.data[2] = (data->seqnum >> 8) & 0xff;
149   map.data[3] = data->seqnum & 0xff;
150
151   data->seqnum++;
152   gst_buffer_unmap (buffer, &map);
153
154   res = gst_pad_chain (pad, buffer);
155
156   return res;
157 }
158
159 static GstFlowReturn
160 dummy_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
161 {
162   gst_buffer_unref (buffer);
163
164   return GST_FLOW_OK;
165 }
166
167 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
168     GST_PAD_SINK,
169     GST_PAD_ALWAYS,
170     GST_STATIC_CAPS ("application/x-rtp"));
171
172
173 static GstPad *
174 make_sinkpad (CleanupData * data)
175 {
176   GstPad *pad;
177
178   pad = gst_pad_new_from_static_template (&sink_factory, "sink");
179
180   gst_pad_set_chain_function (pad, dummy_chain);
181   gst_pad_set_active (pad, TRUE);
182
183   data->pads = g_list_prepend (data->pads, pad);
184
185   return pad;
186 }
187
188 static void
189 pad_added_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
190 {
191   GstPad *sinkpad;
192
193   GST_DEBUG ("pad added %s:%s\n", GST_DEBUG_PAD_NAME (pad));
194
195   if (GST_PAD_IS_SINK (pad))
196     return;
197
198   fail_unless (data->pad_added == FALSE);
199
200   sinkpad = make_sinkpad (data);
201   fail_unless (gst_pad_link (pad, sinkpad) == GST_PAD_LINK_OK);
202
203   g_mutex_lock (data->lock);
204   data->pad_added = TRUE;
205   data->pad = pad;
206   g_cond_signal (data->cond);
207   g_mutex_unlock (data->lock);
208 }
209
210 static void
211 pad_removed_cb (GstElement * rtpbin, GstPad * pad, CleanupData * data)
212 {
213   GST_DEBUG ("pad removed %s:%s\n", GST_DEBUG_PAD_NAME (pad));
214
215   if (data->pad != pad)
216     return;
217
218   fail_unless (data->pad_added == TRUE);
219
220   g_mutex_lock (data->lock);
221   data->pad_added = FALSE;
222   g_cond_signal (data->cond);
223   g_mutex_unlock (data->lock);
224 }
225
226 GST_START_TEST (test_cleanup_recv)
227 {
228   GstElement *rtpbin;
229   GstPad *rtp_sink;
230   CleanupData data;
231   GstStateChangeReturn ret;
232   GstFlowReturn res;
233   gint count = 2;
234
235   init_data (&data);
236
237   rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
238
239   g_signal_connect (rtpbin, "pad-added", (GCallback) pad_added_cb, &data);
240   g_signal_connect (rtpbin, "pad-removed", (GCallback) pad_removed_cb, &data);
241
242   ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
243   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
244
245   while (count--) {
246     /* request session 0 */
247     rtp_sink = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_0");
248     fail_unless (rtp_sink != NULL);
249     ASSERT_OBJECT_REFCOUNT (rtp_sink, "rtp_sink", 2);
250
251     /* no sourcepads are created yet */
252     fail_unless (rtpbin->numsinkpads == 1);
253     fail_unless (rtpbin->numsrcpads == 0);
254
255     res = chain_rtp_packet (rtp_sink, &data);
256     GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
257     fail_unless (res == GST_FLOW_OK);
258
259     res = chain_rtp_packet (rtp_sink, &data);
260     GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
261     fail_unless (res == GST_FLOW_OK);
262
263     /* we wait for the new pad to appear now */
264     g_mutex_lock (data.lock);
265     while (!data.pad_added)
266       g_cond_wait (data.cond, data.lock);
267     g_mutex_unlock (data.lock);
268
269     /* sourcepad created now */
270     fail_unless (rtpbin->numsinkpads == 1);
271     fail_unless (rtpbin->numsrcpads == 1);
272
273     /* remove the session */
274     gst_element_release_request_pad (rtpbin, rtp_sink);
275     gst_object_unref (rtp_sink);
276
277     /* pad should be gone now */
278     g_mutex_lock (data.lock);
279     while (data.pad_added)
280       g_cond_wait (data.cond, data.lock);
281     g_mutex_unlock (data.lock);
282
283     /* nothing left anymore now */
284     fail_unless (rtpbin->numsinkpads == 0);
285     fail_unless (rtpbin->numsrcpads == 0);
286   }
287
288   ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
289   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
290
291   gst_object_unref (rtpbin);
292
293   clean_data (&data);
294 }
295
296 GST_END_TEST;
297
298 GST_START_TEST (test_cleanup_recv2)
299 {
300   GstElement *rtpbin;
301   GstPad *rtp_sink;
302   CleanupData data;
303   GstStateChangeReturn ret;
304   GstFlowReturn res;
305   gint count = 2;
306
307   init_data (&data);
308
309   rtpbin = gst_element_factory_make ("rtpbin", "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     res = chain_rtp_packet (rtp_sink, &data);
328     GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
329     fail_unless (res == GST_FLOW_OK);
330
331     res = chain_rtp_packet (rtp_sink, &data);
332     GST_DEBUG ("res %d, %s\n", res, gst_flow_get_name (res));
333     fail_unless (res == GST_FLOW_OK);
334
335     /* we wait for the new pad to appear now */
336     g_mutex_lock (data.lock);
337     while (!data.pad_added)
338       g_cond_wait (data.cond, data.lock);
339     g_mutex_unlock (data.lock);
340
341     /* sourcepad created now */
342     fail_unless (rtpbin->numsinkpads == 1);
343     fail_unless (rtpbin->numsrcpads == 1);
344
345     /* change state */
346     ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
347     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
348
349     /* pad should be gone now */
350     g_mutex_lock (data.lock);
351     while (data.pad_added)
352       g_cond_wait (data.cond, data.lock);
353     g_mutex_unlock (data.lock);
354
355     /* back to playing for the next round */
356     ret = gst_element_set_state (rtpbin, GST_STATE_PLAYING);
357     fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
358   }
359
360   /* remove the session */
361   gst_element_release_request_pad (rtpbin, rtp_sink);
362   gst_object_unref (rtp_sink);
363
364   /* nothing left anymore now */
365   fail_unless (rtpbin->numsinkpads == 0);
366   fail_unless (rtpbin->numsrcpads == 0);
367
368   ret = gst_element_set_state (rtpbin, GST_STATE_NULL);
369   fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
370
371   gst_object_unref (rtpbin);
372
373   clean_data (&data);
374 }
375
376 GST_END_TEST;
377
378 GST_START_TEST (test_request_pad_by_template_name)
379 {
380   GstElement *rtpbin;
381   GstPad *rtp_sink1, *rtp_sink2, *rtp_sink3;
382
383   rtpbin = gst_element_factory_make ("rtpbin", "rtpbin");
384   rtp_sink1 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
385   fail_unless (rtp_sink1 != NULL);
386   fail_unless_equals_string (GST_PAD_NAME (rtp_sink1), "recv_rtp_sink_0");
387   ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink1", 2);
388
389   rtp_sink2 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
390   fail_unless (rtp_sink2 != NULL);
391   fail_unless_equals_string (GST_PAD_NAME (rtp_sink2), "recv_rtp_sink_1");
392   ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 2);
393
394   rtp_sink3 = gst_element_get_request_pad (rtpbin, "recv_rtp_sink_%u");
395   fail_unless (rtp_sink3 != NULL);
396   fail_unless_equals_string (GST_PAD_NAME (rtp_sink3), "recv_rtp_sink_2");
397   ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 2);
398
399
400   gst_element_release_request_pad (rtpbin, rtp_sink2);
401   gst_element_release_request_pad (rtpbin, rtp_sink1);
402   gst_element_release_request_pad (rtpbin, rtp_sink3);
403   ASSERT_OBJECT_REFCOUNT (rtp_sink3, "rtp_sink3", 1);
404   ASSERT_OBJECT_REFCOUNT (rtp_sink2, "rtp_sink2", 1);
405   ASSERT_OBJECT_REFCOUNT (rtp_sink1, "rtp_sink", 1);
406   gst_object_unref (rtp_sink1);
407   gst_object_unref (rtp_sink2);
408   gst_object_unref (rtp_sink3);
409
410   gst_object_unref (rtpbin);
411 }
412
413 GST_END_TEST;
414
415 static Suite *
416 gstrtpbin_suite (void)
417 {
418   Suite *s = suite_create ("rtpbin");
419   TCase *tc_chain = tcase_create ("general");
420
421   suite_add_tcase (s, tc_chain);
422   tcase_add_test (tc_chain, test_cleanup_send);
423   tcase_add_test (tc_chain, test_cleanup_recv);
424   tcase_add_test (tc_chain, test_cleanup_recv2);
425   tcase_add_test (tc_chain, test_request_pad_by_template_name);
426
427   return s;
428 }
429
430 int
431 main (int argc, char **argv)
432 {
433   int nf;
434
435   Suite *s = gstrtpbin_suite ();
436   SRunner *sr = srunner_create (s);
437
438   gst_check_init (&argc, &argv);
439
440   srunner_run_all (sr, CK_NORMAL);
441   nf = srunner_ntests_failed (sr);
442   srunner_free (sr);
443
444   return nf;
445 }