Improve media_streamer_node_set_pad_format() for WebRTC node 01/236101/14
authorSangchul Lee <sc11.lee@samsung.com>
Mon, 15 Jun 2020 01:49:26 +0000 (10:49 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Tue, 16 Jun 2020 07:45:35 +0000 (16:45 +0900)
The previous codes can not propagate the pad event because the
pipeline status is not satisfied with the condition to set the
pad format normally. To fix it, a capsfilter element is added
in the creation time of WebRTC node and set new caps to its
property.

A ghost pad for the audio input is newly added to WebRTC node.

[Version] 0.1.63
[Issue Type] Bug fix

Change-Id: I624bca9c0c4376d38587f0dd49e94c6f7e90ee6a
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/capi-media-streamer.spec
src/media_streamer_gst_webrtc.c
src/media_streamer_node.c

index ef8ad8b..ae2c48b 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-streamer
 Summary:    A Media Streamer API
-Version:    0.1.62
+Version:    0.1.63
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index dc354de..4c5da00 100644 (file)
@@ -630,7 +630,6 @@ GstElement *ms_webrtc_element_create(void)
 {
        GstElement *webrtc_container;
        GstElement *webrtcbin;
-       GstGhostPad *ghost_pad_video_in;
 
        ms_debug_fenter();
 
@@ -651,22 +650,11 @@ GstElement *ms_webrtc_element_create(void)
                ms_error("Failed to create webrtcbin element");
                return NULL;
        }
-
        g_object_set(G_OBJECT(webrtcbin), "stun-server", DEFAULT_WEBRTC_STUN_SERVER, NULL);
-
        /* FIXME: should it be set by user? */
        g_object_set(G_OBJECT(webrtcbin), "bundle-policy", 3, NULL); // 3:max-bundle
-
-       ms_bin_add_element(webrtc_container, webrtcbin, FALSE);
-
-       if (!(ghost_pad_video_in = (GstGhostPad *)gst_element_get_static_pad(webrtc_container, MS_RTP_PAD_VIDEO_IN))) {
-               ms_error("Failed to get ghost pad for webrtc_container");
-               return NULL;
-       }
-
-       if (!(gst_ghost_pad_set_target(ghost_pad_video_in, gst_element_get_request_pad(webrtcbin, "sink_%u")))) {
-               ms_info("Failed to gst_ghost_pad_set_target() for %s", MS_RTP_PAD_VIDEO_IN);
-               /* release resources */
+       if (!ms_bin_add_element(webrtc_container, webrtcbin, FALSE)) {
+               ms_error("Failed to add webrtcbin to webrtc_container");
                return NULL;
        }
 
index 53f4c37..ad8fa4e 100644 (file)
@@ -34,6 +34,9 @@
 #define _FEATURE_NAME_CAMERA             "http://tizen.org/feature/camera"
 #define _FEATURE_NAME_MICROPHONE         "http://tizen.org/feature/microphone"
 
+#define _WEBRTC_AUDIO_CAPSFILTER         "audio_capsfilter"
+#define _WEBRTC_VIDEO_CAPSFILTER         "video_capsfilter"
+
 static param_s param_table[] = {
        {MEDIA_STREAMER_PARAM_CAMERA_ID, "camera-id"},
        {MEDIA_STREAMER_PARAM_CAPTURE_WIDTH, "capture-width"},
@@ -1519,8 +1522,74 @@ int ms_rtp_node_prepare(media_streamer_node_s *node)
        return MEDIA_STREAMER_ERROR_NONE;
 }
 
+static int __ms_webrtc_prepare_ghost_sink_pad(GstElement *webrtc_container, GstElement *webrtcbin, const char *capsfilter_name)
+{
+       int ret = MEDIA_STREAMER_ERROR_NONE;
+       GstElement *filter;
+       GstGhostPad *ghost_pad_in = NULL;
+       GstPad *filter_sink_pad = NULL;
+       GstPad *req_pad;
+       gchar *req_pad_name;
+       const gchar *pad_name;
+
+       ms_retvm_if(!webrtc_container, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_container is NULL");
+       ms_retvm_if(!webrtcbin, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtcbin is NULL");
+       ms_retvm_if(!capsfilter_name, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "capsfilter_name is NULL");
+
+       if (g_strcmp0(capsfilter_name, _WEBRTC_AUDIO_CAPSFILTER) &&
+               g_strcmp0(capsfilter_name, _WEBRTC_VIDEO_CAPSFILTER))
+               return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
+
+       pad_name = !g_strcmp0(capsfilter_name, _WEBRTC_AUDIO_CAPSFILTER) ? MS_RTP_PAD_AUDIO_IN : MS_RTP_PAD_VIDEO_IN;
+
+       if (!(filter = ms_find_element_in_bin_by_name(webrtc_container, capsfilter_name))) {
+               ms_debug("No need to export the ghost sink pad for [%s]", pad_name);
+               return MEDIA_STREAMER_ERROR_NONE;
+       }
+
+       ms_info("%s is found, link it with webrtcbin and export the ghost pad[%s] of webrtc_container",
+                       capsfilter_name, pad_name);
+
+       if (!(req_pad = gst_element_get_request_pad(webrtcbin, "sink_%u"))) {
+               ms_error("Failed to get request pad");
+               return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+       }
+       if (!(req_pad_name = gst_pad_get_name(req_pad))) {
+               ms_error("Failed to get request pad name");
+               return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+       }
+       if (!gst_element_link_pads(filter, "src", webrtcbin, req_pad_name)) {
+               ms_error("Failed to link pads, %s - webrtcbin", capsfilter_name);
+               ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+               goto end;
+       }
+       if (!(ghost_pad_in = (GstGhostPad *)gst_element_get_static_pad(webrtc_container, pad_name))) {
+               ms_error("Failed to get ghost pad for webrtc_container");
+               ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+               goto end;
+       }
+       if (!(filter_sink_pad = gst_element_get_static_pad(filter, "sink"))) {
+               ms_error("Failed to get capsfilter sink pad in webrtc_container");
+               ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+               goto end;
+       }
+       if (!gst_ghost_pad_set_target(ghost_pad_in, filter_sink_pad)) {
+               ms_info("Failed to gst_ghost_pad_set_target() for %s", pad_name);
+               ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+               goto end;
+       }
+
+end:
+       MS_SAFE_GFREE(req_pad_name);
+       MS_SAFE_UNREF(filter_sink_pad);
+       MS_SAFE_UNREF(ghost_pad_in);
+
+       return ret;
+}
+
 int ms_webrtc_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s *node)
 {
+       int ret = MEDIA_STREAMER_ERROR_NONE;
        GstElement *webrtcbin = NULL;
        node_info_s *node_klass_type = NULL;
        GObject *send_channel = NULL;
@@ -1545,6 +1614,11 @@ int ms_webrtc_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s
                return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
        }
 
+       if ((ret = __ms_webrtc_prepare_ghost_sink_pad(node->gst_element, webrtcbin, _WEBRTC_AUDIO_CAPSFILTER)))
+               return ret;
+       if ((ret = __ms_webrtc_prepare_ghost_sink_pad(node->gst_element, webrtcbin, _WEBRTC_VIDEO_CAPSFILTER)))
+               return ret;
+
        if (__ms_webrtc_node_is_offerer(node, &is_offerer)) {
                ms_error("Failed to get peer type");
                return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
@@ -1576,7 +1650,6 @@ int ms_webrtc_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s
 
        return MEDIA_STREAMER_ERROR_NONE;
 }
-
 //LCOV_EXCL_STOP
 
 int ms_demux_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s *node)
@@ -1928,6 +2001,75 @@ static int __ms_rtp_node_set_pad_format(media_streamer_node_s *node, const char
        return ret;
 }
 
+static int __ms_webrtc_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, media_format_h fmt)
+{
+       int ret = MEDIA_STREAMER_ERROR_NONE;
+       media_format_mimetype_e mime;
+       const gchar *encoding_name = NULL;
+       const gchar *capsfilter_name = NULL;
+       gchar *caps_str = NULL;
+       gchar *media = NULL;
+       gint payload = 0;
+       GstCaps *caps = NULL;
+       GstElement *capsfilter = NULL;
+
+       ms_retvm_if(node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL");
+       ms_retvm_if(node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node's element is NULL");
+       ms_retvm_if(pad_name == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "pad_name is NULL");
+       ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "fmt is NULL");
+
+       ms_debug_fenter();
+
+       if (!g_strrstr(pad_name, MS_RTP_PAD_VIDEO_IN) && !g_strrstr(pad_name, MS_RTP_PAD_AUDIO_IN)) {
+               ms_error("Not supported pad_name(%s)", pad_name);
+               return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
+       }
+
+       if (g_strrstr(pad_name, MS_RTP_PAD_VIDEO_IN) &&
+               !media_format_get_video_info(fmt, &mime, NULL, NULL, NULL, NULL)) {
+               media = "video";
+               payload = 96;
+               capsfilter_name = _WEBRTC_VIDEO_CAPSFILTER;
+       } else if (g_strrstr(pad_name, MS_RTP_PAD_AUDIO_IN) &&
+               !media_format_get_audio_info(fmt, &mime, NULL, NULL, NULL, NULL)) {
+               media = "audio";
+               payload = 97;
+               capsfilter_name = _WEBRTC_AUDIO_CAPSFILTER;
+       } else {
+               ms_error("Invalid media format for pad_name(%s)", pad_name);
+               return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
+       }
+
+       encoding_name = ms_convert_mime_to_rtp_format(mime);
+       caps = gst_caps_new_simple("application/x-rtp",
+                                                               "media", G_TYPE_STRING, media,
+                                                               "encoding-name", G_TYPE_STRING, encoding_name,
+                                                               "payload", G_TYPE_INT, payload, NULL);
+
+       if (!(capsfilter = ms_find_element_in_bin_by_name(node->gst_element, capsfilter_name))) {
+               ms_debug("Create %s", capsfilter_name);
+
+               if (!(capsfilter = ms_element_create("capsfilter", capsfilter_name))) {
+                       ms_error("Failed to create capsfilter element: %s", capsfilter_name);
+                       return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+               }
+               if (!ms_bin_add_element(node->gst_element, capsfilter, FALSE)) {
+                       ms_error("Failed to add capsfilter(%s) to webrtc_container", capsfilter_name);
+                       return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+               }
+       }
+
+       g_object_set(G_OBJECT(capsfilter), "caps", (GValue *)caps, NULL);
+
+       caps_str = gst_caps_to_string(caps);
+       ms_info("[%s] is set to [%s]", caps_str, capsfilter_name);
+       MS_SAFE_GFREE(caps_str);
+
+       gst_caps_unref(caps);
+
+       return ret;
+}
+
 int ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, media_format_h fmt)
 {
        int ret = MEDIA_STREAMER_ERROR_NONE;
@@ -1942,7 +2084,7 @@ int ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, me
        if (node->type == MEDIA_STREAMER_NODE_TYPE_RTP)
                ret = __ms_rtp_node_set_pad_format(node, pad_name, fmt);
        else if (node->type == MEDIA_STREAMER_NODE_TYPE_WEBRTC)
-               ret = ms_webrtcbin_set_pad_format(node->gst_element, pad_name, fmt);
+               ret = __ms_webrtc_node_set_pad_format(node, pad_name, fmt);
        else
                ret = ms_element_set_fmt(node->gst_element, pad_name, fmt);