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>
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
*/
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);
+
/**
* @}
*/
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;
webrtc_state_e state;
webrtc_state_e pend_state;
+
+ GList *signals;
+
+ webrtc_callbacks_s negotiation_needed_cb;
} webrtc_s;
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);
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
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;
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;
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;
+}
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");
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));
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;
return ret;
}
-
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;
} 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");
}
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");