From: Sangchul Lee Date: Tue, 10 Feb 2015 13:28:35 +0000 (+0900) Subject: Support new features for sound policy X-Git-Tag: submit/tizen/20150715.092047~18 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F93%2F41093%2F2;p=platform%2Fcore%2Fapi%2Fsound-manager.git Support new features for sound policy Public header: Stream Information and Focus Internal header: Virtual stream and getter methods [Version] 0.3.0 [Profile] Common [Issue Type] New feature Change-Id: I3aca6780d1c80ffe111096ca4df4030b8682229a --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 05a3d0a..e0b87d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ SET(service "media") SET(submodule "sound-manager") # for package file -SET(dependents "mm-sound dlog capi-base-common mm-session") +SET(dependents "mm-sound dlog capi-base-common mm-session libpulse gio-2.0") SET(pc_dependents "capi-base-common") # for deb diff --git a/include/sound_manager.h b/include/sound_manager.h index fa13866..0507fa2 100644 --- a/include/sound_manager.h +++ b/include/sound_manager.h @@ -40,16 +40,17 @@ extern "C" */ typedef enum { - SOUND_MANAGER_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ - SOUND_MANAGER_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ - SOUND_MANAGER_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ - SOUND_MANAGER_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */ - SOUND_MANAGER_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ - SOUND_MANAGER_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */ - SOUND_MANAGER_ERROR_NO_DATA = TIZEN_ERROR_NO_DATA, /**< No data */ - SOUND_MANAGER_ERROR_INTERNAL = TIZEN_ERROR_SOUND_MANAGER | 01, /**< Internal error inside the sound system */ - SOUND_MANAGER_ERROR_POLICY = TIZEN_ERROR_SOUND_MANAGER | 02, /**< Noncompliance with the sound system policy */ - SOUND_MANAGER_ERROR_NO_PLAYING_SOUND = TIZEN_ERROR_SOUND_MANAGER | 03, /**< No playing sound */ + SOUND_MANAGER_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ + SOUND_MANAGER_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + SOUND_MANAGER_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + SOUND_MANAGER_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */ + SOUND_MANAGER_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ + SOUND_MANAGER_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */ + SOUND_MANAGER_ERROR_NO_DATA = TIZEN_ERROR_NO_DATA, /**< No data */ + SOUND_MANAGER_ERROR_INTERNAL = TIZEN_ERROR_SOUND_MANAGER | 01, /**< Internal error inside the sound system */ + SOUND_MANAGER_ERROR_POLICY = TIZEN_ERROR_SOUND_MANAGER | 02, /**< Noncompliance with the sound system policy */ + SOUND_MANAGER_ERROR_NO_PLAYING_SOUND = TIZEN_ERROR_SOUND_MANAGER | 03, /**< No playing sound */ + SOUND_MANAGER_ERROR_INVALID_STATE = TIZEN_ERROR_SOUND_MANAGER | 04, /**< Invalid state (Since 2.4) */ } sound_manager_error_e; /** @@ -63,16 +64,111 @@ typedef enum */ typedef enum { - SOUND_TYPE_SYSTEM, /**< Sound type for system */ - SOUND_TYPE_NOTIFICATION, /**< Sound type for notifications */ - SOUND_TYPE_ALARM, /**< Sound type for alarm */ - SOUND_TYPE_RINGTONE, /**< @internal Sound type for ringtones */ - SOUND_TYPE_MEDIA, /**< Sound type for media */ - SOUND_TYPE_CALL, /**< @internal Sound type for call */ - SOUND_TYPE_VOIP, /**< @internal Sound type for voip */ - SOUND_TYPE_VOICE, /**< Sound type for voice */ + SOUND_TYPE_SYSTEM, /**< Sound type for system */ + SOUND_TYPE_NOTIFICATION, /**< Sound type for notifications */ + SOUND_TYPE_ALARM, /**< Sound type for alarm */ + SOUND_TYPE_RINGTONE, /**< @internal Sound type for ringtones */ + SOUND_TYPE_MEDIA, /**< Sound type for media */ + SOUND_TYPE_CALL, /**< @internal Sound type for call */ + SOUND_TYPE_VOIP, /**< @internal Sound type for voip */ + SOUND_TYPE_VOICE, /**< Sound type for voice */ } sound_type_e; +/** + * @} + */ + +/** + * @addtogroup CAPI_MEDIA_SOUND_MANAGER_STREAM_POLICY_MODULE + * @{ + */ + +/** + * @brief Sound stream information handle. + * @since_tizen 2.4 + */ +typedef struct sound_stream_info_s* sound_stream_info_h; + +/** + * @brief Enumeration for sound stream type. + * @since_tizen 2.4 + */ +typedef enum { + SOUND_STREAM_TYPE_MEDIA, /**< Sound stream type for media */ + SOUND_STREAM_TYPE_SYSTEM, /**< Sound stream type for system */ + SOUND_STREAM_TYPE_ALARM, /**< Sound stream type for alarm */ + SOUND_STREAM_TYPE_NOTIFICATION, /**< Sound stream type for notification */ + SOUND_STREAM_TYPE_EMERGENCY, /**< Sound stream type for emergency */ + SOUND_STREAM_TYPE_VOICE_INFORMATION, /**< Sound stream type for voice information */ + SOUND_STREAM_TYPE_VOICE_RECOGNITION, /**< Sound stream type for voice recognition */ + SOUND_STREAM_TYPE_RINGTONE_VOIP, /**< Sound stream type for ringtone for VoIP */ + SOUND_STREAM_TYPE_VOIP, /**< Sound stream type for VoIP */ +} sound_stream_type_e; + +/** + * @brief Enumeration for change reason of sound stream focus state. + * @since_tizen 2.4 + */ +typedef enum { + SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA, /**< Changed by the stream type for media */ + SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM, /**< Changed by the stream type for system */ + SOUND_STREAM_FOCUS_CHANGED_BY_ALARM, /**< Changed by the stream type for alarm */ + SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION, /**< Changed by the stream type for notification */ + SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY, /**< Changed by the stream type for emergency */ + SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION, /**< Changed by the stream type for voice information */ + SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION, /**< Changed by the stream type for voice recognition */ + SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE, /**< Changed by the stream type for ringtone */ + SOUND_STREAM_FOCUS_CHANGED_BY_VOIP, /**< Changed by the stream type for VoIP */ + SOUND_STREAM_FOCUS_CHANGED_BY_CALL, /**< Changed by the stream type for voice-call or video-call */ +} sound_stream_focus_change_reason_e; + +/** + * @brief Enumeration for sound stream focus mask. + * @since_tizen 2.4 + */ +typedef enum { + SOUND_STREAM_FOCUS_FOR_PLAYBACK = 0x0001, /**< Mask for playback focus */ + SOUND_STREAM_FOCUS_FOR_RECORDING = 0x0002, /**< Mask for recording focus */ +} sound_stream_focus_mask_e; + +/** + * @brief Enumeration for sound stream focus state. + * @since_tizen 2.4 + */ +typedef enum { + SOUND_STREAM_FOCUS_STATE_RELEASED, /**< Focus state for release */ + SOUND_STREAM_FOCUS_STATE_ACQUIRED, /**< Focus state for acquisition */ +} sound_stream_focus_state_e; + +/** + * @brief Called when the state of focus that belongs to the stream_info is changed. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[in] reason_for_change The reason for state change of the focus + * @param[in] additional_info The additional information + * @param[in] user_data The user data passed from the callback registration function + * + * @pre You should register this callback using sound_manager_create_stream_information(). + * @post Use sound_manager_get_focus_state() in this callback to figure out how the focus state of the stream_info has been changed. + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + */ +typedef void (* sound_stream_focus_state_changed_cb) (sound_stream_info_h stream_info, sound_stream_focus_change_reason_e reason_for_change, const char *additional_info, void *user_data); + +/** + * @brief Called when the focus state for each sound stream type is changed regardless of the process. + * @since_tizen 2.4 + * @param[in] changed_focus_mask The changed focus mask + * @param[in] changed_focus_state The changed focus state + * @param[in] reason_for_change The reason for state change of the focus + * @param[in] additional_info The additional information + * @param[in] user_data The user data passed from the callback registration function + * @pre You should register this callback using sound_manager_set_focus_state_watch_cb(). + * @see sound_manager_set_focus_state_watch_cb() + * @see sound_manager_unset_focus_state_watch_cb() + */ +typedef void (* sound_stream_focus_state_watch_cb) (sound_stream_focus_mask_e changed_focus_mask, sound_stream_focus_state_e changed_focus_state, sound_stream_focus_change_reason_e reason_for_change, const char *additional_info, void *user_data); + /** * @} */ @@ -83,11 +179,11 @@ typedef enum */ /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() and sound_stream_type_e instead. * @brief Enumeration for session type. * @since_tizen 2.3 */ -typedef enum -{ +typedef enum { SOUND_SESSION_TYPE_MEDIA = 0, /**< Media type */ SOUND_SESSION_TYPE_ALARM, /**< Alarm type */ SOUND_SESSION_TYPE_NOTIFICATION, /**< Notification type */ @@ -97,41 +193,41 @@ typedef enum } sound_session_type_e; /** + * @deprecated Deprecated since 2.4. Use sound_manager_acquire_focus() or not instead. * @brief Enumeration for session option for starting. * @since_tizen 2.3 */ -typedef enum -{ +typedef enum { SOUND_SESSION_OPTION_MIX_WITH_OTHERS_WHEN_START = 0, /**< This session will be mixed with others when starting (default) */ SOUND_SESSION_OPTION_PAUSE_OTHERS_WHEN_START, /**< This session will interrupt other sessions when starting */ } sound_session_option_for_starting_e; /** + * @deprecated Deprecated since 2.4. In sound_stream_focus_state_changed_cb, you can choose to stop playing or not. * @brief Enumeration for session option during play. * @since_tizen 2.3 */ -typedef enum -{ +typedef enum { SOUND_SESSION_OPTION_INTERRUPTIBLE_DURING_PLAY = 0, /**< This session will be interrupted by other sessions during play (default) */ SOUND_SESSION_OPTION_UNINTERRUPTIBLE_DURING_PLAY, /**< This session will not be interrupted by other media sessions */ } sound_session_option_for_during_play_e; /** + * @deprecated Deprecated since 2.4. In sound_stream_focus_state_changed_cb, you can choose to resume playing or not. * @brief Enumeration for session option for resumption. * @since_tizen 2.3 */ -typedef enum -{ +typedef enum { SOUND_SESSION_OPTION_RESUMPTION_BY_SYSTEM = 0, /**< This session will be resumed according to system policy (default) */ SOUND_SESSION_OPTION_RESUMPTION_BY_SYSTEM_OR_MEDIA_PAUSED, /**< This session will be resumed according to system policy and when the media session which interrupted this session is paused */ } sound_session_option_for_resumption_e; /** + * @deprecated Deprecated since 2.4. Use sound_manager_apply_stream_routing() instead. * @brief Enumeration for voip session mode. * @since_tizen 2.3 */ -typedef enum -{ +typedef enum { SOUND_SESSION_VOIP_MODE_RINGTONE = 0, /**< voip mode for ringtone */ SOUND_SESSION_VOIP_MODE_VOICE_WITH_BUILTIN_RECEIVER, /**< voip mode for during call with built-in receiver */ SOUND_SESSION_VOIP_MODE_VOICE_WITH_BUILTIN_SPEAKER, /**< voip mode for during call with built-in speaker */ @@ -142,10 +238,9 @@ typedef enum /** * @internal * @brief Enumeration for call session mode. - * @since_tizen 2.3 + * @since_tizen 2.3.1 */ -typedef enum -{ +typedef enum { SOUND_SESSION_CALL_MODE_RINGTONE = 0, /**< call mode for ringtone */ SOUND_SESSION_CALL_MODE_VOICE_WITH_BUILTIN_RECEIVER, /**< call mode for during call with built-in receiver */ SOUND_SESSION_CALL_MODE_VOICE_WITH_BUILTIN_SPEAKER, /**< call mode for during call with built-in speaker */ @@ -154,22 +249,23 @@ typedef enum } sound_session_call_mode_e; /** + * @deprecated Deprecated since 2.4. Use sound_stream_focus_state_changed_cb instead. * @brief Enumeration for sound session interrupted type. * @since_tizen 2.3 */ -typedef enum -{ - SOUND_SESSION_INTERRUPTED_COMPLETED = 0, /**< Interrupt completed*/ - SOUND_SESSION_INTERRUPTED_BY_MEDIA, /**< Interrupted by media application*/ - SOUND_SESSION_INTERRUPTED_BY_CALL, /**< Interrupted by an incoming call*/ - SOUND_SESSION_INTERRUPTED_BY_EARJACK_UNPLUG, /**< Interrupted by unplugging headphones*/ - SOUND_SESSION_INTERRUPTED_BY_RESOURCE_CONFLICT, /**< Interrupted by a resource conflict*/ - SOUND_SESSION_INTERRUPTED_BY_ALARM, /**< Interrupted by an alarm*/ - SOUND_SESSION_INTERRUPTED_BY_EMERGENCY, /**< Interrupted by an emergency*/ - SOUND_SESSION_INTERRUPTED_BY_NOTIFICATION, /**< Interrupted by a notification*/ +typedef enum { + SOUND_SESSION_INTERRUPTED_COMPLETED = 0, /**< Interrupt completed*/ + SOUND_SESSION_INTERRUPTED_BY_MEDIA, /**< Interrupted by media application*/ + SOUND_SESSION_INTERRUPTED_BY_CALL, /**< Interrupted by an incoming call*/ + SOUND_SESSION_INTERRUPTED_BY_EARJACK_UNPLUG, /**< Interrupted by unplugging headphones*/ + SOUND_SESSION_INTERRUPTED_BY_RESOURCE_CONFLICT, /**< Interrupted by a resource conflict*/ + SOUND_SESSION_INTERRUPTED_BY_ALARM, /**< Interrupted by an alarm*/ + SOUND_SESSION_INTERRUPTED_BY_EMERGENCY, /**< Interrupted by an emergency*/ + SOUND_SESSION_INTERRUPTED_BY_NOTIFICATION, /**< Interrupted by a notification*/ } sound_session_interrupted_code_e; /** + * @deprecated Deprecated since 2.4. Use sound_stream_focus_state_changed_cb instead. * @brief Called when the playing sound session is interrupted. * @since_tizen 2.3 * @param[in] code The interrupted code @@ -178,7 +274,7 @@ typedef enum * @see sound_manager_set_session_interrupted_cb() * @see sound_manager_unset_session_interrupted_cb() */ -typedef void(* sound_session_interrupted_cb)(sound_session_interrupted_code_e code, void *user_data); +typedef void (* sound_session_interrupted_cb) (sound_session_interrupted_code_e code, void *user_data); /** * @} @@ -190,13 +286,13 @@ typedef void(* sound_session_interrupted_cb)(sound_session_interrupted_code_e co */ /** - * @brief sound device handle + * @brief Sound device handle. * @since_tizen 2.3 */ typedef void* sound_device_h; /** - * @brief sound device list handle + * @brief Sound device list handle. * @since_tizen 2.3 */ typedef void* sound_device_list_h; @@ -205,14 +301,15 @@ typedef void* sound_device_list_h; * @brief Enumeration for sound device type. * @since_tizen 2.3 */ -typedef enum{ +typedef enum { SOUND_DEVICE_BUILTIN_SPEAKER, /**< Built-in speaker */ SOUND_DEVICE_BUILTIN_RECEIVER, /**< Built-in receiver */ SOUND_DEVICE_BUILTIN_MIC, /**< Built-in mic */ SOUND_DEVICE_AUDIO_JACK, /**< Audio jack that can be connected to wired accessory such as headphone, headset, and so on */ SOUND_DEVICE_BLUETOOTH, /**< Bluetooth */ SOUND_DEVICE_HDMI, /**< HDMI */ - SOUND_DEVICE_MIRRORING, /**< MIRRORING */ + SOUND_DEVICE_MIRRORING, /**< MIRRORING (Deprecated since 2.4) */ + SOUND_DEVICE_FORWARDING = SOUND_DEVICE_MIRRORING, /**< Device for forwarding (Since 2.4) */ SOUND_DEVICE_USB_AUDIO, /**< USB Audio */ } sound_device_type_e; @@ -264,13 +361,13 @@ typedef enum { * @brief Called when the state of connection of a sound device was changed. * @since_tizen 2.3 * @param[in] sound_device_h The sound_device - * @param[in] is_connected The state of device connection + * @param[in] is_connected The state of device connection: (@c true = connected, @c false = disconnected) * @param[in] user_data The user data passed from the callback registration function * @pre You should register this callback using sound_manager_set_device_connected_cb(). * @see sound_manager_set_device_connected_cb() * @see sound_manager_unset_device_connected_cb() */ -typedef void(* sound_device_connected_cb)(sound_device_h device, bool is_connected, void *user_data); +typedef void (* sound_device_connected_cb) (sound_device_h device, bool is_connected, void *user_data); /** * @brief Called when the information of a sound device was changed. @@ -282,7 +379,7 @@ typedef void(* sound_device_connected_cb)(sound_device_h device, bool is_connect * @see sound_manager_set_device_information_changed_cb() * @see sound_manager_unset_device_information_changed_cb() */ -typedef void(* sound_device_information_changed_cb)(sound_device_h device, sound_device_changed_info_e changed_info, void *user_data); +typedef void (* sound_device_information_changed_cb) (sound_device_h device, sound_device_changed_info_e changed_info, void *user_data); /** * @} @@ -303,7 +400,7 @@ typedef void(* sound_device_information_changed_cb)(sound_device_h device, sound * @see sound_manager_set_volume_changed_cb() * @see sound_manager_unset_volume_changed_cb() */ -typedef void (*sound_manager_volume_changed_cb)(sound_type_e type, unsigned int volume, void *user_data); +typedef void (*sound_manager_volume_changed_cb) (sound_type_e type, unsigned int volume, void *user_data); /** * @brief Gets the maximum volume level supported for a particular sound type. @@ -317,7 +414,7 @@ typedef void (*sound_manager_volume_changed_cb)(sound_type_e type, unsigned int * @see sound_manager_set_volume() * @see sound_manager_get_volume() */ -int sound_manager_get_max_volume(sound_type_e type, int *max); +int sound_manager_get_max_volume (sound_type_e type, int *max); /** * @brief Sets the volume level specified for a particular sound type. @@ -335,7 +432,7 @@ int sound_manager_get_max_volume(sound_type_e type, int *max); * @see sound_manager_get_max_volume() * @see sound_manager_get_volume() */ -int sound_manager_set_volume(sound_type_e type, int volume); +int sound_manager_set_volume (sound_type_e type, int volume); /** * @brief Gets the volume level specified for a particular sound type. @@ -350,7 +447,7 @@ int sound_manager_set_volume(sound_type_e type, int volume); * @see sound_manager_get_max_volume() * @see sound_manager_set_volume() */ -int sound_manager_get_volume(sound_type_e type, int *volume); +int sound_manager_get_volume (sound_type_e type, int *volume); /** * @brief Sets the type of the sound being currently played. @@ -364,7 +461,7 @@ int sound_manager_get_volume(sound_type_e type, int *volume); * @see sound_manager_get_current_sound_type() * @see sound_manager_unset_current_sound_type() */ -int sound_manager_set_current_sound_type(sound_type_e type); +int sound_manager_set_current_sound_type (sound_type_e type); /** * @brief Gets the type of the sound being currently played. @@ -379,7 +476,7 @@ int sound_manager_set_current_sound_type(sound_type_e type); * @see sound_manager_set_current_sound_type() * @see sound_manager_unset_current_sound_type() */ -int sound_manager_get_current_sound_type(sound_type_e *type); +int sound_manager_get_current_sound_type (sound_type_e *type); /** * @brief Unsets the type of the sound being currently played. @@ -391,7 +488,7 @@ int sound_manager_get_current_sound_type(sound_type_e *type); * @see sound_manager_set_current_sound_type() * @see sound_manager_get_current_sound_type() */ -int sound_manager_unset_current_sound_type(void); +int sound_manager_unset_current_sound_type (void); /** * @brief Registers a callback function to be invoked when the volume level is changed. @@ -407,7 +504,7 @@ int sound_manager_unset_current_sound_type(void); * @see sound_manager_unset_volume_changed_cb() * @see sound_manager_volume_changed_cb() */ -int sound_manager_set_volume_changed_cb(sound_manager_volume_changed_cb callback, void *user_data); +int sound_manager_set_volume_changed_cb (sound_manager_volume_changed_cb callback, void *user_data); /** * @brief Unregisters the volume change callback. @@ -417,7 +514,219 @@ int sound_manager_set_volume_changed_cb(sound_manager_volume_changed_cb callback * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system * @see sound_manager_set_volume_changed_cb() */ -int sound_manager_unset_volume_changed_cb(void); +int sound_manager_unset_volume_changed_cb (void); + +/** + * @} + */ + +/** + * @addtogroup CAPI_MEDIA_SOUND_MANAGER_STREAM_POLICY_MODULE + * @{ + */ + +/** + * @brief Creates a handle for stream information. + * @since_tizen 2.4 + * @details To apply the stream policy according to this stream information, this handle should be passed to other APIs\n + * related to playback or recording. (e.g., player, wav-player, audio-io, etc.) + * @param[in] stream_type The type of stream + * @param[in] callback The focus state change callback function (mandatory) + * @param[in] user_data The user data to be passed to the callback function + * @param[out] stream_info The handle of stream information + * + * @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_information() + * @see sound_manager_add_device_for_stream_routing() + * @see sound_manager_remove_device_for_stream_routing() + * @see sound_manager_apply_stream_routing() + * @see sound_manager_acquire_focus() + * @see sound_manager_destroy_focus() + * @see sound_manager_get_focus_state() + */ +int sound_manager_create_stream_information (sound_stream_type_e stream_type, sound_stream_focus_state_changed_cb callback, void *user_data, sound_stream_info_h *stream_info); + +/** + * @brief Destroys the handle for stream information. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * + * @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_information() + * @see sound_manager_add_device_for_stream_routing() + * @see sound_manager_remove_device_for_stream_routing() + * @see sound_manager_apply_stream_routing() + * @see sound_manager_acquire_focus() + * @see sound_manager_destroy_focus() + * @see sound_manager_get_focus_state() + */ +int sound_manager_destroy_stream_information (sound_stream_info_h stream_info); + +/** + * @brief Adds the device to the stream information for the stream routing. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[in] device The device item from sound_device_list_h + * + * @remarks @a Use sound_manager_get_current_device_list() and sound_manager_get_next_device() to get the device.\n + * SOUND_MANAGER_ERROR_POLICY could be returned according to the stream type of the stream_info.\n + * The available type of the stream_info for this API is SOUND_STREAM_TYPE_VOIP. + * + * @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_POLICY Noncompliance with the sound system policy + * @pre Call sound_manager_create_stream_information() before calling this function. + * @post You can apply this setting by calling sound_manager_apply_stream_routing(). + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_remove_device_for_stream_routing() + * @see sound_manager_apply_stream_routing() + */ +int sound_manager_add_device_for_stream_routing (sound_stream_info_h stream_info, sound_device_h device); + +/** + * @brief Removes the device to the stream information for the stream routing. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[in] device The device item from sound_device_list_h + * + * @remarks @a Use sound_manager_get_current_device_list() and sound_manager_get_next_device() to get the device.\n + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre Call sound_manager_create_stream_information()/sound_manager_add_device_for_stream_routing() before calling this function. + * @post You can apply this setting by calling sound_manager_apply_stream_routing(). + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_add_device_for_stream_routing() + * @see sound_manager_apply_stream_routing() + */ +int sound_manager_remove_device_for_stream_routing (sound_stream_info_h stream_info, sound_device_h device); + +/** + * @brief Applies the stream routing. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * + * @remarks @a If the stream has not been made yet, this setting will be applied when the stream starts to play.\n + * + * @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_INVALID_STATE Invalid state + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @pre Call sound_manager_create_stream_information()/sound_manager_add_device_for_stream_routing() before calling this function. + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_add_device_for_stream_routing() + * @see sound_manager_remove_device_for_stream_routing() + */ +int sound_manager_apply_stream_routing (sound_stream_info_h stream_info); + +/** + * @brief Acquires the stream focus. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[in] focus_mask The focus mask that user wants to acquire + * @param[in] additional_info Additional information for this request (optional, this can be null) + * + * @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_INVALID_STATE Invalid state + * @retval #SOUND_MANAGER_ERROR_POLICY Noncompliance with the sound system policy + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @pre Call sound_manager_create_stream_information() before calling this function. + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_release_focus() + * @see sound_manager_get_focus_state() + */ +int sound_manager_acquire_focus (sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, const char *additional_info); + +/** + * @brief Releases the acquired focus. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[in] focus_mask The focus mask that user wants to release + * @param[in] additional_info Additional information for this request (optional, this can be null) + * + * @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_INVALID_STATE Invalid state + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @pre Call sound_manager_create_stream_information()/sound_manager_acquire_focus() before calling this function. + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_acquire_focus() + * @see sound_manager_get_focus_state() + */ +int sound_manager_release_focus (sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, const char *additional_info); + +/** + * @brief Gets the state of focus. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[out] state_for_playback The state of playback focus + * @param[out] state_for_recording The state of recording focus + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre Call sound_manager_create_stream_information() before calling this function. + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_acquire_focus() + * @see sound_manager_release_focus() + */ +int sound_manager_get_focus_state (sound_stream_info_h stream_info, sound_stream_focus_state_e *state_for_playback, sound_stream_focus_state_e *state_for_recording); + +/** + * @brief Registers the watch callback function to be invoked when the focus state for each sound stream type is changed regardless of the process. + * @since_tizen 2.4 + * @param[in] focus_mask The focus mask that user wants to watch + * @param[in] callback The focus state change watch callback function + * @param[in] user_data The user data to be passed to the callback function + * + * @remarks @a You can set this callback only once per process. + * + * @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_unset_focus_state_watch_cb() + */ +int sound_manager_set_focus_state_watch_cb (sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_watch_cb callback, void *user_data); + +/** + * @brief Unregisters the focus state watch callback. + * @since_tizen 2.4 + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @see sound_manager_set_focus_state_watch_cb() + */ +int sound_manager_unset_focus_state_watch_cb (void); /** * @} @@ -429,6 +738,7 @@ int sound_manager_unset_volume_changed_cb(void); */ /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() instead. * @brief Sets the application's sound session type. * @since_tizen 2.3 * @param[in] type The session type to set @@ -447,9 +757,10 @@ int sound_manager_unset_volume_changed_cb(void); * @see sound_manager_set_voip_session_mode() * @see sound_manager_get_voip_session_mode() */ -int sound_manager_set_session_type(sound_session_type_e type); +int sound_manager_set_session_type (sound_session_type_e type); /** + * @deprecated Deprecated since 2.4 * @brief Gets the application's sound session type. * @since_tizen 2.3 * @param[in] type The session type @@ -465,9 +776,10 @@ int sound_manager_set_session_type(sound_session_type_e type); * @see sound_manager_set_voip_session_mode() * @see sound_manager_get_voip_session_mode() */ -int sound_manager_get_session_type(sound_session_type_e *type); +int sound_manager_get_session_type (sound_session_type_e *type); /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() instead. * @brief Sets the media sound session option. * @since_tizen 2.3 * @param[in] s_option The session option for starting @@ -485,9 +797,10 @@ int sound_manager_get_session_type(sound_session_type_e *type); * @see sound_manager_set_media_session_resumption_option() * @see sound_manager_get_media_session_resumption_option() */ -int sound_manager_set_media_session_option(sound_session_option_for_starting_e s_option, sound_session_option_for_during_play_e d_option); +int sound_manager_set_media_session_option (sound_session_option_for_starting_e s_option, sound_session_option_for_during_play_e d_option); /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() instead. * @brief Gets the media sound session option. * @since_tizen 2.3 * @param[out] s_option The session option for starting @@ -504,9 +817,10 @@ int sound_manager_set_media_session_option(sound_session_option_for_starting_e s * @see sound_manager_set_media_session_resumption_option() * @see sound_manager_get_media_session_resumption_option() */ -int sound_manager_get_media_session_option(sound_session_option_for_starting_e *s_option, sound_session_option_for_during_play_e *d_option); +int sound_manager_get_media_session_option (sound_session_option_for_starting_e *s_option, sound_session_option_for_during_play_e *d_option); /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() instead. * @brief Sets the media sound session resumption option. * @since_tizen 2.3 * @param[in] option The session resumption option @@ -523,9 +837,10 @@ int sound_manager_get_media_session_option(sound_session_option_for_starting_e * * @see sound_manager_get_media_session_option() * @see sound_manager_get_media_session_resumption_option() */ -int sound_manager_set_media_session_resumption_option(sound_session_option_for_resumption_e option); +int sound_manager_set_media_session_resumption_option (sound_session_option_for_resumption_e option); /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() instead. * @brief Gets the media sound session resumption option. * @since_tizen 2.3 * @param[out] option The session resumption option @@ -541,9 +856,10 @@ int sound_manager_set_media_session_resumption_option(sound_session_option_for_r * @see sound_manager_get_media_session_option() * @see sound_manager_set_media_session_resumption_option() */ -int sound_manager_get_media_session_resumption_option(sound_session_option_for_resumption_e *option); +int sound_manager_get_media_session_resumption_option (sound_session_option_for_resumption_e *option); /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() instead. * @brief Sets the mode of the voip sound session. * @since_tizen 2.3 * @param[in] mode The voip session mode @@ -559,9 +875,10 @@ int sound_manager_get_media_session_resumption_option(sound_session_option_for_r * @see sound_manager_get_session_type() * @see sound_manager_get_voip_session_mode() */ -int sound_manager_set_voip_session_mode(sound_session_voip_mode_e mode); +int sound_manager_set_voip_session_mode (sound_session_voip_mode_e mode); /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() instead. * @brief Gets the mode of the voip sound session. * @since_tizen 2.3 * @param[out] mode The voip session mode @@ -577,12 +894,12 @@ int sound_manager_set_voip_session_mode(sound_session_voip_mode_e mode); * @see sound_manager_get_session_type() * @see sound_manager_set_voip_session_mode() */ -int sound_manager_get_voip_session_mode(sound_session_voip_mode_e *mode); +int sound_manager_get_voip_session_mode (sound_session_voip_mode_e *mode); /** * @internal * @brief Sets the mode of the call sound session. - * @since_tizen 2.3 + * @since_tizen 2.3.1 * @param[in] mode The call session mode * @return @c 0 on success, * otherwise a negative error value @@ -596,12 +913,12 @@ int sound_manager_get_voip_session_mode(sound_session_voip_mode_e *mode); * @see sound_manager_get_session_type() * @see sound_manager_get_call_session_mode() */ -int sound_manager_set_call_session_mode(sound_session_call_mode_e mode); +int sound_manager_set_call_session_mode (sound_session_call_mode_e mode); /** * @internal * @brief Gets the mode of the call sound session. - * @since_tizen 2.3 + * @since_tizen 2.3.1 * @param[out] mode The call session mode * @return @c 0 on success, * otherwise a negative error value @@ -615,9 +932,10 @@ int sound_manager_set_call_session_mode(sound_session_call_mode_e mode); * @see sound_manager_get_session_type() * @see sound_manager_set_call_session_mode() */ -int sound_manager_get_call_session_mode(sound_session_call_mode_e *mode); +int sound_manager_get_call_session_mode (sound_session_call_mode_e *mode); /** + * @deprecated Deprecated since 2.4. Use sound_manager_create_stream_information() instead. * @brief Registers a callback function to be invoked when the sound session being played was interrupted. * @since_tizen 2.3 * @param[in] callback The interrupted callback function @@ -631,9 +949,10 @@ int sound_manager_get_call_session_mode(sound_session_call_mode_e *mode); * @see sound_manager_unset_session_interrupted_cb() * @see sound_session_interrupted_cb() */ -int sound_manager_set_session_interrupted_cb(sound_session_interrupted_cb callback, void *user_data); +int sound_manager_set_session_interrupted_cb (sound_session_interrupted_cb callback, void *user_data); /** + * @deprecated Deprecated since 2.4 * @brief Unregisters the callback function which is called when the sound session being played is interrupted. * @since_tizen 2.3 * @return 0 on success, @@ -642,7 +961,7 @@ int sound_manager_set_session_interrupted_cb(sound_session_interrupted_cb callba * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system * @see sound_manager_set_session_interrupted_cb() */ -int sound_manager_unset_session_interrupted_cb(void); +int sound_manager_unset_session_interrupted_cb (void); /** * @} @@ -675,7 +994,7 @@ int sound_manager_unset_session_interrupted_cb(void); * @see sound_manager_get_device_name() * @see sound_manager_get_device_state() */ -int sound_manager_get_current_device_list(sound_device_mask_e device_mask, sound_device_list_h *device_list); +int sound_manager_get_current_device_list (sound_device_mask_e device_mask, sound_device_list_h *device_list); /** * @brief Gets the next item of the device list. diff --git a/include/sound_manager_internal.h b/include/sound_manager_internal.h index c79a1cf..568d8df 100644 --- a/include/sound_manager_internal.h +++ b/include/sound_manager_internal.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,11 +22,265 @@ extern "C" { #endif +/** + * @file sound_manager_internal.h + * @brief This file contains the Sound Manager Internal API. + */ + +/** + * @addtogroup CAPI_MEDIA_SOUND_MANAGER_MODULE + * @{ + */ + #define SOUND_TYPE_NUM SOUND_TYPE_VOICE + 1 /** - * @file sound_manager_internal.h - * @brief This file contains the Sound Manager API (internal header) + * @internal + * @brief Virtual sound stream handle. + * @since_tizen 2.4 + */ +typedef struct virtual_sound_stream_s* virtual_sound_stream_h; + +/** + * @internal + * @brief Enumeration for Native API. + * @since_tizen 2.4 + */ +typedef enum { + NATIVE_API_SOUND_MANAGER, /**< Sound-manager Native API */ + NATIVE_API_PLAYER, /**< Player Native API */ + NATIVE_API_WAV_PLAYER, /**< Wav-player Native API */ + NATIVE_API_TONE_PLAYER, /**< Tone-player Native API */ + NATIVE_API_AUDIO_IO, /**< Audio-io Native API */ + NATIVE_API_RECORDER, /**< Recorder Native API */ +} native_api_e; + +/** + * @internal + * @brief Enumeration for sound stream type for internal. + * @since_tizen 2.4 + */ +typedef enum { + SOUND_STREAM_TYPE_RINGTONE_CALL = 100, /**< Sound stream type for ringtone for call */ + SOUND_STREAM_TYPE_VOICE_CALL, /**< Sound stream type for voice-call */ + SOUND_STREAM_TYPE_VIDEO_CALL, /**< Sound stream type for video-call */ + SOUND_STREAM_TYPE_RADIO, /**< Sound stream type for radio */ + SOUND_STREAM_TYPE_LOOPBACK, /**< Sound stream type for loopback */ +} sound_stream_type_internal_e; + +/** + * @internal + * @brief Creates a handle for stream information. + * @since_tizen 2.4 + * @details To apply the stream policy according to this stream information, this handle should be passed to other APIs\n + * related to playback or recording. (e.g., player, wav-player, audio-io, etc.) + * @param[in] stream_type The type of stream for internal usage + * @param[in] callback The focus state change callback function (mandatory) + * @param[in] user_data The user data to be passed to the callback function + * @param[out] stream_info The handle of stream information + * + * @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_information() + * @see sound_manager_add_device_for_stream_routing() + * @see sound_manager_remove_device_for_stream_routing() + * @see sound_manager_apply_stream_routing() + * @see sound_manager_acquire_focus() + * @see sound_manager_destroy_focus() + * @see sound_manager_get_focus_state() + */ +int sound_manager_create_stream_information_internal (sound_stream_type_internal_e stream_type, sound_stream_focus_state_changed_cb callback, void *user_data, sound_stream_info_h *stream_info); + +/** + * @internal + * @brief Adds the option to the stream information for the stream routing. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[in] option The option for the stream routing + * + * @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 + * @pre Call sound_manager_create_stream_information() or sound_manager_create_stream_information_internal() before calling this function. + * @post You can apply this setting by calling sound_manager_apply_stream_routing_options(). + * @see sound_manager_create_stream_information() + * @see sound_manager_create_stream_information_internal() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_remove_option_for_stream_routing() + * @see sound_manager_apply_stream_routing_options() + */ +int sound_manager_add_option_for_stream_routing (sound_stream_info_h stream_info, const char *option); + +/** + * @brief Removes the option to the stream information for the stream routing. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[in] option The option for the stream routing + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre Call sound_manager_create_stream_information()/sound_manager_add_option_for_stream_routing() before calling this function. + * @post You can apply this setting by calling sound_manager_apply_stream_routing_options(). + * @see sound_manager_create_stream_information() + * @see sound_manager_create_stream_information_internal() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_remove_option_for_stream_routing() + * @see sound_manager_apply_stream_routing_options() + */ +int sound_manager_remove_option_for_stream_routing (sound_stream_info_h stream_info, const char *option); + +/** + * @brief Applies the stream routing options. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * + * @remarks @a If the stream has not been made yet, this setting will be applied when the stream starts to play.\n + * + * @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 + * @pre Call sound_manager_create_stream_information()/sound_manager_add_option_for_stream_routing() before calling this function. + * @see sound_manager_create_stream_information() + * @see sound_manager_create_stream_information_internal() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_add_option_for_stream_routing() + * @see sound_manager_remove_option_for_stream_routing() + */ +int sound_manager_apply_stream_routing_options (sound_stream_info_h stream_info); + +/** + * @internal + * @brief Queries if this stream information handle is available for the API. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[in] api_name The native API name + * @param[out] is_available If @c true the api_name is available, @c false the api_name is not available for this strema_info + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + */ +int sound_manager_is_available_stream_information (sound_stream_info_h stream_info, native_api_e api_name, bool *is_available); + +/** + * @internal + * @brief Gets stream type from the stream information handle. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[out] type The stream type + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + */ +int sound_manager_get_type_from_stream_information (sound_stream_info_h stream_info, char **type); + +/** + * @internal + * @brief Gets the index of the stream information handle. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[out] index The unique index + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SOUND_MANAGER_ERROR_NONE Success + * @retval #SOUND_MANAGER_ERROR_INVALID_PARAMETER Invalid parameter + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + */ +int sound_manager_get_index_from_stream_information (sound_stream_info_h stream_info, int *index); + +/** + * @internal + * @brief Creates a virtual stream handle. + * @since_tizen 2.4 + * @param[in] stream_info The handle of stream information + * @param[out] virtual_stream The handle of virtual stream + * + * @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 + * @retval #SOUND_MANAGER_ERROR_NOT_SUPPORTED Not supported + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + * @see sound_manager_destroy_virtual_stream() + * @see sound_manager_start_virtual_stream() + * @see sound_manager_stop_virtual_stream() + */ +int sound_manager_create_virtual_stream (sound_stream_info_h stream_info, virtual_sound_stream_h *virtual_stream); + +/** + * @internal + * @brief Destroys the virtual stream handle. + * @since_tizen 2.4 + * @param[in] virtual_stream The handle of virtual stream + * + * @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_INVALID_STATE Invalid state + * @see sound_manager_create_virtual_stream() + * @see sound_manager_start_virtual_stream() + * @see sound_manager_stop_virtual_stream() + */ +int sound_manager_destroy_virtual_stream (virtual_sound_stream_h virtual_stream); + +/** + * @internal + * @brief Starts the virtual stream. + * @since_tizen 2.4 + * @param[in] virtual_stream The handle of virtual stream + * + * @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_INVALID_STATE Invalid state + * @retval #SOUND_MANAGER_ERROR_INTERNAL Internal error inside the sound system + * @see sound_manager_create_virtual_stream() + * @see sound_manager_destroy_virtual_stream() + * @see sound_manager_stop_virtual_stream() + */ +int sound_manager_start_virtual_stream (virtual_sound_stream_h virtual_stream); + +/** + * @internal + * @brief Stops the virtual stream. + * @since_tizen 2.4 + * @param[in] virtual_stream The handle of virtual stream + * + * @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_INVALID_STATE Invalid state + * @see sound_manager_create_virtual_stream() + * @see sound_manager_destroy_virtual_stream() + * @see sound_manager_start_virtual_stream() + */ +int sound_manager_stop_virtual_stream (virtual_sound_stream_h virtual_stream); + +/** + * @} */ #ifdef __cplusplus diff --git a/include/sound_manager_private.h b/include/sound_manager_private.h index 78acfad..d44a002 100644 --- a/include/sound_manager_private.h +++ b/include/sound_manager_private.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ extern "C" { #endif +#define LOG_TAG "TIZEN_N_SOUND_MANAGER" #include #include @@ -28,16 +29,103 @@ extern "C" #include #include #include +#include +#include +#include +#include + +#include +#include #include #include #include +#include #include #include "sound_manager_internal.h" +#define _CHECK_CONDITION(condition,error,msg) \ + if(condition) {} else \ + { LOGE("[%s] %s(0x%08x)",__FUNCTION__, msg,error); return error;}; \ + +#define SM_INSTANCE_CHECK(handle) \ + _CHECK_CONDITION(handle != NULL, SOUND_MANAGER_ERROR_INVALID_PARAMETER,"SOUND_MANAGER_ERROR_INVALID_PARAMETER") + +#define SM_NULL_ARG_CHECK(arg) \ + _CHECK_CONDITION(arg != NULL,SOUND_MANAGER_ERROR_INVALID_PARAMETER,"SOUND_MANAGER_ERROR_INVALID_PARAMETER") + +#define SM_STATE_CHECK(handle,expected_state) \ + _CHECK_CONDITION(handle->state == expected_state,SOUND_MANAGER_ERROR_INVALID_STATE,"SOUND_MANAGER_ERROR_INVALID_STATE") + +#define SM_RANGE_ARG_CHECK(arg, min, max) \ + _CHECK_CONDITION(arg <= max,SOUND_MANAGER_ERROR_INVALID_PARAMETER,"SOUND_MANAGER_ERROR_INVALID_PARAMETER") \ + _CHECK_CONDITION(arg >= min,SOUND_MANAGER_ERROR_INVALID_PARAMETER,"SOUND_MANAGER_ERROR_INVALID_PARAMETER") + #define SOUND_SESSION_TYPE_DEFAULT SOUND_SESSION_TYPE_MEDIA +#define SOUND_STREAM_INFO_ARR_MAX 128 +#define SOUND_STREAM_TYPE_LEN 64 +#define SOUND_STREAM_DIRECTION_MAX 2 +#define SOUND_DEVICE_TYPE_LEN 64 -typedef enum -{ +typedef enum _sound_stream_direction { + SOUND_STREAM_DIRECTION_OUTPUT = 1, + SOUND_STREAM_DIRECTION_INPUT +} sound_stream_direction_e; + +/* it should be synchronized with pulseaudio's */ +typedef enum stream_route_type { + STREAM_ROUTE_TYPE_AUTO, /* the policy of decision device(s) is automatic and it's routing path is particular to one device */ + STREAM_ROUTE_TYPE_AUTO_ALL, /* the policy of decision device(s) is automatic and it's routing path can be several devices */ + STREAM_ROUTE_TYPE_MANUAL, /* the policy of decision device(s) is manual */ +} stream_route_type; +#define AVAIL_DEVICES_MAX 16 +#define AVAIL_FRAMEWORKS_MAX 16 +#define ROUTE_OPTIONS_MAX 16 + +typedef struct _stream_conf_info_s { + int priority; + int route_type; + gchar *avail_in_devices[AVAIL_DEVICES_MAX]; + gchar *avail_out_devices[AVAIL_DEVICES_MAX]; + gchar *avail_frameworks[AVAIL_FRAMEWORKS_MAX]; +} stream_conf_info_s; + +typedef struct _manual_route_info_s { + char *route_in_devices[AVAIL_DEVICES_MAX]; + char *route_out_devices[AVAIL_DEVICES_MAX]; + int route_in_devices_idx[AVAIL_DEVICES_MAX]; + int route_out_devices_idx[AVAIL_DEVICES_MAX]; +} manual_route_info_s; + +typedef struct _sound_stream_info_s { + unsigned int index; + char stream_type[SOUND_STREAM_TYPE_LEN]; + pa_threaded_mainloop *pa_mainloop; + pa_context *pa_context; + stream_conf_info_s stream_conf_info; + sound_stream_focus_mask_e acquired_focus; + sound_stream_focus_state_changed_cb user_cb; + void *user_data; + manual_route_info_s manual_route_info; + char *route_options[ROUTE_OPTIONS_MAX]; +} sound_stream_info_s; +sound_stream_info_s *sound_stream_info_arr[SOUND_STREAM_INFO_ARR_MAX]; + +typedef enum { + _VSTREAM_STATE_READY, + _VSTREAM_STATE_RUNNING, +} _vstream_state; + +typedef struct _virtual_stream_info_s { + _vstream_state state; + char stream_type[SOUND_STREAM_TYPE_LEN]; + pa_threaded_mainloop *pa_mainloop; + pa_context *pa_context; + pa_stream *pa_stream[SOUND_STREAM_DIRECTION_MAX]; + pa_proplist *pa_proplist; + stream_conf_info_s *stream_conf_info; +} virtual_sound_stream_info_s; + +typedef enum { _SESSION_MODE_RINGTONE = 0, /**< session mode(voip/call) for ringtone */ _SESSION_MODE_VOICE_WITH_BUILTIN_RECEIVER, /**< session mode(voip/call) for during call with built-in receiver */ _SESSION_MODE_VOICE_WITH_BUILTIN_SPEAKER, /**< session mode(voip/call) for during call with built-in speaker */ @@ -56,6 +144,11 @@ typedef struct { sound_manager_volume_changed_cb user_cb; }_volume_changed_info_s; +typedef struct { + void *user_data; + sound_stream_focus_state_watch_cb user_cb; +}_focus_watch_info_s; + typedef struct { void *user_data; sound_device_connected_cb user_cb; @@ -66,13 +159,62 @@ typedef struct { sound_device_information_changed_cb user_cb; }_device_changed_info_s; -int __convert_sound_manager_error_code(const char *func, int code); +#define SOUND_STRNCPY(dst,src,size,err) \ +do { \ + if(src != NULL && dst != NULL && size > 0) { \ + strncpy(dst,src,size); \ + dst[size-1] = '\0'; \ + } else if(dst == NULL) { \ + LOGE("STRNCPY ERROR: Destination String is NULL\n"); \ + err = MM_ERROR_SOUND_INTERNAL; \ + } else if(size <= 0) { \ + LOGE("STRNCPY ERROR: Destination String is NULL\n"); \ + err = MM_ERROR_SOUND_INTERNAL; \ + } else { \ + LOGE("STRNCPY ERROR: Destination String is NULL\n"); \ + err = MM_ERROR_SOUND_INTERNAL; \ + } \ +} while(0) + +void _focus_state_change_callback (int index, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data); + +void _focus_watch_callback (mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data); + +int __convert_sound_manager_error_code (const char *func, int code); + +int __find_empty_slot (int *index); + +int __convert_stream_type (sound_stream_type_e enum_type, char *stream_type); + +int __convert_stream_type_for_internal (sound_stream_type_internal_e stream_type_enum, char *stream_type); + +int __convert_stream_type_to_change_reason (const char *stream_type, sound_stream_focus_change_reason_e *change_reason); + +int __convert_device_type (sound_device_type_e device_type_enum, char *device_type); + +int __convert_device_type_to_enum (char *device_type, sound_device_type_e *device_type_enum); + +const char* __convert_api_name (native_api_e api_name); + +int __get_stream_conf_info (const char *stream_type, stream_conf_info_s *info); + +int __set_manual_route_info (unsigned int index, manual_route_info_s *info); + +int __set_route_options (unsigned int index, char **route_options); + +void _pa_context_state_cb (pa_context *c, void *userdata); + +void _pa_stream_state_cb (pa_stream *s, void * userdata); + +void _session_interrupt_cb (session_msg_t msg, session_event_t event, void *user_data); + +int __set_session_mode (_session_mode_e mode); -void __session_interrupt_cb(session_msg_t msg, session_event_t event, void *user_data); +int __get_session_mode (_session_mode_e *mode); -int __set_session_mode(_session_mode_e mode); +int _make_pa_connection_and_register_focus(sound_stream_info_s *stream_h, sound_stream_focus_state_changed_cb callback, void *user_data); -int __get_session_mode(_session_mode_e *mode); +int _destroy_pa_connection_and_unregister_focus(sound_stream_info_s *stream_h); #ifdef __cplusplus } diff --git a/packaging/capi-media-sound-manager.spec b/packaging/capi-media-sound-manager.spec index daf0fad..9093111 100755 --- 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.2.28 +Version: 0.3.0 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -12,6 +12,8 @@ BuildRequires: pkgconfig(mm-sound) BuildRequires: pkgconfig(mm-session) BuildRequires: pkgconfig(capi-base-common) BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(libpulse) +BuildRequires: pkgconfig(gio-2.0) Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig Requires(post): libprivilege-control diff --git a/src/sound_manager.c b/src/sound_manager.c index a1a8d96..f7126da 100644 --- a/src/sound_manager.c +++ b/src/sound_manager.c @@ -14,26 +14,19 @@ * limitations under the License. */ - -#define LOG_TAG "TIZEN_N_SOUND_MANAGER" - -#include -#include - -typedef struct { - void *user_data; - sound_manager_volume_changed_cb user_cb; -}_changed_volume_info_s; +#include "sound_manager.h" +#include "sound_manager_private.h" _session_interrupt_info_s g_session_interrupt_cb_table = {0, NULL, NULL}; _volume_changed_info_s g_volume_changed_cb_table = {NULL, NULL}; +_focus_watch_info_s g_focus_watch_cb_table = {NULL, NULL}; _device_connected_info_s g_device_connected_cb_table = {NULL, NULL}; _device_changed_info_s g_device_info_changed_cb_table = {NULL, NULL}; sound_session_type_e g_cached_session = -1; _session_mode_e g_cached_session_mode = -1; -int sound_manager_get_max_volume(sound_type_e type, int *max) +int sound_manager_get_max_volume (sound_type_e type, int *max) { int volume; if(max == NULL) @@ -49,7 +42,7 @@ int sound_manager_get_max_volume(sound_type_e type, int *max) return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_set_volume(sound_type_e type, int volume) +int sound_manager_set_volume (sound_type_e type, int volume) { if(type >= SOUND_TYPE_NUM || type < 0) return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT); @@ -57,12 +50,12 @@ int sound_manager_set_volume(sound_type_e type, int volume) return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT); int ret = mm_sound_volume_set_value(type, volume); - LOGI("returns : type=%d, volume=%d, ret=0x%x", type, volume, ret); + LOGI("returns : type=%d, volume=%d, ret=%p", type, volume, ret); return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_get_volume(sound_type_e type, int *volume) +int sound_manager_get_volume (sound_type_e type, int *volume) { unsigned int uvolume; if(type >= SOUND_TYPE_NUM || type < 0) @@ -74,12 +67,12 @@ int sound_manager_get_volume(sound_type_e type, int *volume) if(ret == 0) *volume = uvolume; - LOGI("returns : type=%d, volume=%d, ret=0x%x", type, *volume, ret); + LOGI("returns : type=%d, volume=%d, ret=%p", type, *volume, ret); return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_set_current_sound_type(sound_type_e type) +int sound_manager_set_current_sound_type (sound_type_e type) { int ret = MM_ERROR_NONE; if(type >= SOUND_TYPE_NUM || type < 0) @@ -90,19 +83,19 @@ int sound_manager_set_current_sound_type(sound_type_e type) return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_get_current_sound_type(sound_type_e *type) +int sound_manager_get_current_sound_type (sound_type_e *type) { int ret = MM_ERROR_NONE; if(type == NULL) return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT); ret = mm_sound_volume_get_current_playing_type((volume_type_t *)type); - LOGI("returns : type=%d, ret=0x%x", *type, ret); + LOGI("returns : type=%d, ret=%p", *type, ret); return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_unset_current_sound_type(void) +int sound_manager_unset_current_sound_type (void) { int ret = MM_ERROR_NONE; ret = mm_sound_volume_primary_type_clear(); @@ -110,7 +103,7 @@ int sound_manager_unset_current_sound_type(void) return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_set_volume_changed_cb(sound_manager_volume_changed_cb callback, void* user_data) +int sound_manager_set_volume_changed_cb (sound_manager_volume_changed_cb callback, void* user_data) { int ret = MM_ERROR_NONE; @@ -123,7 +116,7 @@ int sound_manager_set_volume_changed_cb(sound_manager_volume_changed_cb callback return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_unset_volume_changed_cb(void) +int sound_manager_unset_volume_changed_cb (void) { int ret = MM_ERROR_NONE; @@ -140,7 +133,349 @@ int sound_manager_unset_volume_changed_cb(void) return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_set_session_type(sound_session_type_e type) +int sound_manager_create_stream_information (sound_stream_type_e stream_type, sound_stream_focus_state_changed_cb callback, void *user_data, sound_stream_info_h *stream_info) +{ + int ret = MM_ERROR_NONE; + + LOGI(">> enter"); + + SM_NULL_ARG_CHECK(stream_info); + SM_NULL_ARG_CHECK(callback); + + sound_stream_info_s *stream_h = malloc(sizeof(sound_stream_info_s)); + if (!stream_h) { + ret = MM_ERROR_OUT_OF_MEMORY; + } else { + memset(stream_h, 0, sizeof(sound_stream_info_s)); + ret = __convert_stream_type(stream_type, stream_h->stream_type); + if (ret == MM_ERROR_NONE) { + ret = _make_pa_connection_and_register_focus(stream_h, callback, user_data); + if (!ret) { + *stream_info = (sound_stream_info_h)stream_h; + LOGI("<< leave : stream_h(%p), index(%u), user_cb(%p), ret(%p)", stream_h, stream_h->index, stream_h->user_cb, ret); + } + } + } + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_destroy_stream_information (sound_stream_info_h stream_info) +{ + int ret = MM_ERROR_NONE; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + + ret = _destroy_pa_connection_and_unregister_focus(stream_h); + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_add_device_for_stream_routing (sound_stream_info_h stream_info, sound_device_h device) +{ + int ret = MM_ERROR_NONE; + int i = 0; + int j = 0; + bool added_successfully = false; + char device_type_str[SOUND_DEVICE_TYPE_LEN] = {0,}; + mm_sound_device_type_e device_type; + mm_sound_device_io_direction_e device_direction; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + SM_NULL_ARG_CHECK(device); + + if (stream_h->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL) { + ret = mm_sound_get_device_type(device, &device_type); + if (ret) { + return __convert_sound_manager_error_code(__func__, ret); + } + ret = __convert_device_type(device_type, device_type_str); + if (ret) { + return __convert_sound_manager_error_code(__func__, ret); + } + ret = mm_sound_get_device_io_direction(device, &device_direction); + if (ret) { + return __convert_sound_manager_error_code(__func__, ret); + } + if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_IN || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) { + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (stream_h->stream_conf_info.avail_in_devices[i]) { + if(!strncmp(stream_h->stream_conf_info.avail_in_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) { + for (j = 0; j < AVAIL_DEVICES_MAX; j++) { + if (!stream_h->manual_route_info.route_in_devices[j]) { + stream_h->manual_route_info.route_in_devices[j] = strdup(device_type_str); + added_successfully = true; + break; + } + if (!strncmp(stream_h->manual_route_info.route_in_devices[j], device_type_str, SOUND_DEVICE_TYPE_LEN)) { + /* it was already set */ + return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_DUPLICATED); + } + } + } + } else { + break; + } + } + } + if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_OUT || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) { + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (stream_h->stream_conf_info.avail_out_devices[i]) { + if(!strncmp(stream_h->stream_conf_info.avail_out_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) { + for (j = 0; j < AVAIL_DEVICES_MAX; j++) { + if (!stream_h->manual_route_info.route_out_devices[j]) { + stream_h->manual_route_info.route_out_devices[j] = strdup(device_type_str); + added_successfully = true; + break; + } + if (!strncmp(stream_h->manual_route_info.route_out_devices[j], device_type_str, SOUND_DEVICE_TYPE_LEN)) { + /* it was already set */ + return __convert_sound_manager_error_code(__func__, MM_ERROR_POLICY_DUPLICATED); + } + } + } + } else { + break; + } + } + } + } + + if (!added_successfully) { + ret = MM_ERROR_POLICY_INTERNAL; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_remove_device_for_stream_routing (sound_stream_info_h stream_info, sound_device_h device) +{ + int ret = MM_ERROR_NONE; + int i = 0; + int j = 0; + bool removed_successfully = false; + char device_type_str[SOUND_DEVICE_TYPE_LEN] = {0,}; + mm_sound_device_type_e device_type; + mm_sound_device_io_direction_e device_direction; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + SM_NULL_ARG_CHECK(device); + + if (stream_h->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL) { + ret = mm_sound_get_device_type(device, &device_type); + if (ret) { + return __convert_sound_manager_error_code(__func__, ret); + } + ret = __convert_device_type(device_type, device_type_str); + if (ret) { + return __convert_sound_manager_error_code(__func__, ret); + } + ret = mm_sound_get_device_io_direction(device, &device_direction); + if (ret) { + return __convert_sound_manager_error_code(__func__, ret); + } + if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_IN || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) { + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (stream_h->stream_conf_info.avail_in_devices[i]) { + if(!strncmp(stream_h->stream_conf_info.avail_in_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) { + for (j = 0; j < AVAIL_DEVICES_MAX; j++) { + if (!strncmp(stream_h->manual_route_info.route_in_devices[j], device_type_str, SOUND_DEVICE_TYPE_LEN)) { + removed_successfully = true; + free(stream_h->manual_route_info.route_in_devices[j]); + stream_h->manual_route_info.route_in_devices[j] = NULL; + break; + } + } + } + } else { + break; + } + } + } + if (device_direction == MM_SOUND_DEVICE_IO_DIRECTION_OUT || device_direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH) { + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (stream_h->stream_conf_info.avail_out_devices[i]) { + if(!strncmp(stream_h->stream_conf_info.avail_out_devices[i], device_type_str, SOUND_DEVICE_TYPE_LEN)) { + for (j = 0; j < AVAIL_DEVICES_MAX; j++) { + if (!strncmp(stream_h->manual_route_info.route_out_devices[j], device_type_str, SOUND_DEVICE_TYPE_LEN)) { + removed_successfully = true; + free(stream_h->manual_route_info.route_out_devices[j]); + stream_h->manual_route_info.route_out_devices[j] = NULL; + break; + } + } + } + } else { + break; + } + } + } + } + + if (!removed_successfully) { + ret = MM_ERROR_INVALID_ARGUMENT; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_apply_stream_routing (sound_stream_info_h stream_info) +{ + int ret = MM_ERROR_NONE; + int i = 0; + bool need_to_apply = false; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + + if (stream_h->stream_conf_info.route_type == STREAM_ROUTE_TYPE_MANUAL) { + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (stream_h->manual_route_info.route_in_devices[i]) { + need_to_apply = true; + break; + } + if (stream_h->manual_route_info.route_out_devices[i]) { + need_to_apply = true; + break; + } + } + if (need_to_apply) { + ret = __set_manual_route_info(stream_h->index, &stream_h->manual_route_info); + } else { + __convert_sound_manager_error_code(__func__, MM_ERROR_SOUND_INVALID_STATE); + } + } else { + ret = MM_ERROR_SOUND_INVALID_STATE; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_acquire_focus (sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, const char *additional_info) +{ + int ret = MM_ERROR_NONE; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + + ret = mm_sound_acquire_focus(stream_h->index, (mm_sound_focus_type_e)focus_mask, additional_info); + if (ret == MM_ERROR_NONE) { + stream_h->acquired_focus |= focus_mask; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_release_focus (sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask, const char *additional_info) +{ + int ret = MM_ERROR_NONE; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + + ret = mm_sound_release_focus(stream_h->index, (mm_sound_focus_type_e)focus_mask, additional_info); + if (ret == MM_ERROR_NONE) { + stream_h->acquired_focus &= ~focus_mask; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_get_focus_state (sound_stream_info_h stream_info, sound_stream_focus_state_e *state_for_playback, sound_stream_focus_state_e *state_for_recording) +{ + int ret = MM_ERROR_NONE; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + if (!state_for_playback && !state_for_recording) + ret = MM_ERROR_INVALID_ARGUMENT; + + if (state_for_playback) + *state_for_playback = (stream_h->acquired_focus & SOUND_STREAM_FOCUS_FOR_PLAYBACK)?SOUND_STREAM_FOCUS_STATE_ACQUIRED:SOUND_STREAM_FOCUS_STATE_RELEASED; + if (state_for_recording) + *state_for_recording = (stream_h->acquired_focus & SOUND_STREAM_FOCUS_FOR_RECORDING)?SOUND_STREAM_FOCUS_STATE_ACQUIRED:SOUND_STREAM_FOCUS_STATE_RELEASED; + + LOGI("<< leave : acquired_focus(%p)", stream_h->acquired_focus); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_set_focus_state_watch_cb (sound_stream_focus_mask_e focus_mask, sound_stream_focus_state_watch_cb callback, void *user_data) +{ + int ret = MM_ERROR_NONE; + + LOGI(">> enter"); + + SM_NULL_ARG_CHECK(callback); + + if (!g_focus_watch_cb_table.user_cb) { + ret = mm_sound_set_focus_watch_callback((mm_sound_focus_type_e)focus_mask, _focus_watch_callback, user_data); + if (ret == MM_ERROR_NONE) { + g_focus_watch_cb_table.user_cb = callback; + g_focus_watch_cb_table.user_data = user_data; + } + } else { + ret = MM_ERROR_SOUND_INTERNAL; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_unset_focus_state_watch_cb (void) +{ + int ret = MM_ERROR_NONE; + + LOGI(">> enter"); + + if (g_focus_watch_cb_table.user_cb) { + ret = mm_sound_unset_focus_watch_callback(); + if (ret == MM_ERROR_NONE) { + g_focus_watch_cb_table.user_cb = NULL; + g_focus_watch_cb_table.user_data = NULL; + } else { + ret = MM_ERROR_SOUND_INTERNAL; + } + } else { + ret = MM_ERROR_SOUND_INTERNAL; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_set_session_type (sound_session_type_e type) { int ret = MM_ERROR_NONE; int cur_session = -1; @@ -190,7 +525,7 @@ int sound_manager_set_session_type(sound_session_type_e type) if(g_session_interrupt_cb_table.is_registered) { if (new_session == cur_session || ((new_session == SOUND_SESSION_TYPE_MEDIA) && (cur_session == MM_SESSION_TYPE_MEDIA_RECORD))) { - LOGI("<< leave : already set type=%d, ret=0x%x", type, ret); + LOGI("<< leave : already set type=%d, ret=%p", type, ret); return SOUND_MANAGER_ERROR_NONE; } else { ret = mm_session_finish(); @@ -201,7 +536,7 @@ int sound_manager_set_session_type(sound_session_type_e type) g_cached_session_mode = -1; } } - ret = mm_session_init_ex(new_session , __session_interrupt_cb, NULL); + ret = mm_session_init_ex(new_session , _session_interrupt_cb, NULL); if(ret == 0){ g_session_interrupt_cb_table.is_registered = 1; } @@ -213,12 +548,12 @@ int sound_manager_set_session_type(sound_session_type_e type) } g_cached_session_mode = _SESSION_MODE_RINGTONE; } - LOGI("<< leave : type=%d, ret=0x%x", type, ret); + LOGI("<< leave : type=%d, ret=%p", type, ret); return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_get_session_type(sound_session_type_e *type) +int sound_manager_get_session_type (sound_session_type_e *type) { int ret = MM_ERROR_NONE; int cur_session; @@ -262,12 +597,12 @@ int sound_manager_get_session_type(sound_session_type_e *type) break; } - LOGI("returns : type=%d, ret=0x%x", *type, ret); + LOGI("returns : type=%d, ret=%p", *type, ret); return 0; } -int sound_manager_set_media_session_option(sound_session_option_for_starting_e s_option, sound_session_option_for_during_play_e d_option) +int sound_manager_set_media_session_option (sound_session_option_for_starting_e s_option, sound_session_option_for_during_play_e d_option) { int ret = MM_ERROR_NONE; int session = 0; @@ -347,7 +682,7 @@ int sound_manager_set_media_session_option(sound_session_option_for_starting_e s return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_get_media_session_option(sound_session_option_for_starting_e *s_option, sound_session_option_for_during_play_e *d_option) +int sound_manager_get_media_session_option (sound_session_option_for_starting_e *s_option, sound_session_option_for_during_play_e *d_option) { int ret = MM_ERROR_NONE; int session = 0; @@ -388,7 +723,7 @@ int sound_manager_get_media_session_option(sound_session_option_for_starting_e * return SOUND_MANAGER_ERROR_NONE; } -int sound_manager_set_media_session_resumption_option(sound_session_option_for_resumption_e option) +int sound_manager_set_media_session_resumption_option (sound_session_option_for_resumption_e option) { int ret = MM_ERROR_NONE; int session = 0; @@ -445,7 +780,7 @@ int sound_manager_set_media_session_resumption_option(sound_session_option_for_r return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_get_media_session_resumption_option(sound_session_option_for_resumption_e *option) +int sound_manager_get_media_session_resumption_option (sound_session_option_for_resumption_e *option) { int ret = MM_ERROR_NONE; int session = 0; @@ -480,7 +815,7 @@ int sound_manager_get_media_session_resumption_option(sound_session_option_for_r return SOUND_MANAGER_ERROR_NONE; } -int sound_manager_set_voip_session_mode(sound_session_voip_mode_e mode) +int sound_manager_set_voip_session_mode (sound_session_voip_mode_e mode) { int ret = MM_ERROR_NONE; int session = 0; @@ -500,12 +835,12 @@ int sound_manager_set_voip_session_mode(sound_session_voip_mode_e mode) } ret = __set_session_mode ((_session_mode_e)mode); - LOGI("<< leave : session=%p, mode=%d, ret=0x%x", session, mode, ret); + LOGI("<< leave : session=%p, mode=%d, ret=%p", session, mode, ret); return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_get_voip_session_mode(sound_session_voip_mode_e *mode) +int sound_manager_get_voip_session_mode (sound_session_voip_mode_e *mode) { int ret = MM_ERROR_NONE; int session = 0; @@ -526,12 +861,12 @@ int sound_manager_get_voip_session_mode(sound_session_voip_mode_e *mode) if (ret == MM_ERROR_NONE) *mode = (sound_session_voip_mode_e)_mode; - LOGI("returns : session=%p, mode=%d, ret=0x%x", session, *mode, ret); + LOGI("returns : session=%p, mode=%d, ret=%p", session, *mode, ret); return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_set_call_session_mode(sound_session_call_mode_e mode) +int sound_manager_set_call_session_mode (sound_session_call_mode_e mode) { int ret = MM_ERROR_NONE; int session = 0; @@ -551,12 +886,12 @@ int sound_manager_set_call_session_mode(sound_session_call_mode_e mode) } ret = __set_session_mode ((_session_mode_e)mode); - LOGI("<< leave : session=%p, mode=%d, ret=0x%x", session, mode, ret); + LOGI("<< leave : session=%p, mode=%d, ret=%p", session, mode, ret); return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_get_call_session_mode(sound_session_call_mode_e *mode) +int sound_manager_get_call_session_mode (sound_session_call_mode_e *mode) { int ret = MM_ERROR_NONE; int session = 0; @@ -577,19 +912,19 @@ int sound_manager_get_call_session_mode(sound_session_call_mode_e *mode) if (ret == MM_ERROR_NONE) *mode = (sound_session_call_mode_e)_mode; - LOGI("returns : session=%p, mode=%d, ret=0x%x", session, *mode, ret); + LOGI("returns : session=%p, mode=%d, ret=%p", session, *mode, ret); return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_set_session_interrupted_cb(sound_session_interrupted_cb callback, void *user_data) +int sound_manager_set_session_interrupted_cb (sound_session_interrupted_cb callback, void *user_data) { int ret = MM_ERROR_NONE; if(callback == NULL) return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT); if(g_session_interrupt_cb_table.is_registered ==0){ - ret = mm_session_init_ex(SOUND_SESSION_TYPE_DEFAULT /*default*/ , __session_interrupt_cb, NULL); + ret = mm_session_init_ex(SOUND_SESSION_TYPE_DEFAULT /*default*/ , _session_interrupt_cb, NULL); if(ret != 0) return __convert_sound_manager_error_code(__func__, ret); g_session_interrupt_cb_table.is_registered = 1; @@ -600,7 +935,7 @@ int sound_manager_set_session_interrupted_cb(sound_session_interrupted_cb callba return SOUND_MANAGER_ERROR_NONE; } -int sound_manager_unset_session_interrupted_cb(void) +int sound_manager_unset_session_interrupted_cb (void) { int ret = MM_ERROR_NONE; if (g_session_interrupt_cb_table.user_cb) { @@ -612,7 +947,7 @@ int sound_manager_unset_session_interrupted_cb(void) return __convert_sound_manager_error_code(__func__, ret); } -int sound_manager_get_current_device_list(sound_device_mask_e device_mask, sound_device_list_h *device_list) +int sound_manager_get_current_device_list (sound_device_mask_e device_mask, sound_device_list_h *device_list) { int ret = MM_ERROR_NONE; ret = mm_sound_get_current_device_list((mm_sound_device_flags_e)device_mask, device_list); @@ -733,7 +1068,7 @@ int sound_manager_unset_device_information_changed_cb (void) } __attribute__ ((destructor)) -void __sound_manager_finalize(void) +void __sound_manager_finalize (void) { int ret = MM_ERROR_NONE; @@ -741,7 +1076,7 @@ void __sound_manager_finalize(void) LOGI(""); ret = mm_session_finish(); if (ret != MM_ERROR_NONE) { - LOGE("[%s] failed to mm_session_finish(), ret(0x%x)", __func__, ret); + LOGE("[%s] failed to mm_session_finish(), ret(%p)", __func__, ret); } g_session_interrupt_cb_table.is_registered = 0; LOGI(""); @@ -749,7 +1084,7 @@ void __sound_manager_finalize(void) } __attribute__ ((constructor)) -void __sound_manager_initialize(void) +void __sound_manager_initialize (void) { } diff --git a/src/sound_manager_internal.c b/src/sound_manager_internal.c new file mode 100644 index 0000000..bbddeff --- /dev/null +++ b/src/sound_manager_internal.c @@ -0,0 +1,381 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include + +int sound_manager_create_stream_information_internal (sound_stream_type_internal_e stream_type, sound_stream_focus_state_changed_cb callback, void *user_data, sound_stream_info_h *stream_info) +{ + int ret = MM_ERROR_NONE; + + LOGI(">> enter"); + + SM_NULL_ARG_CHECK(stream_info); + SM_NULL_ARG_CHECK(callback); + + sound_stream_info_s *stream_h = malloc(sizeof(sound_stream_info_s)); + if (!stream_h) { + ret = MM_ERROR_OUT_OF_MEMORY; + } else { + memset(stream_h, 0, sizeof(sound_stream_info_s)); + ret = __convert_stream_type_for_internal(stream_type, stream_h->stream_type); + if (ret == MM_ERROR_NONE) { + ret = _make_pa_connection_and_register_focus(stream_h, callback, user_data); + if (!ret) { + *stream_info = (sound_stream_info_h)stream_h; + LOGI("<< leave : stream_h(%p), index(%u), user_cb(%p), ret(%p)", stream_h, stream_h->index, stream_h->user_cb, ret); + } + } + } + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_add_option_for_stream_routing (sound_stream_info_h stream_info, const char *option) +{ + int ret = MM_ERROR_NONE; + int i = 0; + bool added_successfully = false; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + SM_NULL_ARG_CHECK(option); + + for (i = 0; i < ROUTE_OPTIONS_MAX; i++) { + if (stream_h->route_options[i]) { + if (!strncmp (stream_h->route_options[i], option, strlen(option))) { + return __convert_sound_manager_error_code(__func__, MM_ERROR_INVALID_ARGUMENT); + } + continue; + } else { + stream_h->route_options[i] = strdup(option); + added_successfully = true; + break; + } + } + + if (!added_successfully) { + ret = MM_ERROR_SOUND_INTERNAL; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_remove_option_for_stream_routing (sound_stream_info_h stream_info, const char *option) +{ + int ret = MM_ERROR_NONE; + int i = 0; + bool removed_successfully = false; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + SM_NULL_ARG_CHECK(option); + + for (i = 0; i < ROUTE_OPTIONS_MAX; i++) { + if (stream_h->route_options[i] && !strncmp (stream_h->route_options[i], option, strlen(option))) { + free(stream_h->route_options[i]); + stream_h->route_options[i] = NULL; + removed_successfully = true; + break; + } + } + + if (!removed_successfully) { + ret = MM_ERROR_INVALID_ARGUMENT; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_apply_stream_routing_options (sound_stream_info_h stream_info) +{ + int ret = MM_ERROR_NONE; + int i = 0; + bool need_to_apply = false; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(stream_h); + + for (i = 0; i < ROUTE_OPTIONS_MAX; i++) { + if (stream_h->route_options[i]) { + need_to_apply = true; + break; + } + } + if (need_to_apply) { + ret = __set_route_options(stream_h->index, stream_h->route_options); + } else { + __convert_sound_manager_error_code(__func__, MM_ERROR_SOUND_INTERNAL); + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_is_available_stream_information (sound_stream_info_h stream_info, native_api_e api_name, bool *is_available) +{ + int ret = MM_ERROR_NONE; + int i = 0; + const char *name = NULL; + sound_stream_info_s* stream_h = (sound_stream_info_s*)stream_info; + + SM_INSTANCE_CHECK(stream_h); + SM_NULL_ARG_CHECK(is_available); + *is_available = false; + + name = __convert_api_name(api_name); + for (i = 0; i < AVAIL_FRAMEWORKS_MAX; i++) { + if (stream_h->stream_conf_info.avail_frameworks[i] && !strncmp(stream_h->stream_conf_info.avail_frameworks[i], name, strlen(name))) { + *is_available = true; + } else { + break; + } + } + LOGI("stream_type[%s], native api[%s], is_available[%d]", stream_h->stream_type, name, *is_available); + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_get_type_from_stream_information (sound_stream_info_h stream_info, char **type) +{ + int ret = MM_ERROR_NONE; + sound_stream_info_s* stream_h = (sound_stream_info_s*)stream_info; + + SM_INSTANCE_CHECK(stream_h); + SM_NULL_ARG_CHECK(type); + + *type = stream_h->stream_type; + LOGI("stream_type[%s]", *type); + + return __convert_sound_manager_error_code(__func__, ret); +} +int sound_manager_get_index_from_stream_information (sound_stream_info_h stream_info, int *index) +{ + int ret = MM_ERROR_NONE; + sound_stream_info_s* stream_h = (sound_stream_info_s*)stream_info; + SM_INSTANCE_CHECK(stream_h); + SM_NULL_ARG_CHECK(index); + + *index = stream_h->index; + LOGI("stream_index[%d]", stream_h->index); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_create_virtual_stream (sound_stream_info_h stream_info, virtual_sound_stream_h *virtual_stream) +{ + int ret = MM_ERROR_NONE; + bool result = false; + virtual_sound_stream_info_s *vstream_h = NULL; + sound_stream_info_s *stream_h = (sound_stream_info_s*)stream_info; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(virtual_stream); + SM_INSTANCE_CHECK(stream_h); + + /* check if this stream_info is available for virtual stream */ + ret = sound_manager_is_available_stream_information(stream_info, NATIVE_API_SOUND_MANAGER, &result); + if (ret == MM_ERROR_NONE && result == true) { + vstream_h = malloc(sizeof(virtual_sound_stream_info_s)); + if(!vstream_h) { + ret = MM_ERROR_OUT_OF_MEMORY; + } else { + memset(vstream_h, 0, sizeof(virtual_sound_stream_info_s)); + memcpy(vstream_h->stream_type, stream_h->stream_type, SOUND_STREAM_TYPE_LEN); + vstream_h->pa_mainloop = stream_h->pa_mainloop; + vstream_h->pa_context = stream_h->pa_context; + vstream_h->pa_proplist = pa_proplist_new(); + pa_proplist_sets(vstream_h->pa_proplist, PA_PROP_MEDIA_ROLE, vstream_h->stream_type); + pa_proplist_setf(vstream_h->pa_proplist, PA_PROP_MEDIA_PARENT_ID, "%u", stream_h->index); + vstream_h->state = _VSTREAM_STATE_READY; + vstream_h->stream_conf_info = &(stream_h->stream_conf_info); + *virtual_stream = (virtual_sound_stream_h)vstream_h; + } + } else { + ret = MM_ERROR_SOUND_NOT_SUPPORTED_OPERATION; + } + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_destroy_virtual_stream (virtual_sound_stream_h virtual_stream) +{ + int ret = MM_ERROR_NONE; + virtual_sound_stream_info_s *vstream_h = (virtual_sound_stream_info_s*)virtual_stream; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(vstream_h); + SM_STATE_CHECK(vstream_h, _VSTREAM_STATE_READY); + + vstream_h->pa_mainloop = NULL; + vstream_h->pa_context = NULL; + if (vstream_h->pa_proplist) + pa_proplist_free(vstream_h->pa_proplist); + + free(vstream_h); + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_start_virtual_stream (virtual_sound_stream_h virtual_stream) +{ + int ret = MM_ERROR_NONE; + int pa_ret = PA_OK; + int i = 0; + int io_direction = 0; + pa_sample_spec ss; + pa_channel_map maps; + + virtual_sound_stream_info_s *vstream_h = (virtual_sound_stream_info_s*)virtual_stream; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(vstream_h); + SM_STATE_CHECK(vstream_h, _VSTREAM_STATE_READY); + + /* check route-type(auto/manual) and error handling as per the type */ + if (vstream_h->stream_conf_info->route_type == STREAM_ROUTE_TYPE_MANUAL) { + /* TODO : check if the device info. is set when it comes to the manual route type */ + /* if no, return error */ + } + + /* fill up with default value */ + ss.channels = 2; + ss.rate = 44100; + ss.format = PA_SAMPLE_S16LE; + pa_channel_map_init_auto(&maps, ss.channels, PA_CHANNEL_MAP_ALSA); + + /* check direction of this stream */ + if (vstream_h->stream_conf_info->avail_in_devices[0] != NULL) + io_direction |= SOUND_STREAM_DIRECTION_INPUT; + if (vstream_h->stream_conf_info->avail_out_devices[0] != NULL) + io_direction |= SOUND_STREAM_DIRECTION_OUTPUT; + + /* LOCK the pa_threaded_mainloop */ + pa_threaded_mainloop_lock(vstream_h->pa_mainloop); + + for (i = 0; i < SOUND_STREAM_DIRECTION_MAX; i++) { + if (io_direction & (i + 1)) { + vstream_h->pa_stream[i] = pa_stream_new_with_proplist(vstream_h->pa_context, "VIRTUAL_STREAM", &ss, &maps, vstream_h->pa_proplist); + if(vstream_h->pa_stream[i] == NULL) { + LOGE("failed to pa_stream_new_with_proplist()"); + pa_ret = pa_context_errno(vstream_h->pa_context); + goto ERROR_WITH_UNLOCK; + } + pa_stream_set_state_callback(vstream_h->pa_stream[i], _pa_stream_state_cb, vstream_h); + + if ((i + 1) == SOUND_STREAM_DIRECTION_OUTPUT) { + pa_ret = pa_stream_connect_playback(vstream_h->pa_stream[i], NULL, NULL, 0, NULL, NULL); + if (pa_ret < 0) { + LOGE("failed to pa_stream_connect_playback()"); + pa_ret = pa_context_errno(vstream_h->pa_context); + goto ERROR_WITH_UNLOCK; + } + } else if ((i + 1) == SOUND_STREAM_DIRECTION_INPUT) { + pa_ret = pa_stream_connect_record(vstream_h->pa_stream[i], NULL, NULL, 0); + if (pa_ret < 0) { + LOGE("failed to pa_stream_connect_record()"); + pa_ret = pa_context_errno(vstream_h->pa_context); + goto ERROR_WITH_UNLOCK; + } + } + + /* wait for ready state of the stream */ + for (;;) { + pa_stream_state_t state; + state = pa_stream_get_state(vstream_h->pa_stream[i]); + if (state == PA_STREAM_READY) { + break; + } + if (!PA_STREAM_IS_GOOD(state)) { + pa_ret = pa_context_errno(vstream_h->pa_context); + } + pa_threaded_mainloop_wait(vstream_h->pa_mainloop); + } + } + } + vstream_h->state = _VSTREAM_STATE_RUNNING; + + /* UNLOCK the pa_threaded_mainloop */ + pa_threaded_mainloop_unlock(vstream_h->pa_mainloop); + goto SUCCESS; +ERROR_WITH_UNLOCK: + /* UNLOCK the pa_threaded_mainloop */ + pa_threaded_mainloop_unlock(vstream_h->pa_mainloop); + + for (i = 0; i < SOUND_STREAM_DIRECTION_MAX; i++) { + if (vstream_h->pa_stream[i]) { + pa_stream_unref(vstream_h->pa_stream[i]); + vstream_h->pa_stream[i] = NULL; + } + } + LOGE("pa_ret(%d)", pa_ret); + ret = MM_ERROR_SOUND_INTERNAL; +SUCCESS: + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} + +int sound_manager_stop_virtual_stream (virtual_sound_stream_h virtual_stream) +{ + int ret = MM_ERROR_NONE; + int i = 0; + virtual_sound_stream_info_s *vstream_h = (virtual_sound_stream_info_s*)virtual_stream; + + LOGI(">> enter"); + + SM_INSTANCE_CHECK(vstream_h); + SM_STATE_CHECK(vstream_h, _VSTREAM_STATE_RUNNING); + + /* LOCK the pa_threaded_mainloop */ + pa_threaded_mainloop_lock(vstream_h->pa_mainloop); + + for (i = 0; i < SOUND_STREAM_DIRECTION_MAX; i++) { + if (vstream_h->pa_stream[i]) { + pa_stream_disconnect(vstream_h->pa_stream[i]); + pa_stream_unref(vstream_h->pa_stream[i]); + vstream_h->pa_stream[i] = NULL; + } + } + + /* UNLOCK the pa_threaded_mainloop */ + pa_threaded_mainloop_unlock(vstream_h->pa_mainloop); + + vstream_h->state = _VSTREAM_STATE_READY; + + LOGI("<< leave : ret(%p)", ret); + + return __convert_sound_manager_error_code(__func__, ret); +} diff --git a/src/sound_manager_private.c b/src/sound_manager_private.c index 3b7be76..1d7b7da 100644 --- a/src/sound_manager_private.c +++ b/src/sound_manager_private.c @@ -16,62 +16,628 @@ #include #include - #include -#include + +#define PA_BUS_NAME "org.pulseaudio.Server" +#define PA_STREAM_MANAGER_OBJECT_PATH "/org/pulseaudio/Ext/StreamManager" +#define PA_STREAM_MANAGER_INTERFACE "org.pulseaudio.Ext.StreamManager" +#define PA_STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO "GetStreamInfo" +#define PA_STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES "SetStreamRouteDevices" +#define PA_STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTIONS "SetStreamRouteOptions" extern _session_interrupt_info_s g_session_interrupt_cb_table; extern _session_mode_e g_cached_session_mode; +extern _focus_watch_info_s g_focus_watch_cb_table; +extern sound_stream_info_s* sound_stream_info_arr[SOUND_STREAM_INFO_ARR_MAX]; -int __convert_sound_manager_error_code(const char *func, int code) { +int __convert_sound_manager_error_code (const char *func, int code) { int ret = SOUND_MANAGER_ERROR_NONE; char *errorstr = NULL; - switch(code) - { - case MM_ERROR_FILE_WRITE: - case MM_ERROR_INVALID_HANDLE: - ret = SOUND_MANAGER_ERROR_INVALID_OPERATION; - errorstr = "INVALID_OPERATION"; - break; - case MM_ERROR_NONE: - ret = SOUND_MANAGER_ERROR_NONE; - errorstr = "ERROR_NONE"; - break; - case MM_ERROR_INVALID_ARGUMENT: - case MM_ERROR_SOUND_INVALID_POINTER: - ret = SOUND_MANAGER_ERROR_INVALID_PARAMETER; - errorstr = "INVALID_PARAMETER"; - break; - case MM_ERROR_SOUND_PERMISSION_DENIED: - ret = SOUND_MANAGER_ERROR_PERMISSION_DENIED; - errorstr = "PERMISSION_DENIED"; - break; - case MM_ERROR_SOUND_NO_DATA: - ret = SOUND_MANAGER_ERROR_NO_DATA; - errorstr = "NO_DATA"; - break; - case MM_ERROR_SOUND_INTERNAL: - case MM_ERROR_SOUND_VOLUME_CAPTURE_ONLY: - ret = SOUND_MANAGER_ERROR_INTERNAL; - errorstr = "INTERNAL"; + switch(code) { + case MM_ERROR_FILE_WRITE: + case MM_ERROR_INVALID_HANDLE: + ret = SOUND_MANAGER_ERROR_INVALID_OPERATION; + errorstr = "INVALID_OPERATION"; + break; + case MM_ERROR_NONE: + ret = SOUND_MANAGER_ERROR_NONE; + errorstr = "ERROR_NONE"; + break; + case MM_ERROR_INVALID_ARGUMENT: + case MM_ERROR_SOUND_INVALID_POINTER: + ret = SOUND_MANAGER_ERROR_INVALID_PARAMETER; + errorstr = "INVALID_PARAMETER"; + break; + case MM_ERROR_SOUND_PERMISSION_DENIED: + ret = SOUND_MANAGER_ERROR_PERMISSION_DENIED; + errorstr = "PERMISSION_DENIED"; + break; + case MM_ERROR_SOUND_NO_DATA: + ret = SOUND_MANAGER_ERROR_NO_DATA; + errorstr = "NO_DATA"; + break; + case MM_ERROR_SOUND_INTERNAL: + case MM_ERROR_SOUND_VOLUME_CAPTURE_ONLY: + case MM_ERROR_OUT_OF_MEMORY: + ret = SOUND_MANAGER_ERROR_INTERNAL; + errorstr = "INTERNAL"; + break; + case MM_ERROR_POLICY_DUPLICATED: + case MM_ERROR_POLICY_INTERNAL: + case MM_ERROR_POLICY_BLOCKED: + ret = SOUND_MANAGER_ERROR_POLICY; + errorstr = "POLICY"; + break; + case MM_ERROR_SOUND_VOLUME_NO_INSTANCE: + ret = SOUND_MANAGER_ERROR_NO_PLAYING_SOUND; + errorstr = "NO_PLAYING_SOUND"; + break; + case MM_ERROR_NOT_SUPPORT_API: + case MM_ERROR_SOUND_NOT_SUPPORTED_OPERATION: + ret = SOUND_MANAGER_ERROR_NOT_SUPPORTED; + errorstr = "NOT_SUPPORTED"; + break; + case MM_ERROR_SOUND_INVALID_STATE: + ret = SOUND_MANAGER_ERROR_INVALID_STATE; + errorstr = "INVALID_STATE"; + break; + } + if (ret) { + LOGE("[%s] %s(0x%08x) : core frameworks error code(0x%08x)",func, errorstr, ret, code); + } else { + LOGD("[%s] %s(0x%08x) : core frameworks error code(0x%08x)",func, errorstr, ret, code); + } + return ret; +} + +int __convert_stream_type (sound_stream_type_e stream_type_enum, char *stream_type) +{ + int ret = MM_ERROR_NONE; + switch (stream_type_enum) { + case SOUND_STREAM_TYPE_MEDIA: + SOUND_STRNCPY(stream_type,"media",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_SYSTEM: + SOUND_STRNCPY(stream_type,"system",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_ALARM: + SOUND_STRNCPY(stream_type,"alarm",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_NOTIFICATION: + SOUND_STRNCPY(stream_type,"notification",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_EMERGENCY: + SOUND_STRNCPY(stream_type,"emergency",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_VOICE_INFORMATION: + SOUND_STRNCPY(stream_type,"voice-information",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_VOICE_RECOGNITION: + SOUND_STRNCPY(stream_type,"voice-recognition",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_RINGTONE_VOIP: + SOUND_STRNCPY(stream_type,"ringtone-voip",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_VOIP: + SOUND_STRNCPY(stream_type,"voip",SOUND_STREAM_TYPE_LEN,ret); + break; + } + if (!strncmp(stream_type,"",SOUND_STREAM_TYPE_LEN)) { + LOGE("could not find the stream_type[%d] in this switch case statement", stream_type_enum); + ret = MM_ERROR_SOUND_INTERNAL; + } else { + LOGI("stream_type[%s]", stream_type); + } + return ret; +} + +int __convert_stream_type_for_internal (sound_stream_type_internal_e stream_type_enum, char *stream_type) +{ + int ret = MM_ERROR_NONE; + + SM_NULL_ARG_CHECK(stream_type); + + switch (stream_type_enum) { + case SOUND_STREAM_TYPE_RINGTONE_CALL: + SOUND_STRNCPY(stream_type,"ringtone-call",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_VOICE_CALL: + SOUND_STRNCPY(stream_type,"call-voice",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_VIDEO_CALL: + SOUND_STRNCPY(stream_type,"call-video",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_RADIO: + SOUND_STRNCPY(stream_type,"radio",SOUND_STREAM_TYPE_LEN,ret); + break; + case SOUND_STREAM_TYPE_LOOPBACK: + SOUND_STRNCPY(stream_type,"loopback",SOUND_STREAM_TYPE_LEN,ret); + break; + } + if (!strncmp(stream_type,"",SOUND_STREAM_TYPE_LEN)) { + LOGE("could not find the stream_type[%d] in this switch case statement", stream_type_enum); + ret = MM_ERROR_SOUND_INTERNAL; + } else { + LOGI("stream_type_for_internal[%s]", stream_type); + } + return ret; +} + +int __convert_stream_type_to_change_reason (const char *stream_type, sound_stream_focus_change_reason_e *change_reason) +{ + int ret = MM_ERROR_NONE; + + SM_NULL_ARG_CHECK(stream_type); + SM_NULL_ARG_CHECK(change_reason); + + if (!strncmp(stream_type, "media", SOUND_STREAM_TYPE_LEN) || + !strncmp(stream_type, "radio", SOUND_STREAM_TYPE_LEN) || + !strncmp(stream_type, "loopback", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA; + + } else if (!strncmp(stream_type, "system", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM; + + } else if (!strncmp(stream_type, "alarm", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_ALARM; + + } else if (!strncmp(stream_type, "notification", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION; + + } else if (!strncmp(stream_type, "emergency", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY; + + } else if (!strncmp(stream_type, "voice-information", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION; + + } else if (!strncmp(stream_type, "voice-recognition", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION; + + } else if (!strncmp(stream_type, "ringtone-voip", SOUND_STREAM_TYPE_LEN) || + !strncmp(stream_type, "ringtone-call", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE; + + } else if (!strncmp(stream_type, "voip", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_VOIP; + + } else if (!strncmp(stream_type, "call-voice", SOUND_STREAM_TYPE_LEN) || + !strncmp(stream_type, "call-video", SOUND_STREAM_TYPE_LEN)) { + *change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_CALL; + } else { + ret = MM_ERROR_INVALID_ARGUMENT; + LOGE("not supported stream_type(%s), err(0x%08x)", stream_type, ret); + } + return ret; +} + +int __convert_device_type (sound_device_type_e device_type_enum, char *device_type) +{ + int ret = MM_ERROR_NONE; + + SM_NULL_ARG_CHECK(device_type); + + switch (device_type_enum) { + case SOUND_DEVICE_BUILTIN_SPEAKER: + SOUND_STRNCPY(device_type,"builtin-speaker",SOUND_DEVICE_TYPE_LEN,ret); + break; + case SOUND_DEVICE_BUILTIN_RECEIVER: + SOUND_STRNCPY(device_type,"builtin-receiver",SOUND_DEVICE_TYPE_LEN,ret); + break; + case SOUND_DEVICE_BUILTIN_MIC: + SOUND_STRNCPY(device_type,"builtin-mic",SOUND_DEVICE_TYPE_LEN,ret); + break; + case SOUND_DEVICE_AUDIO_JACK: + SOUND_STRNCPY(device_type,"audio-jack",SOUND_DEVICE_TYPE_LEN,ret); + break; + case SOUND_DEVICE_BLUETOOTH: + SOUND_STRNCPY(device_type,"bt",SOUND_DEVICE_TYPE_LEN,ret); + break; + case SOUND_DEVICE_HDMI: + SOUND_STRNCPY(device_type,"hdmi",SOUND_DEVICE_TYPE_LEN,ret); + break; + case SOUND_DEVICE_USB_AUDIO: + SOUND_STRNCPY(device_type,"usb-audio",SOUND_DEVICE_TYPE_LEN,ret); + break; + case SOUND_DEVICE_FORWARDING: + SOUND_STRNCPY(device_type,"forwarding",SOUND_DEVICE_TYPE_LEN,ret); + break; + } + if (!strncmp(device_type,"",SOUND_DEVICE_TYPE_LEN)) { + LOGE("could not find the device_type[%d] in this switch case statement", device_type_enum); + ret = MM_ERROR_SOUND_INTERNAL; + } else { + LOGI("device_type[%s]", device_type); + } + return ret; +} + +/* it will be deprecated after ready for changing device type that is from server to string */ +int __convert_device_type_to_enum (char *device_type, sound_device_type_e *device_type_enum) +{ + int ret = MM_ERROR_NONE; + + SM_NULL_ARG_CHECK(device_type); + SM_NULL_ARG_CHECK(device_type_enum); + + if (!strncmp(device_type, "builtin-speaker", SOUND_DEVICE_TYPE_LEN)) { + *device_type_enum = SOUND_DEVICE_BUILTIN_SPEAKER; + } else if (!strncmp(device_type, "builtin-receiver", SOUND_DEVICE_TYPE_LEN)) { + *device_type_enum = SOUND_DEVICE_BUILTIN_RECEIVER; + } else if (!strncmp(device_type, "builtin-mic", SOUND_DEVICE_TYPE_LEN)) { + *device_type_enum = SOUND_DEVICE_BUILTIN_MIC; + } else if (!strncmp(device_type, "audio-jack", SOUND_DEVICE_TYPE_LEN)) { + *device_type_enum = SOUND_DEVICE_AUDIO_JACK; + } else if (!strncmp(device_type, "bt", SOUND_DEVICE_TYPE_LEN)) { + *device_type_enum = SOUND_DEVICE_BLUETOOTH; + } else if (!strncmp(device_type, "hdmi", SOUND_DEVICE_TYPE_LEN)) { + *device_type_enum = SOUND_DEVICE_HDMI; + } else if (!strncmp(device_type, "usb-audio", SOUND_DEVICE_TYPE_LEN)) { + *device_type_enum = SOUND_DEVICE_USB_AUDIO; + } else { + ret = MM_ERROR_INVALID_ARGUMENT; + LOGE("not supported device_type(%s), err(0x%08x)", device_type, ret); + } + + return ret; +} + +const char* __convert_api_name (native_api_e api_name) +{ + const char* name = NULL; + switch (api_name) { + case NATIVE_API_SOUND_MANAGER: + name = "sound-manager"; + break; + case NATIVE_API_PLAYER: + name = "player"; + break; + case NATIVE_API_WAV_PLAYER: + name = "wav-player"; + break; + case NATIVE_API_TONE_PLAYER: + name = "tone-player"; + break; + case NATIVE_API_AUDIO_IO: + name = "audio-io"; + break; + case NATIVE_API_RECORDER: + name = "recorder"; + break; + } + return name; +} + +void _focus_state_change_callback (int index, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data) +{ + int ret = MM_ERROR_NONE; + int i = 0; + + LOGI(">> enter"); + + sound_stream_focus_change_reason_e change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA; + ret = __convert_stream_type_to_change_reason(reason_for_change, &change_reason); + if (ret) { + LOGE("failed to __convert_stream_type_to_enum(), reason_for_change(%s), err(0x%08x)", reason_for_change, ret); + } else { + for (i = 0; i < SOUND_STREAM_INFO_ARR_MAX; i++) { + if (sound_stream_info_arr[i] && sound_stream_info_arr[i]->index == index) { + if (state == FOCUS_IS_RELEASED) { + sound_stream_info_arr[i]->acquired_focus &= ~focus_type; + } else if (state == FOCUS_IS_ACQUIRED) { + sound_stream_info_arr[i]->acquired_focus |= focus_type; + } + LOGI("[FOCUS USER CALLBACK(%p) START]", sound_stream_info_arr[i]->user_cb); + sound_stream_info_arr[i]->user_cb((sound_stream_info_h)sound_stream_info_arr[i], change_reason, additional_info, sound_stream_info_arr[i]->user_data); + LOGI("[FOCUS USER CALLBACK(%p) END]", sound_stream_info_arr[i]->user_cb); + break; + } + } + if (i == SOUND_STREAM_INFO_ARR_MAX) { + LOGE("could not find index(%d), failed to call user callback", index); + } + } + + LOGI("<< leave"); + + return; +} + +void _focus_watch_callback (mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, const char *reason_for_change, const char *additional_info, void *user_data) +{ + int ret = MM_ERROR_NONE; + sound_stream_focus_change_reason_e change_reason = SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA; + ret = __convert_stream_type_to_change_reason(reason_for_change, &change_reason); + if (ret) + LOGE("failed to __convert_stream_type_to_enum(), reason_for_change(%s), err(0x%08x)", reason_for_change, ret); + if (g_focus_watch_cb_table.user_cb) + g_focus_watch_cb_table.user_cb(focus_type, state, change_reason, additional_info, g_focus_watch_cb_table.user_data); + return; +} + +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; + assert(c); + + state = pa_context_get_state(c); + LOGI ("[%p] context state = [%d]", stream_info_h, 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); + break; + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + } +} + +void _pa_stream_state_cb (pa_stream *s, void * userdata) +{ + pa_stream_state_t state; + virtual_sound_stream_info_s *vstream_h = (virtual_sound_stream_info_s*)userdata; + assert(s); + + state = pa_stream_get_state(s); + LOGI ("[%p] stream [%d] state = [%d]", vstream_h, pa_stream_get_index(s), state); + + switch (state) { + case PA_STREAM_READY: + case PA_STREAM_FAILED: + case PA_STREAM_TERMINATED: + pa_threaded_mainloop_signal(vstream_h->pa_mainloop, 0); + break; + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + break; + } +} + +int __get_stream_conf_info (const char *stream_type, stream_conf_info_s *info) +{ + int ret = MM_ERROR_NONE; + GVariant *result = NULL; + GVariant *child = NULL; + GDBusConnection *conn = NULL; + GError *err = NULL; + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (!conn && err) { + LOGE("g_bus_get_sync() error (%s)", err->message); + g_error_free (err); + ret = MM_ERROR_SOUND_INTERNAL; + 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_STREAM_INFO, + g_variant_new ("(s)", stream_type), + G_VARIANT_TYPE("(vvvvv)"), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + &err); + if (!result && err) { + LOGE("g_dbus_connection_call_sync() error (%s)", err->message); + ret = MM_ERROR_SOUND_INTERNAL; + } else { + GVariantIter iter; + GVariant *item = NULL; + gchar *name = NULL; + gsize size = 0; + int i = 0; + + /* get priority */ + child = g_variant_get_child_value(result, 0); + item = g_variant_get_variant(child); + info->priority = g_variant_get_int32(item); + g_variant_unref (item); + g_variant_unref (child); + LOGI ("priority(%d)", info->priority); + + /* get route type */ + child = g_variant_get_child_value(result, 1); + item = g_variant_get_variant(child); + info->route_type = g_variant_get_int32(item); + g_variant_unref (item); + g_variant_unref (child); + LOGI ("route_type(%d)", info->route_type); + + /* get availabe in-devices */ + child = g_variant_get_child_value(result, 2); + item = g_variant_get_variant(child); + size = g_variant_n_children(item); + LOGI ("num of avail-in-devices are %d", size); + g_variant_iter_init(&iter, item); + i = 0; + while (g_variant_iter_loop(&iter, "&s", &name)) { + if (size == 1 && !strncmp (name, "none", strlen("none"))) { + LOGI (" in-device is [%s], skip it", name); + break; + } else { + LOGI (" in-device name : %s", name); + info->avail_in_devices[i++] = strdup(name); + } + } + g_variant_iter_free (&iter); + g_variant_unref (item); + g_variant_unref (child); + + /* get available out-devices */ + child = g_variant_get_child_value(result, 3); + item = g_variant_get_variant(child); + size = g_variant_n_children(item); + LOGI ("num of avail-out-devices are %d", size); + g_variant_iter_init(&iter, item); + i = 0; + while (g_variant_iter_loop(&iter, "&s", &name)) { + if (size == 1 && !strncmp (name, "none", strlen("none"))) { + LOGI (" out-device is [%s], skip it", name); + break; + } else { + LOGI (" out-device name : %s", name); + info->avail_out_devices[i++] = strdup(name); + } + } + g_variant_iter_free (&iter); + g_variant_unref (item); + g_variant_unref (child); + + /* get available frameworks */ + child = g_variant_get_child_value(result, 4); + item = g_variant_get_variant(child); + size = g_variant_n_children(item); + LOGI ("num of avail-frameworks are %d", size); + g_variant_iter_init(&iter, item); + i = 0; + while (g_variant_iter_loop(&iter, "&s", &name)) { + if (size == 1 && !strncmp (name, "none", strlen("none"))) { + LOGI (" framework is [%s], skip it", name); + break; + } else { + LOGI (" framework name : %s", name); + info->avail_frameworks[i++] = strdup(name); + } + } + g_variant_iter_free (&iter); + g_variant_unref (item); + g_variant_unref (child); + g_variant_unref(result); + } + g_object_unref(conn); + return ret; +} + +int __set_manual_route_info (unsigned int index, manual_route_info_s *info) +{ + int ret = MM_ERROR_NONE; + int i = 0; + GVariantBuilder *builder_for_in_devices; + GVariantBuilder *builder_for_out_devices; + GVariant *result = NULL; + GDBusConnection *conn = NULL; + GError *err = NULL; + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (!conn && err) { + LOGE("g_bus_get_sync() error (%s)", err->message); + g_error_free (err); + ret = MM_ERROR_SOUND_INTERNAL; + return ret; + } + + builder_for_in_devices = g_variant_builder_new(G_VARIANT_TYPE("as")); + builder_for_out_devices = g_variant_builder_new(G_VARIANT_TYPE("as")); + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (info->route_in_devices[i]) { + g_variant_builder_add(builder_for_in_devices, "s", info->route_in_devices[i]); + LOGI("[IN] %s", info->route_in_devices[i]); + } else { break; - case MM_ERROR_POLICY_DUPLICATED: - case MM_ERROR_POLICY_INTERNAL: - case MM_ERROR_POLICY_BLOCKED: - ret = SOUND_MANAGER_ERROR_POLICY; - errorstr = "POLICY"; + } + } + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (info->route_out_devices[i]) { + g_variant_builder_add(builder_for_out_devices, "s", info->route_out_devices[i]); + LOGI("[OUT] %s", info->route_out_devices[i]); + } else { break; - case MM_ERROR_SOUND_VOLUME_NO_INSTANCE: - ret = SOUND_MANAGER_ERROR_NO_PLAYING_SOUND; - errorstr = "NO_PLAYING_SOUND"; + } + } + + result = g_dbus_connection_call_sync (conn, + PA_BUS_NAME, + PA_STREAM_MANAGER_OBJECT_PATH, + PA_STREAM_MANAGER_INTERFACE, + PA_STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES, + g_variant_new ("(uasas)", index, builder_for_in_devices, builder_for_out_devices), + G_VARIANT_TYPE("(s)"), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + &err); + if (!result && err) { + LOGE("g_dbus_connection_call_sync() error (%s)", err->message); + ret = MM_ERROR_SOUND_INTERNAL; + } else { + const gchar *dbus_ret = NULL; + 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_INVALID_STATE; + } + g_variant_unref(result); + } + g_variant_builder_unref(builder_for_in_devices); + g_variant_builder_unref(builder_for_out_devices); + g_object_unref(conn); + return ret; +} + +int __set_route_options (unsigned int index, char **route_options) +{ + int ret = MM_ERROR_NONE; + int i = 0; + GVariantBuilder *builder; + + GVariant *result = NULL; + GDBusConnection *conn = NULL; + GError *err = NULL; + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (!conn && err) { + LOGE("g_bus_get_sync() error (%s)", err->message); + g_error_free (err); + ret = MM_ERROR_SOUND_INTERNAL; + return ret; + } + + builder = g_variant_builder_new(G_VARIANT_TYPE("as")); + for (i = 0; i < ROUTE_OPTIONS_MAX; i++) { + if (route_options[i]) { + g_variant_builder_add(builder, "s", route_options[i]); + LOGI("[OPTIONS] %s", route_options[i]); + } else { break; + } + } + + result = g_dbus_connection_call_sync (conn, + PA_BUS_NAME, + PA_STREAM_MANAGER_OBJECT_PATH, + PA_STREAM_MANAGER_INTERFACE, + PA_STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTIONS, + g_variant_new ("(uas)", index, builder), + G_VARIANT_TYPE("(s)"), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + &err); + if (!result && err) { + LOGE("g_dbus_connection_call_sync() error (%s)", err->message); + ret = MM_ERROR_SOUND_INTERNAL; + } else { + const gchar *dbus_ret = NULL; + 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; + } + g_variant_unref(result); } - LOGE("[%s] %s(0x%08x) : core frameworks error code(0x%08x)",func, errorstr, ret, code); + g_variant_builder_unref(builder); + g_object_unref(conn); return ret; } -void __session_interrupt_cb(session_msg_t msg, session_event_t event, void *user_data){ +void _session_interrupt_cb (session_msg_t msg, session_event_t event, void *user_data){ if( g_session_interrupt_cb_table.user_cb ){ sound_session_interrupted_code_e e = SOUND_SESSION_INTERRUPTED_COMPLETED; if( msg == MM_SESSION_MSG_RESUME ) @@ -108,7 +674,7 @@ void __session_interrupt_cb(session_msg_t msg, session_event_t event, void *user } } -int __set_session_mode(_session_mode_e mode) +int __set_session_mode (_session_mode_e mode) { int ret = MM_ERROR_NONE; mm_sound_route route = MM_SOUND_ROUTE_IN_MIC_OUT_SPEAKER; @@ -208,7 +774,7 @@ ERROR_CASE: return ret; } -int __get_session_mode(_session_mode_e *mode) +int __get_session_mode (_session_mode_e *mode) { int ret = MM_ERROR_NONE; int subsession = 0; @@ -267,3 +833,168 @@ int __get_session_mode(_session_mode_e *mode) ERROR_CASE: return ret; } + +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 pa_ret = PA_OK; + int i = 0; + if (!(stream_h->pa_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"))) + goto PA_ERROR; + + pa_context_set_state_callback(stream_h->pa_context, _pa_context_state_cb, stream_h); + + if (pa_context_connect(stream_h->pa_context, NULL, 0, NULL) < 0) { + pa_ret = pa_context_errno(stream_h->pa_context); + goto PA_ERROR; + } + + pa_threaded_mainloop_lock(stream_h->pa_mainloop); + + if (pa_threaded_mainloop_start(stream_h->pa_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); + if (state == PA_CONTEXT_READY) + break; + if (!PA_CONTEXT_IS_GOOD(state)) { + pa_ret = pa_context_errno(stream_h->pa_context); + goto PA_ERROR_WITH_UNLOCK; + } + pa_threaded_mainloop_wait(stream_h->pa_mainloop); + } + + /* get uniq id of this context */ + stream_h->index = pa_context_get_index(stream_h->pa_context); + + /* get configuration information of this stream type */ + ret = __get_stream_conf_info(stream_h->stream_type, &stream_h->stream_conf_info); + if (ret) { + goto PA_ERROR_WITH_UNLOCK; + } else { + LOGI("stream_conf_info : priority[%d], route type[%d]", stream_h->stream_conf_info.priority, stream_h->stream_conf_info.route_type); + } + + pa_threaded_mainloop_unlock(stream_h->pa_mainloop); + + /* register focus */ + ret = mm_sound_register_focus(stream_h->index, stream_h->stream_type, _focus_state_change_callback, user_data); + if (ret == MM_ERROR_NONE) { + int i = 0; + stream_h->user_cb = callback; + stream_h->user_data = user_data; + for (i = 0; i < SOUND_STREAM_INFO_ARR_MAX; i++) { + if (sound_stream_info_arr[i] == NULL) { + sound_stream_info_arr[i] = stream_h; + break; + } + } + if (i == SOUND_STREAM_INFO_ARR_MAX) { + LOGE("client sound stream info array is full"); + ret = mm_sound_unregister_focus(stream_h->index); + goto PA_ERROR; + } + } else { + /* disconnect */ + goto PA_ERROR; + } + goto SUCCESS; +PA_ERROR_WITH_UNLOCK: + pa_threaded_mainloop_unlock(stream_h->pa_mainloop); +PA_ERROR: + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (stream_h->stream_conf_info.avail_in_devices[i]) { + free(stream_h->stream_conf_info.avail_in_devices[i]); + } else { + break; + } + } + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (stream_h->stream_conf_info.avail_out_devices[i]) { + free(stream_h->stream_conf_info.avail_out_devices[i]); + } else { + break; + } + } + for (i = 0; i < AVAIL_FRAMEWORKS_MAX; i++) { + if (stream_h->stream_conf_info.avail_frameworks[i]) { + free(stream_h->stream_conf_info.avail_frameworks[i]); + } else { + break; + } + } + 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; + } + free(stream_h); + ret = MM_ERROR_SOUND_INTERNAL; + LOGE("pa_ret(%d), ret(%p)", pa_ret, ret); +SUCCESS: + return ret; +} + +int _destroy_pa_connection_and_unregister_focus(sound_stream_info_s *stream_h) +{ + int i = 0; + int ret = MM_ERROR_NONE; + + 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; + } + + /* unregister focus */ + ret = mm_sound_unregister_focus(stream_h->index); + + for (i = 0; i < AVAIL_DEVICES_MAX; i++) { + if (stream_h->stream_conf_info.avail_in_devices[i]) { + free(stream_h->stream_conf_info.avail_in_devices[i]); + } + if (stream_h->stream_conf_info.avail_out_devices[i]) { + free(stream_h->stream_conf_info.avail_out_devices[i]); + } + if (stream_h->manual_route_info.route_in_devices[i]) { + free (stream_h->manual_route_info.route_in_devices[i]); + } + if (stream_h->manual_route_info.route_out_devices[i]) { + free (stream_h->manual_route_info.route_out_devices[i]); + } + } + for (i = 0; i < AVAIL_FRAMEWORKS_MAX; i++) { + if (stream_h->stream_conf_info.avail_frameworks[i]) { + free(stream_h->stream_conf_info.avail_frameworks[i]); + } + } + for (i = 0; i < ROUTE_OPTIONS_MAX; i++) { + if (stream_h->route_options[i]) { + free(stream_h->route_options[i]); + } + } + for (i = 0; i < SOUND_STREAM_INFO_ARR_MAX; i++) { + if (sound_stream_info_arr[i] && sound_stream_info_arr[i]->index == stream_h->index) { + sound_stream_info_arr[i] = NULL; + break; + } + } + free(stream_h); + + return ret; +} diff --git a/test/sound_manager_test.c b/test/sound_manager_test.c index 8a704e5..ebdfed0 100644 --- a/test/sound_manager_test.c +++ b/test/sound_manager_test.c @@ -19,6 +19,7 @@ #include #include +#include #include #include //#include @@ -58,6 +59,23 @@ enum CURRENT_STATUS_UNSET_DEVICE_CONNECTED_CB, CURRENT_STATUS_SET_DEVICE_INFO_CHANGED_CB, CURRENT_STATUS_UNSET_DEVICE_INFO_CHANGED_CB, + CURRENT_STATUS_CREATE_STREAM_INFO, + CURRENT_STATUS_ADD_DEVICE_FOR_STREAM_ROUTING, + CURRENT_STATUS_REMOVE_DEVICE_FOR_STREAM_ROUTING, + CURRENT_STATUS_APPLY_STREAM_ROUTING, + CURRENT_STATUS_ADD_OPTION_FOR_STREAM_ROUTING, + CURRENT_STATUS_REMOVE_OPTION_FOR_STREAM_ROUTING, + CURRENT_STATUS_APPLY_STREAM_ROUTING_OPTIONS, + CURRENT_STATUS_ACQUIRE_FOCUS, + CURRENT_STATUS_RELEASE_FOCUS, + CURRENT_STATUS_GET_ACQUIRED_FOCUS, + CURRENT_STATUS_DESTROY_STREAM_INFO, + CURRENT_STATUS_SET_FOCUS_WATCH_CB, + CURRENT_STATUS_UNSET_FOCUS_WATCH_CB, + CURRENT_STATUS_CREATE_VIRTUAL_STREAM, + CURRENT_STATUS_START_VIRTUAL_STREAM, + CURRENT_STATUS_STOP_VIRTUAL_STREAM, + CURRENT_STATUS_DESTROY_VIRTUAL_STREAM }; @@ -66,6 +84,34 @@ static int g_menu_state = CURRENT_STATUS_MAINMENU; GMainLoop* g_loop; sound_device_list_h g_device_list = 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; + +void focus_callback (sound_stream_info_h stream_info, sound_stream_focus_change_reason_e reason_for_change, const char *additional_info, void *user_data) { + int ret = 0; + sound_stream_focus_state_e playback_focus_state; + sound_stream_focus_state_e recording_focus_state; + g_print("*** FOCUS callback is called, stream_info(%p) ***\n", stream_info); + g_print(" - reason_for_change(%d), additional_info(%s), user_data(%p)\n", reason_for_change, additional_info, user_data); + ret = sound_manager_get_focus_state (stream_info, &playback_focus_state, &recording_focus_state); + if (!ret) + g_print(" - focus_state(playback_focus:%d, recording_focus:%d)\n", playback_focus_state, recording_focus_state); + if (playback_focus_state == SOUND_STREAM_FOCUS_STATE_ACQUIRED) { + g_print(" -- PLAYBACK_FOCUS acquired\n"); + } + if (recording_focus_state == SOUND_STREAM_FOCUS_STATE_ACQUIRED) { + g_print(" -- FOCUS_RECORDING acquired\n"); + } + g_print("*** FOCUS callback is ended, stream_info(%p) ****\n", stream_info); + return; +} + +void focus_watch_callback (sound_stream_focus_mask_e changed_focus_type, sound_stream_focus_state_e changed_focus_state, sound_stream_focus_change_reason_e reason_for_change, const char *additional_info, void *user_data) { + g_print("*** FOCUS WATCH callback is called ***\n"); + g_print(" - changed_focus_type(%d), changed_focus_state(%d), reason_for_change(%d), additional_info(%s), user_data(%p)\n", + changed_focus_type, changed_focus_state, reason_for_change, additional_info, user_data); + return; +} void quit_program() { @@ -74,123 +120,191 @@ void quit_program() void _interpret_main_menu(char *cmd) { - if (strncmp(cmd, "gx", 2) == 0) + if (strncmp(cmd, "gx", 3) == 0) { g_menu_state = CURRENT_STATUS_GET_MAX_VOLUME; } - else if (strncmp(cmd, "sv", 2) == 0) + else if (strncmp(cmd, "sv", 3) == 0) { g_menu_state = CURRENT_STATUS_SET_VOLUME; - } - else if (strncmp(cmd, "gv", 2) == 0) + } + else if (strncmp(cmd, "gv", 3) == 0) { g_menu_state = CURRENT_STATUS_GET_VOLUME; } - else if (strncmp(cmd, "st", 2) == 0) + else if (strncmp(cmd, "st", 3) == 0) { g_menu_state = CURRENT_STATUS_SET_CURRENT_SOUND_TYPE; } - else if (strncmp(cmd, "gt", 2) == 0) + else if (strncmp(cmd, "gt", 3) == 0) { g_menu_state = CURRENT_STATUS_GET_CURRENT_SOUND_TYPE; } - else if (strncmp(cmd, "ut", 2) == 0) + else if (strncmp(cmd, "ut", 3) == 0) { g_menu_state = CURRENT_STATUS_UNSET_CURRENT_SOUND_TYPE; - } - else if (strncmp(cmd, "vc", 2) == 0) + } + else if (strncmp(cmd, "vc", 3) == 0) { g_menu_state = CURRENT_STATUS_SET_VOLUME_CHANGED_CB; } - else if (strncmp(cmd, "uv", 2) == 0) + else if (strncmp(cmd, "uv", 3) == 0) { g_menu_state = CURRENT_STATUS_UNSET_VOLUME_CHANGED_CB; } - else if (strncmp(cmd, "ss", 2) == 0 ) + else if (strncmp(cmd, "ss", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_SESSION_TYPE; - } - else if (strncmp(cmd, "gs", 2) == 0 ) + } + else if (strncmp(cmd, "gs", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_SESSION_TYPE; } - else if (strncmp(cmd, "sm", 2) == 0 ) + else if (strncmp(cmd, "sm", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_MEDIA_SESSION_OPTION; } - else if (strncmp(cmd, "gm", 2) == 0 ) + else if (strncmp(cmd, "gm", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_MEDIA_SESSION_OPTION; } - else if (strncmp(cmd, "sr", 2) == 0 ) + else if (strncmp(cmd, "sr", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_MEDIA_SESSION_RESUMPTION_OPTION; } - else if (strncmp(cmd, "gr", 2) == 0 ) + else if (strncmp(cmd, "gr", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_MEDIA_SESSION_RESUMPTION_OPTION; } - else if (strncmp(cmd, "so", 2) == 0 ) + else if (strncmp(cmd, "so", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_VOIP_SESSION_MODE; } - else if (strncmp(cmd, "go", 2) == 0 ) + else if (strncmp(cmd, "go", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_VOIP_SESSION_MODE; } - else if (strncmp(cmd, "sl", 2) == 0 ) + else if (strncmp(cmd, "sl", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_CALL_SESSION_MODE; } - else if (strncmp(cmd, "gc", 2) == 0 ) + else if (strncmp(cmd, "gc", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_CALL_SESSION_MODE; } - else if (strncmp(cmd, "sc", 2) == 0 ) + else if (strncmp(cmd, "sc", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_SESSION_INTERRUPTED_CB; } - else if (strncmp(cmd, "us", 2) == 0 ) + else if (strncmp(cmd, "us", 3) == 0 ) { g_menu_state = CURRENT_STATUS_UNSET_SESSION_INTERRUPTED_CB; } - else if (strncmp(cmd, "sk", 2) == 0 ) + else if (strncmp(cmd, "sk", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_DEVICE_MASK; } - else if (strncmp(cmd, "gk", 2) == 0 ) + else if (strncmp(cmd, "gk", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_DEVICE_MASK; } - else if (strncmp(cmd, "gl", 2) == 0 ) + else if (strncmp(cmd, "gl", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_DEVICE_LIST; } - else if (strncmp(cmd, "gn", 2) == 0 ) + else if (strncmp(cmd, "gn", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_DEVICE_NEXT; } - else if (strncmp(cmd, "gp", 2) == 0 ) + else if (strncmp(cmd, "gp", 3) == 0 ) { g_menu_state = CURRENT_STATUS_GET_DEVICE_PREV; } - else if (strncmp(cmd, "sd", 2) == 0 ) + else if (strncmp(cmd, "sd", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_DEVICE_CONNECTED_CB; } - else if (strncmp(cmd, "ud", 2) == 0 ) + else if (strncmp(cmd, "ud", 3) == 0 ) { g_menu_state = CURRENT_STATUS_UNSET_DEVICE_CONNECTED_CB; } - else if (strncmp(cmd, "si", 2) == 0 ) + else if (strncmp(cmd, "si", 3) == 0 ) { g_menu_state = CURRENT_STATUS_SET_DEVICE_INFO_CHANGED_CB; } - else if (strncmp(cmd, "ui", 2) == 0 ) + else if (strncmp(cmd, "ui", 3) == 0 ) { g_menu_state = CURRENT_STATUS_UNSET_DEVICE_INFO_CHANGED_CB; } - else if (strncmp(cmd, "q", 1) == 0 ) + else if (strncmp(cmd, "csi", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_CREATE_STREAM_INFO; + } + else if (strncmp(cmd, "ads", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_ADD_DEVICE_FOR_STREAM_ROUTING; + } + else if (strncmp(cmd, "rds", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_REMOVE_DEVICE_FOR_STREAM_ROUTING; + } + else if (strncmp(cmd, "aps", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_APPLY_STREAM_ROUTING; + } + else if (strncmp(cmd, "aos", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_ADD_OPTION_FOR_STREAM_ROUTING; + } + else if (strncmp(cmd, "ros", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_REMOVE_OPTION_FOR_STREAM_ROUTING; + } + else if (strncmp(cmd, "aso", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_APPLY_STREAM_ROUTING_OPTIONS; + } + else if (strncmp(cmd, "afc", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_ACQUIRE_FOCUS; + } + else if (strncmp(cmd, "rfc", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_RELEASE_FOCUS; + } + else if (strncmp(cmd, "gfs", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_GET_ACQUIRED_FOCUS; + } + else if (strncmp(cmd, "sfw", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_SET_FOCUS_WATCH_CB; + } + else if (strncmp(cmd, "ufw", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_UNSET_FOCUS_WATCH_CB; + } + else if (strncmp(cmd, "dsi", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_DESTROY_STREAM_INFO; + } + else if (strncmp(cmd, "vcr", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_CREATE_VIRTUAL_STREAM; + } + else if (strncmp(cmd, "vsr", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_START_VIRTUAL_STREAM; + } + else if (strncmp(cmd, "vst", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_STOP_VIRTUAL_STREAM; + } + else if (strncmp(cmd, "vdt", 3) == 0 ) + { + g_menu_state = CURRENT_STATUS_DESTROY_VIRTUAL_STREAM; + } + else if (strncmp(cmd, "q", 3) == 0 ) { g_print("closing the test suite\n"); quit_program(); @@ -219,8 +333,8 @@ void display_sub_basic() g_print("vc. Set Volume Changed CB \t"); g_print("uv. Unset Volume Changed CB \n"); g_print("-----------------------------------------------------------------------------------------\n"); - g_print(" SESSION MODULE \n"); - g_print("-----------------------------------------------------------------------------------------\n"); + g_print(" SESSION MODULE \n"); + g_print("-----------------------------------------------------------------------------------------\n"); g_print("ss. Set Session Type\t\t"); g_print("gs. Get Session Type\n"); g_print("sm. Set Media Session Option \t"); @@ -234,7 +348,7 @@ void display_sub_basic() g_print("sc. Set Session Interruped CB \t"); g_print("us. Unset Session Interrupted CB \n"); g_print("-----------------------------------------------------------------------------------------\n"); - g_print(" DEVICE MODULE \n"); + g_print(" DEVICE MODULE \n"); g_print("-----------------------------------------------------------------------------------------\n"); g_print("sk. Set Devices Mask(default ALL)\t"); g_print("gk. Get Devices Mask\n"); @@ -245,7 +359,27 @@ void display_sub_basic() g_print("ud. Unset Device Connenected CB\n"); g_print("si. Set Device Information Changed CB\t"); g_print("ui. Unset Device Information Changed CB\n"); - g_print("\n"); + g_print("-----------------------------------------------------------------------------------------\n"); + g_print(" STREAM POLICY MODULE \n"); + g_print("-----------------------------------------------------------------------------------------\n"); + g_print("csi. Create Stream Info\t"); + g_print("dsi. Destroy Stream Info\n"); + g_print("ads. Add device for stream routing\t"); + g_print("rds. Remove device for stream routing\t"); + g_print("aps. Apply devices for stream routing\n"); + g_print("afc. Acquire Focus\t"); + g_print("rfc. Release Focus\t"); + g_print("gfs. Get Focus State\n"); + g_print("sfw. Set Focus State Watch CB\t"); + g_print("ufw. Unset Focus State Watch CB\n"); + g_print("aos. *Add option for stream routing\t"); + g_print("ros. *Remove option for stream routing\t"); + g_print("aso. *Apply options for stream routing\n"); + g_print("vcr. *Create VStream\t"); + g_print("vsr. *Start VStream\t"); + g_print("vst. *Stop VStream\t"); + g_print("vdt. *Destroy VStream\n"); + g_print(" * is for internal usage.\n"); g_print("=========================================================================================\n"); } @@ -377,6 +511,74 @@ static void displaymenu() { g_print("*** press enter to unset device information changed cb\n"); } + else if (g_menu_state == CURRENT_STATUS_CREATE_STREAM_INFO) + { + g_print("*** input stream type to create stream information (0:media, 1:alarm, 2:notification, 3:ringtone-call, 4:voice-call)\n"); + } + else if (g_menu_state == CURRENT_STATUS_ADD_DEVICE_FOR_STREAM_ROUTING) + { + g_print("*** input device type to add (0:built-in spk, 1:built-in rcv, 2:audio-jack, 3:bt)\n"); + } + else if (g_menu_state == CURRENT_STATUS_REMOVE_DEVICE_FOR_STREAM_ROUTING) + { + g_print("*** input device type to remove (0:built-in spk, 1:built-in rcv, 2:audio-jack, 3:bt)\n"); + } + else if (g_menu_state == CURRENT_STATUS_APPLY_STREAM_ROUTING) + { + g_print("*** press enter to apply devices for stream routing\n"); + } + else if (g_menu_state == CURRENT_STATUS_ADD_OPTION_FOR_STREAM_ROUTING) + { + g_print("*** input option to add\n"); + } + else if (g_menu_state == CURRENT_STATUS_REMOVE_OPTION_FOR_STREAM_ROUTING) + { + g_print("*** input option to remove\n"); + } + else if (g_menu_state == CURRENT_STATUS_APPLY_STREAM_ROUTING_OPTIONS) + { + g_print("*** press enter to apply options for stream routing \n"); + } + else if (g_menu_state == CURRENT_STATUS_ACQUIRE_FOCUS) + { + g_print("*** input focus type to acquire (0:playback, 1:recording, 2:both)\n"); + } + else if (g_menu_state == CURRENT_STATUS_RELEASE_FOCUS) + { + g_print("*** input focus type to release (0:playback, 1:recording, 2:both)\n"); + } + else if (g_menu_state == CURRENT_STATUS_GET_ACQUIRED_FOCUS) + { + g_print("*** press enter to get focus state\n"); + } + else if (g_menu_state == CURRENT_STATUS_DESTROY_STREAM_INFO) + { + g_print("*** press enter to destroy stream information\n"); + } + else if (g_menu_state == CURRENT_STATUS_SET_FOCUS_WATCH_CB) + { + g_print("*** input focus type to watch for (0:playback, 1:recording, 2:both)\n"); + } + else if (g_menu_state == CURRENT_STATUS_UNSET_FOCUS_WATCH_CB) + { + g_print("*** press enter to unset focus state watch cb\n"); + } + else if (g_menu_state == CURRENT_STATUS_CREATE_VIRTUAL_STREAM) + { + g_print("*** press enter to create virtual stream\n"); + } + else if (g_menu_state == CURRENT_STATUS_START_VIRTUAL_STREAM) + { + g_print("*** press enter to start virtual stream\n"); + } + else if (g_menu_state == CURRENT_STATUS_STOP_VIRTUAL_STREAM) + { + g_print("*** press enter to stop virtual stream\n"); + } + else if (g_menu_state == CURRENT_STATUS_DESTROY_VIRTUAL_STREAM) + { + g_print("*** press enter to destroy virtual stream\n"); + } else { g_print("*** unknown status.\n"); @@ -1009,6 +1211,381 @@ static void interpret (char *cmd) reset_menu_state(); } break; + case CURRENT_STATUS_CREATE_STREAM_INFO: + { + int ret = SOUND_MANAGER_ERROR_NONE; + int stream_type = 0; + sound_stream_type_e type = SOUND_STREAM_TYPE_MEDIA; + if (g_stream_info_h) { + g_print("fail to create stream information, g_stream_info_h(%p) is already set\n", g_stream_info_h); + reset_menu_state(); + break; + } + stream_type = atoi(cmd); + switch(stream_type) { + case 0: /* media */ + type = SOUND_STREAM_TYPE_MEDIA; + break; + case 1: /* alarm */ + type = SOUND_STREAM_TYPE_ALARM; + break; + case 2: /* notification */ + type = SOUND_STREAM_TYPE_NOTIFICATION; + break; + case 3: /* ringtone for call*/ + type = SOUND_STREAM_TYPE_RINGTONE_CALL; + break; + case 4: /* voice call */ + type = SOUND_STREAM_TYPE_VOICE_CALL; + break; + default: + type = SOUND_STREAM_TYPE_MEDIA; + break; + } + if (type == (int)SOUND_STREAM_TYPE_RINGTONE_CALL || type == (int)SOUND_STREAM_TYPE_VOICE_CALL) { + ret = sound_manager_create_stream_information_internal(type, focus_callback, NULL, &g_stream_info_h); + } else { + ret = sound_manager_create_stream_information(type, focus_callback, NULL, &g_stream_info_h); + } + if (ret) { + g_print("fail to sound_manager_create_stream_information(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_ADD_DEVICE_FOR_STREAM_ROUTING: + { + int ret = SOUND_MANAGER_ERROR_NONE; + int device_type = 0; + sound_device_h device = NULL; + sound_device_type_e selected_type = SOUND_DEVICE_BUILTIN_SPEAKER; + sound_device_type_e type = SOUND_DEVICE_BUILTIN_SPEAKER; + bool need_to_go = false; + device_type = atoi(cmd); + switch(device_type) { + case 0: /* built-in spk */ + selected_type = SOUND_DEVICE_BUILTIN_SPEAKER; + break; + case 1: /* built-in rcv */ + selected_type = SOUND_DEVICE_BUILTIN_RECEIVER; + break; + case 2: /* audio-jack */ + selected_type = SOUND_DEVICE_AUDIO_JACK; + break; + case 3: /* bt */ + selected_type = SOUND_DEVICE_BLUETOOTH; + break; + default: + g_print("invalid argument, device_type(%d) is not valid for this feature\n", device_type); + reset_menu_state(); + break; + } + if (!(ret = sound_manager_get_current_device_list(SOUND_DEVICE_ALL_MASK, &g_device_list))) { + g_print("success to get current device list\n"); + while (!sound_manager_get_next_device(g_device_list, &device)) { + if (!(ret = sound_manager_get_device_type (device, &type))) { + if (selected_type == type) { + need_to_go = true; + break; + } + } else { + g_print("fail to get type of device, ret(0x%x)\n", ret); + reset_menu_state(); + break; + } + } + if (need_to_go) { + ret = sound_manager_add_device_for_stream_routing (g_stream_info_h, device); + if (ret) { + g_print("failed to sound_manager_add_device_for_stream_routing(), ret(0x%x)\n", ret); + } + } else { + g_print("the device is not available now\n"); + } + reset_menu_state(); + } else { + g_print("fail to get current device list, ret(0x%x)\n", ret); + reset_menu_state(); + } + } + break; + case CURRENT_STATUS_REMOVE_DEVICE_FOR_STREAM_ROUTING: + { + int ret = SOUND_MANAGER_ERROR_NONE; + int device_type = 0; + sound_device_h device = NULL; + sound_device_type_e selected_type = SOUND_DEVICE_BUILTIN_SPEAKER; + sound_device_type_e type = SOUND_DEVICE_BUILTIN_SPEAKER; + bool need_to_go = false; + device_type = atoi(cmd); + switch(device_type) { + case 0: /* built-in spk */ + selected_type = SOUND_DEVICE_BUILTIN_SPEAKER; + break; + case 1: /* built-in rcv */ + selected_type = SOUND_DEVICE_BUILTIN_RECEIVER; + break; + case 2: /* audio-jack */ + selected_type = SOUND_DEVICE_AUDIO_JACK; + break; + case 3: /* bt */ + selected_type = SOUND_DEVICE_BLUETOOTH; + break; + default: + g_print("invalid argument, device_type(%d) is not valid for this feature\n", device_type); + reset_menu_state(); + break; + } + if (!(ret = sound_manager_get_current_device_list(SOUND_DEVICE_ALL_MASK, &g_device_list))) { + g_print("success to get current device list\n"); + while (!sound_manager_get_next_device(g_device_list, &device)) { + if (!(ret = sound_manager_get_device_type (device, &type))) { + if (selected_type == type) { + need_to_go = true; + break; + } + } else { + g_print("fail to get type of device, ret(0x%x)\n", ret); + reset_menu_state(); + break; + } + } + if (need_to_go) { + ret = sound_manager_remove_device_for_stream_routing (g_stream_info_h, device); + if (ret) { + g_print("failed to sound_manager_remove_device_for_stream_routing(), ret(0x%x)\n", ret); + } + } else { + g_print("the device is not available now\n"); + } + reset_menu_state(); + } else { + g_print("fail to get current device list, ret(0x%x)\n", ret); + reset_menu_state(); + } + } + break; + case CURRENT_STATUS_APPLY_STREAM_ROUTING: + { + int ret = SOUND_MANAGER_ERROR_NONE; + ret = sound_manager_apply_stream_routing (g_stream_info_h); + if (ret) { + g_print("failed to sound_manager_apply_stream_routing(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_ADD_OPTION_FOR_STREAM_ROUTING: + { + int ret = SOUND_MANAGER_ERROR_NONE; + ret = sound_manager_add_option_for_stream_routing (g_stream_info_h, cmd); + if (ret) { + g_print("failed to sound_manager_add_option_for_stream_routing(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_REMOVE_OPTION_FOR_STREAM_ROUTING: + { + int ret = SOUND_MANAGER_ERROR_NONE; + ret = sound_manager_remove_option_for_stream_routing (g_stream_info_h, cmd); + if (ret) { + g_print("failed to sound_manager_remove_option_for_stream_routing(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_APPLY_STREAM_ROUTING_OPTIONS: + { + int ret = SOUND_MANAGER_ERROR_NONE; + ret = sound_manager_apply_stream_routing_options (g_stream_info_h); + if (ret) { + g_print("failed to sound_manager_apply_stream_routing_options(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_ACQUIRE_FOCUS: + { + int ret = SOUND_MANAGER_ERROR_NONE; + int focus_type = 0; + sound_stream_focus_mask_e focus_mask; + focus_type = atoi(cmd); + switch(focus_type) { + case 0: /* playback */ + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK; + break; + case 1: /* recording */ + focus_mask = SOUND_STREAM_FOCUS_FOR_RECORDING; + break; + case 2: /* all */ + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK | SOUND_STREAM_FOCUS_FOR_RECORDING; + break; + default: + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK; + break; + } + ret = sound_manager_acquire_focus(g_stream_info_h, focus_mask, NULL); + if (ret) { + g_print("fail to sound_manager_acquire_focus(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_RELEASE_FOCUS: + { + int ret = SOUND_MANAGER_ERROR_NONE; + int focus_type = 0; + sound_stream_focus_mask_e focus_mask; + focus_type = atoi(cmd); + switch(focus_type) { + case 0: /* playback */ + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK; + break; + case 1: /* recording */ + focus_mask = SOUND_STREAM_FOCUS_FOR_RECORDING; + break; + case 2: /* both */ + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK | SOUND_STREAM_FOCUS_FOR_RECORDING; + break; + default: + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK; + break; + } + ret = sound_manager_release_focus(g_stream_info_h, focus_mask, NULL); + if (ret) { + g_print("fail to sound_manager_acquire_focus(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_GET_ACQUIRED_FOCUS: + { + sound_stream_focus_state_e for_playback; + sound_stream_focus_state_e for_recording; + int ret = SOUND_MANAGER_ERROR_NONE; + if(g_stream_info_h) { + ret = sound_manager_get_focus_state(g_stream_info_h, &for_playback, &for_recording); + if (ret) { + g_print("fail to sound_manager_get_focus_state(), ret(0x%x)\n", ret); + } else { + g_print("focus_state(playback:%d, capture:%d)\n", for_playback, for_recording); + } + } else { + g_print("please create stream info. first\n"); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_DESTROY_STREAM_INFO: + { + int ret = SOUND_MANAGER_ERROR_NONE; + ret = sound_manager_destroy_stream_information(g_stream_info_h); + if (ret) { + g_print("fail to sound_manager_destroy_stream_information(), ret(0x%x)\n", ret); + } else { + g_stream_info_h = NULL; + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_SET_FOCUS_WATCH_CB: + { + int ret = SOUND_MANAGER_ERROR_NONE; + int focus_type = 0; + sound_stream_focus_mask_e focus_mask; + focus_type = atoi(cmd); + switch(focus_type) { + case 0: /* playback */ + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK; + break; + case 1: /* recording */ + focus_mask = SOUND_STREAM_FOCUS_FOR_RECORDING; + break; + case 2: /* both */ + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK | SOUND_STREAM_FOCUS_FOR_RECORDING; + break; + default: + focus_mask = SOUND_STREAM_FOCUS_FOR_PLAYBACK; + break; + } + ret = sound_manager_set_focus_state_watch_cb(focus_mask, focus_watch_callback, NULL); + if (ret) { + g_print("fail to sound_manager_set_focus_state_watch_cb(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_UNSET_FOCUS_WATCH_CB: + { + int ret = SOUND_MANAGER_ERROR_NONE; + ret = sound_manager_unset_focus_state_watch_cb(); + if (ret) { + g_print("fail to sound_manager_unset_focus_state_watch_cb(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_CREATE_VIRTUAL_STREAM: + { + int ret = SOUND_MANAGER_ERROR_NONE; + if (!g_stream_info_h || g_vstream_h) { + g_print("fail to create virtual stream, g_stream_info_h(%p)/g_vstream_h(%p)\n", g_stream_info_h, g_vstream_h); + reset_menu_state(); + break; + } + ret = sound_manager_create_virtual_stream(g_stream_info_h, &g_vstream_h); + if (ret) { + g_print("fail to sound_manager_create_virtual_stream(), ret(0x%x)\n", ret); + } else { + g_print("success to sound_manager_create_virtual_stream(), ret(0x%x)\n", ret); + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_START_VIRTUAL_STREAM: + { + int ret = SOUND_MANAGER_ERROR_NONE; + if (g_vstream_h) { + ret = sound_manager_start_virtual_stream(g_vstream_h); + if (ret) { + g_print("fail to sound_manager_start_virtual_stream(), ret(0x%x)\n", ret); + } else { + g_print("success to sound_manager_start_virtual_stream(), ret(0x%x)\n", ret); + } + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_STOP_VIRTUAL_STREAM: + { + int ret = SOUND_MANAGER_ERROR_NONE; + if (g_vstream_h) { + ret = sound_manager_stop_virtual_stream(g_vstream_h); + if (ret) { + g_print("fail to sound_manager_stop_virtual_stream(), ret(0x%x)\n", ret); + } else { + g_print("success to sound_manager_stop_virtual_stream(), ret(0x%x)\n", ret); + } + } + reset_menu_state(); + } + break; + case CURRENT_STATUS_DESTROY_VIRTUAL_STREAM: + { + int ret = SOUND_MANAGER_ERROR_NONE; + if (g_vstream_h) { + ret = sound_manager_destroy_virtual_stream(g_vstream_h); + if (ret) { + g_print("fail to sound_manager_destroy_virtual_stream(), ret(0x%x)\n", ret); + } else { + g_print("success to sound_manager_destroy_virtual_stream(), ret(0x%x)\n", ret); + } + g_vstream_h = NULL; + } + reset_menu_state(); + } + break; } g_timeout_add(100, timeout_menu_display, 0); }