From: Sangchul Lee Date: Fri, 29 Mar 2024 07:20:44 +0000 (+0900) Subject: Add webrtc_start_media_source() function X-Git-Tag: accepted/tizen/unified/20240618.010058~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F22%2F308722%2F5;p=platform%2Fcore%2Fapi%2Fwebrtc.git Add webrtc_start_media_source() function This function will be used after adding a media source during state of #WEBRTC_STATE_NEGOTIATING or #WEBRTC_STATE_PLAYING. It has been added for re-negotiation scenario. [Version] 1.1.0 [Issue Type] API Change-Id: I0985473ce0c37767c8734072104f9b34132475a5 Signed-off-by: Sangchul Lee --- diff --git a/include/webrtc.h b/include/webrtc.h index fff6aee3..c1b0f864 100644 --- a/include/webrtc.h +++ b/include/webrtc.h @@ -1650,6 +1650,24 @@ int webrtc_screen_source_set_crop(webrtc_h webrtc, unsigned int source_id, int x */ int webrtc_screen_source_unset_crop(webrtc_h webrtc, unsigned int source_id); +/** + * @brief Starts the media source. + * @since_tizen 9.0 + * @remarks This function will be used after adding a media source during state of #WEBRTC_STATE_NEGOTIATING or #WEBRTC_STATE_PLAYING.\n + * If the state is #WEBRTC_STATE_IDLE, this function will have no effect. Rather webrtc_start() will start media sources later. + * @param[in] webrtc WebRTC handle + * @param[in] source_id The media source id + * @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_add_media_source() + * @see webrtc_remove_media_source() + * @see webrtc_start() + */ +int webrtc_start_media_source(webrtc_h webrtc, unsigned int source_id); + /** * @} */ diff --git a/include/webrtc_private.h b/include/webrtc_private.h index 20fb2a65..bbafd1ac 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -747,7 +747,7 @@ void _update_transceivers_for_offer(webrtc_s *webrtc); int _set_payload_type(webrtc_s *webrtc, webrtc_gst_slot_s *source, int av_idx, const gchar *media_type); int _get_fixed_payload_type(const gchar *media_type); void _return_payload_type(webrtc_s *webrtc, unsigned int payload_type); -void _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source); +int _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source); int _add_transceiver(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info); int _set_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction); int _get_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction); @@ -810,6 +810,7 @@ const char *_get_video_media_type(const char *codec_name); void _source_slot_destroy_cb(gpointer data); int _add_media_source(webrtc_s *webrtc, int type, unsigned int *source_id); int _add_media_source_internal(webrtc_s *webrtc, int type, unsigned int *source_id); +int _start_media_source(webrtc_s *webrtc, unsigned int source_id); int _remove_media_source(webrtc_s *webrtc, unsigned int source_id); bool _check_if_codec_is_set_to_null_sources(webrtc_s *webrtc); bool _check_if_format_is_set_to_packet_sources(webrtc_s *webrtc); diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 4ecae432..0f54ce34 100644 --- a/packaging/capi-media-webrtc.spec +++ b/packaging/capi-media-webrtc.spec @@ -1,6 +1,6 @@ Name: capi-media-webrtc Summary: A WebRTC library in Tizen Native API -Version: 1.0.5 +Version: 1.1.0 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc.c b/src/webrtc.c index be1ebffe..71307fb5 100644 --- a/src/webrtc.c +++ b/src/webrtc.c @@ -720,7 +720,6 @@ int webrtc_file_source_get_looping(webrtc_h webrtc, unsigned int source_id, bool return _get_filesrc_looping(_webrtc, source_id, looping); } -//LCOV_EXCL_START int webrtc_screen_source_set_crop(webrtc_h webrtc, unsigned int source_id, int x, int y, int width, int height) { g_autoptr(GMutexLocker) locker = NULL; @@ -766,7 +765,24 @@ int webrtc_screen_source_unset_crop(webrtc_h webrtc, unsigned int source_id) return WEBRTC_ERROR_INVALID_OPERATION; #endif } -//LCOV_EXCL_STOP + +int webrtc_start_media_source(webrtc_h webrtc, unsigned int source_id) +{ + 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(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0"); + + locker = g_mutex_locker_new(&_webrtc->mutex); + + if (_webrtc->state == WEBRTC_STATE_IDLE) { + LOG_DEBUG("webrtc_start() will take charge of starting media sources"); + return WEBRTC_ERROR_NONE; + } + + return _start_media_source(webrtc, source_id); +} int webrtc_set_sound_stream_info(webrtc_h webrtc, unsigned int track_id, sound_stream_info_h stream_info) { diff --git a/src/webrtc_internal.c b/src/webrtc_internal.c index ce6c5eff..b26fc7fc 100644 --- a/src/webrtc_internal.c +++ b/src/webrtc_internal.c @@ -132,7 +132,6 @@ int webrtc_media_source_set_video_loopback_to_ecore_wl(webrtc_h webrtc, unsigned int webrtc_add_media_source_internal(webrtc_h webrtc, webrtc_media_source_type_internal_e type, unsigned int *source_id) { - int ret = WEBRTC_ERROR_NONE; g_autoptr(GMutexLocker) locker = NULL; webrtc_s *_webrtc = (webrtc_s *)webrtc; @@ -141,11 +140,7 @@ int webrtc_add_media_source_internal(webrtc_h webrtc, webrtc_media_source_type_i locker = g_mutex_locker_new(&_webrtc->mutex); - ret = _add_media_source_internal(webrtc, type, source_id); - if (ret == WEBRTC_ERROR_NONE) - LOG_INFO("source_id[%u]", *source_id); - - return ret; + return _add_media_source_internal(webrtc, type, source_id); } int webrtc_media_source_set_payload_type(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, unsigned int pt) diff --git a/src/webrtc_source.c b/src/webrtc_source.c index 06055da8..53404ca5 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -306,9 +306,39 @@ exit: return WEBRTC_ERROR_INVALID_OPERATION; } +static int __complete_source(webrtc_s *webrtc, webrtc_gst_slot_s *source) +{ + int ret; + + RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); + + LOG_DEBUG("source[id:%u, type:%d, media_types:0x%x]", source->id, source->type, source->media_types); + + if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE) + return WEBRTC_ERROR_NONE; + + if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET || + source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL) + goto add_transceiver; + + ret = (source->media_types == MEDIA_TYPE_AUDIO) ? + __complete_rest_of_audiosrc(webrtc, source) : __complete_rest_of_videosrc(webrtc, source); + if (ret != WEBRTC_ERROR_NONE) + return ret; + if (!gst_element_sync_state_with_parent(GST_ELEMENT(source->bin))) { + LOG_ERROR("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(source->bin)); + return WEBRTC_ERROR_INVALID_OPERATION; + } + +add_transceiver: + return _check_and_add_recvonly_transceiver(source); +} + int _complete_sources(webrtc_s *webrtc) { int i; + int ret; webrtc_gst_slot_s *source; RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); @@ -316,25 +346,64 @@ int _complete_sources(webrtc_s *webrtc) if (!(source = webrtc->gst.sources[i])) continue; - LOG_DEBUG("source[id:%u, type:%d, media_types:0x%x]", source->id, source->type, source->media_types); + if ((ret = __complete_source(webrtc, source)) != WEBRTC_ERROR_NONE) + return ret; + } - if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE) - continue; + return WEBRTC_ERROR_NONE; +} - if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET || - source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL) { - goto add_transceiver; - } +int _start_media_source(webrtc_s *webrtc, unsigned int source_id) +{ + int ret; + webrtc_gst_slot_s *source; - if (source->media_types == MEDIA_TYPE_AUDIO) - __complete_rest_of_audiosrc(webrtc, source); - else - __complete_rest_of_videosrc(webrtc, source); + ASSERT(webrtc); -add_transceiver: - _check_and_add_recvonly_transceiver(source); + RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0"); + RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "could not find source"); + + switch (source->type) { + case WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET: + if (!source->media_format) { + LOG_ERROR("media format must be set to the media packet"); + return WEBRTC_ERROR_INVALID_OPERATION; + } + break; + case WEBRTC_MEDIA_SOURCE_TYPE_FILE: { + gchar *location = NULL; + g_object_get(G_OBJECT(gst_bin_get_by_name(GST_BIN(source->filesrc_pipeline), ELEMENT_NAME_FILE_SRC)), "location", &location, NULL); + if (!location) { + LOG_ERROR("location must be set to the file source"); + return WEBRTC_ERROR_INVALID_OPERATION; + } + g_free(location); + break; + } + case WEBRTC_MEDIA_SOURCE_TYPE_NULL: { + int i; + bool found = false; + for (i = 0; i < AV_IDX_MAX; i++) { + if (source->av[i].codec) { + found = true; + break; + } + } + if (!found) { + LOG_ERROR("codec must be set to the null source"); + return WEBRTC_ERROR_INVALID_OPERATION; + } + break; + } } + /* TODO: add resource check */ + + ret = __complete_source(webrtc, source); + RET_VAL_IF(ret != WEBRTC_ERROR_NONE, ret, "failed to complete sources"); + + LOG_INFO("webrtc[%p] source[type:%d, id:%u]", webrtc, source->type, source_id); + return WEBRTC_ERROR_NONE; } diff --git a/src/webrtc_source_private.c b/src/webrtc_source_private.c index 5df60b4b..c871ba5e 100644 --- a/src/webrtc_source_private.c +++ b/src/webrtc_source_private.c @@ -1077,6 +1077,7 @@ static gboolean __foreach_src_pad_cb(GstElement *element, GstPad *pad, gpointer { webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)user_data; GstPad *peer = gst_pad_get_peer(pad); + GstWebRTCRTPTransceiver *transceiver; RET_VAL_IF(source == NULL, FALSE, "source is NULL"); RET_VAL_IF(source->webrtc == NULL, FALSE, "webrtc is NULL"); @@ -1087,6 +1088,17 @@ static gboolean __foreach_src_pad_cb(GstElement *element, GstPad *pad, gpointer LOG_DEBUG("about to release request pad[%s]", GST_PAD_NAME(peer)); + /* Should it be done manually? */ + g_object_get(peer, "transceiver", &transceiver, NULL); + g_object_set(transceiver, "direction", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE, NULL); + + gst_pad_unlink(pad, peer); + LOG_DEBUG("unlink pads[%s - %s]", GST_PAD_NAME(pad), GST_PAD_NAME(peer)); + + /* FIXME: setting gst state to NULL when WEBRTC_STATE_NEGOTIATING occurs a blocking issue. */ + if (source->webrtc->state == WEBRTC_STATE_PLAYING) + gst_element_set_state(GST_ELEMENT(source->bin), GST_STATE_NULL); + gst_element_release_request_pad(source->webrtc->gst.webrtcbin, peer); /* Two unrefing here, one for getting request pad, another one for getting peer pad */ diff --git a/src/webrtc_transceiver.c b/src/webrtc_transceiver.c index 56d2fd38..31f70875 100644 --- a/src/webrtc_transceiver.c +++ b/src/webrtc_transceiver.c @@ -417,25 +417,25 @@ static int __add_transceiver_for_simulcast(webrtc_gst_slot_s *source, webrtc_med return WEBRTC_ERROR_NONE; } -void _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source) +int _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source) { rtp_payload_info_s *payload_info = NULL; + int i; + webrtc_media_type_e media_type; - RET_IF(source == NULL, "source is NULL"); - - if (source->av[AV_IDX_AUDIO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_AUDIO].codec) { - if (g_hash_table_size(source->av[AV_IDX_AUDIO].encodings) > 0) - __add_transceiver_for_simulcast(source, WEBRTC_MEDIA_TYPE_AUDIO); - else if ((payload_info = __get_payload_info_by_encoding_name(source->av[AV_IDX_AUDIO].codec))) - _add_transceiver(source, WEBRTC_MEDIA_TYPE_AUDIO, payload_info); - } + RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); - if (source->av[AV_IDX_VIDEO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_VIDEO].codec) { - if (g_hash_table_size(source->av[AV_IDX_VIDEO].encodings) > 0) - __add_transceiver_for_simulcast(source, WEBRTC_MEDIA_TYPE_VIDEO); - else if ((payload_info = __get_payload_info_by_encoding_name(source->av[AV_IDX_VIDEO].codec))) - _add_transceiver(source, WEBRTC_MEDIA_TYPE_VIDEO, payload_info); + for (i = AV_IDX_AUDIO; i < AV_IDX_MAX; i++) { + media_type = (i == AV_IDX_AUDIO) ? WEBRTC_MEDIA_TYPE_AUDIO : WEBRTC_MEDIA_TYPE_VIDEO; + if (source->av[i].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[i].codec) { + if (g_hash_table_size(source->av[i].encodings) > 0) + __add_transceiver_for_simulcast(source, media_type); + else if (!(payload_info = __get_payload_info_by_encoding_name(source->av[i].codec))) + return WEBRTC_ERROR_INVALID_OPERATION; + _add_transceiver(source, media_type, payload_info); + } } + return WEBRTC_ERROR_NONE; } static GstCaps *__make_transceiver_caps(rtp_payload_info_s *payload_info)