Enums are added as below.
- WEBRTC_MEDIA_TYPE_AUDIO
- WEBRTC_MEDIA_TYPE_VIDEO
- WEBRTC_TRANSCEIVER_DIRECTION_SENDONLY
- WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY
- WEBRTC_TRANSCEIVER_DIRECTION_SENDRECV
Functions are added as below.
- webrtc_get_transceiver_direction()
- webrtc_set_transceiver_direction()
Test cases for these functions are added to webrtc_test.
[Version] 0.1.31
[Issue Type] API
Change-Id: I6753b7480a6b363f262cf9edbcdf08c9cb20f24c
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST, /**< Video test */
} webrtc_media_source_type_e;
+/**
+ * @brief Enumeration for WebRTC media type.
+ * @since_tizen 6.5
+ */
+typedef enum {
+ WEBRTC_MEDIA_TYPE_AUDIO,
+ WEBRTC_MEDIA_TYPE_VIDEO,
+} webrtc_media_type_e;
+
+/**
+ * @brief Enumeration for WebRTC transceiver direction type.
+ * @since_tizen 6.5
+ */
+typedef enum {
+ WEBRTC_TRANSCEIVER_DIRECTION_SENDONLY,
+ WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY,
+ WEBRTC_TRANSCEIVER_DIRECTION_SENDRECV,
+} webrtc_transceiver_direction_e;
+
/**
* @brief Called when an error occurs.
* @details The following error codes can be received:\n
* @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
* @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
* @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
+ * @pre Add media source to @a webrtc to get @a source_id by calling webrtc_add_media_source().
* @pre @a webrtc state must be set to #WEBRTC_STATE_IDLE.
- * @pre Add media source to @a webrtc by calling webrtc_add_media_source().
* @see webrtc_add_media_source()
*/
int webrtc_remove_media_source(webrtc_h webrtc, unsigned int source_id);
+/**
+ * @brief Gets the transceiver direction of the media source with specified media type.
+ * @since_tizen 6.5
+ * @param[in] webrtc WebRTC handle
+ * @param[in] source_id The media source id
+ * @param[in] media_type The media type
+ * @param[out] direction Current transceiver direction
+ * @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
+ * @pre Add media source to @a webrtc to get @a source_id by calling webrtc_add_media_source().
+ * @see webrtc_set_transceiver_direction()
+ */
+int webrtc_get_transceiver_direction(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction);
+
+/**
+ * @brief Sets the transceiver direction to the media source with specified media type.
+ * @since_tizen 6.5
+ * @param[in] webrtc WebRTC handle
+ * @param[in] source_id The media source id
+ * @param[in] media_type The media type
+ * @param[in] direction The transceiver direction to set
+ * @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 Add media source to @a webrtc to get @a source_id by calling webrtc_add_media_source().
+ * @pre @a webrtc state must be set to #WEBRTC_STATE_IDLE.
+ * @see webrtc_get_transceiver_direction()
+ */
+int webrtc_set_transceiver_direction(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction);
+
/**
* @brief Sets a STUN server URL.
* @since_tizen 6.5
int _gst_pipeline_set_state(webrtc_s *webrtc, GstState state);
int _add_media_source(webrtc_s *webrtc, webrtc_media_source_type_e type, unsigned int *source_id);
int _remove_media_source(webrtc_s *webrtc, unsigned int source_id);
+int _get_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction);
+int _set_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction);
int _webrtcbin_create_offer(webrtc_s *webrtc, char **offer);
int _webrtcbin_create_answer(webrtc_s *webrtc, char **answer);
Name: capi-media-webrtc
Summary: A WebRTC library in Tizen Native API
-Version: 0.1.30
+Version: 0.1.31
Release: 0
Group: Multimedia/API
License: Apache-2.0
g_mutex_unlock(&_webrtc->mutex);
if (ret == WEBRTC_ERROR_NONE)
- LOG_INFO("source_id[%d]", *source_id);
+ LOG_INFO("source_id[%u]", *source_id);
return ret;
}
RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be IDLE");
- LOG_INFO("source_id[%d]", source_id);
+ LOG_INFO("source_id[%u]", source_id);
ret = _remove_media_source(webrtc, source_id);
return ret;
}
+int webrtc_get_transceiver_direction(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction)
+{
+ 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(direction == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "direction is NULL");
+
+ g_mutex_lock(&_webrtc->mutex);
+
+ ret = _get_transceiver_direction(webrtc, source_id, media_type, direction);
+
+ g_mutex_unlock(&_webrtc->mutex);
+
+ if (ret == WEBRTC_ERROR_NONE)
+ LOG_INFO("source_id[%u], media_type[%d], direction[%d]", source_id, media_type, *direction);
+
+ return ret;
+}
+
+int webrtc_set_transceiver_direction(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ 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 = _set_transceiver_direction(webrtc, source_id, media_type, direction);
+
+ g_mutex_unlock(&_webrtc->mutex);
+
+ LOG_INFO("source_id[%u], media_type[%d], direction[%d]", source_id, media_type, direction);
+
+ return ret;
+}
+
int webrtc_set_stun_server(webrtc_h webrtc, const char *stun_server)
{
webrtc_s *_webrtc = (webrtc_s*)webrtc;
"PLAYING",
};
+static const char* __direction_str[] = {
+ "SENDONLY",
+ "RECVONLY",
+ "SENDRECV",
+};
+
+static GstWebRTCRTPTransceiverDirection __direction_gst[] = {
+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY,
+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY,
+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV
+};
+
static void __generate_dot(webrtc_s *webrtc, const gchar *name)
{
gchar *dot_name;
RET_IF(webrtc == NULL, "webrtc is NULL");
RET_IF(webrtc->ice_candidate_cb.callback == NULL, "ice_candidate_cb is NULL");
+ LOG_DEBUG("mlineindex[%u], candidate[%s]", mlineindex, candidate);
+
_candidate = __make_ice_candidate_message(mlineindex, candidate);
if (!_candidate)
return;
return ret;
}
+static gboolean __check_id_equal_cb(gpointer key, gpointer value, gpointer user_data)
+{
+ webrtc_gst_slot_s *slot = value;
+
+ if (slot->id == GPOINTER_TO_UINT(user_data)) {
+ LOG_DEBUG("found slot[%s] of id[%u]", GST_ELEMENT_NAME(slot->bin), slot->id);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static webrtc_gst_slot_s* __get_slot_by_id(GHashTable *slots, unsigned int id)
+{
+ webrtc_gst_slot_s *slot;
+
+ RET_VAL_IF(slots == NULL, NULL, "slots is NULL");
+
+ slot = g_hash_table_find(slots, __check_id_equal_cb, GUINT_TO_POINTER(id));
+ if (!slot)
+ LOG_ERROR("could not find any slot of id[%u]", id);
+
+ return slot;
+}
+
+static int __convert_direction(GstWebRTCRTPTransceiverDirection gst_direction, webrtc_transceiver_direction_e *direction)
+{
+ RET_VAL_IF(direction == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "direction is NULL");
+
+ if (gst_direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_NONE ||
+ gst_direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE) {
+ LOG_ERROR("not expected gst direction[%d]", gst_direction);
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ if (gst_direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY)
+ *direction = WEBRTC_TRANSCEIVER_DIRECTION_SENDONLY;
+ else if (gst_direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY)
+ *direction = WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY;
+ else
+ *direction = WEBRTC_TRANSCEIVER_DIRECTION_SENDRECV;
+
+ return WEBRTC_ERROR_NONE;
+}
+
+int _get_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ webrtc_gst_slot_s *source;
+ GstWebRTCRTPTransceiver *trans;
+ GArray *transceivers;
+ int mline;
+ int i;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(direction == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "direction is NULL");
+ RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+ RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
+ RET_VAL_IF((source = __get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+
+ if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) {
+ mline = source->mlines[MLINES_IDX_AUDIO];
+
+ } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) {
+ mline = source->mlines[MLINES_IDX_VIDEO];
+
+ } else {
+ LOG_ERROR("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id);
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+ }
+
+ g_signal_emit_by_name(webrtc->gst.webrtcbin, "get-transceivers", &transceivers);
+ for (i = 0; i < transceivers->len; i++) {
+ trans = g_array_index(transceivers, GstWebRTCRTPTransceiver *, i);
+ if (trans->mline == mline) {
+ ret = __convert_direction(trans->direction, direction);
+ if (ret != WEBRTC_ERROR_NONE)
+ return ret;
+ LOG_DEBUG("found transceiver[%p, index:%d, mline:%u, mid:%s, direction:%s]",
+ trans, i, trans->mline, trans->mid, __direction_str[*direction]);
+ return WEBRTC_ERROR_NONE;
+ }
+ }
+
+ LOG_ERROR("could not find a transceiver with mline[%d]", mline);
+
+ return WEBRTC_ERROR_INVALID_OPERATION;
+}
+
+int _set_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction)
+{
+ webrtc_gst_slot_s *source;
+ GstWebRTCRTPTransceiver *trans;
+ GArray *transceivers;
+ int mline;
+ int i;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(direction > WEBRTC_TRANSCEIVER_DIRECTION_SENDRECV, WEBRTC_ERROR_INVALID_PARAMETER, "invalid direction");
+ RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+ RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
+ RET_VAL_IF((source = __get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+
+ if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) {
+ mline = source->mlines[MLINES_IDX_AUDIO];
+
+ } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) {
+ mline = source->mlines[MLINES_IDX_VIDEO];
+
+ } else {
+ LOG_ERROR("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id);
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+ }
+
+ g_signal_emit_by_name(webrtc->gst.webrtcbin, "get-transceivers", &transceivers);
+ for (i = 0; i < transceivers->len; i++) {
+ trans = g_array_index(transceivers, GstWebRTCRTPTransceiver *, i);
+ if (trans->mline == mline) {
+ trans->direction = __direction_gst[direction];
+ LOG_DEBUG("Set direction to transceiver[%p, index:%d, mline:%u, direction:%s]",
+ trans, i, trans->mline, __direction_str[direction]);
+ return WEBRTC_ERROR_NONE;
+ }
+ }
+
+ LOG_ERROR("could not find a transceiver with mline[%d]", mline);
+
+ return WEBRTC_ERROR_INVALID_OPERATION;
+}
+
void _webrtcbin_on_negotiation_needed(GstElement *webrtcbin, gpointer user_data)
{
webrtc_s *webrtc = (webrtc_s *)user_data;
CURRENT_STATUS_MAINMENU,
CURRENT_STATUS_ADD_MEDIA_SOURCE,
CURRENT_STATUS_REMOVE_MEDIA_SOURCE,
+ CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION,
+ CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION,
CURRENT_STATUS_SET_STUN_SERVER,
CURRENT_STATUS_SET_LOCAL_DESCRIPTION,
CURRENT_STATUS_SET_REMOTE_DESCRIPTION,
"PLAYING",
};
+static const char* g_webrtc_media_type_str[] = {
+ "AUDIO",
+ "VIDEO",
+};
+
+static const char* g_webrtc_transceiver_direction_str[] = {
+ "SENDONLY",
+ "RECVONLY",
+ "SENDRECV",
+};
+
/* for video display */
static Evas_Object *g_eo;
static Evas_Object *g_win_id;
static gchar g_proxy[MAX_STRING_LEN];
static int g_server_status = SERVER_STATUS_DISCONNECTED;
static int g_menu_state = CURRENT_STATUS_MAINMENU;
+static int g_cnt;
static void win_del(void *data, Evas_Object *obj, void *event)
{
if (ret != WEBRTC_ERROR_NONE)
g_print("failed to webrtc_add_media_source(), ret[0x%x]\n", ret);
else
- g_print("webrtc_add_media_source() success, source_id[%d]\n", source_id);
+ g_print("webrtc_add_media_source() success, source_id[%u]\n", source_id);
}
static void _webrtc_remove_media_source(unsigned int source_id)
ret = webrtc_remove_media_source(g_webrtc, source_id);
if (ret != WEBRTC_ERROR_NONE)
- g_print("failed to webrtc_remove_media_source(), source_id[%d], ret[0x%x]\n", source_id, ret);
+ g_print("failed to webrtc_remove_media_source(), source_id[%u], ret[0x%x]\n", source_id, ret);
+ else
+ g_print("webrtc_remove_media_source() success, source_id[%u]\n", source_id);
+}
+
+static void _webrtc_get_transceiver_direction(unsigned int source_id, webrtc_media_type_e media_type)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ webrtc_transceiver_direction_e direction;
+
+ ret = webrtc_get_transceiver_direction(g_webrtc, source_id, media_type, &direction);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_print("failed to webrtc_get_transceiver_direction(), ret[0x%x]\n", ret);
else
- g_print("webrtc_remove_media_source() success, source_id[%d]\n", source_id);
+ g_print("webrtc_get_transceiver_direction() success, source_id[%u], media_type[%s], direction[%s]\n",
+ source_id, g_webrtc_media_type_str[media_type], g_webrtc_transceiver_direction_str[direction]);
+}
+
+static void _webrtc_set_transceiver_direction(unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction)
+{
+ int ret = WEBRTC_ERROR_NONE;
+
+ ret = webrtc_set_transceiver_direction(g_webrtc, source_id, media_type, direction);
+ if (ret != WEBRTC_ERROR_NONE)
+ g_print("failed to webrtc_set_transceiver_direction(), source_id[%u], ret[0x%x]\n", source_id, ret);
+ else
+ g_print("webrtc_set_transceiver_direction() success, source_id[%u], media_type[%s], direction[%s]\n",
+ source_id, g_webrtc_media_type_str[media_type], g_webrtc_transceiver_direction_str[direction]);
}
static int __copy_string_arr(gchar *dest_arr, char *string)
}
} else if (len == 2) {
- if (strncmp(cmd, "se", 2) == 0) {
+ if (strncmp(cmd, "gd", 2) == 0) {
+ g_menu_state = CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION;
+
+ } else if (strncmp(cmd, "td", 2) == 0) {
+ g_menu_state = CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION;
+
+ } else if (strncmp(cmd, "se", 2) == 0) {
_webrtc_set_error_cb();
} else if (strncmp(cmd, "ue", 2) == 0) {
g_print("g. Get state\n");
g_print("a. Add media source\t");
g_print("r. Remove media source\n");
+ g_print("gd. Get transceiver direction\t");
+ g_print("td. Set transceiver direction\n");
g_print("se. Set error callback\t");
g_print("ue. Unset error callback\n");
g_print("sc. Set state changed callback\t");
{
if (g_menu_state == CURRENT_STATUS_MAINMENU) {
display_sub_basic();
+
} else if (g_menu_state == CURRENT_STATUS_ADD_MEDIA_SOURCE) {
g_print("*** input media source type.(1:camera, 2:mic, 3:audiotest, 4:videotest)\n");
+
} else if (g_menu_state == CURRENT_STATUS_REMOVE_MEDIA_SOURCE) {
g_print("*** input media source id to remove.\n");
+
+ } else if (g_menu_state == CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION) {
+ if (g_cnt == 0)
+ g_print("*** input source id.\n");
+ else if (g_cnt == 1)
+ g_print("*** input media type.(1:audio 2:video)\n");
+
+ } else if (g_menu_state == CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION) {
+ if (g_cnt == 0)
+ g_print("*** input source id.\n");
+ else if (g_cnt == 1)
+ g_print("*** input media type.(1:audio 2:video)\n");
+ else if (g_cnt == 2)
+ g_print("*** input transceiver direction.(1:sendonly 2:recvonly, 3:sendrecv)\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_SETTING_SIGNALING_SERVER) {
g_print("*** input signaling server URL.\n");
+
} else if (g_menu_state == CURRENT_STATUS_SETTING_PROXY) {
g_print("*** input proxy URL.\n");
+
} else if (g_menu_state == CURRENT_STATUS_REQUEST_SESSION) {
g_print("*** input remote peer id.\n");
+
} else if (g_menu_state == CURRENT_STATUS_SEND_LOCAL_DESCRIPTION) {
g_print("*** input type of local description to send to the sever.(1:offer, 2:answer)\n");
+
} else {
g_print("*** unknown status.\n");
quit_program();
}
+
g_print(" >>> ");
}
reset_menu_state();
break;
}
+ case CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION: {
+ static unsigned int id;
+ static unsigned int media_type;
+ value = atoi(cmd);
+
+ switch (g_cnt) {
+ case 0:
+ id = value;
+ g_cnt++;
+ break;
+ case 1:
+ media_type = value - 1;
+ _webrtc_get_transceiver_direction(id, media_type);
+ id = media_type = 0;
+ g_cnt = 0;
+ reset_menu_state();
+ break;
+ }
+ break;
+ }
+ case CURRENT_STATUS_SET_TRANSCEIVER_DIRECTION: {
+ static unsigned int id;
+ static unsigned int media_type;
+ static unsigned int direction;
+ value = atoi(cmd);
+
+ switch (g_cnt) {
+ case 0:
+ id = value;
+ g_cnt++;
+ break;
+ case 1:
+ media_type = value - 1;
+ g_cnt++;
+ break;
+ case 2:
+ direction = value - 1;
+ _webrtc_set_transceiver_direction(id, media_type, direction);
+ id = media_type = direction = 0;
+ g_cnt = 0;
+ reset_menu_state();
+ break;
+ }
+ break;
+ }
case CURRENT_STATUS_SET_STUN_SERVER: {
_webrtc_set_stun_server(cmd);
reset_menu_state();