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