Add new asynchronous API to create offer/answer 82/263182/3
authorSangchul Lee <sc11.lee@samsung.com>
Fri, 27 Aug 2021 09:27:18 +0000 (18:27 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Wed, 1 Sep 2021 03:55:42 +0000 (12:55 +0900)
Functions are added as below.
 - webrtc_create_offer_async()
 - webrtc_create_answer_async()

[Version] 0.2.91
[Issue Type] API

Change-Id: I5641f98fcd272ddd52f5173c048a9db3a94a9222
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

index a0115f42e63c69c0ad291b84d651e4da550b9508..f07aae62a90969fb8f2507d3b129bb108425dfcb 100644 (file)
@@ -297,6 +297,24 @@ typedef void (*webrtc_error_cb)(webrtc_h webrtc, webrtc_error_e error, webrtc_st
  */
 typedef void (*webrtc_state_changed_cb)(webrtc_h webrtc, webrtc_state_e previous, webrtc_state_e current, void *user_data);
 
+/**
+ * @brief Called when the session description is created.
+ * @since_tizen 6.5
+ * @remarks The @a webrtc is the same object for which the callback was set.\n
+ *          The @a webrtc should not be released.\n
+ *          @a description is a JSON string.\n
+ *          It will be {"sdp":{"type":"offer or answer","sdp":"..."}}.
+ * @param[in] webrtc       WebRTC handle
+ * @param[in] description  The session description
+ * @param[in] user_data    The user data passed from the callback registration function
+ * @post @a description must be set as a local description by calling webrtc_set_local_description()
+ * @post @a description must be sent to the remote peer via the signaling channel.
+ * @see webrtc_create_offer_async()
+ * @see webrtc_create_answer_async()
+ * @see webrtc_set_local_description()
+ */
+typedef void (*webrtc_session_description_created_cb)(webrtc_h webrtc, const char *description, void *user_data);
+
 /**
  * @brief Called when the WebRTC peer connection state is changed.
  * @since_tizen 6.5
@@ -670,6 +688,7 @@ int webrtc_destroy(webrtc_h webrtc);
  * @see webrtc_state_changed_cb()
  * @see webrtc_get_state()
  * @see webrtc_create_offer()
+ * @see webrtc_create_offer_async()
  */
 int webrtc_set_state_changed_cb(webrtc_h webrtc, webrtc_state_changed_cb callback, void *user_data);
 
@@ -1701,6 +1720,57 @@ int webrtc_create_offer(webrtc_h webrtc, bundle *options, char **offer);
  */
 int webrtc_create_answer(webrtc_h webrtc, bundle *options, char **answer);
 
+/**
+ * @brief Creates SDP offer asynchronously to start a new WebRTC connection to a remote peer.
+ * @since_tizen 6.5
+ * @remarks The registered callback will be invoked in the main thread.\n
+ *          The @a options currently has no effect.
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] options     Configuration options for the offer (optional, this can be NULL)
+ * @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_NEGOTIATING.
+ * @post webrtc_session_description_created_cb() will be invoked.
+ * @see webrtc_state_changed_cb()
+ * @see webrtc_negotiation_needed_cb()
+ * @see webrtc_set_local_description()
+ * @see webrtc_session_description_created_cb()
+ */
+int webrtc_create_offer_async(webrtc_h webrtc, bundle *options, webrtc_session_description_created_cb callback, void *user_data);
+
+/**
+ * @brief Creates SDP answer asynchronously to an offer received from a remote peer during the negotiation of a WebRTC connection.
+ * @since_tizen 6.5
+ * @remarks The registered callback will be invoked in the main thread.\n
+ *          The @a options currently has no effect.
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] options     Configuration options for the answer (optional, this can be NULL)
+ * @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_NEGOTIATING.
+ * @pre The remote SDP offer must be set by calling webrtc_set_remote_description().
+ * @pre The signaling state must be set to #WEBRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER.
+ * @post webrtc_session_description_created_cb() will be invoked.
+ * @see webrtc_set_remote_description()
+ * @see webrtc_set_local_description()
+ * @see webrtc_get_signaling_state()
+ * @see webrtc_set_signaling_state_change_cb()
+ * @see webrtc_session_description_created_cb()
+ */
+int webrtc_create_answer_async(webrtc_h webrtc, bundle *options, webrtc_session_description_created_cb callback, void *user_data);
+
 /**
  * @brief Sets the session description for a local peer associated with a WebRTC connection.
  * @since_tizen 6.5
@@ -1716,7 +1786,9 @@ int webrtc_create_answer(webrtc_h webrtc, bundle *options, char **answer);
  * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
  * @pre @a webrtc state must be set to #WEBRTC_STATE_NEGOTIATING.
  * @see webrtc_create_offer()
+ * @see webrtc_create_offer_async()
  * @see webrtc_create_answer()
+ * @see webrtc_create_answer_async()
  * @see webrtc_set_signaling_state_change_cb()
  * @see webrtc_get_signaling_state()
  */
index 921f6058c3818808b20e8255b44ceb5b58a1bfc9..9dd72b2b265cfd266a6246fe30b5af3444b387de 100644 (file)
@@ -619,6 +619,7 @@ void *_get_unused_tbm_bo(webrtc_tbm_s *tbm, unsigned int timeout_sec);
 void _release_tbm_bo(webrtc_tbm_s *tbm, void *bo);
 
 int _webrtcbin_create_session_description(webrtc_s *webrtc, bool is_offer, char **desc);
+int _webrtcbin_create_session_description_async(webrtc_s *webrtc, bool is_offer, webrtc_session_description_created_cb callback, void *user_data);
 int _webrtcbin_set_session_description(webrtc_s *webrtc, const char *description, bool is_remote);
 int _webrtcbin_add_ice_candidate(webrtc_s *webrtc, const char *candidate);
 void _webrtcbin_on_data_channel_cb(GstElement *webrtcbin, GObject *data_channel, gpointer user_data);
index 3724909960fe83e9cbb6c963b33fe2bd968e6a8b..aa4de3bf9b9e4abf577ce8c771082c2a757dea86 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.2.90
+Version:    0.2.91
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 98a03f2cb7f8a7bef555e561a67d798dae059992..c0123e6434c03a7f5da85da5d7c3883fde158269 100644 (file)
@@ -1398,6 +1398,37 @@ int webrtc_create_answer(webrtc_h webrtc, bundle *options, char **answer)
        return _webrtcbin_create_session_description(webrtc, false, answer);
 }
 
+int webrtc_create_offer_async(webrtc_h webrtc, bundle *options, webrtc_session_description_created_cb callback, void *user_data)
+{
+       g_autoptr(GMutexLocker) locker = NULL;
+       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");
+
+       locker = g_mutex_locker_new(&_webrtc->mutex);
+
+       RET_VAL_IF(_webrtc->state != WEBRTC_STATE_NEGOTIATING, WEBRTC_ERROR_INVALID_STATE, "the state should be NEGOTIATING");
+
+       return _webrtcbin_create_session_description_async(webrtc, true, callback, user_data);
+}
+
+int webrtc_create_answer_async(webrtc_h webrtc, bundle *options, webrtc_session_description_created_cb callback, void *user_data)
+{
+       g_autoptr(GMutexLocker) locker = NULL;
+       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");
+
+       locker = g_mutex_locker_new(&_webrtc->mutex);
+
+       RET_VAL_IF(_webrtc->state != WEBRTC_STATE_NEGOTIATING, WEBRTC_ERROR_INVALID_STATE, "the state should be NEGOTIATING");
+       RET_VAL_IF(!_webrtcbin_have_remote_offer(_webrtc), WEBRTC_ERROR_INVALID_STATE, "remote offer should be set");
+
+       return _webrtcbin_create_session_description_async(webrtc, false, callback, user_data);
+}
+
 int webrtc_set_local_description(webrtc_h webrtc, const char *description)
 {
        g_autoptr(GMutexLocker) locker = NULL;
index e9471bfd8b5645faf4bd677b00e4f4e28ae5309d..bda78f9ed1db0023602404f887f3cb09c21e560e 100644 (file)
@@ -409,6 +409,12 @@ typedef struct _idle_userdata {
        } new;
 } idle_userdata_s;
 
+typedef struct _description_created_userdata {
+       webrtc_s *webrtc;
+       webrtc_session_description_created_cb callback;
+       void *user_data;
+} description_created_userdata;
+
 static gboolean __idle_cb(gpointer user_data)
 {
        idle_userdata_s *data = (idle_userdata_s*)user_data;
@@ -1362,39 +1368,71 @@ static void __update_session_description(GstPromise *promise, bool is_offer, gpo
 
 static void __offer_created_cb(GstPromise *promise, gpointer user_data)
 {
-       webrtc_s *webrtc = (webrtc_s *)user_data;
+       description_created_userdata *data = (description_created_userdata *)user_data;
+       webrtc_s *webrtc;
 
-       RET_IF(promise == NULL, "promise is NULL");
-       RET_IF(webrtc == NULL, "webrtc is NULL");
+       RET_IF(data == NULL, "data is NULL");
+
+       if (!(webrtc = data->webrtc)) {
+               LOG_ERROR("webrtc is NULL");
+               g_free(data);
+               return;
+       }
 
        LOG_DEBUG_ENTER();
 
        __update_session_description(promise, true, webrtc);
+       if (data->callback) {
+               LOG_DEBUG(">>> callback[%p], user_data[%p]", data->callback, data->user_data);
+               ((webrtc_session_description_created_cb)(data->callback))((webrtc_h)webrtc, webrtc->desc_offer, data->user_data);
+               LOG_DEBUG("<<< end of the callback");
+               g_mutex_unlock(&webrtc->desc_mutex);
 
-       g_cond_signal(&webrtc->desc_cond);
+       } else {
+               g_cond_signal(&webrtc->desc_cond);
+       }
 
        LOG_DEBUG_LEAVE();
+
+       g_free(data);
 }
 
 static void __answer_created_cb(GstPromise *promise, gpointer user_data)
 {
-       webrtc_s *webrtc = (webrtc_s *)user_data;
+       description_created_userdata *data = (description_created_userdata *)user_data;
+       webrtc_s *webrtc;
 
-       RET_IF(promise == NULL, "promise is NULL");
-       RET_IF(webrtc == NULL, "webrtc is NULL");
+       RET_IF(data == NULL, "data is NULL");
+
+       if (!(webrtc = data->webrtc)) {
+               LOG_ERROR("webrtc is NULL");
+               g_free(data);
+               return;
+       }
 
        LOG_DEBUG_ENTER();
 
        __update_session_description(promise, false, webrtc);
 
-       g_cond_signal(&webrtc->desc_cond);
+       if (data->callback) {
+               LOG_DEBUG(">>> callback[%p], user_data[%p]", data->callback, data->user_data);
+               ((webrtc_session_description_created_cb)(data->callback))((webrtc_h)webrtc, webrtc->desc_answer, data->user_data);
+               LOG_DEBUG("<<< end of the callback");
+               g_mutex_unlock(&webrtc->desc_mutex);
+
+       } else {
+               g_cond_signal(&webrtc->desc_cond);
+       }
 
        LOG_DEBUG_LEAVE();
+
+       g_free(data);
 }
 
 int _webrtcbin_create_session_description(webrtc_s *webrtc, bool is_offer, char **desc)
 {
        GstPromise *promise;
+       description_created_userdata *data;
        gint64 end_time;
 
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
@@ -1403,7 +1441,10 @@ int _webrtcbin_create_session_description(webrtc_s *webrtc, bool is_offer, char
 
        g_mutex_lock(&webrtc->desc_mutex);
 
-       promise = gst_promise_new_with_change_func(is_offer ? __offer_created_cb : __answer_created_cb, webrtc, NULL);
+       data = g_new0(description_created_userdata, 1);
+       data->webrtc = webrtc;
+
+       promise = gst_promise_new_with_change_func(is_offer ? __offer_created_cb : __answer_created_cb, data, NULL);
        g_signal_emit_by_name(G_OBJECT(webrtc->gst.webrtcbin), is_offer ? "create-offer" : "create-answer", NULL, promise);
 
        end_time = g_get_monotonic_time() + 30 * G_TIME_SPAN_SECOND;
@@ -1422,6 +1463,28 @@ int _webrtcbin_create_session_description(webrtc_s *webrtc, bool is_offer, char
        return WEBRTC_ERROR_NONE;
 }
 
+int _webrtcbin_create_session_description_async(webrtc_s *webrtc, bool is_offer, webrtc_session_description_created_cb callback, void *user_data)
+{
+       GstPromise *promise;
+       description_created_userdata *data;
+
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(callback == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "callback is NULL");
+       RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+
+       g_mutex_lock(&webrtc->desc_mutex);
+
+       data = g_new0(description_created_userdata, 1);
+       data->webrtc = webrtc;
+       data->callback = callback;
+       data->user_data = user_data;
+
+       promise = gst_promise_new_with_change_func(is_offer ? __offer_created_cb : __answer_created_cb, data, NULL);
+       g_signal_emit_by_name(G_OBJECT(webrtc->gst.webrtcbin), is_offer ? "create-offer" : "create-answer", NULL, promise);
+
+       return WEBRTC_ERROR_NONE;
+}
+
 /* Use g_free() to release the sdp and type parameter. */
 static int __get_sdp_from_description(const char *description, gchar **sdp, gchar **type)
 {