Add new param for setting remote session description and ICE candidiate for WebRTC... 01/235501/20
authorHyunil <hyunil46.park@samsung.com>
Fri, 5 Jun 2020 05:48:15 +0000 (14:48 +0900)
committerHyunil <hyunil46.park@samsung.com>
Tue, 9 Jun 2020 05:57:06 +0000 (14:57 +0900)
- add MEDIA_STREAMER_PARAM_WEBRTC_REMOTE_SESSION_DESCRIPTION
- add MEDIA_STREAMER_PARAM_WEBRTC_ADD_ICE_CANDIDATE

Add internal APIs to set remote session description and ICE candidate to WebRTC node

- int ms_webrtcbin_set_remote_session_description(media_streamer_node_s *node, const char *sdp_msg)
- int ms_webrtcbin_add_ice_candidate(media_streamer_node_s *node, const char *ice_msg)

[Version] 0.1.54
[Issue Type] New feature

Change-Id: I5a1a66a61dcb511cebf62628d3bb8217912bc8cd
Signed-off-by: Hyunil <hyunil46.park@samsung.com>
include/media_streamer.h
include/media_streamer_gst_webrtc.h
include/media_streamer_node.h
include/media_streamer_util.h
packaging/capi-media-streamer.spec
src/media_streamer_gst_webrtc.c
src/media_streamer_node.c
src/media_streamer_util.c

