rtpbin: receive bundle support
[platform/upstream/gst-plugins-good.git] / tests / check / elements / rtpbundle.c
1 /* GStreamer
2  *
3  * Copyright (C) 2016 Igalia S.L.
4  *   @author Philippe Normand <philn@igalia.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include <gst/check/gstcheck.h>
23 #include <gst/check/gstconsistencychecker.h>
24 #include <gst/check/gsttestclock.h>
25 #include <gst/rtp/gstrtpbuffer.h>
26
27 static GMainLoop *main_loop;
28
29 static void
30 message_received (GstBus * bus, GstMessage * message, GstPipeline * bin)
31 {
32   GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
33       GST_MESSAGE_SRC (message), message);
34
35   switch (message->type) {
36     case GST_MESSAGE_EOS:
37       g_main_loop_quit (main_loop);
38       break;
39     case GST_MESSAGE_WARNING:{
40       GError *gerror;
41       gchar *debug;
42
43       gst_message_parse_warning (message, &gerror, &debug);
44       gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
45       g_error_free (gerror);
46       g_free (debug);
47       break;
48     }
49     case GST_MESSAGE_ERROR:{
50       GError *gerror;
51       gchar *debug;
52
53       gst_message_parse_error (message, &gerror, &debug);
54       gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
55       g_error_free (gerror);
56       g_free (debug);
57       fail ("Error!");
58       break;
59     }
60     default:
61       break;
62   }
63 }
64
65 static void
66 on_rtpbinreceive_pad_added (GstElement * element, GstPad * new_pad,
67     gpointer data)
68 {
69   GstElement *pipeline = GST_ELEMENT (data);
70   gchar *pad_name = gst_pad_get_name (new_pad);
71
72   if (g_str_has_prefix (pad_name, "recv_rtp_src_")) {
73     GstCaps *caps = gst_pad_get_current_caps (new_pad);
74     GstStructure *s = gst_caps_get_structure (caps, 0);
75     const gchar *media_type = gst_structure_get_string (s, "media");
76     gchar *depayloader_name = g_strdup_printf ("%s_rtpdepayloader", media_type);
77     GstElement *rtpdepayloader =
78         gst_bin_get_by_name (GST_BIN (pipeline), depayloader_name);
79     GstPad *sinkpad;
80
81     g_free (depayloader_name);
82     fail_unless (rtpdepayloader != NULL, NULL);
83
84     sinkpad = gst_element_get_static_pad (rtpdepayloader, "sink");
85     gst_pad_link (new_pad, sinkpad);
86     gst_object_unref (sinkpad);
87     gst_object_unref (rtpdepayloader);
88
89     gst_caps_unref (caps);
90   }
91   g_free (pad_name);
92 }
93
94 static guint
95 on_bundled_ssrc (GstElement * rtpbin, guint ssrc, gpointer user_data)
96 {
97   static gboolean create_session = FALSE;
98   guint session_id = 0;
99
100   if (create_session) {
101     session_id = 1;
102   } else {
103     create_session = TRUE;
104     /* use existing session 0, a new session will be created for the next discovered bundled SSRC */
105   }
106   return session_id;
107 }
108
109 static GstCaps *
110 on_request_pt_map (GstElement * rtpbin, guint session_id, guint pt,
111     gpointer user_data)
112 {
113   GstCaps *caps = NULL;
114   if (pt == 96) {
115     caps =
116         gst_caps_from_string
117         ("application/x-rtp,media=(string)audio,encoding-name=(string)PCMA,clock-rate=(int)8000");
118   } else if (pt == 100) {
119     caps =
120         gst_caps_from_string
121         ("application/x-rtp,media=(string)video,encoding-name=(string)RAW,clock-rate=(int)90000,sampling=(string)\"YCbCr-4:2:0\",depth=(string)8,width=(string)320,height=(string)240");
122   }
123   return caps;
124 }
125
126
127 static GstElement *
128 create_pipeline (gboolean send)
129 {
130   GstElement *pipeline, *rtpbin, *audiosrc, *audio_encoder,
131       *audio_rtppayloader, *sendrtp_udpsink, *recv_rtp_udpsrc,
132       *send_rtcp_udpsink, *recv_rtcp_udpsrc, *sendrtcp_funnel, *sendrtp_funnel;
133   GstElement *audio_rtpdepayloader, *audio_decoder, *audio_sink;
134   GstElement *videosrc, *video_rtppayloader, *video_rtpdepayloader, *video_sink;
135   gboolean res;
136   GstPad *funnel_pad, *rtp_src_pad;
137   GstCaps *rtpcaps;
138   gint rtp_udp_port = 5001;
139   gint rtcp_udp_port = 5002;
140
141   pipeline = gst_pipeline_new (send ? "pipeline_send" : "pipeline_receive");
142
143   rtpbin =
144       gst_element_factory_make ("rtpbin",
145       send ? "rtpbin_send" : "rtpbin_receive");
146   g_object_set (rtpbin, "latency", 200, NULL);
147
148   if (!send) {
149     g_signal_connect (rtpbin, "on-bundled-ssrc",
150         G_CALLBACK (on_bundled_ssrc), NULL);
151     g_signal_connect (rtpbin, "request-pt-map",
152         G_CALLBACK (on_request_pt_map), NULL);
153   }
154
155   g_signal_connect (rtpbin, "pad-added",
156       G_CALLBACK (on_rtpbinreceive_pad_added), pipeline);
157
158   gst_bin_add (GST_BIN (pipeline), rtpbin);
159
160   if (send) {
161     audiosrc = gst_element_factory_make ("audiotestsrc", NULL);
162     audio_encoder = gst_element_factory_make ("alawenc", NULL);
163     audio_rtppayloader = gst_element_factory_make ("rtppcmapay", NULL);
164     g_object_set (audio_rtppayloader, "pt", 96, NULL);
165     g_object_set (audio_rtppayloader, "seqnum-offset", 1, NULL);
166
167     videosrc = gst_element_factory_make ("videotestsrc", NULL);
168     video_rtppayloader = gst_element_factory_make ("rtpvrawpay", NULL);
169     g_object_set (video_rtppayloader, "pt", 100, "seqnum-offset", 1, NULL);
170
171     g_object_set (audiosrc, "num-buffers", 5, NULL);
172     g_object_set (videosrc, "num-buffers", 5, NULL);
173
174     /* muxed rtcp */
175     sendrtcp_funnel = gst_element_factory_make ("funnel", "send_rtcp_funnel");
176     send_rtcp_udpsink = gst_element_factory_make ("udpsink", NULL);
177     g_object_set (send_rtcp_udpsink, "host", "127.0.0.1", NULL);
178     g_object_set (send_rtcp_udpsink, "port", rtcp_udp_port, NULL);
179     g_object_set (send_rtcp_udpsink, "sync", FALSE, NULL);
180     g_object_set (send_rtcp_udpsink, "async", FALSE, NULL);
181
182     /* outgoing bundled stream */
183     sendrtp_funnel = gst_element_factory_make ("funnel", "send_rtp_funnel");
184     sendrtp_udpsink = gst_element_factory_make ("udpsink", NULL);
185     g_object_set (sendrtp_udpsink, "host", "127.0.0.1", NULL);
186     g_object_set (sendrtp_udpsink, "port", rtp_udp_port, NULL);
187
188     gst_bin_add_many (GST_BIN (pipeline), audiosrc, audio_encoder,
189         audio_rtppayloader, sendrtp_udpsink, send_rtcp_udpsink,
190         sendrtp_funnel, sendrtcp_funnel, videosrc, video_rtppayloader, NULL);
191
192     res = gst_element_link (audiosrc, audio_encoder);
193     fail_unless (res == TRUE, NULL);
194     res = gst_element_link (audio_encoder, audio_rtppayloader);
195     fail_unless (res == TRUE, NULL);
196     res =
197         gst_element_link_pads_full (audio_rtppayloader, "src", rtpbin,
198         "send_rtp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
199     fail_unless (res == TRUE, NULL);
200
201     res = gst_element_link (videosrc, video_rtppayloader);
202     fail_unless (res == TRUE, NULL);
203     res =
204         gst_element_link_pads_full (video_rtppayloader, "src", rtpbin,
205         "send_rtp_sink_1", GST_PAD_LINK_CHECK_NOTHING);
206     fail_unless (res == TRUE, NULL);
207
208     res =
209         gst_element_link_pads_full (sendrtp_funnel, "src", sendrtp_udpsink,
210         "sink", GST_PAD_LINK_CHECK_NOTHING);
211     fail_unless (res == TRUE, NULL);
212
213     funnel_pad = gst_element_get_request_pad (sendrtp_funnel, "sink_%u");
214     rtp_src_pad = gst_element_get_static_pad (rtpbin, "send_rtp_src_0");
215     res = gst_pad_link (rtp_src_pad, funnel_pad);
216     gst_object_unref (funnel_pad);
217     gst_object_unref (rtp_src_pad);
218
219     funnel_pad = gst_element_get_request_pad (sendrtp_funnel, "sink_%u");
220     rtp_src_pad = gst_element_get_static_pad (rtpbin, "send_rtp_src_1");
221     res = gst_pad_link (rtp_src_pad, funnel_pad);
222     gst_object_unref (funnel_pad);
223     gst_object_unref (rtp_src_pad);
224
225     res =
226         gst_element_link_pads_full (sendrtcp_funnel, "src", send_rtcp_udpsink,
227         "sink", GST_PAD_LINK_CHECK_NOTHING);
228     fail_unless (res == TRUE, NULL);
229
230     funnel_pad = gst_element_get_request_pad (sendrtcp_funnel, "sink_%u");
231     rtp_src_pad = gst_element_get_request_pad (rtpbin, "send_rtcp_src_0");
232     res =
233         gst_pad_link_full (rtp_src_pad, funnel_pad, GST_PAD_LINK_CHECK_NOTHING);
234     gst_object_unref (funnel_pad);
235     gst_object_unref (rtp_src_pad);
236
237     funnel_pad = gst_element_get_request_pad (sendrtcp_funnel, "sink_%u");
238     rtp_src_pad = gst_element_get_request_pad (rtpbin, "send_rtcp_src_1");
239     res =
240         gst_pad_link_full (rtp_src_pad, funnel_pad, GST_PAD_LINK_CHECK_NOTHING);
241     gst_object_unref (funnel_pad);
242     gst_object_unref (rtp_src_pad);
243
244   } else {
245     recv_rtp_udpsrc = gst_element_factory_make ("udpsrc", NULL);
246     g_object_set (recv_rtp_udpsrc, "port", rtp_udp_port, NULL);
247     rtpcaps = gst_caps_from_string ("application/x-rtp");
248     g_object_set (recv_rtp_udpsrc, "caps", rtpcaps, NULL);
249     gst_caps_unref (rtpcaps);
250
251     recv_rtcp_udpsrc = gst_element_factory_make ("udpsrc", NULL);
252     g_object_set (recv_rtcp_udpsrc, "port", rtcp_udp_port, NULL);
253
254     audio_rtpdepayloader =
255         gst_element_factory_make ("rtppcmadepay", "audio_rtpdepayloader");
256     audio_decoder = gst_element_factory_make ("alawdec", NULL);
257     audio_sink = gst_element_factory_make ("fakesink", NULL);
258     g_object_set (audio_sink, "sync", TRUE, NULL);
259
260     video_rtpdepayloader =
261         gst_element_factory_make ("rtpvrawdepay", "video_rtpdepayloader");
262     video_sink = gst_element_factory_make ("fakesink", NULL);
263     g_object_set (video_sink, "sync", TRUE, NULL);
264
265     gst_bin_add_many (GST_BIN (pipeline), recv_rtp_udpsrc, recv_rtcp_udpsrc,
266         audio_rtpdepayloader, audio_decoder, audio_sink, video_rtpdepayloader,
267         video_sink, NULL);
268
269     res =
270         gst_element_link_pads_full (audio_rtpdepayloader, "src", audio_decoder,
271         "sink", GST_PAD_LINK_CHECK_NOTHING);
272     fail_unless (res == TRUE, NULL);
273     res = gst_element_link (audio_decoder, audio_sink);
274     fail_unless (res == TRUE, NULL);
275
276     res =
277         gst_element_link_pads_full (video_rtpdepayloader, "src", video_sink,
278         "sink", GST_PAD_LINK_CHECK_NOTHING);
279     fail_unless (res == TRUE, NULL);
280
281     /* request a single receiving RTP session. */
282     res =
283         gst_element_link_pads_full (recv_rtcp_udpsrc, "src", rtpbin,
284         "recv_rtcp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
285     fail_unless (res == TRUE, NULL);
286     res =
287         gst_element_link_pads_full (recv_rtp_udpsrc, "src", rtpbin,
288         "recv_rtp_sink_0", GST_PAD_LINK_CHECK_NOTHING);
289     fail_unless (res == TRUE, NULL);
290   }
291
292   return pipeline;
293 }
294
295 GST_START_TEST (test_simple_rtpbin_bundle)
296 {
297   GstElement *send_pipeline, *recv_pipeline;
298   GstBus *send_bus, *recv_bus;
299   GstStateChangeReturn state_res = GST_STATE_CHANGE_FAILURE;
300   GstElement *rtpbin_receive;
301   GObject *rtp_session;
302
303   main_loop = g_main_loop_new (NULL, FALSE);
304
305   send_pipeline = create_pipeline (TRUE);
306   recv_pipeline = create_pipeline (FALSE);
307
308   send_bus = gst_element_get_bus (send_pipeline);
309   gst_bus_add_signal_watch_full (send_bus, G_PRIORITY_HIGH);
310
311   g_signal_connect (send_bus, "message::error", (GCallback) message_received,
312       send_pipeline);
313   g_signal_connect (send_bus, "message::warning", (GCallback) message_received,
314       send_pipeline);
315   g_signal_connect (send_bus, "message::eos", (GCallback) message_received,
316       send_pipeline);
317
318   recv_bus = gst_element_get_bus (recv_pipeline);
319   gst_bus_add_signal_watch_full (recv_bus, G_PRIORITY_HIGH);
320
321   g_signal_connect (recv_bus, "message::error", (GCallback) message_received,
322       recv_pipeline);
323   g_signal_connect (recv_bus, "message::warning", (GCallback) message_received,
324       recv_pipeline);
325   g_signal_connect (recv_bus, "message::eos", (GCallback) message_received,
326       recv_pipeline);
327
328   state_res = gst_element_set_state (recv_pipeline, GST_STATE_PLAYING);
329   ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
330
331   state_res = gst_element_set_state (send_pipeline, GST_STATE_PLAYING);
332   ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
333
334   GST_INFO ("enter mainloop");
335   g_main_loop_run (main_loop);
336   GST_INFO ("exit mainloop");
337
338   rtpbin_receive =
339       gst_bin_get_by_name (GST_BIN (recv_pipeline), "rtpbin_receive");
340   fail_if (rtpbin_receive == NULL, NULL);
341
342   /* Check that 2 RTP sessions where created while only one was explicitely requested. */
343   g_signal_emit_by_name (rtpbin_receive, "get-internal-session", 0,
344       &rtp_session);
345   fail_if (rtp_session == NULL, NULL);
346   g_object_unref (rtp_session);
347   g_signal_emit_by_name (rtpbin_receive, "get-internal-session", 1,
348       &rtp_session);
349   fail_if (rtp_session == NULL, NULL);
350   g_object_unref (rtp_session);
351
352   gst_object_unref (rtpbin_receive);
353
354   state_res = gst_element_set_state (send_pipeline, GST_STATE_NULL);
355   ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
356
357   state_res = gst_element_set_state (recv_pipeline, GST_STATE_NULL);
358   ck_assert_int_ne (state_res, GST_STATE_CHANGE_FAILURE);
359
360   /* cleanup */
361   g_main_loop_unref (main_loop);
362
363   gst_bus_remove_signal_watch (send_bus);
364   gst_object_unref (send_bus);
365   gst_object_unref (send_pipeline);
366
367   gst_bus_remove_signal_watch (recv_bus);
368   gst_object_unref (recv_bus);
369   gst_object_unref (recv_pipeline);
370
371 }
372
373 GST_END_TEST;
374
375 static Suite *
376 rtpbundle_suite (void)
377 {
378   Suite *s = suite_create ("rtpbundle");
379   TCase *tc_chain = tcase_create ("general");
380
381   tcase_set_timeout (tc_chain, 10000);
382
383   suite_add_tcase (s, tc_chain);
384
385   tcase_add_test (tc_chain, test_simple_rtpbin_bundle);
386
387   return s;
388 }
389
390 GST_CHECK_MAIN (rtpbundle);