From: Sangchul Lee Date: Wed, 3 Jun 2020 08:59:00 +0000 (+0900) Subject: Add new APIs to set/unset webrtc message callback X-Git-Tag: submit/tizen/20200714.065000~41 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F74%2F235274%2F10;p=platform%2Fcore%2Fapi%2Fmediastreamer.git Add new APIs to set/unset webrtc message callback - int media_streamer_webrtc_node_set_message_cb(media_streamer_node_h webrtc, media_streamer_webrtc_message_cb callback, void *user_data) - int media_streamer_webrtc_node_unset_message_cb(media_streamer_node_h webrtc) - typedef void (*media_streamer_webrtc_message_cb)(media_streamer_node_h webrtc, const char *message, void *user_data); [Version] 0.1.52 [Issue Type] New feature Change-Id: I452d7c88ff6e6e80cb41388a7d5c6d05d308527e Signed-off-by: Sangchul Lee --- diff --git a/include/media_streamer.h b/include/media_streamer.h index 0d2c397..f686645 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -514,6 +514,21 @@ typedef void (*media_streamer_position_changed_cb)(void *user_data); typedef void (*media_streamer_interrupted_cb)(media_streamer_interrupted_code_e code, void *user_data); /** + * @brief Called when the media streamer WebRTC node needs to send the message to the remote peer of WebRTC connection. + * @since_tizen 6.0 + * @remarks Two types will be delivered with @ message which is JSON string. + * One is for the remote session description and the other is for a new ICE candidate. + * For the remote session description, @ message will be {"sdp":{"type":"offer or answer","sdp":"..."}}. + * For the new ICE candidate, @ message will be {"ice":{"candidate":"..."}}. + * @param[in] webrtc Media streamer WebRTC node handle + * @param[in] message The message to be passed to the remote peer over the signaling channel + * @param[in] user_data The user data passed from the callback registration function + * @see media_streamer_webrtc_node_set_message_cb() + * @see media_streamer_webrtc_node_unset_message_cb() + */ +typedef void (*media_streamer_webrtc_message_cb)(media_streamer_node_h webrtc, const char *message, void *user_data); + +/** * @brief Sets a error callback function to be invoked when an error occurs. * @details Following error codes can be delivered by error callback. * #MEDIA_STREAMER_ERROR_INVALID_OPERATION, @@ -1245,7 +1260,6 @@ int media_streamer_node_get_params(media_streamer_node_h node, bundle **param_li int media_streamer_node_set_param(media_streamer_node_h node, const char *param_name, const char *param_value); - /** * @brief Gets value of parameter. * @details Gets parameter one by one without creating param bundle. @@ -1271,6 +1285,36 @@ int media_streamer_node_get_param(media_streamer_node_h node, const char *param_name, char **param_value); /** + * @brief Sets a callback function to be invoked when WebRTC node needs to send the message to the remote peer of WebRTC connection. + * @details This function can be called only for #MEDIA_STREAMER_NODE_TYPE_WEBRTC type. + * @since_tizen 6.0 + * @param[in] webrtc Media streamer WebRTC node handle + * @param[in] callback The WebRTC message callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre Create a media streamer WebRTC node handle by calling media_streamer_node_create(). + * @post media_streamer_webrtc_message_cb() will be invoked. + * @see media_streamer_webrtc_node_unset_message_cb() + * @see media_streamer_webrtc_message_cb() + */ +int media_streamer_webrtc_node_set_message_cb(media_streamer_node_h webrtc, media_streamer_webrtc_message_cb callback, void *user_data); + +/** + * @brief Unsets the webrtc message callback function. + * @since_tizen 6.0 + * @param[in] src Media streamer WebRTC node handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @see media_streamer_webrtc_node_set_message_cb() + */ +int media_streamer_webrtc_node_unset_message_cb(media_streamer_node_h webrtc); + +/** * @} */ diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index cb2355c..15fe4fc 100644 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -128,6 +128,8 @@ typedef struct { mm_resource_manager_res_h resource; device_policy_manager_h dpm_handle; int policy_changed_cb_id; + + media_streamer_callback_s user_cb; } media_streamer_node_s; /** diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 4def19b..d3a9a81 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.51 +Version: 0.1.52 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer.c b/src/media_streamer.c index b255ac8..dbb28cb 100644 --- a/src/media_streamer.c +++ b/src/media_streamer.c @@ -937,3 +937,37 @@ int media_streamer_unset_interrupted_cb(media_streamer_h streamer) return MEDIA_STREAMER_ERROR_NONE; } + +int media_streamer_webrtc_node_set_message_cb(media_streamer_node_h webrtc, media_streamer_webrtc_message_cb callback, void *user_data) +{ + media_streamer_node_s *ms_node = (media_streamer_node_s *) webrtc; + + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL"); + ms_retvm_if(ms_node->type != MEDIA_STREAMER_NODE_TYPE_WEBRTC, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is not for WebRTC"); + + ms_debug_fenter(); + + ms_node->user_cb.callback = callback; + ms_node->user_cb.user_data = user_data; + + ms_debug_fleave(); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_webrtc_node_unset_message_cb(media_streamer_node_h webrtc) +{ + media_streamer_node_s *ms_node = (media_streamer_node_s *) webrtc; + + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL"); + ms_retvm_if(ms_node->type != MEDIA_STREAMER_NODE_TYPE_WEBRTC, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is not for WebRTC"); + + ms_debug_fenter(); + + ms_node->user_cb.callback = NULL; + ms_node->user_cb.user_data = NULL; + + ms_debug_fleave(); + + return MEDIA_STREAMER_ERROR_NONE; +} \ No newline at end of file diff --git a/src/media_streamer_gst_webrtc.c b/src/media_streamer_gst_webrtc.c index 669be14..371ec64 100644 --- a/src/media_streamer_gst_webrtc.c +++ b/src/media_streamer_gst_webrtc.c @@ -56,6 +56,21 @@ static gchar* __make_sdp_message(GstWebRTCSessionDescription *desc) return text; } +static void __trigger_message_callback(media_streamer_node_s *webrtc_node, gchar *message) +{ + ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL"); + + ms_debug("message is : \n%s", message); + + if (webrtc_node->user_cb.callback) { + ms_debug("=====> Now trigger user callback(%p)", webrtc_node->user_cb.callback); + ((media_streamer_webrtc_message_cb)(webrtc_node->user_cb.callback))(webrtc_node, message, webrtc_node->user_cb.user_data); + ms_debug("<===== End of the callback"); + } else { + ms_warning("message callback is NULL"); + } +} + static void __on_answer_created_cb(GstPromise *promise, gpointer user_data) { GstWebRTCSessionDescription *answer = NULL; @@ -103,15 +118,23 @@ static void __on_offer_created_cb(GstPromise *promise, gpointer user_data) { GstWebRTCSessionDescription *offer = NULL; const GstStructure *reply; - GstElement *webrtcbin = (GstElement *)user_data; + media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data; + node_info_s *node_klass_type = NULL; + GstElement *webrtcbin = NULL; gchar *sdp_msg; ms_retm_if(promise == NULL, "promise is NULL"); - ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL"); + ms_retm_if(webrtc_node == NULL, "webrtc_node 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))) { + 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); @@ -124,11 +147,9 @@ static void __on_offer_created_cb(GstPromise *promise, gpointer user_data) sdp_msg = __make_sdp_message(offer); - /* TODO: need to add to send this message to signalling server */ - ms_debug("SDP message is sent: %s", sdp_msg); + __trigger_message_callback(webrtc_node, sdp_msg); g_free(sdp_msg); - gst_webrtc_session_description_free(offer); ms_debug_fleave(); @@ -154,10 +175,11 @@ void ms_webrtcbin_on_negotiation_needed_cb(GstElement *webrtcbin, gpointer user_ GstPromise *promise; ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL"); + ms_retm_if(user_data == NULL, "user_data is NULL"); ms_debug_fenter(); - promise = gst_promise_new_with_change_func(__on_offer_created_cb, webrtcbin, NULL); + promise = gst_promise_new_with_change_func(__on_offer_created_cb, user_data, NULL); g_signal_emit_by_name(G_OBJECT(webrtcbin), "create-offer", NULL, promise); ms_debug_fleave(); @@ -187,14 +209,15 @@ static gchar *__make_ice_candidate_message(guint mlineindex, gchar *candidate) void ms_webrtcbin_on_ice_candidate_cb(GstElement *webrtcbin, guint mlineindex, gchar *candidate, gpointer user_data) { gchar *ice_candidate_msg = NULL; + media_streamer_node_s *webrtc_node = (media_streamer_node_s *)user_data; ms_retm_if(webrtcbin == NULL, "webrtcbin is NULL"); ms_retm_if(candidate == NULL, "candidate is NULL"); + ms_retm_if(webrtc_node == NULL, "webrtc_node is NULL"); ice_candidate_msg = __make_ice_candidate_message(mlineindex, candidate); - /* TODO: need to add to send this message to signalling server */ - ms_debug("ICE candidate message is sent: %s", ice_candidate_msg); + __trigger_message_callback(webrtc_node, ice_candidate_msg); g_free(ice_candidate_msg); } diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 41536cc..01ced4b 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -1445,7 +1445,8 @@ int ms_webrtc_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s ms_debug_fenter(); ms_retvm_if(!ms_streamer, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer is NULL"); - ms_retvm_if(!node, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "node is NULL"); + ms_retvm_if(!node, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL"); + ms_retvm_if(node->type != MEDIA_STREAMER_NODE_TYPE_WEBRTC, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is not WebRTC"); 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))) { @@ -1453,15 +1454,20 @@ int ms_webrtc_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } + if (!node->user_cb.callback) { + ms_error("message callback should be set before preparing"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + if (__ms_webrtc_node_is_offerer(node, &is_offerer)) { ms_error("Failed to get peer type"); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } if (is_offerer) - ms_signal_create(&node->sig_list, webrtcbin, "on-negotiation-needed", G_CALLBACK(ms_webrtcbin_on_negotiation_needed_cb), NULL); + ms_signal_create(&node->sig_list, webrtcbin, "on-negotiation-needed", G_CALLBACK(ms_webrtcbin_on_negotiation_needed_cb), node); - ms_signal_create(&node->sig_list, webrtcbin, "on-ice-candidate", G_CALLBACK(ms_webrtcbin_on_ice_candidate_cb), NULL); + ms_signal_create(&node->sig_list, webrtcbin, "on-ice-candidate", G_CALLBACK(ms_webrtcbin_on_ice_candidate_cb), node); ms_signal_create(&node->sig_list, webrtcbin, "notify::ice-gathering-state", G_CALLBACK(ms_webrtcbin_notify_ice_gathering_state_cb), NULL); if (ms_element_set_state(webrtcbin, GST_STATE_READY)) {