From c1e74cb034c6048869fda9312757b53fa79ba6d3 Mon Sep 17 00:00:00 2001 From: Jeongmo Yang Date: Wed, 19 Jun 2019 14:19:42 +0900 Subject: [PATCH] [ACR-1422] Add new APIs for sound ducking - sound_manager_create_stream_ducking - sound_manager_is_ducked - sound_manager_activate_ducking - sound_manager_deactivate_ducking - sound_manager_destroy_stream_ducking [Version] 0.5.31 [Issue Type] New feature Change-Id: I69edb909e469a8ce7078a5fe23701856db738b8e Signed-off-by: Jeongmo Yang --- include/sound_manager.h | 129 ++++++++++++++ include/sound_manager_private.h | 29 +++- packaging/capi-media-sound-manager.spec | 2 +- src/sound_manager.c | 237 +++++++++++++++++++++++++- src/sound_manager_internal.c | 10 +- src/sound_manager_private.c | 286 ++++++++++++++++++++++---------- test/sound_manager_test.c | 122 ++++++++++++++ 7 files changed, 712 insertions(+), 103 deletions(-) diff --git a/include/sound_manager.h b/include/sound_manager.h index b3f6017..9ed2da8 100644 --- a/include/sound_manager.h +++ b/include/sound_manager.h @@ -88,6 +88,12 @@ typedef enum { typedef struct sound_stream_info_s* sound_stream_info_h; /** + * @brief Sound stream ducking handle. + * @since_tizen 5.5 + */ +typedef struct sound_stream_ducking_s* sound_stream_ducking_h; + +/** * @brief Enumeration for sound stream type. * @since_tizen 3.0 */ @@ -276,6 +282,23 @@ typedef enum { typedef void (*sound_manager_volume_changed_cb) (sound_type_e type, unsigned int volume, void *user_data); /** + * @brief Called when the ducking activation or deactivation is finished. + * @since_tizen 5.5 + * + * @remarks This function is invoked by the internal thread of the sound manager. + * Therefore it is recommended not to call functions which update the UI from this callback. + * @remarks @a stream_ducking is the same handle for which the callback was set in the sound_manager_create_stream_ducking() call, + * so it should not be released in this callback. + * + * @param[in] stream_ducking The stream ducking handle + * @param[in] is_ducked The flag whether it's ducked or not + * @param[in] user_data The user data passed from the callback registration function + * @pre You should register this callback when sound_manager_create_stream_ducking() is called. + * @see sound_manager_create_stream_ducking() + */ +typedef void (*sound_stream_ducking_state_changed_cb) (sound_stream_ducking_h stream_ducking, bool is_ducked, void *user_data); + +/** * @} */ @@ -484,6 +507,112 @@ int sound_manager_add_volume_changed_cb(sound_manager_volume_changed_cb callback int sound_manager_remove_volume_changed_cb(int id); /** + * @brief Creates a handle for stream ducking. + * @since_tizen 5.5 + * + * @remarks @a stream_ducking should be released using sound_manager_destroy_stream_ducking(). + * + * @param[in] target_stream The type of target stream + * @param[in] callback The ducking state changed callback function (optional, this can be NULL) + * @param[in] user_data The user data to be passed to the callback function (optional, this can be NULL) + * @param[out] stream_ducking The handle of stream ducking + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @see sound_manager_destroy_stream_ducking() + * @see sound_manager_is_ducked() + * @see sound_manager_activate_ducking() + * @see sound_manager_deactivate_ducking() + */ +int sound_manager_create_stream_ducking(sound_stream_type_e target_stream, sound_stream_ducking_state_changed_cb callback, void *user_data, sound_stream_ducking_h *stream_ducking); + +/** + * @brief Checks if the stream is ducked. + * @since_tizen 5.5 + * + * @param[in] stream_ducking The handle of stream ducking + * @param[out] is_ducked Whether the stream is ducked or not: (@c true = ducked, @c false = unducked) + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @see sound_manager_create_stream_ducking() + * @see sound_manager_destroy_stream_ducking() + * @see sound_manager_activate_ducking() + * @see sound_manager_deactivate_ducking() + */ +int sound_manager_is_ducked(sound_stream_ducking_h stream_ducking, bool *is_ducked); + +/** + * @brief Activates ducking, asynchronously. + * @since_tizen 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/volume.set + * @remarks If ducking is activated successfully, the volume of all sound streams + * matched with target_stream (set in sound_manager_create_stream_ducking()) + * is decreased by @a ratio for @a duration. The change is system-wide. + * @param[in] stream_ducking The handle of stream ducking + * @param[in] duration The duration for ducking (msec, 0 <= duration <= 3000) + * @param[in] ratio The volume ratio after ducked (0.0 < ratio < 1.0) + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_PERMISSION_DENIED Permission denied + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SOUND_MANAGER_ERROR_INVALID_STATE Invalid state + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @pre The stream should be unducked before calling this function, + * otherwise, #SOUND_MANAGER_ERROR_INVALID_STATE is returned. + * @see sound_manager_create_stream_ducking() + * @see sound_manager_destroy_stream_ducking() + * @see sound_manager_is_ducked() + * @see sound_manager_deactivate_ducking() + */ +int sound_manager_activate_ducking(sound_stream_ducking_h stream_ducking, unsigned int duration, double ratio); + +/** + * @brief Deactivates ducking, asynchronously. + * @since_tizen 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/volume.set + * @param[in] stream_ducking The handle of stream ducking + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_PERMISSION_DENIED Permission denied + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SOUND_MANAGER_ERROR_INVALID_STATE Invalid state + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @pre The stream should be ducked before calling this function, + * otherwise, #SOUND_MANAGER_ERROR_INVALID_STATE is returned. + * @see sound_manager_create_stream_ducking() + * @see sound_manager_destroy_stream_ducking() + * @see sound_manager_is_ducked() + * @see sound_manager_activate_ducking() + */ +int sound_manager_deactivate_ducking(sound_stream_ducking_h stream_ducking); + +/** + * @brief Destroys the handle for stream ducking. + * @since_tizen 5.5 + * + * @param[in] stream_ducking The handle of stream ducking + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @see sound_manager_create_stream_ducking() + * @see sound_manager_is_ducked() + * @see sound_manager_activate_ducking() + * @see sound_manager_deactivate_ducking() + */ +int sound_manager_destroy_stream_ducking(sound_stream_ducking_h stream_ducking); + +/** * @} */ diff --git a/include/sound_manager_private.h b/include/sound_manager_private.h index 0502cd0..2434576 100644 --- a/include/sound_manager_private.h +++ b/include/sound_manager_private.h @@ -159,6 +159,7 @@ if (pthread_mutex_unlock(x_mutex)) { \ #define SOUND_STREAM_DIRECTION_MAX 2 #define SOUND_DEVICE_TYPE_LEN 64 #define SOUND_SAMPLE_FORMAT_LEN 12 +#define SOUND_DUCKING_ARR_MAX 128 #define DIRECTION_OUT_STR "out" #define SOUND_TYPE_MASTER_STR "master" @@ -194,14 +195,18 @@ typedef struct _manual_route_info_s { bool is_set; } manual_route_info_s; +typedef struct _sound_pa_info_s { + pa_threaded_mainloop *mainloop; + pa_context *context; + unsigned int index; +} sound_pa_info_s; + typedef struct _sound_stream_info_s { - unsigned int pa_index; int focus_id; char *stream_type; bool is_focus_unavailable; bool is_requesting; - pa_threaded_mainloop *pa_mainloop; - pa_context *pa_context; + sound_pa_info_s pa_info; stream_conf_info_s stream_conf_info; unsigned int prev_acquired_focus; unsigned int acquired_focus; @@ -212,6 +217,16 @@ typedef struct _sound_stream_info_s { pthread_mutex_t focus_cb_mutex; } sound_stream_info_s; +typedef struct _sound_stream_ducking_s { + char *target_stream; + bool is_ducked; + unsigned int duration; + double ratio; + sound_pa_info_s pa_info; + sound_stream_ducking_state_changed_cb user_cb; + void *user_data; +} sound_stream_ducking_s; + typedef enum { _VSTREAM_STATE_READY, _VSTREAM_STATE_RUNNING, @@ -313,8 +328,12 @@ void _pa_context_state_cb(pa_context *c, void *userdata); void _pa_stream_state_cb(pa_stream *s, void * userdata); +int _make_pa_connection(sound_pa_info_s *pa_info, const char *context_name); + int _make_pa_connection_and_register_focus(sound_stream_info_s *stream_h, sound_stream_focus_state_changed_cb callback, void *user_data); +void _destroy_pa_connection(sound_pa_info_s *pa_info); + int _destroy_pa_connection_and_unregister_focus(sound_stream_info_s *stream_h); int _add_device_for_stream_routing(sound_stream_info_s *stream_info, sound_device_h device); @@ -343,6 +362,10 @@ int _set_virtual_stream_volume(virtual_sound_stream_info_s *virtual_stream, doub int _set_acm_master_mode(bool on); +int _activate_ducking(uint32_t stream_index, bool enable, const char *target_stream, uint32_t duration, double ratio); + +int _get_ducking_state(uint32_t stream_index, bool *is_ducked); + #ifdef __cplusplus } #endif diff --git a/packaging/capi-media-sound-manager.spec b/packaging/capi-media-sound-manager.spec index 1071c84..13b9125 100644 --- a/packaging/capi-media-sound-manager.spec +++ b/packaging/capi-media-sound-manager.spec @@ -1,6 +1,6 @@ Name: capi-media-sound-manager Summary: Sound Manager library -Version: 0.5.30 +Version: 0.5.31 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/sound_manager.c b/src/sound_manager.c index eabfbc5..ce9db51 100644 --- a/src/sound_manager.c +++ b/src/sound_manager.c @@ -17,8 +17,40 @@ #include "sound_manager.h" #include "sound_manager_private.h" +static int ducking_arr_count; +static unsigned int ducking_cb_subs_id; +static pthread_mutex_t ducking_mutex; +static sound_stream_ducking_s *ducking_arr[SOUND_DUCKING_ARR_MAX]; + _focus_watch_info_s focus_watch_info_arr[SOUND_STREAM_INFO_ARR_MAX]; +static void _ducking_state_changed_cb(int pa_index, bool is_ducked, void *user_data) +{ + int i = 0; + + SM_ENTER_CRITICAL_SECTION(&ducking_mutex); + + for (i = 0 ; i < SOUND_DUCKING_ARR_MAX ; i++) { + if (ducking_arr[i] && ducking_arr[i]->pa_info.index == pa_index) + break; + } + + if (i < SOUND_DUCKING_ARR_MAX) { + LOGI("ducking state changed [i:%d,ducked:%u]", pa_index, is_ducked); + + if (ducking_arr[i]->user_cb) + ducking_arr[i]->user_cb((sound_stream_ducking_h)ducking_arr[i], is_ducked, ducking_arr[i]->user_data); + else + LOGW("no user callback for pa_index %d", pa_index); + } else { + LOGE("could not found for pa_index %d", pa_index); + } + + SM_LEAVE_CRITICAL_SECTION(&ducking_mutex); + + return; +} + int sound_manager_get_max_volume(sound_type_e type, int *max) { const char *volume_type = NULL; @@ -136,7 +168,7 @@ int sound_manager_create_stream_information(sound_stream_type_e stream_type, sou if (ret == MM_ERROR_NONE) { *stream_info = (sound_stream_info_h)stream_h; LOGI("stream_h(%p), pa_index(%u), focus_id(%d), user_cb(%p), ret(0x%x)", - stream_h, stream_h->pa_index, stream_h->focus_id, stream_h->user_cb, ret); + stream_h, stream_h->pa_info.index, stream_h->focus_id, stream_h->user_cb, ret); } } @@ -325,7 +357,7 @@ int sound_manager_acquire_focus(sound_stream_info_h stream_info, sound_stream_fo if (ret == MM_ERROR_NONE) { stream_h->acquired_focus |= focus_mask; stream_h->prev_acquired_focus |= focus_mask; - _update_focus_status(stream_h->pa_index, (unsigned int)stream_h->acquired_focus); + _update_focus_status(stream_h->pa_info.index, (unsigned int)stream_h->acquired_focus); } LOGI("acquired_focus[0x%x], prev[0x%x]", stream_h->acquired_focus, stream_h->prev_acquired_focus); @@ -385,7 +417,7 @@ int sound_manager_release_focus(sound_stream_info_h stream_info, sound_stream_fo if (ret == MM_ERROR_NONE) { stream_h->acquired_focus &= ~focus_mask; stream_h->prev_acquired_focus &= ~focus_mask; - _update_focus_status(stream_h->pa_index, (unsigned int)stream_h->acquired_focus); + _update_focus_status(stream_h->pa_info.index, (unsigned int)stream_h->acquired_focus); } LOGI("acquired_focus[0x%x], prev[0x%x]", stream_h->acquired_focus, stream_h->prev_acquired_focus); @@ -457,7 +489,7 @@ int sound_manager_acquire_focus_all(sound_stream_info_h stream_info, int sound_b if (ret == MM_ERROR_NONE) { stream_h->acquired_focus |= focus_mask; stream_h->prev_acquired_focus |= focus_mask; - _update_focus_status(stream_h->pa_index, (unsigned int)stream_h->acquired_focus); + _update_focus_status(stream_h->pa_info.index, (unsigned int)stream_h->acquired_focus); } LEAVE: @@ -515,7 +547,7 @@ int sound_manager_release_focus_all(sound_stream_info_h stream_info, int sound_b if (ret == MM_ERROR_NONE) { stream_h->acquired_focus = 0; stream_h->prev_acquired_focus = 0; - _update_focus_status(stream_h->pa_index, (unsigned int)stream_h->acquired_focus); + _update_focus_status(stream_h->pa_info.index, (unsigned int)stream_h->acquired_focus); } LEAVE: @@ -616,7 +648,7 @@ int sound_manager_is_stream_on_device(sound_stream_info_h stream_info, sound_dev SM_NULL_ARG_CHECK(device); SM_NULL_ARG_CHECK(is_on); - ret = mm_sound_is_stream_on_device(stream_h->pa_index, device, is_on); + ret = mm_sound_is_stream_on_device(stream_h->pa_info.index, device, is_on); return _convert_sound_manager_error_code(__func__, ret); } @@ -1115,3 +1147,196 @@ int sound_manager_remove_device_state_changed_cb(int id) return _convert_sound_manager_error_code(__func__, ret); } +int sound_manager_create_stream_ducking(sound_stream_type_e target_stream, sound_stream_ducking_state_changed_cb callback, void *user_data, sound_stream_ducking_h *stream_ducking) +{ + int i = 0; + int ret = MM_ERROR_NONE; + sound_stream_ducking_s *new_ducking = NULL; + + SM_NULL_ARG_CHECK(stream_ducking); + + SM_ENTER_CRITICAL_SECTION_WITH_RETURN(&ducking_mutex, SOUND_MANAGER_ERROR_INTERNAL); + + for (i = 0 ; i < SOUND_DUCKING_ARR_MAX ; i++) + if (ducking_arr[i] == NULL) + break; + + if (i == SOUND_DUCKING_ARR_MAX) { + LOGE("ducking array is full"); + ret = MM_ERROR_SOUND_INTERNAL; + goto LEAVE; + } + + new_ducking = (sound_stream_ducking_s *)calloc(1, sizeof(sound_stream_ducking_s)); + if (!new_ducking) { + ret = MM_ERROR_OUT_OF_MEMORY; + goto LEAVE; + } + + ret = _convert_stream_type(target_stream, &new_ducking->target_stream); + if (ret != MM_ERROR_NONE) + goto LEAVE; + + ret = _make_pa_connection(&new_ducking->pa_info, "SOUND_MANAGER_STREAM_DUCKING"); + +LEAVE: + if (ret == MM_ERROR_NONE) { + if (++ducking_arr_count == 1) { + /* subscribe ducking finished signal */ + ret = mm_sound_add_ducking_state_changed_callback((mm_sound_ducking_state_changed_cb)_ducking_state_changed_cb, + NULL, &ducking_cb_subs_id); + if (ret != MM_ERROR_NONE) { + ducking_arr_count = 0; + goto LEAVE; + } + + LOGI("ducking state changed cb subs id %d", ducking_cb_subs_id); + } + + new_ducking->user_cb = callback; + new_ducking->user_data = user_data; + + ducking_arr[i] = new_ducking; + *stream_ducking = (sound_stream_ducking_h)new_ducking; + + LOGI("new stream_ducking(%p), target_stream(%s), pa_index(%u), user_cb(%p)", + new_ducking, new_ducking->target_stream, new_ducking->pa_info.index, new_ducking->user_cb); + } else { + if (new_ducking) { + _destroy_pa_connection(&new_ducking->pa_info); + free(new_ducking); + } + } + + SM_LEAVE_CRITICAL_SECTION(&ducking_mutex); + + return _convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_destroy_stream_ducking(sound_stream_ducking_h stream_ducking) +{ + int i = 0; + int ret = MM_ERROR_NONE; + bool is_ducked = false; + sound_stream_ducking_s *ducking = (sound_stream_ducking_s*)stream_ducking; + + LOGI(">> enter %p", ducking); + + SM_INSTANCE_CHECK(ducking); + + ret = _get_ducking_state(ducking->pa_info.index, &is_ducked); + if (ret != MM_ERROR_NONE) + return _convert_sound_manager_error_code(__func__, ret); + + SM_ENTER_CRITICAL_SECTION_WITH_RETURN(&ducking_mutex, SOUND_MANAGER_ERROR_INTERNAL); + + if (!is_ducked) { + _destroy_pa_connection(&ducking->pa_info); + } else { + LOGE("ducked now, it should be deactivated first."); + ret = MM_ERROR_SOUND_INVALID_STATE; + } + + if (ret == MM_ERROR_NONE) { + LOGI("destroy stream ducking(%p)", ducking); + + for (i = 0 ; i < SOUND_DUCKING_ARR_MAX ; i++) + if (ducking_arr[i] == ducking) + ducking_arr[i] = NULL; + + if (--ducking_arr_count == 0) { + /* unsubscribe ducking finished signal */ + if (mm_sound_remove_ducking_state_changed_callback(ducking_cb_subs_id) != MM_ERROR_NONE) + LOGW("mm_sound_remove_ducking_state_changed_callback(id:%u) failed", ducking_cb_subs_id); + + ducking_cb_subs_id = 0; + } + + free(ducking); + } + + SM_LEAVE_CRITICAL_SECTION(&ducking_mutex); + + return _convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_is_ducked(sound_stream_ducking_h stream_ducking, bool *is_ducked) +{ + int ret = MM_ERROR_NONE; + sound_stream_ducking_s *ducking = (sound_stream_ducking_s*)stream_ducking; + + LOGI(">> enter %p", ducking); + + SM_INSTANCE_CHECK(ducking); + SM_NULL_ARG_CHECK(is_ducked); + + ret = _get_ducking_state(ducking->pa_info.index, is_ducked); + + return _convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_activate_ducking(sound_stream_ducking_h stream_ducking, unsigned int duration, double ratio) +{ + int ret = MM_ERROR_NONE; + bool is_ducked = false; + sound_stream_ducking_s *ducking = (sound_stream_ducking_s*)stream_ducking; + + if (duration > 3000 || ratio >= 1.0 || ratio <= 0.0) { + LOGE("Invalid params : duration(%u) or ratio(%lf)", duration, ratio); + return SOUND_MANAGER_ERROR_INVALID_PARAMETER; + } + + LOGI(">> enter %p - duration(%u), ratio(%lf)", ducking, duration, ratio); + + SM_INSTANCE_CHECK(ducking); + + ret = _get_ducking_state(ducking->pa_info.index, &is_ducked); + if (ret != MM_ERROR_NONE) + return _convert_sound_manager_error_code(__func__, ret); + + SM_ENTER_CRITICAL_SECTION_WITH_RETURN(&ducking_mutex, SOUND_MANAGER_ERROR_INTERNAL); + + if (!is_ducked) { + ducking->duration = duration; + ducking->ratio = ratio; + + ret = _activate_ducking(ducking->pa_info.index, + true, ducking->target_stream, ducking->duration, ducking->ratio); + } else { + LOGE("already ducked"); + ret = MM_ERROR_SOUND_INVALID_STATE; + } + + SM_LEAVE_CRITICAL_SECTION(&ducking_mutex); + + return _convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_deactivate_ducking(sound_stream_ducking_h stream_ducking) +{ + int ret = MM_ERROR_NONE; + bool is_ducked = false; + sound_stream_ducking_s *ducking = (sound_stream_ducking_s*)stream_ducking; + + LOGI(">> enter %p", ducking); + + SM_INSTANCE_CHECK(ducking); + + ret = _get_ducking_state(ducking->pa_info.index, &is_ducked); + if (ret != MM_ERROR_NONE) + return _convert_sound_manager_error_code(__func__, ret); + + SM_ENTER_CRITICAL_SECTION_WITH_RETURN(&ducking_mutex, SOUND_MANAGER_ERROR_INTERNAL); + + if (is_ducked) { + ret = _activate_ducking(ducking->pa_info.index, + false, ducking->target_stream, ducking->duration, ducking->ratio); + } else { + LOGE("not ducked"); + ret = MM_ERROR_SOUND_INVALID_STATE; + } + + SM_LEAVE_CRITICAL_SECTION(&ducking_mutex); + + return _convert_sound_manager_error_code(__func__, ret); +} diff --git a/src/sound_manager_internal.c b/src/sound_manager_internal.c index a2670a1..106fe93 100644 --- a/src/sound_manager_internal.c +++ b/src/sound_manager_internal.c @@ -113,7 +113,7 @@ int sound_manager_create_stream_information_internal(sound_stream_type_internal_ if (!ret) { *stream_info = (sound_stream_info_h)stream_h; LOGI("stream_h(%p), pa_index(%u), focus_id(%d), user_cb(%p), ret(0x%x)", - stream_h, stream_h->pa_index, stream_h->focus_id, stream_h->user_cb, ret); + stream_h, stream_h->pa_info.index, stream_h->focus_id, stream_h->user_cb, ret); } } @@ -134,7 +134,7 @@ int sound_manager_set_stream_routing_option(sound_stream_info_h stream_info, con SM_INSTANCE_CHECK(stream_h); SM_NULL_ARG_CHECK(name); - ret = _set_route_option(stream_h->pa_index, name, value); + ret = _set_route_option(stream_h->pa_info.index, name, value); return _convert_sound_manager_error_code(__func__, ret); } @@ -182,8 +182,8 @@ int sound_manager_get_index_from_stream_information(sound_stream_info_h stream_i SM_INSTANCE_CHECK(stream_h); SM_NULL_ARG_CHECK(index); - *index = stream_h->pa_index; - LOGI("stream_index[%u]", stream_h->pa_index); + *index = stream_h->pa_info.index; + LOGI("stream_index[%u]", stream_h->pa_info.index); return _convert_sound_manager_error_code(__func__, ret); } @@ -692,7 +692,7 @@ int sound_manager_is_stream_on_device_by_id(sound_stream_info_h stream_info, int SM_NULL_ARG_CHECK(stream_h); SM_NULL_ARG_CHECK(is_on); - ret = mm_sound_is_stream_on_device_by_id(stream_h->pa_index, device_id, is_on); + ret = mm_sound_is_stream_on_device_by_id(stream_h->pa_info.index, device_id, is_on); return _convert_sound_manager_error_code(__func__, ret); } diff --git a/src/sound_manager_private.c b/src/sound_manager_private.c index 30f2294..225aa4e 100644 --- a/src/sound_manager_private.c +++ b/src/sound_manager_private.c @@ -34,6 +34,8 @@ #define PA_STREAM_MANAGER_METHOD_NAME_GET_CURRENT_MEDIA_ROUTING_PATH "GetCurrentMediaRoutingPath" #define PA_STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS "UpdateFocusStatus" #define PA_STREAM_MANAGER_METHOD_NAME_CHECK_STREAM_EXIST_BY_PID "CheckStreamExistByPid" +#define PA_STREAM_MANAGER_METHOD_NAME_ACTIVATE_DUCKING "ActivateDucking" +#define PA_STREAM_MANAGER_METHOD_NAME_GET_DUCKING_STATE "GetDuckingState" #define PA_DEVICE_MANAGER_OBJECT_PATH "/org/pulseaudio/DeviceManager" #define PA_DEVICE_MANAGER_INTERFACE "org.pulseaudio.DeviceManager" @@ -53,38 +55,26 @@ #define VCONF_PATH_PREFIX_VOLUME "file/private/sound/volume/" #define VCONF_PATH_MAX 64 -#define DBUS_ERR_MSG_MAX 24 - //LCOV_EXCL_START int _convert_dbus_error(const char *error_msg) { int ret = MM_ERROR_NONE; - const char ch = '.'; - char *ret_str; if (!error_msg) return MM_ERROR_SOUND_INTERNAL; - /* parsing dbus error message, for example, - * GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: - * org.tizen.multimedia.audio.InvalidArgument */ - if (!(ret_str = strrchr(error_msg, ch))) - return MM_ERROR_SOUND_INTERNAL; - - ret_str = ret_str + 1; - if (ret_str[0] == '\0') - return MM_ERROR_SOUND_INTERNAL; - - if (!strncmp(ret_str, "InvalidArgument", DBUS_ERR_MSG_MAX)) + if (strstr(error_msg, "InvalidArgument")) ret = MM_ERROR_INVALID_ARGUMENT; - else if (!strncmp(ret_str, "InvalidOperation", DBUS_ERR_MSG_MAX)) + else if (strstr(error_msg, "InvalidOperation")) ret = MM_ERROR_SOUND_INVALID_OPERATION; - else if (!strncmp(ret_str, "PolicyInternal", DBUS_ERR_MSG_MAX)) + else if (strstr(error_msg, "PolicyInternal")) ret = MM_ERROR_POLICY_INTERNAL; + else if (strstr(error_msg, "AccessDenied")) + ret = MM_ERROR_SOUND_PERMISSION_DENIED; else ret = MM_ERROR_SOUND_INTERNAL; - LOGE("%s => 0x%x", ret_str, ret); + LOGE("%s => 0x%x", error_msg, ret); return ret; } @@ -165,8 +155,6 @@ int _convert_sound_manager_error_code(const char *func, int code) int _convert_stream_type(sound_stream_type_e stream_type_enum, char **stream_type) { - int ret = MM_ERROR_NONE; - if (stream_type == NULL) return MM_ERROR_INVALID_ARGUMENT; @@ -204,13 +192,13 @@ int _convert_stream_type(sound_stream_type_e stream_type_enum, char **stream_typ default: //LCOV_EXCL_START LOGE("could not find the stream_type[%d] in this switch case statement", stream_type_enum); - ret = MM_ERROR_SOUND_INTERNAL; - break; + return MM_ERROR_SOUND_INTERNAL; //LCOV_EXCL_STOP } + LOGI("stream_type[%s]", *stream_type); - return ret; + return MM_ERROR_NONE; } //LCOV_EXCL_START @@ -765,7 +753,7 @@ void _focus_state_change_callback(int index, mm_sound_focus_type_e focus_type, m stream_info->acquired_focus |= focus_type; if (state == FOCUS_IS_ACQUIRED) - _update_focus_status(stream_info->pa_index, (unsigned int)stream_info->acquired_focus); + _update_focus_status(stream_info->pa_info.index, (unsigned int)stream_info->acquired_focus); LOGI("[FOCUS USER CALLBACK(%p) START]", stream_info->user_cb); stream_info->user_cb((sound_stream_info_h)stream_info, focus_type, state, change_reason, @@ -773,7 +761,7 @@ void _focus_state_change_callback(int index, mm_sound_focus_type_e focus_type, m LOGI("[FOCUS USER CALLBACK(%p) END]", stream_info->user_cb); if (state == FOCUS_IS_RELEASED) - _update_focus_status(stream_info->pa_index, (unsigned int)stream_info->acquired_focus); + _update_focus_status(stream_info->pa_info.index, (unsigned int)stream_info->acquired_focus); if (state == FOCUS_IS_RELEASED) stream_info->prev_acquired_focus &= ~focus_type; @@ -823,17 +811,17 @@ LEAVE: void _pa_context_state_cb(pa_context *c, void *userdata) { pa_context_state_t state; - sound_stream_info_s *stream_info_h = (sound_stream_info_s*)userdata; + sound_pa_info_s *pa_info = (sound_pa_info_s *)userdata; assert(c); state = pa_context_get_state(c); - LOGI("[%p] context state = [%d]", stream_info_h, state); + LOGI("[%p] context state = [%d]", pa_info, state); switch (state) { case PA_CONTEXT_READY: case PA_CONTEXT_TERMINATED: case PA_CONTEXT_FAILED: - pa_threaded_mainloop_signal(stream_info_h->pa_mainloop, 0); + pa_threaded_mainloop_signal(pa_info->mainloop, 0); break; case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: @@ -1956,61 +1944,82 @@ LEAVE: } //LCOV_EXCL_STOP -int _make_pa_connection_and_register_focus(sound_stream_info_s *stream_h, sound_stream_focus_state_changed_cb callback, void *user_data) +int _make_pa_connection(sound_pa_info_s *pa_info, const char *context_name) { - int ret = MM_ERROR_NONE; int pa_ret = PA_OK; - int i = 0; - bool is_focus_cb_thread = false; - - if ((ret = mm_sound_focus_is_cb_thread(&is_focus_cb_thread, NULL))) - return ret; - - if (is_focus_cb_thread) - return MM_ERROR_SOUND_INVALID_OPERATION; - - /* get configuration information of this stream type */ - if ((ret = _get_stream_conf_info(stream_h->stream_type, &stream_h->stream_conf_info))) - return ret; - LOGI("stream_conf_info : stream type[%s], priority[%d], route type[%d]", - stream_h->stream_type, stream_h->stream_conf_info.priority, stream_h->stream_conf_info.route_type); + SM_NULL_ARG_CHECK_FOR_PRIV(pa_info); - if (!(stream_h->pa_mainloop = pa_threaded_mainloop_new())) + if (!(pa_info->mainloop = pa_threaded_mainloop_new())) goto PA_ERROR; - if (!(stream_h->pa_context = pa_context_new(pa_threaded_mainloop_get_api(stream_h->pa_mainloop), "SOUND_MANAGER_STREAM_INFO"))) + if (!(pa_info->context = pa_context_new(pa_threaded_mainloop_get_api(pa_info->mainloop), context_name))) goto PA_ERROR; - pa_context_set_state_callback(stream_h->pa_context, _pa_context_state_cb, stream_h); + pa_context_set_state_callback(pa_info->context, _pa_context_state_cb, pa_info); - if (pa_context_connect(stream_h->pa_context, NULL, 0, NULL) < 0) { - pa_ret = pa_context_errno(stream_h->pa_context);//LCOV_EXCL_LINE + if (pa_context_connect(pa_info->context, NULL, 0, NULL) < 0) { + pa_ret = pa_context_errno(pa_info->context);//LCOV_EXCL_LINE goto PA_ERROR; } - pa_threaded_mainloop_lock(stream_h->pa_mainloop); + pa_threaded_mainloop_lock(pa_info->mainloop); - if (pa_threaded_mainloop_start(stream_h->pa_mainloop) < 0) + if (pa_threaded_mainloop_start(pa_info->mainloop) < 0) goto PA_ERROR_WITH_UNLOCK; /* wait for ready state of the context */ for (;;) { pa_context_state_t state; - state = pa_context_get_state(stream_h->pa_context); + state = pa_context_get_state(pa_info->context); if (state == PA_CONTEXT_READY) break; if (!PA_CONTEXT_IS_GOOD(state)) { - pa_ret = pa_context_errno(stream_h->pa_context);//LCOV_EXCL_LINE + pa_ret = pa_context_errno(pa_info->context);//LCOV_EXCL_LINE goto PA_ERROR_WITH_UNLOCK; } - pa_threaded_mainloop_wait(stream_h->pa_mainloop); + pa_threaded_mainloop_wait(pa_info->mainloop); } /* get index of this context */ - stream_h->pa_index = pa_context_get_index(stream_h->pa_context); + pa_info->index = pa_context_get_index(pa_info->context); - pa_threaded_mainloop_unlock(stream_h->pa_mainloop); + pa_threaded_mainloop_unlock(pa_info->mainloop); + + return MM_ERROR_NONE; +//LCOV_EXCL_START +PA_ERROR_WITH_UNLOCK: + pa_threaded_mainloop_unlock(pa_info->mainloop); + +PA_ERROR: + _destroy_pa_connection(pa_info); + LOGE("pa_ret %d", pa_ret); + + return MM_ERROR_SOUND_INTERNAL; +//LCOV_EXCL_STOP +} + +int _make_pa_connection_and_register_focus(sound_stream_info_s *stream_h, sound_stream_focus_state_changed_cb callback, void *user_data) +{ + int ret = MM_ERROR_NONE; + int i = 0; + bool is_focus_cb_thread = false; + + if ((ret = mm_sound_focus_is_cb_thread(&is_focus_cb_thread, NULL))) + return ret; + + if (is_focus_cb_thread) + return MM_ERROR_SOUND_INVALID_OPERATION; + + /* get configuration information of this stream type */ + if ((ret = _get_stream_conf_info(stream_h->stream_type, &stream_h->stream_conf_info))) + return ret; + + LOGI("stream_conf_info : stream type[%s], priority[%d], route type[%d]", + stream_h->stream_type, stream_h->stream_conf_info.priority, stream_h->stream_conf_info.route_type); + + if ((ret = _make_pa_connection(&stream_h->pa_info, "SOUND_MANAGER_STREAM_INFO"))) + goto ERROR; /* register focus */ if (!stream_h->is_focus_unavailable) { @@ -2021,15 +2030,12 @@ int _make_pa_connection_and_register_focus(sound_stream_info_s *stream_h, sound_ } else { LOGE("failed to register focus, ret(0x%x)", ret);//LCOV_EXCL_LINE /* disconnect */ - goto PA_ERROR; + goto ERROR; } } goto SUCCESS; //LCOV_EXCL_START -PA_ERROR_WITH_UNLOCK: - pa_threaded_mainloop_unlock(stream_h->pa_mainloop); - -PA_ERROR: +ERROR: for (i = 0; i < AVAIL_DEVICES_MAX; i++) { SM_SAFE_FREE(stream_h->stream_conf_info.avail_in_devices[i]); SM_SAFE_FREE(stream_h->stream_conf_info.avail_out_devices[i]); @@ -2039,22 +2045,40 @@ PA_ERROR: SM_SAFE_FREE(stream_h->stream_conf_info.volume_type); - if (stream_h->pa_context) { - pa_context_disconnect(stream_h->pa_context); - pa_context_unref(stream_h->pa_context); - stream_h->pa_context = NULL; - } - if (stream_h->pa_mainloop) { - pa_threaded_mainloop_free(stream_h->pa_mainloop); - stream_h->pa_mainloop = NULL; - } + _destroy_pa_connection(&stream_h->pa_info); + ret = MM_ERROR_SOUND_INTERNAL; - LOGE("pa_ret(%d), ret(0x%x)", pa_ret, ret); //LCOV_EXCL_STOP SUCCESS: return ret; } +void _destroy_pa_connection(sound_pa_info_s *pa_info) +{ + if (!pa_info) { + LOGW("NULL pa info - skip.."); + return; + } + + LOGI("[%p][%p]", pa_info->mainloop, pa_info->context); + + if (pa_info->mainloop) + pa_threaded_mainloop_stop(pa_info->mainloop); + + if (pa_info->context) { + pa_context_disconnect(pa_info->context); + pa_context_unref(pa_info->context); + pa_info->context = NULL; + } + + if (pa_info->mainloop) { + pa_threaded_mainloop_free(pa_info->mainloop); + pa_info->mainloop = NULL; + } + + return; +} + int _destroy_pa_connection_and_unregister_focus(sound_stream_info_s *stream_h) { int i = 0; @@ -2068,19 +2092,7 @@ int _destroy_pa_connection_and_unregister_focus(sound_stream_info_s *stream_h) if (is_focus_cb_thread) return MM_ERROR_SOUND_INVALID_OPERATION; - if (stream_h->pa_mainloop) - pa_threaded_mainloop_stop(stream_h->pa_mainloop); - - if (stream_h->pa_context) { - pa_context_disconnect(stream_h->pa_context); - pa_context_unref(stream_h->pa_context); - stream_h->pa_context = NULL; - } - - if (stream_h->pa_mainloop) { - pa_threaded_mainloop_free(stream_h->pa_mainloop); - stream_h->pa_mainloop = NULL; - } + _destroy_pa_connection(&stream_h->pa_info); /* unregister focus */ if (!stream_h->is_focus_unavailable) { @@ -2399,7 +2411,7 @@ int _apply_stream_routing(sound_stream_info_s *stream_info) for (i = 0; i < AVAIL_DEVICES_MAX; i++) { if (stream_info->manual_route_info.route_in_devices[i] || stream_info->manual_route_info.route_out_devices[i]) - return _set_manual_route_info(stream_info->pa_index, &stream_info->manual_route_info); + return _set_manual_route_info(stream_info->pa_info.index, &stream_info->manual_route_info); } return MM_ERROR_SOUND_INVALID_STATE; @@ -2438,11 +2450,11 @@ int _create_virtual_stream(sound_stream_info_s *stream_info, virtual_sound_strea memset((*virtual_stream), 0, sizeof(virtual_sound_stream_info_s)); (*virtual_stream)->stream_type = stream_info->stream_type; - (*virtual_stream)->pa_mainloop = stream_info->pa_mainloop; - (*virtual_stream)->pa_context = stream_info->pa_context; + (*virtual_stream)->pa_mainloop = stream_info->pa_info.mainloop; + (*virtual_stream)->pa_context = stream_info->pa_info.context; (*virtual_stream)->pa_proplist = pa_proplist_new(); pa_proplist_sets((*virtual_stream)->pa_proplist, PA_PROP_MEDIA_ROLE, (*virtual_stream)->stream_type); - pa_proplist_setf((*virtual_stream)->pa_proplist, PA_PROP_MEDIA_PARENT_ID, "%u", stream_info->pa_index); + pa_proplist_setf((*virtual_stream)->pa_proplist, PA_PROP_MEDIA_PARENT_ID, "%u", stream_info->pa_info.index); (*virtual_stream)->state = _VSTREAM_STATE_READY; (*virtual_stream)->stream_info = stream_info; @@ -2704,3 +2716,101 @@ LEAVE: return ret; } //LCOV_EXCL_STOP + +int _activate_ducking(uint32_t stream_index, bool enable, const char *target_stream, uint32_t duration, double ratio) +{ + int ret = MM_ERROR_NONE; + GDBusConnection *conn = NULL; + GError *err = NULL; + GVariant *result = NULL; + const gchar *dbus_ret = NULL; + + if ((ret = __get_dbus_connection(&conn))) + return ret; + + result = g_dbus_connection_call_sync(conn, + PA_BUS_NAME, + PA_STREAM_MANAGER_OBJECT_PATH, + PA_STREAM_MANAGER_INTERFACE, + PA_STREAM_MANAGER_METHOD_NAME_ACTIVATE_DUCKING, + g_variant_new("(ubsud)", stream_index, enable, target_stream, duration, ratio), + G_VARIANT_TYPE("(s)"), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + &err); + if (!result || err) { + LOGE("g_dbus_connection_call_sync() for ACTIVATE_DUCKING error"); + ret = _convert_dbus_error(err ? err->message : NULL); + if (err) + g_error_free(err); + goto LEAVE; + } + + g_variant_get(result, "(&s)", &dbus_ret); + + LOGI("g_dbus_connection_call_sync() success, method return value is (%s)", dbus_ret); + + if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) + ret = MM_ERROR_SOUND_INTERNAL; + +LEAVE: + g_variant_unref(result); + g_object_unref(conn); + + return ret; +} + +int _get_ducking_state(uint32_t stream_index, bool *is_ducked) +{ + int ret = MM_ERROR_NONE; + gboolean _is_ducked = FALSE; + GDBusConnection *conn = NULL; + GError *err = NULL; + GVariant *result = NULL; + const gchar *dbus_ret = NULL; + + SM_NULL_ARG_CHECK_FOR_PRIV(is_ducked); + + if ((ret = __get_dbus_connection(&conn))) + return ret; + + result = g_dbus_connection_call_sync(conn, + PA_BUS_NAME, + PA_STREAM_MANAGER_OBJECT_PATH, + PA_STREAM_MANAGER_INTERFACE, + PA_STREAM_MANAGER_METHOD_NAME_GET_DUCKING_STATE, + g_variant_new("(u)", stream_index), + G_VARIANT_TYPE("(bs)"), + G_DBUS_CALL_FLAGS_NONE, + 1000, + NULL, + &err); + if (!result || err) { + LOGE("g_dbus_connection_call_sync() for GET_DUCKING_STATE error"); + ret = _convert_dbus_error(err ? err->message : NULL); + if (err) + g_error_free(err); + goto LEAVE; + } + + g_variant_get(result, "(b&s)", &_is_ducked, &dbus_ret); + + LOGI("dbus return value is (%s)", dbus_ret); + + if (!strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) { + *is_ducked = (bool)_is_ducked; + LOGI("is_ducked %u", *is_ducked); + } else { + ret = MM_ERROR_SOUND_INTERNAL; + } + + if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) + ret = MM_ERROR_SOUND_INTERNAL; + +LEAVE: + g_variant_unref(result); + g_object_unref(conn); + + return ret; +} diff --git a/test/sound_manager_test.c b/test/sound_manager_test.c index bfa5522..64314b9 100644 --- a/test/sound_manager_test.c +++ b/test/sound_manager_test.c @@ -99,6 +99,11 @@ enum { CURRENT_STATUS_GET_MASTER_VOLUME, CURRENT_STATUS_SET_ACM_MASTER_MODE, #endif + CURRENT_STATUS_CREATE_STREAM_DUCKING, + CURRENT_STATUS_DESTROY_STREAM_DUCKING, + CURRENT_STATUS_ACTIVATE_DUCKING, + CURRENT_STATUS_DEACTIVATE_DUCKING, + CURRENT_STATUS_GET_DUCKING_STATE, }; @@ -110,6 +115,7 @@ sound_device_h g_device = NULL; sound_device_mask_e g_device_mask = SOUND_DEVICE_ALL_MASK; sound_stream_info_h g_stream_info_h = NULL; virtual_sound_stream_h g_vstream_h = NULL; +sound_stream_ducking_h g_stream_ducking_h = NULL; int g_volume_cb_id; int g_device_conn_cb_id; int g_device_state_cb_id; @@ -177,6 +183,13 @@ void focus_watch_callback(int id, sound_stream_focus_mask_e focus_mask, sound_s return; } +void ducking_state_changed_cb(sound_stream_ducking_h stream_ducking, bool is_ducked, void *user_data) +{ + g_print("stream_ducking %p, is_ducked %u\n", stream_ducking, is_ducked); + + return; +} + void quit_program() { g_main_loop_quit(g_loop); @@ -318,6 +331,16 @@ void _interpret_main_menu(char *cmd) else if (strncmp(cmd, "acm", MAX_CMD_LEN) == 0) g_menu_state = CURRENT_STATUS_SET_ACM_MASTER_MODE; #endif + else if (strncmp(cmd, "csd", MAX_CMD_LEN) == 0) + g_menu_state = CURRENT_STATUS_CREATE_STREAM_DUCKING; + else if (strncmp(cmd, "dsd", MAX_CMD_LEN) == 0) + g_menu_state = CURRENT_STATUS_DESTROY_STREAM_DUCKING; + else if (strncmp(cmd, "adk", MAX_CMD_LEN) == 0) + g_menu_state = CURRENT_STATUS_ACTIVATE_DUCKING; + else if (strncmp(cmd, "ddk", MAX_CMD_LEN) == 0) + g_menu_state = CURRENT_STATUS_DEACTIVATE_DUCKING; + else if (strncmp(cmd, "gds", MAX_CMD_LEN) == 0) + g_menu_state = CURRENT_STATUS_GET_DUCKING_STATE; else if (strncmp(cmd, "q", MAX_CMD_LEN) == 0) { g_print("closing the test suite\n"); quit_program(); @@ -346,6 +369,11 @@ void display_sub_basic() g_print("mgv. *Get Master Volume \t"); g_print("msv. *Set Master Volume \n"); #endif + g_print("csd. Create Stream Ducking\t"); + g_print("dsd. Destroy Stream Ducking\n"); + g_print("adk. Activate Ducking\t\t"); + g_print("ddk. Deactivate Ducking\n"); + g_print("gds. Get Ducking State\n"); g_print("-----------------------------------------------------------------------------------------\n"); g_print(" DEVICE MODULE \n"); g_print("-----------------------------------------------------------------------------------------\n"); @@ -557,6 +585,18 @@ static void displaymenu() else if (g_menu_state == CURRENT_STATUS_SET_ACM_MASTER_MODE) g_print("*** input master mode enable or disable (0:disable 1:enable)\n"); #endif + else if (g_menu_state == CURRENT_STATUS_CREATE_STREAM_DUCKING) + g_print("*** input target stream (0:MEDIA 1:SYSTEM 2:ALARM 3:NOTIFICATION 4:EMERGENCY 5:VOICE_INFORMATION 6:VOICE_RECOGNITION 7:RINGTONE_VOIP 8:VOIP 9:MEDIA_EXTERNAL_ONLY\n"); + else if (g_menu_state == CURRENT_STATUS_DESTROY_STREAM_DUCKING) + g_print("*** press enter to destroy stream ducking\n"); + else if (g_menu_state == CURRENT_STATUS_ACTIVATE_DUCKING) { + if (flag == 0) + g_print("*** input duration (0 <= duration <= 3000) and ratio (0.0 < ratio < 1.0)\n"); + flag = 1; + } else if (g_menu_state == CURRENT_STATUS_DEACTIVATE_DUCKING) + g_print("*** press enter to deactivate ducking\n"); + else if (g_menu_state == CURRENT_STATUS_GET_DUCKING_STATE) + g_print("*** press enter to get ducking state\n"); else { g_print("*** unknown status.\n"); quit_program(); @@ -2176,6 +2216,88 @@ static void interpret(char *cmd) break; } #endif + case CURRENT_STATUS_CREATE_STREAM_DUCKING: { + int ret = SOUND_MANAGER_ERROR_NONE; + sound_stream_type_e target_stream = SOUND_STREAM_TYPE_MEDIA; + + if (g_stream_ducking_h) { + g_print("fail to create stream ducking, g_stream_ducking_h(%p) is already set\n", g_stream_ducking_h); + reset_menu_state(); + break; + } + + target_stream = (sound_stream_type_e)atoi(cmd); + + ret = sound_manager_create_stream_ducking(target_stream, + ducking_state_changed_cb, NULL, &g_stream_ducking_h); + if (ret) + g_print("fail to sound_manager_create_stream_ducking(t:%u), ret(0x%x)\n", target_stream, ret); + + reset_menu_state(); + break; + } + case CURRENT_STATUS_DESTROY_STREAM_DUCKING: { + int ret = SOUND_MANAGER_ERROR_NONE; + ret = sound_manager_destroy_stream_ducking(g_stream_ducking_h); + if (ret) + g_print("fail to sound_manager_destroy_stream_ducking(), ret(0x%x)\n", ret); + else + g_stream_ducking_h = NULL; + + reset_menu_state(); + break; + } + case CURRENT_STATUS_ACTIVATE_DUCKING: { + int ret = SOUND_MANAGER_ERROR_NONE; + static int cnt = 0; + static unsigned int duration = 0; + static double ratio = 0; + + switch (cnt) { + case 0: + duration = (unsigned int)atoi(cmd); + cnt++; + break; + case 1: + ratio = (double)atof(cmd); + + ret = sound_manager_activate_ducking(g_stream_ducking_h, duration, ratio); + if (ret) + g_print("fail to activate_ducking(%u,%lf), ret(0x%x)\n", duration, ratio, ret); + else + g_print("success to sound_manager_activate_ducking()\n"); + + cnt = 0; + reset_menu_state(); + break; + } + break; + } + case CURRENT_STATUS_DEACTIVATE_DUCKING: { + int ret = SOUND_MANAGER_ERROR_NONE; + + ret = sound_manager_deactivate_ducking(g_stream_ducking_h); + if (ret) + g_print("fail to sound_manager_deactivate_ducking(), ret(0x%x)\n", ret); + else + g_print("success to sound_manager_deactivate_ducking()\n"); + + reset_menu_state(); + break; + } + case CURRENT_STATUS_GET_DUCKING_STATE: { + int ret = SOUND_MANAGER_ERROR_NONE; + bool is_ducked = false; + + ret = sound_manager_is_ducked(g_stream_ducking_h, &is_ducked); + if (ret) + g_print("fail to sound_manager_is_ducked(), ret(0x%x)\n", ret); + else + g_print("success to sound_manager_is_ducked() - is_ducked %u\n", is_ducked); + + reset_menu_state(); + break; + } } g_timeout_add(100, timeout_menu_display, 0); } -- 2.7.4