Add internal API for getting webrtcbin from webrtc node
[platform/core/api/mediastreamer.git] / src / media_streamer_gst_webrtc.c
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef GST_USE_UNSTABLE_API
18 #define GST_USE_UNSTABLE_API
19 #include <gst/webrtc/webrtc.h>
20 #endif
21 #include "media_streamer_util.h"
22 #include "media_streamer_priv.h"
23 #include "media_streamer_gst.h"
24 #include "media_streamer_gst_webrtc.h"
25 #include "media_streamer_node.h"
26
27 int ms_webrtcbin_set_pad_format(GstElement *webrtc_container, const char *pad_name, media_format_h fmt)
28 {
29         int ret = MEDIA_STREAMER_ERROR_NONE;
30         media_format_mimetype_e mime;
31         GstCaps *caps = NULL;
32         GstPad *sinkpad = NULL;
33         gchar *media = NULL;
34         gchar *caps_str = NULL;
35         const gchar *encoding_name = NULL;
36         gint payload = 0;
37
38         ms_retvm_if(webrtc_container == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_container is NULL");
39         ms_retvm_if(pad_name == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "pad_name is NULL");
40         ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "fmt is NULL");
41
42         ms_debug_fenter();
43
44         sinkpad = gst_element_get_static_pad(webrtc_container, pad_name);
45         if (!sinkpad) {
46                 ms_error("[%s] doesn`t have valid pad [%s]", GST_ELEMENT_NAME(webrtc_container), pad_name);
47                 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
48         }
49
50         if (!media_format_get_video_info(fmt, &mime, NULL, NULL, NULL, NULL) &&
51                 g_strrstr(pad_name, MS_RTP_PAD_VIDEO_IN)) {
52                 media = "video";
53                 payload = 96;
54         } else if (!media_format_get_audio_info(fmt, &mime, NULL, NULL, NULL, NULL) &&
55                 g_strrstr(pad_name, MS_RTP_PAD_AUDIO_IN)) {
56                 media = "audio";
57                 payload = 97;
58         } else {
59                 ms_error("format is not video or audio format");
60                 goto end;
61         }
62         encoding_name = ms_convert_mime_to_rtp_format(mime);
63
64         caps = gst_caps_new_simple("application/x-rtp",
65                                                                 "media", G_TYPE_STRING, media,
66                                                                 "encoding-name", G_TYPE_STRING, encoding_name,
67                                                                 "payload", G_TYPE_INT, payload, NULL);
68
69         if (!gst_pad_set_caps(sinkpad, caps)) {
70                 ms_error("[%s]'s pad [%s] can't be set with the given format", GST_ELEMENT_NAME(webrtc_container), pad_name);
71                 ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
72                 goto end;
73         }
74         caps_str = gst_caps_to_string(caps);
75         ms_info("[%s]'s pad [%s] is set with the given format[%s]", GST_ELEMENT_NAME(webrtc_container), pad_name, caps_str);
76         MS_SAFE_GFREE(caps_str);
77
78 end:
79         MS_SAFE_UNREF(sinkpad);
80         MS_SAFE_UNREF(caps);
81
82         return ret;
83 }
84
85 static gchar *__make_ice_candidate_message(guint mlineindex, gchar *candidate)
86 {
87         JsonObject *ice, *msg;
88         gchar *text;
89
90         ms_retvm_if(candidate == NULL, NULL, "candidate is NULL");
91
92         ice = json_object_new();
93         json_object_set_string_member(ice, "candidate", candidate);
94         json_object_set_int_member(ice, "sdpMLineIndex", mlineindex);
95
96         msg = json_object_new();
97         json_object_set_object_member(msg, "ice", ice);
98
99         text = ms_get_string_from_json_object(msg);
100
101         json_object_unref(msg);
102
103         return text;
104 }
105
106 static gchar* __make_sdp_message(GstWebRTCSessionDescription *desc)
107 {
108         gchar *text;
109         JsonObject *msg, *sdp;
110
111         text = gst_sdp_message_as_text(desc->sdp);
112         sdp = json_object_new();
113
114         if (desc->type == GST_WEBRTC_SDP_TYPE_OFFER) {
115                 ms_info("Making offer message:\n%s", text);
116                 json_object_set_string_member(sdp, "type", "offer");
117         } else if (desc->type == GST_WEBRTC_SDP_TYPE_ANSWER) {
118                 ms_info("Making answer message:\n%s", text);
119                 json_object_set_string_member(sdp, "type", "answer");
120         } else {
121                 ms_error("invalid description type");
122                 return NULL;
123         }
124
125         json_object_set_string_member(sdp, "sdp", text);
126         g_free(text);
127
128         msg = json_object_new();
129         json_object_set_object_member(msg, "sdp", sdp);
130
131         text = ms_get_string_from_json_object(msg);
132
133         json_object_unref(msg);
134
135         return text;
136 }
137
138 static void __trigger_message_callback(media_streamer_node_s *webrtc_node, gchar *message)
139 {
140         media_streamer_webrtc_callbacks_s *_callbacks;
141
142         ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
143         ms_retm_if(message == NULL, "message is NULL");
144
145         ms_debug("message is : \n%s", message);
146
147         _callbacks = (media_streamer_webrtc_callbacks_s *) webrtc_node->callbacks_structure;
148         if (_callbacks->message_cb.callback) {
149                 ms_debug("=====> invoke message callback(%p)", _callbacks->message_cb.callback);
150                 ((media_streamer_webrtc_message_cb)(_callbacks->message_cb.callback))(webrtc_node, message, _callbacks->message_cb.user_data);
151                 ms_debug("<===== end of the callback");
152         } else {
153                 ms_warning("message callback is NULL");
154         }
155 }
156
157 static void __ms_webrtcbin_set_session_description(GstElement *webrtcbin, GstWebRTCSessionDescription *session_description, gboolean is_remote)
158 {
159         GstPromise *promise;
160         ms_retm_if(session_description == NULL, "session_description is NULL");
161         ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL");
162
163         ms_debug_fenter();
164
165         promise = gst_promise_new();
166         g_signal_emit_by_name(webrtcbin, is_remote? "set-remote-description" : "set-local-description", session_description, promise);
167         gst_promise_interrupt(promise);
168         gst_promise_unref(promise);
169
170         ms_debug_fleave();
171 }
172
173 static void __on_offer_created_cb(GstPromise *promise, gpointer user_data)
174 {
175         GstWebRTCSessionDescription *offer = NULL;
176         const GstStructure *reply;
177         media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data;
178         GstElement *webrtcbin = NULL;
179         gchar *sdp_msg;
180
181         ms_retm_if(promise == NULL, "promise is NULL");
182         ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
183         ms_retm_if(gst_promise_wait(promise) != GST_PROMISE_RESULT_REPLIED, "promise is not for replied result");
184
185         ms_debug_fenter();
186
187         if (!(webrtcbin = ms_webrtc_node_get_webrtcbin(webrtc_node)))
188                 return;
189
190         reply = gst_promise_get_reply(promise);
191         gst_structure_get(reply, "offer",
192                 GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
193         gst_promise_unref(promise);
194
195         __ms_webrtcbin_set_session_description(webrtcbin, offer, FALSE);
196
197         sdp_msg = __make_sdp_message(offer);
198         gst_webrtc_session_description_free(offer);
199
200         /* Send local description to peer */
201         __trigger_message_callback(webrtc_node, sdp_msg);
202         g_free(sdp_msg);
203
204         ms_debug_fleave();
205 }
206
207 static void __on_answer_created_cb(GstPromise * promise, gpointer user_data)
208 {
209         GstWebRTCSessionDescription *answer = NULL;
210         const GstStructure *reply;
211         media_streamer_node_s *node = (media_streamer_node_s *)user_data;
212         gchar *sdp_msg;
213         GstElement *webrtcbin;
214
215         ms_retm_if(promise == NULL, "promise is NULL");
216         ms_retm_if(node == NULL, "node is NULL");
217         ms_retm_if(node->gst_element == NULL, "webrtc_container is NULL");
218         ms_retm_if(gst_promise_wait(promise) != GST_PROMISE_RESULT_REPLIED, "promise is not for replied result");
219
220         ms_debug_fenter();
221
222         if (!(webrtcbin = ms_webrtc_node_get_webrtcbin(node)))
223                 return;
224
225         reply = gst_promise_get_reply(promise);
226         gst_structure_get(reply, "answer", GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL);
227         gst_promise_unref(promise);
228
229         __ms_webrtcbin_set_session_description(webrtcbin, answer, FALSE);
230
231         sdp_msg = __make_sdp_message(answer);
232         gst_webrtc_session_description_free(answer);
233
234         /* Send local description to peer */
235         __trigger_message_callback(node, sdp_msg);
236         g_free(sdp_msg);
237
238         ms_debug_fleave();
239 }
240
241 int ms_webrtcbin_set_remote_session_description(media_streamer_node_s *webrtc_node, const char *sdp_msg)
242 {
243         GstSDPMessage *gst_sdp;
244         gchar *sdp;
245         gchar *type;
246         GstWebRTCSessionDescription *answer, *offer;
247         GstElement *webrtcbin;
248         int ret = MEDIA_STREAMER_ERROR_NONE;
249
250         ms_retvm_if(webrtc_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_node is NULL");
251         ms_retvm_if(webrtc_node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_container is NULL");
252         ms_retvm_if(sdp_msg == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "sdp_msg is NULL");
253
254         ms_debug_fenter();
255
256         if (!(webrtcbin = ms_webrtc_node_get_webrtcbin(webrtc_node)))
257                 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
258
259         ret = ms_webrtc_get_sdp_from_message(sdp_msg, &sdp, &type);
260         if (ret != MEDIA_STREAMER_ERROR_NONE)
261                 goto end;
262
263         ret = gst_sdp_message_new(&gst_sdp);
264         if (ret != GST_SDP_OK) {
265                 ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
266                 goto end;
267         }
268
269         ret = gst_sdp_message_parse_buffer((guint8 *)sdp, strlen(sdp), gst_sdp);
270         if (ret != GST_SDP_OK) {
271                 ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
272                 goto end;
273         }
274
275         if (g_str_equal(type, "answer")) {
276                 answer = gst_webrtc_session_description_new(GST_WEBRTC_SDP_TYPE_ANSWER, gst_sdp);
277                 g_assert_nonnull(answer);
278
279                 __ms_webrtcbin_set_session_description(webrtcbin, answer, TRUE);
280                 gst_webrtc_session_description_free(answer);
281         } else if (g_str_equal(type, "offer")) {
282                 offer = gst_webrtc_session_description_new(GST_WEBRTC_SDP_TYPE_OFFER, gst_sdp);
283                 g_assert_nonnull(offer);
284
285                 __ms_webrtcbin_set_session_description(webrtcbin, offer, TRUE);
286                 gst_webrtc_session_description_free(offer);
287
288                 ms_webrtcbin_on_negotiation_process_answer(webrtcbin, webrtc_node);
289         } else {
290                 ms_error("type is %s, it is not a answer or offer", type);
291         }
292
293 end:
294         MS_SAFE_GFREE(sdp);
295         MS_SAFE_GFREE(type);
296
297         ms_debug_fleave();
298
299         return ret;
300 }
301
302 int ms_webrtcbin_add_ice_candidate(media_streamer_node_s *webrtc_node, const char *ice_msg)
303 {
304         gchar *candidate;
305         gint sdpmlineindex;
306         GstElement *webrtcbin;
307         int ret;
308
309         ms_retvm_if(webrtc_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_node is NULL");
310         ms_retvm_if(webrtc_node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_container is NULL");
311         ms_retvm_if(ice_msg == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ice_msg is NULL");
312
313         ms_debug_fenter();
314
315         if (!(webrtcbin = ms_webrtc_node_get_webrtcbin(webrtc_node)))
316                 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
317
318         ret = ms_webrtc_get_ice_candidate_from_message(ice_msg, &candidate, &sdpmlineindex);
319         if (ret != MEDIA_STREAMER_ERROR_NONE)
320                 return ret;
321
322         /*Add ice candidate sent by remote peer */
323         g_signal_emit_by_name(webrtcbin, "add-ice-candidate", sdpmlineindex, candidate);
324
325         g_free(candidate);
326
327         return MEDIA_STREAMER_ERROR_NONE;
328 }
329
330 int ms_webrtcbin_set_stun_server(media_streamer_node_s *webrtc_node, const char *stun_server_url)
331 {
332         GstElement *webrtcbin;
333         GValue *val;
334         const gchar *stun_server = NULL;
335
336         ms_retvm_if(webrtc_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_node is NULL");
337         ms_retvm_if(webrtc_node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_container is NULL");
338         ms_retvm_if(stun_server_url == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "stun_server_url is NULL");
339
340         if (!(webrtcbin = ms_webrtc_node_get_webrtcbin(webrtc_node)))
341                 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
342
343         val = (GValue *)g_object_get_data(G_OBJECT(webrtc_node->gst_element), MEDIA_STREAMER_PARAM_WEBRTC_STUN_SERVER);
344         if (!val) {
345                 ms_error("Failed to get [%s] val from [%s]", MEDIA_STREAMER_PARAM_WEBRTC_STUN_SERVER, GST_ELEMENT_NAME(webrtc_node->gst_element));
346                 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
347         }
348
349         if (!(stun_server = g_value_get_string(val))) {
350                 ms_error("Failed to g_value_get_string()");
351                 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
352         }
353
354         g_object_set(G_OBJECT(webrtcbin), "stun-server", stun_server, NULL);
355
356         ms_info("STUN server: %s", stun_server);
357
358         return MEDIA_STREAMER_ERROR_NONE;
359 }
360
361 void ms_webrtcbin_on_negotiation_process_answer(GstElement *webrtcbin, media_streamer_node_s *webrtc_node)
362 {
363         GstPromise *promise;
364
365         ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL");
366
367         ms_debug_fenter();
368
369         promise = gst_promise_new_with_change_func(__on_answer_created_cb, webrtc_node, NULL);
370         g_signal_emit_by_name(G_OBJECT(webrtcbin), "create-answer", NULL, promise);
371
372         ms_debug_fleave();
373 }
374
375 void ms_webrtcbin_on_negotiation_needed_cb(GstElement *webrtcbin, gpointer user_data)
376 {
377         GstPromise *promise;
378
379         ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL");
380         ms_retm_if(user_data == NULL, "user_data is NULL");
381
382         ms_debug_fenter();
383
384         promise = gst_promise_new_with_change_func(__on_offer_created_cb, user_data, NULL);
385         g_signal_emit_by_name(G_OBJECT(webrtcbin), "create-offer", NULL, promise);
386
387         ms_debug_fleave();
388 }
389
390 void ms_webrtcbin_on_ice_candidate_cb(GstElement *webrtcbin, guint mlineindex, gchar *candidate, gpointer user_data)
391 {
392         gchar *ice_candidate_msg = NULL;
393         media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data;
394
395         ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL");
396         ms_retm_if(candidate == NULL, "candidate is NULL");
397         ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
398
399         ice_candidate_msg = __make_ice_candidate_message(mlineindex, candidate);
400
401         __trigger_message_callback(webrtc_node, ice_candidate_msg);
402
403         g_free(ice_candidate_msg);
404 }
405
406 void ms_webrtcbin_notify_ice_gathering_state_cb(GstElement *webrtcbin, GParamSpec * pspec, gpointer user_data)
407 {
408         GstWebRTCICEGatheringState ice_gather_state;
409         const gchar *new_state = "UNKNOWN";
410
411         g_object_get(webrtcbin, "ice-gathering-state", &ice_gather_state, NULL);
412
413         switch (ice_gather_state) {
414         case GST_WEBRTC_ICE_GATHERING_STATE_NEW:
415                 new_state = "NEW";
416                 break;
417         case GST_WEBRTC_ICE_GATHERING_STATE_GATHERING:
418                 new_state = "GATHERING";
419                 break;
420         case GST_WEBRTC_ICE_GATHERING_STATE_COMPLETE:
421                 new_state = "COMPLETE";
422                 break;
423         }
424
425         ms_info("ICE gathering state changed to [%s]", new_state);
426 }
427
428 static void __data_channel_on_error_cb(GObject *data_channel, gpointer user_data)
429 {
430         ms_retm_if(data_channel == NULL, "data_channel is NULL");
431
432         ms_debug_fenter();
433
434         ms_debug_fleave();
435 }
436
437 static void __data_channel_on_open_cb(GObject *data_channel, gpointer user_data)
438 {
439         GBytes *bytes = NULL;
440
441         ms_retm_if(data_channel == NULL, "data_channel is NULL");
442
443         ms_debug_fenter();
444
445         bytes = g_bytes_new("data", strlen("data"));
446
447         g_signal_emit_by_name(data_channel, "send-string", "Hi! from GStreamer");
448         g_signal_emit_by_name(data_channel, "send-data", bytes);
449
450         g_bytes_unref(bytes);
451
452         ms_debug_fleave();
453 }
454
455 static void __data_channel_on_close_cb(GObject *data_channel, gpointer user_data)
456 {
457         ms_retm_if(data_channel == NULL, "data_channel is NULL");
458
459         ms_debug_fenter();
460
461         ms_debug_fleave();
462 }
463
464 static void __data_channel_on_message_string_cb(GObject *data_channel, gchar *message, gpointer user_data)
465 {
466         ms_retm_if(data_channel == NULL, "data_channel is NULL");
467         ms_retm_if(message == NULL, "message is NULL");
468
469         ms_info("Received message: %s", message);
470 }
471
472 static void __connect_data_channel_signals(GObject *data_channel)
473 {
474         ms_retm_if(data_channel == NULL, "data_channel is NULL");
475
476         ms_debug_fenter();
477
478         g_signal_connect(data_channel, "on-error", G_CALLBACK(__data_channel_on_error_cb), NULL);
479         g_signal_connect(data_channel, "on-open", G_CALLBACK(__data_channel_on_open_cb), NULL);
480         g_signal_connect(data_channel, "on-close", G_CALLBACK(__data_channel_on_close_cb), NULL);
481         g_signal_connect(data_channel, "on-message-string", G_CALLBACK(__data_channel_on_message_string_cb), NULL);
482
483         ms_debug_fleave();
484 }
485
486 void ms_webrtcbin_on_data_channel_cb(GstElement *webrtcbin, GObject *data_channel, gpointer user_data)
487 {
488         media_streamer_s *ms_streamer = (media_streamer_s *)user_data;
489
490         ms_retm_if(ms_streamer == NULL, "ms_streamer is NULL");
491         ms_retm_if(data_channel == NULL, "data_channel is NULL");
492
493         ms_debug_fenter();
494
495         __connect_data_channel_signals(data_channel);
496
497         ms_debug_fleave();
498 }
499
500 static void __trigger_decoded_ready_callback(media_streamer_node_s *webrtc_node, const gchar *new_pad_name, const gchar *media_type)
501 {
502         media_streamer_webrtc_callbacks_s *_callbacks;
503
504         ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
505         ms_retm_if(new_pad_name == NULL, "new_pad_name is NULL");
506         ms_retm_if(media_type == NULL, "media_type is NULL");
507
508         _callbacks = (media_streamer_webrtc_callbacks_s *) webrtc_node->callbacks_structure;
509         if (!_callbacks->decoded_ready_cb.callback) {
510                 ms_warning("decoded_ready_cb.callback is NULL");
511                 return;
512         }
513
514         ms_debug("=====> invoke decoded ready callback(%p)", _callbacks->decoded_ready_cb.callback);
515         ((media_streamer_node_decoded_ready_cb)(_callbacks->decoded_ready_cb.callback))(webrtc_node,
516                                                                                                                                         (const char *)new_pad_name,
517                                                                                                                                         (const char *)media_type,
518                                                                                                                                         _callbacks->decoded_ready_cb.user_data);
519         ms_debug("<===== end of the callback");
520 }
521
522 static void __decodebin_pad_added_cb(GstElement *decodebin, GstPad *new_pad, gpointer user_data)
523 {
524         media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data;
525         const gchar *new_pad_name;
526         const gchar *media_type;
527         GstPad *src_pad = NULL;
528         const gchar *src_pad_name = NULL;
529
530         ms_retm_if(decodebin == NULL, "decodebin is NULL");
531         ms_retm_if(new_pad == NULL, "new_pad is NULL");
532         ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
533         ms_retm_if(GST_PAD_DIRECTION(new_pad) != GST_PAD_SRC, "new_pad is not for source");
534         ms_retm_if(gst_pad_has_current_caps(new_pad) == FALSE, "new_pad does not have caps");
535
536         media_type = gst_structure_get_name(gst_caps_get_structure(gst_pad_get_current_caps(new_pad), 0));
537         ms_debug("type is [%s]", media_type);
538
539         if (MS_ELEMENT_IS_VIDEO(media_type)) {
540                 src_pad_name = MS_RTP_PAD_VIDEO_OUT;
541         } else if (MS_ELEMENT_IS_AUDIO(media_type)) {
542                 src_pad_name = MS_RTP_PAD_AUDIO_OUT;
543         } else {
544                 ms_error("Not supported media type[%s]", media_type);
545                 return;
546         }
547
548         src_pad = gst_element_get_static_pad(webrtc_node->gst_element, src_pad_name);
549         if (!src_pad) {
550                 ms_error("Failed to get pad of %s", src_pad_name);
551                 return;
552         }
553         new_pad_name = GST_PAD_NAME(src_pad);
554
555         if (!gst_ghost_pad_set_target(GST_GHOST_PAD(src_pad), new_pad)) {
556                 ms_error("Failed to link %s:%s", src_pad_name, GST_PAD_NAME(new_pad));
557                 return;
558         }
559
560         ms_debug("new_pad_name[%s], media_type[%s]", new_pad_name, media_type);
561
562         __trigger_decoded_ready_callback(webrtc_node, new_pad_name, media_type);
563
564         gst_object_unref(src_pad);
565 }
566
567 void ms_webrtcbin_pad_added_cb(GstElement *webrtcbin, GstPad *new_pad, gpointer user_data)
568 {
569         media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data;
570         media_streamer_webrtc_callbacks_s *_callbacks;
571         GstPad *sink_pad = NULL;
572         GstElement *decodebin = NULL;
573
574         ms_retm_if(new_pad == NULL, "new_pad is NULL");
575         ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
576         ms_retm_if(webrtc_node->callbacks_structure == NULL, "callbacks_structure is NULL");
577         ms_retm_if(GST_PAD_DIRECTION(new_pad) != GST_PAD_SRC, "new_pad is not for source");
578
579         ms_debug_fenter();
580
581         ms_debug("Pad [%s] added on [%s]", GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(webrtcbin));
582
583         _callbacks = (media_streamer_webrtc_callbacks_s *) webrtc_node->callbacks_structure;
584         if (!_callbacks->decoded_ready_cb.callback) {
585                 ms_warning("decoded_ready_cb.callback is null, skip it");
586                 return;
587         }
588
589         decodebin = ms_element_create(DEFAULT_DECODEBIN, NULL);
590         ms_retm_if(decodebin == NULL, "decodebin is NULL");
591
592         ms_retm_if(webrtc_node->gst_element == NULL, "webrtc_container is NULL");
593         gst_bin_add(GST_BIN(webrtc_node->gst_element), decodebin);
594         gst_element_sync_state_with_parent(decodebin);
595
596         g_signal_connect(decodebin, "pad-added", G_CALLBACK(__decodebin_pad_added_cb), webrtc_node);
597         sink_pad = gst_element_get_static_pad(decodebin, "sink");
598         ms_retm_if(sink_pad == NULL, "sink_pad is NULL");
599
600         if (gst_pad_link(new_pad, sink_pad) != GST_PAD_LINK_OK)
601                 ms_error("Failed to link %s:%s", GST_PAD_NAME(new_pad), GST_PAD_NAME(sink_pad));
602
603         gst_object_unref(sink_pad);
604
605         ms_debug_fleave();
606 }
607
608 GstElement *ms_webrtc_element_create(void)
609 {
610         GstElement *webrtc_container;
611         GstElement *webrtcbin;
612
613         ms_debug_fenter();
614
615         webrtc_container = gst_bin_new("webrtc_container");
616         ms_retvm_if(!webrtc_container, (GstElement *) NULL, "Failed to create webrtc container");
617
618         ms_add_no_target_ghostpad(webrtc_container, MS_RTP_PAD_VIDEO_IN, GST_PAD_SINK);
619         ms_add_no_target_ghostpad(webrtc_container, MS_RTP_PAD_VIDEO_OUT, GST_PAD_SRC);
620         ms_add_no_target_ghostpad(webrtc_container, MS_RTP_PAD_AUDIO_IN, GST_PAD_SINK);
621         ms_add_no_target_ghostpad(webrtc_container, MS_RTP_PAD_AUDIO_OUT, GST_PAD_SRC);
622
623         MS_SET_INT_STATIC_STRING_PARAM(webrtc_container, MEDIA_STREAMER_PARAM_WEBRTC_PEER_TYPE, DEFAULT_WEBRTC_PEER);
624         MS_SET_INT_STATIC_STRING_PARAM(webrtc_container, MEDIA_STREAMER_PARAM_WEBRTC_STUN_SERVER, DEFAULT_WEBRTC_STUN_SERVER);
625         MS_SET_INT_STATIC_STRING_PARAM(webrtc_container, MEDIA_STREAMER_PARAM_WEBRTC_REMOTE_SESSION_DESCRIPTION, NULL);
626         MS_SET_INT_STATIC_STRING_PARAM(webrtc_container, MEDIA_STREAMER_PARAM_WEBRTC_ADD_ICE_CANDIDATE, NULL);
627
628         if (!(webrtcbin = ms_element_create("webrtcbin", NULL))) {
629                 ms_error("Failed to create webrtcbin element");
630                 return NULL;
631         }
632         g_object_set(G_OBJECT(webrtcbin), "stun-server", DEFAULT_WEBRTC_STUN_SERVER, NULL);
633         /* FIXME: should it be set by user? */
634         g_object_set(G_OBJECT(webrtcbin), "bundle-policy", 3, NULL); // 3:max-bundle
635         if (!ms_bin_add_element(webrtc_container, webrtcbin, FALSE)) {
636                 ms_error("Failed to add webrtcbin to webrtc_container");
637                 return NULL;
638         }
639
640         ms_debug_fleave();
641
642         return webrtc_container;
643 }