index f686645..3f11575 100644 (file)
@@ -303,6 +303,22 @@ typedef enum {
 #define MEDIA_STREAMER_PARAM_WEBRTC_PEER_TYPE "webrtc-peer-type"
 
 /**
+ * @brief Definition for remote session description.
+ * @details Value of the session description of the remote peer over its signaling channel
+ *          Data type is string.
+ * @since_tizen 6.0
+ * @see media_streamer_node_get_params() */
+#define MEDIA_STREAMER_PARAM_WEBRTC_REMOTE_SESSION_DESCRIPTION "webrtc-remote-session-description"
+
+/**
+ * @brief Definition for ICE candidate of WebRTC node.
+ * @details Value of ICE candidate of the remote peer over its signaling channel
+ *          Data type is string.
+ * @since_tizen 6.0
+ * @see media_streamer_node_get_params() */
+#define MEDIA_STREAMER_PARAM_WEBRTC_ADD_ICE_CANDIDATE "webrtc-add-ice-candidate"
+
+/**
  * @brief Definition for audio device name parameter of source or sink node.
  * @details ALSA device, as defined in an asound configuration file.
  *          ex) "hw:0,0", "hw:0,1"
index 0b89f50..6f1fe74 100644 (file)
@@ -40,6 +40,11 @@ void ms_webrtcbin_on_negotiation_needed_cb(GstElement *webrtcbin, gpointer user_
 
 void ms_webrtcbin_on_negotiation_process_answer(GstElement *webrtcbin, media_streamer_node_s *webrtc_node);
 
+int ms_webrtcbin_set_remote_session_description(media_streamer_node_s *node, const char *sdp_msg);
+
+int ms_webrtcbin_add_ice_candidate(media_streamer_node_s *node, const char *ice_msg);
+
+
 #ifdef __cplusplus
 }
 #endif
index 071cae9..b93bfd1 100644 (file)
@@ -123,7 +123,6 @@ gboolean ms_src_node_prepare_iter(const GValue *item, GValue *g_ret, gpointer us
 gboolean ms_node_resources_acquire_iter(const GValue *item, GValue *ret, gpointer user_data);
 gboolean ms_node_resources_release_iter(const GValue *item, GValue *ret, gpointer user_data);
 gboolean ms_node_dpm_policy_check_iter(const GValue *item, GValue *ret, gpointer user_data);
-
 #ifdef __cplusplus
 }
 #endif
index 910283c..bbfe35d 100644 (file)
@@ -312,8 +312,8 @@ int ms_util_uri_path_check(const char *file_uri);
 /* Use g_free() to free the return value. */
 gchar* ms_get_string_from_json_object(JsonObject *object);
 
-/* Use g_free() to free the sdp parameter. */
-int ms_webrtc_get_sdp_from_message(const char *sdp_msg, gchar **sdp);
+/* Use g_free() to free the sdp and type parameter. */
+int ms_webrtc_get_sdp_from_message(const char *sdp_msg, gchar **sdp, gchar **type);
 
 /* Use g_free() to free the candidate parameter. */
 int ms_webrtc_get_ice_candidate_from_message(const char *ice_msg, gchar **candidate, gint *mlineindex);
index 40ef7b7..b5fa0e0 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-streamer
 Summary:    A Media Streamer API
-Version:    0.1.53
+Version:    0.1.54
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 371ec64..f19b0a8 100644 (file)
 #include "media_streamer_gst_webrtc.h"
 #include "media_streamer_node.h"
 
+static gchar *__make_ice_candidate_message(guint mlineindex, gchar *candidate)
+{
+       JsonObject *ice, *msg;
+       gchar *text;
+
+       ms_retvm_if(candidate == NULL, NULL, "candidate is NULL");
+
+       ice = json_object_new();
+       json_object_set_string_member(ice, "candidate", candidate);
+       json_object_set_int_member(ice, "sdpMLineIndex", mlineindex);
+
+       msg = json_object_new();
+       json_object_set_object_member(msg, "ice", ice);
+
+       text = ms_get_string_from_json_object(msg);
+
+       json_object_unref(msg);
+
+       return text;
+}
+
 static gchar* __make_sdp_message(GstWebRTCSessionDescription *desc)
 {
        gchar *text;
@@ -71,9 +92,25 @@ static void __trigger_message_callback(media_streamer_node_s *webrtc_node, gchar
        }
 }
 
-static void __on_answer_created_cb(GstPromise *promise, gpointer user_data)
+static void __ms_webrtcbin_set_session_description(GstElement *webrtcbin, GstWebRTCSessionDescription *session_description, gboolean is_remote)
 {
-       GstWebRTCSessionDescription *answer = NULL;
+       GstPromise *promise;
+       ms_retm_if(session_description == NULL, "session_description is NULL");
+       ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL");
+
+       ms_debug_fenter();
+
+       promise = gst_promise_new();
+       g_signal_emit_by_name(webrtcbin, is_remote? "set-remote-description" : "set-local-description", session_description, promise);
+       gst_promise_interrupt(promise);
+       gst_promise_unref(promise);
+
+       ms_debug_fleave();
+}
+
+static void __on_offer_created_cb(GstPromise *promise, gpointer user_data)
+{
+       GstWebRTCSessionDescription *offer = NULL;
        const GstStructure *reply;
        media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data;
        node_info_s *node_klass_type = NULL;
@@ -93,74 +130,161 @@ static void __on_answer_created_cb(GstPromise *promise, gpointer user_data)
        }
 
        reply = gst_promise_get_reply(promise);
-       gst_structure_get(reply, "answer",
-               GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL);
-       gst_promise_unref(promise);
-
-       promise = gst_promise_new();
-       g_signal_emit_by_name(G_OBJECT(webrtcbin), "set-local-description", answer, promise);
-       gst_promise_interrupt(promise);
+       gst_structure_get(reply, "offer",
+               GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
        gst_promise_unref(promise);
 
-       sdp_msg = __make_sdp_message(answer);
+       __ms_webrtcbin_set_session_description(webrtcbin, offer, FALSE);
 
-       /* TODO: need to add to send this message to signalling server */
-       ms_debug("SDP message is sent: %s", sdp_msg);
+       sdp_msg = __make_sdp_message(offer);
+       gst_webrtc_session_description_free(offer);
 
+       /* Send local description to peer */
+       __trigger_message_callback(webrtc_node, sdp_msg);
        g_free(sdp_msg);
 
-       gst_webrtc_session_description_free(answer);
-
        ms_debug_fleave();
 }
 
-static void __on_offer_created_cb(GstPromise *promise, gpointer user_data)
+static void __on_answer_created_cb(GstPromise * promise, gpointer user_data)
 {
-       GstWebRTCSessionDescription *offer = NULL;
+       GstWebRTCSessionDescription *answer = NULL;
        const GstStructure *reply;
-       media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data;
+       media_streamer_node_s *node = (media_streamer_node_s *)user_data;
        node_info_s *node_klass_type = NULL;
-       GstElement *webrtcbin = NULL;
        gchar *sdp_msg;
+       GstElement *webrtcbin;
 
        ms_retm_if(promise == NULL, "promise is NULL");
-       ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
+       ms_retm_if(node == NULL, "node is NULL");
+       ms_retm_if(node->gst_element == NULL, "webrtc_container is NULL");
        ms_retm_if(gst_promise_wait(promise) != GST_PROMISE_RESULT_REPLIED, "promise is not for replied result");
 
        ms_debug_fenter();
 
        node_klass_type = ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_WEBRTC);
-       if (!(webrtcbin = ms_find_element_in_bin_by_type(webrtc_node->gst_element, node_klass_type))) {
+       if (!(webrtcbin = ms_find_element_in_bin_by_type(node->gst_element, node_klass_type))) {
                ms_error("Could not find webrtcbin by type[%s, %s]", node_klass_type->klass_name, node_klass_type->default_name);
                return;
        }
 
        reply = gst_promise_get_reply(promise);
-       gst_structure_get(reply, "offer",
-               GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &offer, NULL);
-       gst_promise_unref(promise);
-
-       promise = gst_promise_new();
-       g_signal_emit_by_name(G_OBJECT(webrtcbin), "set-local-description", offer, promise);
-       gst_promise_interrupt(promise);
+       gst_structure_get(reply, "answer", GST_TYPE_WEBRTC_SESSION_DESCRIPTION, &answer, NULL);
        gst_promise_unref(promise);
 
-       sdp_msg = __make_sdp_message(offer);
+       __ms_webrtcbin_set_session_description(webrtcbin, answer, FALSE);
 
-       __trigger_message_callback(webrtc_node, sdp_msg);
+       sdp_msg = __make_sdp_message(answer);
+       gst_webrtc_session_description_free(answer);
 
+       /* Send local description to peer */
+       __trigger_message_callback(node, sdp_msg);
        g_free(sdp_msg);
-       gst_webrtc_session_description_free(offer);
 
        ms_debug_fleave();
 }
 
+int ms_webrtcbin_set_remote_session_description(media_streamer_node_s *node, const char *sdp_msg)
+{
+       GstSDPMessage *gst_sdp;
+       gchar *sdp;
+       gchar *type;
+       GstWebRTCSessionDescription *answer, *offer;
+       node_info_s *node_klass_type;
+       GstElement *webrtcbin;
+       int ret = MEDIA_STREAMER_ERROR_NONE;
+
+       ms_retvm_if(node == NULL || node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error: empty webrtcbin");
+       ms_retvm_if(sdp_msg == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "sdp_msg is NULL");
+
+       ms_debug_fenter();
+
+
+       node_klass_type = ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_WEBRTC);
+       if (!(webrtcbin = ms_find_element_in_bin_by_type(node->gst_element, node_klass_type))) {
+               ms_error("Could not find webrtcbin by type[%s, %s]", node_klass_type->klass_name, node_klass_type->default_name);
+               return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+       }
+
+       ret = ms_webrtc_get_sdp_from_message(sdp_msg, &sdp, &type);
+       if (ret != MEDIA_STREAMER_ERROR_NONE)
+               goto end;
+
+       ret = gst_sdp_message_new(&gst_sdp);
+       if (ret != GST_SDP_OK) {
+               ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+               goto end;
+       }
+
+       ret = gst_sdp_message_parse_buffer((guint8 *)sdp, strlen(sdp), gst_sdp);
+       if (ret != GST_SDP_OK) {
+               ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+               goto end;
+       }
+
+       if (g_str_equal(type, "answer")) {
+               answer = gst_webrtc_session_description_new(GST_WEBRTC_SDP_TYPE_ANSWER, gst_sdp);
+               g_assert_nonnull(answer);
+
+               __ms_webrtcbin_set_session_description(webrtcbin, answer, TRUE);
+               gst_webrtc_session_description_free(answer);
+       } else if (g_str_equal(type, "offer")) {
+               offer = gst_webrtc_session_description_new(GST_WEBRTC_SDP_TYPE_OFFER, gst_sdp);
+               g_assert_nonnull(offer);
+
+               __ms_webrtcbin_set_session_description(webrtcbin, offer, TRUE);
+               gst_webrtc_session_description_free(offer);
+
+               ms_webrtcbin_on_negotiation_process_answer(webrtcbin, node);
+       } else {
+               ms_error("type is %s, it is not a answer or offer", type);
+       }
+
+end:
+       MS_SAFE_GFREE(sdp);
+       MS_SAFE_GFREE(type);
+
+       ms_debug_fleave();
+
+       return ret;
+}
+
+int ms_webrtcbin_add_ice_candidate(media_streamer_node_s *node, const char *ice_msg)
+{
+       gchar *candidate;
+       gint sdpmlineindex;
+       node_info_s *node_klass_type;
+       GstElement *webrtcbin;
+       int ret;
+
+       ms_retvm_if(node == NULL || node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error: empty webrtcbin");
+       ms_retvm_if(ice_msg == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ice_msg is NULL");
+
+       ms_debug_fenter();
+
+       node_klass_type = ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_WEBRTC);
+       if (!(webrtcbin = ms_find_element_in_bin_by_type(node->gst_element, node_klass_type))) {
+               ms_error("Could not find webrtcbin by type[%s, %s]", node_klass_type->klass_name, node_klass_type->default_name);
+               return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
+       }
+
+       ret = ms_webrtc_get_ice_candidate_from_message(ice_msg, &candidate, &sdpmlineindex);
+       if (ret != MEDIA_STREAMER_ERROR_NONE)
+               return ret;
+
+       /*Add ice candidate sent by remote peer */
+       g_signal_emit_by_name(webrtcbin, "add-ice-candidate", sdpmlineindex, candidate);
+
+       g_free(candidate);
+
+       return MEDIA_STREAMER_ERROR_NONE;
+}
+
 void ms_webrtcbin_on_negotiation_process_answer(GstElement *webrtcbin, media_streamer_node_s *webrtc_node)
 {
        GstPromise *promise;
 
        ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL");
-       ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL");
 
        ms_debug_fenter();
 
@@ -185,27 +309,6 @@ void ms_webrtcbin_on_negotiation_needed_cb(GstElement *webrtcbin, gpointer user_
        ms_debug_fleave();
 }
 
-static gchar *__make_ice_candidate_message(guint mlineindex, gchar *candidate)
-{
-       JsonObject *ice, *msg;
-       gchar *text;
-
-       ms_retvm_if(candidate == NULL, NULL, "candidate is NULL");
-
-       ice = json_object_new();
-       json_object_set_string_member(ice, "candidate", candidate);
-       json_object_set_int_member(ice, "sdpMLineIndex", mlineindex);
-
-       msg = json_object_new();
-       json_object_set_object_member(msg, "ice", ice);
-
-       text = ms_get_string_from_json_object(msg);
-
-       json_object_unref(msg);
-
-       return text;
-}
-
 void ms_webrtcbin_on_ice_candidate_cb(GstElement *webrtcbin, guint mlineindex, gchar *candidate, gpointer user_data)
 {
        gchar *ice_candidate_msg = NULL;
@@ -345,6 +448,8 @@ GstElement *ms_webrtc_element_create(void)
        ms_add_no_target_ghostpad(webrtc_container, MS_RTP_PAD_VIDEO_IN, GST_PAD_SINK);
 
        MS_SET_INT_STATIC_STRING_PARAM(webrtc_container, MEDIA_STREAMER_PARAM_WEBRTC_PEER_TYPE, DEFAULT_WEBRTC_PEER);
+       MS_SET_INT_STATIC_STRING_PARAM(webrtc_container, MEDIA_STREAMER_PARAM_WEBRTC_REMOTE_SESSION_DESCRIPTION, NULL);
+       MS_SET_INT_STATIC_STRING_PARAM(webrtc_container, MEDIA_STREAMER_PARAM_WEBRTC_ADD_ICE_CANDIDATE, NULL);
 
        if (!(webrtcbin = ms_element_create("webrtcbin", NULL))) {
                ms_error("Failed to create webrtcbin element");
index 01ced4b..cd1576f 100644 (file)
@@ -51,6 +51,8 @@ static param_s param_table[] = {
        {MEDIA_STREAMER_PARAM_AUDIO_OUT_PORT, "audio_out_port"},
        {MEDIA_STREAMER_PARAM_IP_ADDRESS, "address"},
        {MEDIA_STREAMER_PARAM_WEBRTC_PEER_TYPE, "webrtc-peer-type"},
+       {MEDIA_STREAMER_PARAM_WEBRTC_REMOTE_SESSION_DESCRIPTION, "webrtc-remote-session-description"},
+       {MEDIA_STREAMER_PARAM_WEBRTC_ADD_ICE_CANDIDATE, "webrtc-add-ice-candidate"},
        {MEDIA_STREAMER_PARAM_AUDIO_DEVICE, "audio_device"},
        {MEDIA_STREAMER_PARAM_CLOCK_SYNCHRONIZED, "sync"},
        {MEDIA_STREAMER_PARAM_ROTATE, "rotate"},
@@ -222,6 +224,7 @@ static gboolean __ms_webrtc_node_has_property(media_streamer_node_s *node, const
 static int __ms_webrtc_node_set_property(media_streamer_node_s *node, param_s *param, const char *param_value)
 {
        GValue *val = NULL;
+       int ret;
 
        ms_debug_fenter();
 
@@ -244,6 +247,21 @@ static int __ms_webrtc_node_set_property(media_streamer_node_s *node, param_s *p
                g_value_unset(val);
                g_value_init(val, G_TYPE_STRING);
                g_value_set_string(val, param_value);
+       } else if (!strcmp(param->param_name, MEDIA_STREAMER_PARAM_WEBRTC_REMOTE_SESSION_DESCRIPTION)) {
+               ret = ms_webrtcbin_set_remote_session_description(node, param_value);
+               if (ret != MEDIA_STREAMER_ERROR_NONE) {
+                       ms_error("failed to set remote session description\n%s", param_value);
+                       return ret;
+               }
+               g_value_unset(val);
+               g_value_init(val, G_TYPE_STRING);
+               g_value_set_string(val, param_value);
+       } else if (!strcmp(param->param_name, MEDIA_STREAMER_PARAM_WEBRTC_ADD_ICE_CANDIDATE)) {
+               ret = ms_webrtcbin_add_ice_candidate(node, param_value);
+               if (ret != MEDIA_STREAMER_ERROR_NONE) {
+                       ms_error("failed to add ICE candidate\n%s", param_value);
+                       return ret;
+               }
        } else {
                ms_error("failed to set property, undefined param name[%s]", param->param_name);
                return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
@@ -1555,7 +1573,6 @@ static int __ms_node_set_display(media_streamer_node_s *node, const char *param_
        return ret;
 }
 //LCOV_EXCL_STOP
-
 int ms_node_set_param_value(media_streamer_node_s *node, param_s *param, const char *param_value)
 {
 
index 44c71f2..27344c2 100644 (file)
@@ -424,8 +424,8 @@ gchar* ms_get_string_from_json_object(JsonObject *object)
        return text;
 }
 
-/* Use g_free() to free the sdp parameter. */
-int ms_webrtc_get_sdp_from_message(const char *sdp_msg, gchar **sdp)
+/* Use g_free() to free the sdp and type parameter. */
+int ms_webrtc_get_sdp_from_message(const char *sdp_msg, gchar **sdp, gchar **type)
 {
        int ret = MEDIA_STREAMER_ERROR_NONE;
        JsonNode *root;
@@ -470,6 +470,7 @@ int ms_webrtc_get_sdp_from_message(const char *sdp_msg, gchar **sdp)
                ret = MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
                goto end;
        }
+       *type = g_strdup(member_type);
 
        member_sdp = json_object_get_string_member(child, "sdp");
        if (!member_sdp) {
@@ -480,7 +481,8 @@ int ms_webrtc_get_sdp_from_message(const char *sdp_msg, gchar **sdp)
 
        *sdp = g_strdup(member_sdp);
 
-       ms_debug("sdp: %s", *sdp);
+       ms_info("type: %s", *type);
+       ms_info("sdp:\n%s", *sdp);
 end:
        g_object_unref (parser);
        return ret;