Add webrtc_set[unset]_negotiation_needed_cb() API 57/242857/11
authorSangchul Lee <sc11.lee@samsung.com>
Tue, 1 Sep 2020 09:29:42 +0000 (18:29 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 10 Sep 2020 01:16:00 +0000 (10:16 +0900)
It corresponds to the negotiationneeded event of RTCPeerConnection.
Internal functions regarding signal connection are added.

[Version] 0.1.8
[Issue Type] API

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

index 2b5717e94314a9ec1f75a0b812b5d3e4c5c5155a..b2867c0fb8b58ffe83822322804a891af724cd43 100644 (file)
@@ -80,6 +80,16 @@ typedef enum {
        WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST
 } webrtc_media_source_type_e;
 
+/**
+ * @brief Called when the WebRTC needs session negotiation.
+ * @since_tizen 6.0
+ * @param[in] webrtc     WebRTC handle
+ * @param[in] user_data  The user data passed from the callback registration function
+ * @see webrtc_set_negotiation_needed_cb()
+ * @see webrtc_unset_negotiation_needed_cb()
+ */
+typedef void (*webrtc_negotiation_needed_cb)(webrtc_h webrtc, void *user_data);
+
 /**
  * @brief Creates an instance of WebRTC.
  * @since_tizen 6.0
@@ -205,6 +215,38 @@ int webrtc_remove_media_source(webrtc_h webrtc, unsigned int source_id);
  */
 int webrtc_set_stun_server(webrtc_h webrtc, const char *stun_server);
 
+/**
+ * @brief Sets a negotiation needed callback function to be invoked when a change has occurred which requires session negotiation.
+ * @since_tizen 6.0
+ * @param [in] webrtc      WebRTC handle
+ * @param [in] callback    Callback function pointer
+ * @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 #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
+ * @pre @a webrtc state must be set to #WEBRTC_STATE_IDLE.
+ * @post webrtc_negotiation_needed_cb() will be invoked.
+ * @see webrtc_unset_negotiation_needed_cb()
+ * @see webrtc_negotiation_needed_cb()
+ */
+int webrtc_set_negotiation_needed_cb(webrtc_h webrtc, webrtc_negotiation_needed_cb callback, void *user_data);
+
+/**
+ * @brief Unsets the negotiation needed callback function.
+ * @since_tizen 6.0
+ * @param [in] webrtc      WebRTC handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @see webrtc_set_negotiation_needed_cb()
+ */
+int webrtc_unset_negotiation_needed_cb(webrtc_h webrtc);
+
 /**
  * @}
  */
index ddf70b2ac24cc19fb2c52eaca17e8fddc78a7d6a..1509645e489e598d1d217356cf899675209adccd 100644 (file)
@@ -122,6 +122,11 @@ typedef struct _webrtc_gst_s {
        GHashTable *source_slots;
 } webrtc_gst_s;
 
+typedef struct _webrtc_callbacks {
+       void *callback;
+       void *user_data;
+} webrtc_callbacks_s;
+
 typedef struct _webrtc_s {
        webrtc_ini_s ini;
 
@@ -133,6 +138,10 @@ typedef struct _webrtc_s {
 
        webrtc_state_e state;
        webrtc_state_e pend_state;
+
+       GList *signals;
+
+       webrtc_callbacks_s negotiation_needed_cb;
 } webrtc_s;
 
 typedef struct _element_info_s {
@@ -141,6 +150,11 @@ typedef struct _element_info_s {
        GstCaps *sink_caps;
 } element_info_s;
 
+typedef struct _webrtc_signal_s {
+       GObject *obj;
+       gulong signal_id;
+} webrtc_signal_s;
+
 int _ini_load(webrtc_s *webrtc);
 int _gst_init(webrtc_s *webrtc);
 int _gst_build_pipeline(webrtc_s *webrtc);
index ba7d7be1b19148823fdf7d53b7b73caec1831577..5c04bc7f19ef6e816e315ebb4cfd66304e04d041 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.1.7
+Version:    0.1.8
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 84ab7181103fcdf3e9e261e239cb808371620a98..335b06220fe27a7452c6707bab4e1641c3e32e88 100644 (file)
@@ -83,8 +83,7 @@ int webrtc_start(webrtc_h webrtc)
        g_mutex_lock(&_webrtc->mutex);
 
        RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be IDLE");
-
-       /* Implementation */
+       RET_VAL_WITH_UNLOCK_IF(_webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, &_webrtc->mutex, "webrtcbin is NULL");
 
        _gst_pipeline_set_state(webrtc, GST_STATE_PLAYING);
        _webrtc->pend_state = WEBRTC_STATE_PLAYING;
@@ -106,8 +105,6 @@ int webrtc_stop(webrtc_h webrtc)
 
        RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_PLAYING, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be PLAYING");
 
-       /* Implementation */
-
        _gst_pipeline_set_state(webrtc, GST_STATE_READY);
        _webrtc->pend_state = WEBRTC_STATE_IDLE;
 
@@ -200,3 +197,45 @@ int webrtc_set_stun_server(webrtc_h webrtc, const char *stun_server)
        return WEBRTC_ERROR_NONE;
 }
 
+int webrtc_set_negotiation_needed_cb(webrtc_h webrtc, webrtc_negotiation_needed_cb callback, void *user_data)
+{
+       webrtc_s *_webrtc = (webrtc_s*)webrtc;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(callback == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "callback is NULL");
+
+       g_mutex_lock(&_webrtc->mutex);
+
+       RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be IDLE");
+
+       _webrtc->negotiation_needed_cb.callback = callback;
+       _webrtc->negotiation_needed_cb.user_data = user_data;
+
+       LOG_INFO("callback[%p] user_data[%p]", callback, user_data);
+
+       g_mutex_unlock(&_webrtc->mutex);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_unset_negotiation_needed_cb(webrtc_h webrtc)
+{
+       webrtc_s *_webrtc = (webrtc_s*)webrtc;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+
+       g_mutex_lock(&_webrtc->mutex);
+
+       RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be IDLE");
+       RET_VAL_WITH_UNLOCK_IF(_webrtc->negotiation_needed_cb.callback == NULL, WEBRTC_ERROR_INVALID_OPERATION, &_webrtc->mutex, "callback was not set");
+
+       LOG_INFO("callback[%p] user_data[%p] is reset to NULL",
+               _webrtc->negotiation_needed_cb.callback, _webrtc->negotiation_needed_cb.user_data);
+
+       _webrtc->negotiation_needed_cb.callback = NULL;
+       _webrtc->negotiation_needed_cb.user_data = NULL;
+
+       g_mutex_unlock(&_webrtc->mutex);
+
+       return WEBRTC_ERROR_NONE;
+}
index c50b372275cc84ef161d224c4dff2cd967d24420..52d8b8fd38bc08966c34873f9acca231ab7a71e7 100644 (file)
@@ -312,6 +312,62 @@ int _gst_init(webrtc_s *webrtc)
        return WEBRTC_ERROR_NONE;
 }
 
+static void __connect_and_append_signal(GList **signals, GstElement *obj, const char *sig_name, GCallback cb, gpointer user_data)
+{
+       webrtc_signal_s *sig_data;
+
+       RET_IF(signals == NULL, "sig_list is NULL");
+       RET_IF(obj == NULL, "obj is NULL");
+       RET_IF(sig_name == NULL, "sig_name is NULL");
+       RET_IF(cb == NULL, "cb is NULL");
+
+       sig_data = (webrtc_signal_s *)g_malloc0(sizeof(webrtc_signal_s));
+       sig_data->obj = G_OBJECT(obj);
+       sig_data->signal_id = g_signal_connect(sig_data->obj, sig_name, cb, user_data);
+       if (sig_data->signal_id == 0) {
+               LOG_ERROR("failed to g_signal_connect(), [%s] for object [%s]", sig_name, GST_OBJECT_NAME(obj));
+               g_free(sig_data);
+               return;
+       }
+
+       *signals = g_list_append(*signals, sig_data);
+       LOG_DEBUG("signal [%s] with id[%lu] is connected to object [%s].", sig_name, sig_data->signal_id, GST_OBJECT_NAME(sig_data->obj));
+}
+
+static void __disconnect_signal(gpointer data)
+{
+       webrtc_signal_s *sig_data = (webrtc_signal_s *)data;
+
+       RET_IF(data == NULL, "data is NULL");
+
+       if (GST_IS_ELEMENT(sig_data->obj)) {
+               if (g_signal_handler_is_connected(sig_data->obj, sig_data->signal_id)) {
+                       g_signal_handler_disconnect(sig_data->obj, sig_data->signal_id);
+                       LOG_DEBUG("signal with id[%lu] is disconnected from object [%s].", sig_data->signal_id, GST_OBJECT_NAME(sig_data->obj));
+               }
+       }
+
+       g_free(sig_data);
+}
+
+static void __webrtcbin_on_negotiation_needed(GstElement *webrtcbin, gpointer user_data)
+{
+       webrtc_s *webrtc = (webrtc_s *)user_data;
+
+       RET_IF(webrtcbin == NULL, "webrtcbin is NULL");
+       RET_IF(webrtc == NULL, "webrtc is NULL");
+
+       if (webrtc->negotiation_needed_cb.callback == NULL) {
+               LOG_DEBUG("negotiation_needed_cb is NULL, skip it");
+               return;
+       }
+
+       LOG_DEBUG(">>> invoke negotiation_needed_cb[%p], user_data[%p]",
+               webrtc->negotiation_needed_cb.callback, webrtc->negotiation_needed_cb.user_data);
+       ((webrtc_negotiation_needed_cb)(webrtc->negotiation_needed_cb.callback))((webrtc_h)webrtc, webrtc->negotiation_needed_cb.user_data);
+       LOG_DEBUG("<<< end of the callback");
+}
+
 int _gst_build_pipeline(webrtc_s *webrtc)
 {
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
@@ -333,6 +389,7 @@ int _gst_build_pipeline(webrtc_s *webrtc)
                LOG_ERROR("failed to create webrtcbin");
                goto error;
        }
+       __connect_and_append_signal(&webrtc->signals, webrtc->gst.webrtcbin, "on-negotiation-needed", G_CALLBACK(__webrtcbin_on_negotiation_needed), webrtc);
 
        if (!gst_bin_add(GST_BIN(webrtc->gst.pipeline), webrtc->gst.webrtcbin)) {
                LOG_ERROR("failed to gst_bin_add(), [%s] -> [%s] pipeline", GST_ELEMENT_NAME(webrtc->gst.webrtcbin), GST_ELEMENT_NAME(webrtc->gst.pipeline));
@@ -365,6 +422,10 @@ void _gst_destroy_pipeline(webrtc_s *webrtc)
                gst_object_unref(webrtc->gst.bus);
                webrtc->gst.bus = NULL;
        }
+       if (webrtc->signals) {
+               g_list_free_full(webrtc->signals, __disconnect_signal);
+               webrtc->signals = NULL;
+       }
        if (webrtc->gst.webrtcbin) {
                gst_bin_remove(GST_BIN(webrtc->gst.pipeline), webrtc->gst.webrtcbin);
                webrtc->gst.webrtcbin = NULL;
@@ -804,4 +865,3 @@ int _remove_media_source(webrtc_s *webrtc, unsigned int source_id)
 
        return ret;
 }
-
index 1a56255c00a4e9fd324e43d827d4bc631483d3d9..8b4faae877c671f0b10d49bb14f92ca2d25f6dba 100644 (file)
@@ -311,6 +311,33 @@ static void _webrtc_set_stun_server(char *uri)
                g_print("webrtc_set_stun_server() success, uri[%s]\n", g_stun_server);
 }
 
+static void __negotiation_needed_cb(webrtc_h webrtc, void *user_data)
+{
+       g_print("__negotiation_needed_cb() is invoked\n");
+}
+
+static void _webrtc_set_negotiation_needed_cb()
+{
+       int ret = WEBRTC_ERROR_NONE;
+
+       ret = webrtc_set_negotiation_needed_cb(g_webrtc, __negotiation_needed_cb, g_webrtc);
+       if (ret != WEBRTC_ERROR_NONE)
+               g_print("failed to webrtc_set_negotiation_needed_cb()\n");
+       else
+               g_print("webrtc_set_negotiation_needed_cb() success\n");
+}
+
+static void _webrtc_unset_negotiation_needed_cb()
+{
+       int ret = WEBRTC_ERROR_NONE;
+
+       ret = webrtc_unset_negotiation_needed_cb(g_webrtc);
+       if (ret != WEBRTC_ERROR_NONE)
+               g_print("failed to webrtc_unset_negotiation_needed_cb()\n");
+       else
+               g_print("webrtc_unset_negotiation_needed_cb() success\n");
+}
+
 static void _setting_signalling_server(char *uri)
 {
        int ret = 0;
@@ -384,6 +411,12 @@ void _interpret_main_menu(char *cmd)
                } else if (strncmp(cmd, "px", 2) == 0) {
                        g_menu_state = CURRENT_STATUS_SETTING_PROXY;
 
+               } else if (strncmp(cmd, "sn", 2) == 0) {
+                       _webrtc_set_negotiation_needed_cb();
+
+               } else if (strncmp(cmd, "un", 2) == 0) {
+                       _webrtc_unset_negotiation_needed_cb();
+
                } else {
                        g_print("unknown menu \n");
                }
@@ -403,10 +436,12 @@ void display_sub_basic()
        g_print("d. Destroy\n");
        g_print("s. Start\t");
        g_print("t. Stop\n");
+       g_print("g. Get state\n");
        g_print("a. Add media source\t");
        g_print("r. Remove media source\n");
+       g_print("sn. Set negotiation needed callback\t");
+       g_print("un. Unset negotiation needed callback\n");
        g_print("st. Set STUN server\n");
-       g_print("g. Get state\n");
        g_print("----------------------------------- App. Setting ----------------------------------------\n");
        g_print("ss. Signalling server\n");
        g_print("px. Proxy\n");