From b15df7e312e104210c0c020201b9659fe50fb4f2 Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Thu, 1 Jul 2021 21:04:51 +0900 Subject: [PATCH] Add API to set sound stream info. to the MIC source webrtc_mic_source_set_sound_stream_info() is added. For example, audio device(e.g. USB) can be set by the stream info handle of capi-media-sound-manager. By passing this handle to the new function, the MIC source will be read data from the device. [Version] 0.2.29 [Issue Type] API Change-Id: I0027109ae5ee3b546e40aadef1740551ad6a2e40 Signed-off-by: Sangchul Lee --- CMakeLists.txt | 2 +- include/webrtc.h | 29 ++++++++++++- include/webrtc_private.h | 2 + packaging/capi-media-webrtc.spec | 3 +- src/webrtc.c | 19 +++++++++ src/webrtc_source.c | 52 ++++++++++++++++++++++- test/webrtc_test.c | 72 ++++++++++++++++++++------------ 7 files changed, 148 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 514ed676..951af7f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ INCLUDE_DIRECTORIES(${INC_DIR}) SET(dependents "dlog glib-2.0 gstreamer-1.0 gstreamer-webrtc-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 \ gstreamer-allocators-1.0 json-glib-1.0 iniparser mm-common mm-display-interface capi-media-tool \ - libtbm libwebsockets cynara-client libsmack capi-system-info libsoup-2.4 bundle") + libtbm libwebsockets cynara-client libsmack capi-system-info libsoup-2.4 bundle capi-media-sound-manager") IF(NOT TIZEN_PROFILE_TV) SET(dependents "${dependents} mm-resource-manager") ELSE() diff --git a/include/webrtc.h b/include/webrtc.h index 7bb769e3..83b30813 100644 --- a/include/webrtc.h +++ b/include/webrtc.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -788,7 +789,7 @@ int webrtc_media_source_set_mute(webrtc_h webrtc, unsigned int source_id, webrtc /** * @brief Gets the mute of the media source. - * @details if @a source_id is a media source of #WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET, this function will return #WEBRTC_ERROR_INVALID_PARAMETER. + * @details If @a source_id is a media source of #WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET, this function will return #WEBRTC_ERROR_INVALID_PARAMETER. * @since_tizen 6.5 * @remarks The default value is @c false. * @param[in] webrtc WebRTC handle @@ -848,6 +849,32 @@ int webrtc_media_source_set_video_resolution(webrtc_h webrtc, unsigned int sourc */ int webrtc_media_source_get_video_resolution(webrtc_h webrtc, unsigned int source_id, int *width, int *height); +/** + * @brief Sets the mic source's sound manager stream information. + * @details If @a source_id is not a media source of #WEBRTC_MEDIA_SOURCE_TYPE_MIC, this function will return #WEBRTC_ERROR_INVALID_PARAMETER. + * @since_tizen 6.5 + * @remarks You can set sound stream information including audio routing.\n + * The following sound stream types can be used for the @a stream_info:\n + * #SOUND_STREAM_TYPE_MEDIA\n + * #SOUND_STREAM_TYPE_VOICE_RECOGNITION\n + * #SOUND_STREAM_TYPE_VOIP\n + * #SOUND_STREAM_TYPE_MEDIA_EXTERNAL_ONLY\n + * For more details, please refer to @ref CAPI_MEDIA_SOUND_MANAGER_MODULE. + * @param[in] webrtc WebRTC handle + * @param[in] source_id The mic source id + * @param[in] stream_info The sound stream information + * @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. + * @see #sound_stream_info_h + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + */ +int webrtc_mic_source_set_sound_stream_info(webrtc_h webrtc, unsigned int source_id, sound_stream_info_h stream_info); + /** * @brief Sets a callback function to be invoked when the buffer state of media packet source is changed. * @since_tizen 6.5 diff --git a/include/webrtc_private.h b/include/webrtc_private.h index ad8a0bed..d0e1e41d 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -29,6 +29,7 @@ #ifndef TIZEN_TV #include #endif +#include #include #include #include @@ -525,6 +526,7 @@ int _set_video_mute(webrtc_s *webrtc, unsigned int source_id, bool mute); int _get_video_mute(webrtc_s *webrtc, unsigned int source_id, bool *muted); int _set_video_resolution(webrtc_s *webrtc, unsigned int source_id, int width, int height); int _get_video_resolution(webrtc_s *webrtc, unsigned int source_id, int *width, int *height); +int _set_sound_stream_info(webrtc_s *webrtc, unsigned int source_id, sound_stream_info_h stream_info); int _set_media_format(webrtc_s *webrtc, unsigned int source_id, media_format_h format); bool _check_if_format_is_set_to_packet_sources(webrtc_s *webrtc); int _push_media_packet(webrtc_s *webrtc, unsigned int source_id, media_packet_h packet); diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index e53d9c74..f00ffad4 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: 0.2.28 +Version: 0.2.29 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -29,6 +29,7 @@ BuildRequires: pkgconfig(libwebsockets) BuildRequires: pkgconfig(cynara-client) BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(capi-system-info) +BuildRequires: pkgconfig(capi-media-sound-manager) BuildRequires: pkgconfig(bundle) %if "%{tizen_profile_name}" != "tv" BuildRequires: pkgconfig(mm-resource-manager) diff --git a/src/webrtc.c b/src/webrtc.c index 62d7110b..42f499b0 100644 --- a/src/webrtc.c +++ b/src/webrtc.c @@ -473,6 +473,25 @@ int webrtc_media_source_get_video_resolution(webrtc_h webrtc, unsigned int sourc return ret; } +int webrtc_mic_source_set_sound_stream_info(webrtc_h webrtc, unsigned int source_id, sound_stream_info_h stream_info) +{ + 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(stream_info == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "stream_info 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_sound_stream_info(webrtc, source_id, stream_info); + + g_mutex_unlock(&_webrtc->mutex); + + return ret; +} + int webrtc_media_packet_source_set_buffer_state_changed_cb(webrtc_h webrtc, unsigned int source_id, webrtc_media_packet_source_buffer_state_changed_cb callback, void *user_data) { webrtc_s *_webrtc = (webrtc_s*)webrtc; diff --git a/src/webrtc_source.c b/src/webrtc_source.c index 3e71a9f9..0935ac9c 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -47,6 +47,7 @@ #define ELEMENT_NAME_VIDEO_SWITCH "videoSwitch" #define ELEMENT_NAME_VIDEO_MUTE_SRC "videoMuteSrc" #define ELEMENT_NAME_VOLUME "volume" +#define ELEMENT_NAME_MIC_SRC "micSrc" #define APPEND_ELEMENT(x_list, x_element) \ do { \ @@ -1214,7 +1215,7 @@ static int __build_audiosrc(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool us source->zerocopy_enabled = __is_hw_encoder_used(webrtc, source->type, source->media_types); source_factory_name = __get_source_element(webrtc, use_mic ? WEBRTC_MEDIA_SOURCE_TYPE_MIC : WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST); - if (!(audiosrc = _create_element(source_factory_name, NULL))) + if (!(audiosrc = _create_element(source_factory_name, use_mic ? ELEMENT_NAME_MIC_SRC: NULL))) return WEBRTC_ERROR_INVALID_OPERATION; APPEND_ELEMENT(element_list, audiosrc); @@ -2112,6 +2113,55 @@ int _get_video_resolution(webrtc_s *webrtc, unsigned int source_id, int *width, return WEBRTC_ERROR_NONE; } +int _set_sound_stream_info(webrtc_s *webrtc, unsigned int source_id, sound_stream_info_h stream_info) +{ + webrtc_gst_slot_s *source; + GstElement *element; + int ret = SOUND_MANAGER_ERROR_NONE; + bool available = false; + char *stream_type; + int stream_index; + GstStructure *structure; + char values[64] = {'\0',}; + + RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "could not find source"); + RET_VAL_IF((source->type != WEBRTC_MEDIA_SOURCE_TYPE_MIC), WEBRTC_ERROR_INVALID_PARAMETER, "this API only support the mic source"); + RET_VAL_IF(stream_info == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "stream_info is NULL"); + RET_VAL_IF(!(element = gst_bin_get_by_name(source->bin, ELEMENT_NAME_MIC_SRC)), WEBRTC_ERROR_INVALID_OPERATION, "could not find element for mic"); + RET_VAL_IF(!g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(element)), "stream-properties"), + WEBRTC_ERROR_INVALID_OPERATION, "mic source element does not have 'stream-properties"); + + sound_manager_get_type_from_stream_information(stream_info, &stream_type); + sound_manager_get_index_from_stream_information(stream_info, &stream_index); + + ret = sound_manager_is_available_stream_information(stream_info, NATIVE_API_WEBRTC, &available); + if (ret != SOUND_MANAGER_ERROR_NONE) { + LOG_ERROR("failed to sound_manager_is_available_stream_information()"); + return WEBRTC_ERROR_INVALID_OPERATION; + } + + if (!available) { + LOG_ERROR("this stream info[%p, type:%s, index:%d] is not allowed to this framework", stream_info, stream_type, stream_index); + return WEBRTC_ERROR_INVALID_PARAMETER; + } + + LOG_INFO("source_id[%u], stream_info[%p, type:%s, index:%d]", source_id, stream_info, stream_type, stream_index); + + snprintf(values, sizeof(values) - 1, "props,media.role=%s, media.parent_id=%d", stream_type, stream_index); + structure = gst_structure_from_string(values, NULL); + if (!structure) { + LOG_ERROR("failed to gst_structure_from_string(), [%s]", values); + return WEBRTC_ERROR_INVALID_OPERATION; + } + + LOG_INFO("stream-properties[%s]", values); + g_object_set(G_OBJECT(element), "stream-properties", structure, NULL); + gst_structure_free(structure); + + return WEBRTC_ERROR_NONE; +} + int _set_media_format(webrtc_s *webrtc, unsigned int source_id, media_format_h format) { int ret; diff --git a/test/webrtc_test.c b/test/webrtc_test.c index 949615e2..fd9fa918 100644 --- a/test/webrtc_test.c +++ b/test/webrtc_test.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -501,37 +502,54 @@ static void _webrtc_add_media_source(int index, int value) unsigned int source_id = 0; int i; - switch (value) { - case 1: /* WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST */ - case 2: /* WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST */ - case 3: /* WEBRTC_MEDIA_SOURCE_TYPE_MIC */ - case 4: /* WEBRTC_MEDIA_SOURCE_TYPE_CAMERA */ - case 5: /* WEBRTC_MEDIA_SOURCE_TYPE_SCREEN */ - case 6: /* WEBRTC_MEDIA_SOURCE_TYPE_FILE */ - case 7: /* WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET */ - if ((value - 1) == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) { - i = _get_empty_packet_sources_index(index); - RET_IF(i == -1, "media packet source can be added up to %d", MAX_MEDIA_PACKET_SOURCE_LEN); + if (value - 1 <= WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) { + webrtc_media_source_type_e type = value - 1; + switch (type) { + case WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST ... WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET: + if (type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) { + i = _get_empty_packet_sources_index(index); + RET_IF(i == -1, "media packet source can be added up to %d", MAX_MEDIA_PACKET_SOURCE_LEN); + } + ret = webrtc_add_media_source(g_conns[index].webrtc, type, &source_id); + RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); + + if (type == WEBRTC_MEDIA_SOURCE_TYPE_MIC) { + sound_stream_info_h stream_info; + ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info); + RET_IF(ret != SOUND_MANAGER_ERROR_NONE, "failed to sound_manager_create_stream_information(), ret[0x%x]", ret); + + ret = webrtc_mic_source_set_sound_stream_info(g_conns[index].webrtc, source_id, stream_info); + if (ret != WEBRTC_ERROR_NONE) + g_printerr("failed to webrtc_mic_source_set_sound_stream_info(), ret[0x%x]\n", ret); + + sound_manager_destroy_stream_information(stream_info); + } + break; + default: + g_printerr("failed to _webrtc_add_media_source(), invalid type(%d)\n", type); + return; + } + if (type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) { + g_conns[index].packet_sources[i].source_id = source_id; + g_mutex_init(&g_conns[index].packet_sources[i].mutex); + g_cond_init(&g_conns[index].packet_sources[i].cond); } - ret = webrtc_add_media_source(g_conns[index].webrtc, (webrtc_media_source_type_e)(value - 1), &source_id); - RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); - break; - case 8: /* WEBRTC_MEDIA_SOURCE_TYPE_CUSTOM_AUDIO */ - case 9: /* WEBRTC_MEDIA_SOURCE_TYPE_CUSTOM_VIDEO */ - ret = webrtc_add_media_source_internal(g_conns[index].webrtc, (webrtc_media_source_type_internal_e)(value - 1), &source_id); - RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); - break; - default: - break; - } - if ((value - 1) == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) { - g_conns[index].packet_sources[i].source_id = source_id; - g_mutex_init(&g_conns[index].packet_sources[i].mutex); - g_cond_init(&g_conns[index].packet_sources[i].cond); + } else { + webrtc_media_source_type_internal_e type = value - 1; + switch (type) { + case WEBRTC_MEDIA_SOURCE_TYPE_CUSTOM_AUDIO: + case WEBRTC_MEDIA_SOURCE_TYPE_CUSTOM_VIDEO: + ret = webrtc_add_media_source_internal(g_conns[index].webrtc, type, &source_id); + RET_IF(ret != WEBRTC_ERROR_NONE, "ret[0x%x]", ret); + break; + default: + g_printerr("failed to _webrtc_add_media_source(), invalid type(%d)\n", type); + return; + } } - g_print("webrtc_add_media_source() success, source_id[%u]\n", source_id); + g_print("_webrtc_add_media_source() success, source_id[%u]\n", source_id); } static void _webrtc_remove_media_source(int index, unsigned int source_id) -- 2.34.1