* @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
* @pre @a webrtc state must be set to #WEBRTC_STATE_PLAYING.
* @see webrtc_negotiation_needed_cb()
+ * @see webrtc_set_local_description()
*/
int webrtc_create_offer(webrtc_h webrtc, char **offer);
* @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
* @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
* @pre @a webrtc state must be set to #WEBRTC_STATE_PLAYING.
+ * @see webrtc_set_local_description()
*/
int webrtc_create_answer(webrtc_h webrtc, char **answer);
+/**
+ * @brief Sets the session description for a local peer associated with a WebRTC connection.
+ * @since_tizen 6.0
+ * @remarks @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 local session description
+ * @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_PLAYING.
+ * @see webrtc_create_offer()
+ * @see webrtc_create_answer()
+ */
+int webrtc_set_local_description(webrtc_h webrtc, const char *description);
+
+/**
+ * @brief Sets the session description of the remote peer's current offer or answer.
+ * @since_tizen 6.0
+ * @remarks @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 remote session description
+ * @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_PLAYING.
+ */
+int webrtc_set_remote_description(webrtc_h webrtc, const char *description);
+
/**
* @}
*/
int _webrtcbin_create_offer(webrtc_s *webrtc, char **offer);
int _webrtcbin_create_answer(webrtc_s *webrtc, char **answer);
+int _webrtcbin_set_session_description(webrtc_s *webrtc, const char *description, gboolean is_remote);
#ifdef __cplusplus
}
Name: capi-media-webrtc
Summary: A WebRTC library in Tizen Native API
-Version: 0.1.9
+Version: 0.1.10
Release: 0
Group: Multimedia/API
License: Apache-2.0
g_mutex_unlock(&_webrtc->mutex);
+ return ret;
+}
+
+int webrtc_set_local_description(webrtc_h webrtc, const char *description)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ webrtc_s *_webrtc = (webrtc_s*)webrtc;
+
+ RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(description == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "description is NULL");
+
+ g_mutex_lock(&_webrtc->mutex);
+
+ RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_PLAYING, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be PLAYING");
+
+ LOG_INFO("description[ %s ]", description);
+
+ ret = _webrtcbin_set_session_description(webrtc, description, FALSE);
+
+ g_mutex_unlock(&_webrtc->mutex);
+
+ return ret;
+}
+
+int webrtc_set_remote_description(webrtc_h webrtc, const char *description)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ webrtc_s *_webrtc = (webrtc_s*)webrtc;
+
+ RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(description == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "description is NULL");
+
+ g_mutex_lock(&_webrtc->mutex);
+
+ RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_PLAYING, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be PLAYING");
+
+ LOG_INFO("description[ %s ]", description);
+
+ ret = _webrtcbin_set_session_description(webrtc, description, TRUE);
+
+ g_mutex_unlock(&_webrtc->mutex);
+
return ret;
}
\ No newline at end of file
return _create_session_description(webrtc, FALSE, answer);
}
+
+/* Use g_free() to free the sdp and type parameter. */
+static int __get_sdp_from_description(const char *description, gchar **sdp, gchar **type)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ JsonNode *root;
+ JsonObject *object;
+ JsonObject *child;
+ JsonParser *parser;
+ const gchar *member_sdp;
+ const gchar *member_type;
+
+ RET_VAL_IF(description == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "description is NULL");
+ RET_VAL_IF(sdp == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "sdp is NULL");
+ RET_VAL_IF(type == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "type is NULL");
+
+ parser = json_parser_new();
+ if (!JSON_IS_PARSER(parser))
+ return WEBRTC_ERROR_INVALID_OPERATION;
+
+ if (!json_parser_load_from_data(parser, description, -1, NULL)) {
+ LOG_ERROR("unknown description: %s", description);
+ ret = WEBRTC_ERROR_INVALID_PARAMETER;
+ goto end;
+ }
+
+ root = json_parser_get_root(parser);
+ if (!JSON_NODE_HOLDS_OBJECT(root)) {
+ LOG_ERROR("it does not contain a JsonObject: %s", description);
+ ret = WEBRTC_ERROR_INVALID_PARAMETER;
+ goto end;
+ }
+
+ object = json_node_get_object(root);
+ if (!json_object_has_member(object, "sdp")) {
+ LOG_ERROR("it does not contain 'sdp' member: %s", description);
+ ret = WEBRTC_ERROR_INVALID_PARAMETER;
+ goto end;
+ }
+
+ child = json_object_get_object_member(object, "sdp");
+
+ member_type = json_object_get_string_member(child, "type");
+ if (!member_type || !(g_str_equal(member_type, "answer") || g_str_equal(member_type, "offer"))) {
+ LOG_ERROR("could not find valid type member: %s", description);
+ ret = WEBRTC_ERROR_INVALID_PARAMETER;
+ goto end;
+ }
+
+ member_sdp = json_object_get_string_member(child, "sdp");
+ if (!member_sdp) {
+ LOG_ERROR("could not find sdb member: %s", description);
+ ret = WEBRTC_ERROR_INVALID_PARAMETER;
+ goto end;
+ }
+
+ *type = g_strdup(member_type);
+ *sdp = g_strdup(member_sdp);
+
+ LOG_DEBUG("type: %s", *type);
+ LOG_DEBUG("sdp:\n%s", *sdp);
+end:
+ g_object_unref (parser);
+ return ret;
+}
+
+int _webrtcbin_set_session_description(webrtc_s *webrtc, const char *description, gboolean is_remote)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ gchar *sdp;
+ gchar *type;
+ GstSDPMessage *gst_sdp;
+ GstWebRTCSDPType sdp_type;
+ GstWebRTCSessionDescription *desc;
+ GstPromise *promise;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(description == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "description is NULL");
+ RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+
+ ret = __get_sdp_from_description(description, &sdp, &type);
+ if (ret != WEBRTC_ERROR_NONE)
+ return ret;
+
+ ret = gst_sdp_message_new(&gst_sdp);
+ if (ret != GST_SDP_OK) {
+ LOG_ERROR("failed to gst_sdp_message_new()");
+ ret = WEBRTC_ERROR_INVALID_OPERATION;
+ goto end;
+ }
+
+ ret = gst_sdp_message_parse_buffer((guint8 *)sdp, strlen(sdp), gst_sdp);
+ if (ret != GST_SDP_OK) {
+ LOG_ERROR("failed to gst_sdp_message_parse_buffer()");
+ ret = WEBRTC_ERROR_INVALID_OPERATION;
+ goto end;
+ }
+
+ sdp_type = g_str_equal(type, "answer") ? GST_WEBRTC_SDP_TYPE_ANSWER : GST_WEBRTC_SDP_TYPE_OFFER;
+ desc = gst_webrtc_session_description_new(sdp_type, gst_sdp);
+
+ promise = gst_promise_new();
+ g_signal_emit_by_name(webrtc->gst.webrtcbin, is_remote? "set-remote-description" : "set-local-description", desc, promise);
+ gst_promise_interrupt(promise);
+ gst_promise_unref(promise);
+
+ gst_webrtc_session_description_free(desc);
+
+ LOG_DEBUG("[%s] signal is emitted", is_remote? "set-remote-description" : "set-local-description");
+
+end:
+ g_free(sdp);
+ g_free(type);
+
+ return ret;
+}
+
CURRENT_STATUS_ADD_MEDIA_SOURCE,
CURRENT_STATUS_REMOVE_MEDIA_SOURCE,
CURRENT_STATUS_SET_STUN_SERVER,
+ CURRENT_STATUS_SET_LOCAL_DESCRIPTION,
+ CURRENT_STATUS_SET_REMOTE_DESCRIPTION,
CURRENT_STATUS_SETTING_SIGNALLING_SERVER,
CURRENT_STATUS_SETTING_PROXY,
};
static appdata ad;
static webrtc_h g_webrtc;
+static char *g_offer;
+static char *g_answer;
static gchar g_signalling_server[MAX_STRING_LEN];
static gchar g_stun_server[MAX_STRING_LEN];
static gchar g_proxy[MAX_STRING_LEN];
static void _webrtc_create_offer()
{
int ret = WEBRTC_ERROR_NONE;
- char *offer = NULL;
- ret = webrtc_create_offer(g_webrtc, &offer);
- if (ret != WEBRTC_ERROR_NONE) {
- g_print("failed to webrtc_create_offer()\n");
- } else {
- g_print("webrtc_create_offer() success\noffer:\n%s\n", offer);
- free(offer);
+ if (g_offer) {
+ free(g_offer);
+ g_offer = NULL;
}
+
+ ret = webrtc_create_offer(g_webrtc, &g_offer);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_print("failed to webrtc_create_offer()\n");
+ else
+ g_print("webrtc_create_offer() success\noffer:\n%s\n", g_offer);
}
static void _webrtc_create_answer()
{
int ret = WEBRTC_ERROR_NONE;
- char *answer = NULL;
- ret = webrtc_create_answer(g_webrtc, &answer);
- if (ret != WEBRTC_ERROR_NONE) {
- g_print("failed to webrtc_create_answer()\n");
- } else {
- g_print("webrtc_create_answer() success\nanswer:\n%s\n", answer);
- free(answer);
+ if (g_answer) {
+ free(g_answer);
+ g_answer = NULL;
}
+
+ ret = webrtc_create_answer(g_webrtc, &g_answer);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_print("failed to webrtc_create_answer()\n");
+ else
+ g_print("webrtc_create_answer() success\nanswer:\n%s\n", g_answer);
+}
+
+static void _webrtc_set_local_description(char *desc)
+{
+ int ret = WEBRTC_ERROR_NONE;
+
+ ret = webrtc_set_local_description(g_webrtc, desc);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_print("failed to webrtc_set_local_description()\n");
+ else
+ g_print("webrtc_set_local_description() success\n");
+}
+
+static void _webrtc_set_remote_description(char *desc)
+{
+ int ret = WEBRTC_ERROR_NONE;
+
+ ret = webrtc_set_remote_description(g_webrtc, desc);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_print("failed to webrtc_set_remote_description()\n");
+ else
+ g_print("webrtc_set_remote_description() success\n");
}
static void _setting_signalling_server(char *uri)
} else if (strncmp(cmd, "ca", 2) == 0) {
_webrtc_create_answer();
+ } else if (strncmp(cmd, "sl", 2) == 0) {
+ g_menu_state = CURRENT_STATUS_SET_LOCAL_DESCRIPTION;
+
+ } else if (strncmp(cmd, "sr", 2) == 0) {
+ g_menu_state = CURRENT_STATUS_SET_REMOTE_DESCRIPTION;
+
} else {
g_print("unknown menu \n");
}
g_print("un. Unset negotiation needed callback\n");
g_print("co. Create offer\t");
g_print("ca. Create answer\n");
+ g_print("sl. Set local description\t");
+ g_print("sr. Set remote description\n");
g_print("st. Set STUN server\n");
g_print("----------------------------------- App. Setting ----------------------------------------\n");
g_print("ss. Signalling server\n");
g_print("*** input media source id to remove.\n");
} else if (g_menu_state == CURRENT_STATUS_SET_STUN_SERVER) {
g_print("*** input STUN server address.\n");
+ } else if (g_menu_state == CURRENT_STATUS_SET_LOCAL_DESCRIPTION) {
+ g_print("*** input type of local description.(1:offer, 2:answer)\n");
+ } else if (g_menu_state == CURRENT_STATUS_SET_REMOTE_DESCRIPTION) {
+ g_print("*** input type of remote description.(1:offer, 2:answer)\n");
} else if (g_menu_state == CURRENT_STATUS_SETTING_SIGNALLING_SERVER) {
g_print("*** input signalling server url.\n");
} else if (g_menu_state == CURRENT_STATUS_SETTING_PROXY) {
reset_menu_state();
break;
}
+ case CURRENT_STATUS_SET_LOCAL_DESCRIPTION: {
+ value = atoi(cmd);
+ if (value == 1) {
+ _webrtc_set_local_description(g_offer);
+ if (g_offer) {
+ free(g_offer);
+ g_offer = NULL;
+ }
+ } else if (value == 2) {
+ _webrtc_set_local_description(g_answer);
+ if (g_answer) {
+ free(g_answer);
+ g_answer = NULL;
+ }
+ } else {
+ g_print("invalid value[%d]\n", value);
+ }
+ reset_menu_state();
+ break;
+ }
+ case CURRENT_STATUS_SET_REMOTE_DESCRIPTION: {
+ /* FIXME: Setting remote description should be set via signalling server */
+ value = atoi(cmd);
+ if (value == 1) {
+ _webrtc_set_remote_description(g_offer);
+ if (g_offer) {
+ free(g_offer);
+ g_offer = NULL;
+ }
+ } else if (value == 2) {
+ _webrtc_set_remote_description(g_answer);
+ if (g_answer) {
+ free(g_answer);
+ g_answer = NULL;
+ }
+ } else {
+ g_print("invalid value[%d]\n", value);
+ }
+ reset_menu_state();
+ break;
+ }
case CURRENT_STATUS_SETTING_SIGNALLING_SERVER: {
_setting_signalling_server(cmd);
reset_menu_state();