Add capsfilter after RTP payloader 06/244006/8
authorSangchul Lee <sc11.lee@samsung.com>
Fri, 11 Sep 2020 13:22:21 +0000 (22:22 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 24 Sep 2020 07:07:52 +0000 (16:07 +0900)
It is added to set detailed GstCaps to the source
which will be linked to webrtcbin.

__close_websocket() is revised in webrtc_test.

[Version] 0.1.21
[Issue Type] Improvement

Change-Id: I63bd4b3c60faff72600dcdc0974947528e697aa0
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/capi-media-webrtc.spec
src/webrtc_private.c
test/webrtc_test.c

index 29e450d910b0c49452d9fa21ff0d96754ae8977b..1d5a517fe9fe8c2f6ba7ae486a75cae9b7e7e520 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.1.20
+Version:    0.1.21
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 6d23d55329672ae5025102ab395583a073d872d7..47930ea6373c090dc038144850b87e146fa8cf1b 100644 (file)
 #define DEFAULT_AUDIO_CHANNELS            1
 #define DEFAULT_AUDIO_SAMPLERATE          8000
 
+typedef enum {
+       CODEC_TYPE_OPUS,
+       CODEC_TYPE_VORBIS,
+       CODEC_TYPE_VP8,
+       CODEC_TYPE_VP9,
+       CODEC_TYPE_THEORA,
+       CODEC_TYPE_H263,
+       CODEC_TYPE_H264,
+       CODEC_TYPE_H265,
+       CODEC_TYPE_NOT_SUPPORTED,
+} codec_type_e;
+
+typedef struct {
+       const char *encoding_name;
+       const int clock_rate;
+} payload_type_s;
+
+static payload_type_s payload_types[] = {
+       /* AUDIO */
+       [CODEC_TYPE_OPUS] = { "OPUS", 48000 },
+       [CODEC_TYPE_VORBIS] = { "VORBIS", -1 }, /* NOTE: -1 for various clock rate */
+       /* VIDEO */
+       [CODEC_TYPE_VP8] = { "VP8", 90000 },
+       [CODEC_TYPE_VP9] = { "VP9", 90000 },
+       [CODEC_TYPE_THEORA] = { "THEORA", 90000 },
+       [CODEC_TYPE_H263] = { "H263", 90000 },
+       [CODEC_TYPE_H264] = { "H264", 90000 },
+       [CODEC_TYPE_H265] = { "H265", 90000 },
+};
+
 #define CREATE_ELEMENT_FROM_REGISTRY(x_elem_info, x_klass_name, x_sink_caps, x_src_caps, x_element) \
 do { \
        x_elem_info.klass_name = x_klass_name; \
@@ -760,15 +790,18 @@ static GstCaps *__make_default_raw_caps(webrtc_media_source_type_e type)
        return caps;
 }
 
-static GstCaps *__make_default_encoded_caps(webrtc_media_source_type_e type)
+/* Use g_free() to free the media_type parameter. */
+static GstCaps *__make_default_encoded_caps(webrtc_media_source_type_e type, gchar **media_type)
 {
-       GstCaps *caps = NULL;
+       GstCaps *caps;
+       const char *_media_type;
 
        switch (type) {
        case WEBRTC_MEDIA_SOURCE_TYPE_CAMERA:
        case WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST:
                /* FIXME: get default value from ini */
-               caps = gst_caps_new_simple(DEFAULT_VIDEO_ENCODED_MEDIA_TYPE,
+               _media_type = DEFAULT_VIDEO_ENCODED_MEDIA_TYPE;
+               caps = gst_caps_new_simple(_media_type,
                                                "width", G_TYPE_INT, DEFAULT_VIDEO_WIDTH,
                                                "height", G_TYPE_INT, DEFAULT_VIDEO_HEIGHT,
                                                NULL);
@@ -777,6 +810,7 @@ static GstCaps *__make_default_encoded_caps(webrtc_media_source_type_e type)
        case WEBRTC_MEDIA_SOURCE_TYPE_MIC:
        case WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST:
                /* FIXME: get default value from ini */
+               _media_type = DEFAULT_AUDIO_ENCODED_MEDIA_TYPE;
                caps = gst_caps_new_simple(DEFAULT_AUDIO_ENCODED_MEDIA_TYPE,
                                                "channels", G_TYPE_INT, DEFAULT_AUDIO_CHANNELS,
                                                "rate", G_TYPE_INT, DEFAULT_AUDIO_SAMPLERATE,
@@ -785,9 +819,56 @@ static GstCaps *__make_default_encoded_caps(webrtc_media_source_type_e type)
 
        default:
                LOG_ERROR_IF_REACHED("type(%d)", type);
-               break;
+               return NULL;
        }
 
+       if (media_type)
+               *media_type = g_strdup(_media_type);
+
+       return caps;
+}
+
+static codec_type_e __get_codec_type(const gchar *media_type)
+{
+       if (!g_strcmp0(media_type, "audio/x-opus"))
+               return CODEC_TYPE_OPUS;
+       else if (!g_strcmp0(media_type, "audio/x-vorbis"))
+               return CODEC_TYPE_VORBIS;
+       else if (!g_strcmp0(media_type, "video/x-vp8"))
+               return CODEC_TYPE_VP8;
+       else if (!g_strcmp0(media_type, "video/x-vp9"))
+               return CODEC_TYPE_VP9;
+       else if (!g_strcmp0(media_type, "video/x-theora"))
+               return CODEC_TYPE_THEORA;
+       else if (!g_strcmp0(media_type, "video/x-h263"))
+               return CODEC_TYPE_H263;
+       else if (!g_strcmp0(media_type, "video/x-h264"))
+               return CODEC_TYPE_H264;
+       else if (!g_strcmp0(media_type, "video/x-h265"))
+               return CODEC_TYPE_H265;
+       else
+               return CODEC_TYPE_NOT_SUPPORTED;
+}
+
+static GstCaps *__make_rtp_caps(const gchar *media_type)
+{
+       gchar *caps_str;
+       GstCaps *caps;
+       codec_type_e codec_type = __get_codec_type(media_type);
+
+       RET_VAL_IF(codec_type == CODEC_TYPE_NOT_SUPPORTED, NULL, "media_type[%s] is not supported", media_type);
+
+       caps = gst_caps_new_simple("application/x-rtp",
+                               "media", G_TYPE_STRING, g_strrstr(media_type, "video") ? "video" : "audio",
+                               "clock-rate", G_TYPE_INT, payload_types[codec_type].clock_rate, /* FIXME: support various clock-rate */
+                               "encoding-name", G_TYPE_STRING, payload_types[codec_type].encoding_name,
+                               "payload", G_TYPE_INT, 96, NULL); /* FIXME: payload identifier should be assigned dynamically */
+
+       caps_str = gst_caps_to_string(caps);
+       LOG_DEBUG("RTP caps is created [%s]", caps_str);
+
+       g_free(caps_str);
+
        return caps;
 }
 
@@ -816,16 +897,18 @@ static int __set_ghost_pad_target(GstPad *ghost_pad, GstElement *target_element,
        return WEBRTC_ERROR_NONE;
 }
 
-static int __create_rest_of_elements(webrtc_media_source_type_e type, GstElement **capsfilter, GstElement **encoder, GstElement **payloader, GstElement **queue)
+static int __create_rest_of_elements(webrtc_media_source_type_e type, GstElement **capsfilter, GstElement **encoder, GstElement **payloader, GstElement **queue, GstElement **capsfilter2)
 {
        GstCaps *sink_caps;
        element_info_s elem_info;
        const gchar *encoder_klass_name;
+       gchar *media_type;
 
        RET_VAL_IF(capsfilter == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "capsfilter is NULL");
        RET_VAL_IF(encoder == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "encoder is NULL");
        RET_VAL_IF(payloader == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payloader is NULL");
        RET_VAL_IF(queue == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "queue is NULL");
+       RET_VAL_IF(capsfilter2 == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "capsfilter2 is NULL");
 
        if (!(*capsfilter = __create_element(DEFAULT_ELEMENT_CAPSFILTER, NULL))) {
                LOG_ERROR("failed to create capsfilter");
@@ -843,18 +926,31 @@ static int __create_rest_of_elements(webrtc_media_source_type_e type, GstElement
 
        CREATE_ELEMENT_FROM_REGISTRY(elem_info, encoder_klass_name,
                                                __make_default_raw_caps(type),
-                                               __make_default_encoded_caps(type),
+                                               __make_default_encoded_caps(type, NULL),
                                                *encoder);
 
        CREATE_ELEMENT_FROM_REGISTRY(elem_info, GST_KLASS_NAME_PAYLOADER_RTP,
-                                               __make_default_encoded_caps(type),
+                                               __make_default_encoded_caps(type, &media_type),
                                                NULL,
                                                *payloader);
 
        if (!(*queue = __create_element(DEFAULT_ELEMENT_QUEUE, NULL))) {
                LOG_ERROR("failed to create queue");
+               g_free(media_type);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       if (!(*capsfilter2 = __create_element(DEFAULT_ELEMENT_CAPSFILTER, NULL))) {
+               LOG_ERROR("failed to create capsfilter");
+               g_free(media_type);
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
+       if ((sink_caps = __make_rtp_caps(media_type))) {
+               g_object_set(G_OBJECT(*capsfilter2), "caps", sink_caps, NULL);
+               gst_caps_unref(sink_caps);
+       }
+
+       g_free(media_type);
 
        return WEBRTC_ERROR_NONE;
 }
@@ -867,6 +963,7 @@ static int __build_camerasrc(GstElement *bin, webrtc_media_source_type_e type, G
        GstElement *videoenc;
        GstElement *videopay;
        GstElement *queue;
+       GstElement *capsfilter2;
 
        RET_VAL_IF(bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
        RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL");
@@ -878,16 +975,16 @@ static int __build_camerasrc(GstElement *bin, webrtc_media_source_type_e type, G
        }
        /* FIXME: set camera default setting from ini */
 
-       if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE)
                return ret;
 
-       gst_bin_add_many(GST_BIN(bin), camerasrc, capsfilter, videoenc, videopay, queue, NULL);
-       if (!gst_element_link_many(camerasrc, capsfilter, videoenc, videopay, queue, NULL)) {
+       gst_bin_add_many(GST_BIN(bin), camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
+       if (!gst_element_link_many(camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) {
                LOG_ERROR("failed to gst_element_link_many()");
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
-       return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+       return __set_ghost_pad_target(ghost_src_pad, capsfilter2, TRUE);
 }
 
 static int __build_audiosrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
@@ -898,6 +995,7 @@ static int __build_audiosrc(GstElement *bin, webrtc_media_source_type_e type, Gs
        GstElement *audioenc;
        GstElement *audiopay;
        GstElement *queue;
+       GstElement *capsfilter2;
 
        RET_VAL_IF(bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
        RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL");
@@ -907,16 +1005,16 @@ static int __build_audiosrc(GstElement *bin, webrtc_media_source_type_e type, Gs
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
-       if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE)
                return ret;
 
-       gst_bin_add_many(GST_BIN(bin), audiosrc, capsfilter, audioenc, audiopay, queue, NULL);
-       if (!gst_element_link_many(audiosrc, capsfilter, audioenc, audiopay, queue, NULL)) {
+       gst_bin_add_many(GST_BIN(bin), audiosrc, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL);
+       if (!gst_element_link_many(audiosrc, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL)) {
                LOG_ERROR("failed to gst_element_link_many()");
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
-       return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+       return __set_ghost_pad_target(ghost_src_pad, capsfilter2, TRUE);
 }
 
 static int __build_videotestsrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
@@ -927,6 +1025,7 @@ static int __build_videotestsrc(GstElement *bin, webrtc_media_source_type_e type
        GstElement *videoenc;
        GstElement *videopay;
        GstElement *queue;
+       GstElement *capsfilter2;
 
        RET_VAL_IF(bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
        RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL");
@@ -937,16 +1036,16 @@ static int __build_videotestsrc(GstElement *bin, webrtc_media_source_type_e type
        }
        g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, NULL);
 
-       if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE)
                return ret;
 
-       gst_bin_add_many(GST_BIN(bin), videotestsrc, capsfilter, videoenc, videopay, queue, NULL);
-       if (!gst_element_link_many(videotestsrc, capsfilter, videoenc, videopay, queue, NULL)) {
+       gst_bin_add_many(GST_BIN(bin), videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
+       if (!gst_element_link_many(videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) {
                LOG_ERROR("failed to gst_element_link_many()");
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
-       return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+       return __set_ghost_pad_target(ghost_src_pad, capsfilter2, TRUE);
 }
 
 static int __build_audiotestsrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
@@ -957,6 +1056,7 @@ static int __build_audiotestsrc(GstElement *bin, webrtc_media_source_type_e type
        GstElement *audioenc;
        GstElement *audiopay;
        GstElement *queue;
+       GstElement *capsfilter2;
 
        RET_VAL_IF(bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
        RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL");
@@ -967,16 +1067,16 @@ static int __build_audiotestsrc(GstElement *bin, webrtc_media_source_type_e type
        }
        g_object_set(G_OBJECT(audiotestsrc), "is-live", TRUE, NULL);
 
-       if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE)
                return ret;
 
-       gst_bin_add_many(GST_BIN(bin), audiotestsrc, capsfilter, audioenc, audiopay, queue, NULL);
-       if (!gst_element_link_many(audiotestsrc, capsfilter, audioenc, audiopay, queue, NULL)) {
+       gst_bin_add_many(GST_BIN(bin), audiotestsrc, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL);
+       if (!gst_element_link_many(audiotestsrc, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL)) {
                LOG_ERROR("failed to gst_element_link_many()");
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
-       return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+       return __set_ghost_pad_target(ghost_src_pad, capsfilter2, TRUE);
 }
 
 static GstPad* __add_no_target_ghostpad(GstElement *bin, const char *pad_name)
index ab680e4bd4c073a28f029858f4296815eeaebd36..ec68a090b6a5a9d9f72d8350958823ff181b81d7 100644 (file)
@@ -571,16 +571,13 @@ static void _send_local_description(char *desc)
        soup_websocket_connection_send_text(g_ws_conn, desc);
 }
 
-static void __close_websocket(SoupWebsocketConnection *conn, const gchar *message)
+static void __close_websocket(SoupWebsocketConnection *conn)
 {
        if (!conn) {
                g_printerr("conn is NULL\n");
                return;
        }
 
-       if (message)
-               g_printerr("%s\n", message);
-
        if (soup_websocket_connection_get_state(conn) == SOUP_WEBSOCKET_STATE_OPEN)
                soup_websocket_connection_close(conn, 1000, "");
        else
@@ -593,7 +590,7 @@ static void __close_websocket(SoupWebsocketConnection *conn, const gchar *messag
 static void __websocket_closed_cb(SoupWebsocketConnection *conn, gpointer user_data)
 {
        g_print("[%s] is closed\n", g_signaling_server);
-       __close_websocket(conn, "websocket connection closed");
+       __close_websocket(conn);
 }
 
 static void __handle_json_structured_message(const gchar *text)
@@ -705,8 +702,8 @@ static void __websocket_connected_cb(SoupSession *session, GAsyncResult *res, So
        g_print("\n[%s] is connected\n", g_signaling_server);
        ws_conn = soup_session_websocket_connect_finish(session, res, &error);
        if (error) {
-               __close_websocket(ws_conn, error->message);
-               g_print("failed to soup_session_websocket_connect_finish()\n");
+               __close_websocket(ws_conn);
+               g_print("failed to soup_session_websocket_connect_finish(), error[%s]\n", error->message);
                g_error_free(error);
                return;
        }