X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=mm_sound_client.c;h=4ba6246cb1151d79ba9ddcd8809036141e29f7aa;hb=92c5c7f406312a94916abf7e2ec458f0a3277d06;hp=cd3a37cf72fec38abce06aa6908f238cddd5c10a;hpb=c1df34a4849ea344c8da65eb6b5d6d7800471755;p=platform%2Fcore%2Fmultimedia%2Flibmm-sound.git diff --git a/mm_sound_client.c b/mm_sound_client.c index cd3a37c..4ba6246 100644 --- a/mm_sound_client.c +++ b/mm_sound_client.c @@ -19,15 +19,15 @@ * */ +#include #include #include -#include -#include +#include #include #include -#include -#include +#include #include +#include #include #include @@ -36,1406 +36,2295 @@ #include #include "include/mm_sound.h" -#include "include/mm_sound_msg.h" #include "include/mm_sound_client.h" +#include "include/mm_sound_proxy.h" +#include "include/mm_sound_common.h" +#include "include/mm_sound_device.h" +#include "include/mm_sound_stream.h" #include #include -#define __DIRECT_CALLBACK__ -//#define __GIDLE_CALLBACK__ - #include #if defined(__GSOURCE_CALLBACK__) #include #endif -#define MEMTYPE_SUPPORT_MAX (1024 * 1024) /* 1MB */ -#define MEMTYPE_TRANS_PER_MAX (128 * 1024) /* 128K */ +#define CLIENT_HANDLE_MAX 256 +#define FOCUS_HANDLE_MAX 512 +#define FOCUS_HANDLE_INIT_VAL -1 +#define CONFIG_ENABLE_RETCB -int g_msg_scsnd; /* global msg queue id sound client snd */ -int g_msg_scrcv; /* global msg queue id sound client rcv */ -int g_msg_sccb; /* global msg queue id sound client callback */ +#define VOLUME_TYPE_LEN 64 -/* callback */ -struct __callback_param -{ - mm_sound_stop_callback_func callback; - void *data; +struct sigaction system_int_old_action; +struct sigaction system_abrt_old_action; +struct sigaction system_segv_old_action; +struct sigaction system_term_old_action; +struct sigaction system_sys_old_action; +struct sigaction system_xcpu_old_action; + +struct callback_data { + void *user_cb; + void *user_data; + void *extra_data; + guint subs_id; }; -pthread_t g_thread; -static int g_exit_thread = 0; -int g_thread_id = -1; -int g_mutex_initted = -1; -pthread_mutex_t g_thread_mutex; +typedef struct _FocusSource { + GSource source; + GPollFD poll_fd; +} FocusSource; + +#define GET_CB_DATA(_cb_data, _func, _userdata, _extradata) \ + do { \ + _cb_data = (struct callback_data*) g_malloc0(sizeof(struct callback_data)); \ + _cb_data->user_cb = _func; \ + _cb_data->user_data = _userdata; \ + _cb_data->extra_data = _extradata; \ + } while (0) + +#ifdef USE_FOCUS +typedef struct { + int focus_tid; + int handle; + int focus_fd; + FocusSource *fsrc; + bool is_used; + bool auto_reacquire; + GMutex focus_lock; + GThread *focus_cb_thread; + GMainLoop *focus_loop; + mm_sound_focus_changed_cb focus_callback; + mm_sound_focus_changed_watch_cb watch_callback; + void* user_data; + bool unset_watch_callback_requested; + + /* will be removed when the session concept is completely left out*/ + bool is_for_session; + bool is_for_monitor; +} focus_sound_info_t; + +typedef struct { + int pid; + int handle; + int type; + int state; + char stream_type[MAX_STREAM_TYPE_LEN]; + char ext_info[MM_SOUND_NAME_NUM]; + int option; +} focus_cb_data_lib; + +typedef struct { + int watch_cb_id; + mm_sound_focus_session_interrupt_cb user_cb; + void* user_data; +} focus_session_interrupt_info_t; + +typedef gboolean (*focus_callback_handler_t)(gpointer user_data); + +focus_sound_info_t g_focus_sound_handle[FOCUS_HANDLE_MAX]; +focus_session_interrupt_info_t g_focus_session_interrupt_info = {-1, NULL, NULL}; +static pthread_mutex_t g_index_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t g_event_mutex = PTHREAD_MUTEX_INITIALIZER; +guint g_focus_signal_handle; +guint g_idle_event_src; +#endif + +gboolean g_need_emergent_exit = FALSE; + +typedef struct { + /* handle to watch end of playing */ + int watching_handle; + /* subscription id to unsubscribe when handle ended */ + unsigned subs_id; +} play_sound_end_callback_data_t; + +typedef struct _focus_idle_event { + focus_idle_event_type_e type; + int data; +} focus_idle_event_t; + +void _system_signal_handler(int signo, siginfo_t *siginfo, void *context) +{ + int ret = MM_ERROR_NONE; + sigset_t old_mask, all_mask; + + debug_warning("Got signal : signo(%d)", signo); + + /* signal block */ + + sigfillset(&all_mask); + sigprocmask(SIG_BLOCK, &all_mask, &old_mask); + + if (g_need_emergent_exit) { + ret = mm_sound_proxy_emergent_exit(getpid()); + if (ret == MM_ERROR_NONE) + debug_msg("Success to emergnet_exit"); + else + debug_error("Error occurred : 0x%x", ret); + } + + sigprocmask(SIG_SETMASK, &old_mask, NULL); + /* signal unblock */ -static void* callbackfunc(void *param); + switch (signo) { + case SIGINT: + if (system_int_old_action.sa_sigaction) + system_int_old_action.sa_sigaction(signo, siginfo, context); + else + sigaction(signo, &system_int_old_action, NULL); + break; + case SIGABRT: + if (system_abrt_old_action.sa_sigaction) + system_abrt_old_action.sa_sigaction(signo, siginfo, context); + else + sigaction(signo, &system_abrt_old_action, NULL); + break; + case SIGSEGV: + if (system_segv_old_action.sa_sigaction) + system_segv_old_action.sa_sigaction(signo, siginfo, context); + else + sigaction(signo, &system_segv_old_action, NULL); + break; + case SIGTERM: + if (system_term_old_action.sa_sigaction) + system_term_old_action.sa_sigaction(signo, siginfo, context); + else + sigaction(signo, &system_term_old_action, NULL); + break; + case SIGSYS: + if (system_sys_old_action.sa_sigaction) + system_sys_old_action.sa_sigaction(signo, siginfo, context); + else + sigaction(signo, &system_sys_old_action, NULL); + break; + case SIGXCPU: + if (system_xcpu_old_action.sa_sigaction) + system_xcpu_old_action.sa_sigaction(signo, siginfo, context); + else + sigaction(signo, &system_xcpu_old_action, NULL); + break; + default: + break; + } -/* manage IPC (msg contorl) */ -static int __MMIpcCBSndMsg(mm_ipc_msg_t *msg); -static int __MMIpcRecvMsg(int msgtype, mm_ipc_msg_t *msg); -static int __MMIpcSndMsg(mm_ipc_msg_t *msg); -static int __MMIpcCBRecvMsg(int msgtype, mm_ipc_msg_t *msg); -static int __MMSoundGetMsg(void); + debug_warning("signal handling end"); +} -int MMSoundClientInit(void) +int mm_sound_client_initialize(void) { int ret = MM_ERROR_NONE; debug_fenter(); + mm_sound_proxy_initialize(); + g_idle_event_src = 0; + + + struct sigaction system_action; + system_action.sa_sigaction = _system_signal_handler; + system_action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO; + + sigemptyset(&system_action.sa_mask); + + sigaction(SIGINT, &system_action, &system_int_old_action); + sigaction(SIGABRT, &system_action, &system_abrt_old_action); + sigaction(SIGSEGV, &system_action, &system_segv_old_action); + sigaction(SIGTERM, &system_action, &system_term_old_action); + sigaction(SIGSYS, &system_action, &system_sys_old_action); + sigaction(SIGXCPU, &system_action, &system_xcpu_old_action); + debug_fleave(); return ret; } -int MMSoundClientCallbackFini(void) +int mm_sound_client_finalize(void) { - mm_ipc_msg_t msgsnd={0,}; int ret = MM_ERROR_NONE; - + debug_fenter(); - /* When the the callback thread is not created, do not wait destory thread */ - /* g_thread_id is initialized : -1 */ - /* g_thread_id is set to 0, when the callback thread is created */ - if (g_thread_id != -1) - { - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_INF_DESTROY_CB; - msgsnd.sound_msg.msgid = getpid(); - ret = __MMIpcCBSndMsg(&msgsnd); - if (ret != MM_ERROR_NONE) - { - debug_critical("[Client] Fail to send message\n"); - } - /* wait for leave callback thread */ - while (g_exit_thread == 0) - usleep(30000); - g_exit_thread = 0; + if (g_need_emergent_exit) { + ret = mm_sound_proxy_emergent_exit(getpid()); + if (ret == MM_ERROR_NONE) + debug_msg("Success to emergent_exit"); + else + debug_error("Error occurred : 0x%x", ret); } - if (g_mutex_initted != -1) - { - pthread_mutex_destroy(&g_thread_mutex); - g_mutex_initted = -1; + sigaction(SIGINT, &system_int_old_action, NULL); + sigaction(SIGABRT, &system_abrt_old_action, NULL); + sigaction(SIGSEGV, &system_segv_old_action, NULL); + sigaction(SIGTERM, &system_term_old_action, NULL); + sigaction(SIGSYS, &system_sys_old_action, NULL); + sigaction(SIGXCPU, &system_xcpu_old_action, NULL); + + ret = mm_sound_proxy_finalize(); + +#ifdef USE_FOCUS + if (g_idle_event_src > 0) { + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL); + g_source_remove(g_idle_event_src); + MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex); } +#endif + debug_fleave(); - return MM_ERROR_NONE; + return ret; } -#if defined(__GSOURCE_CALLBACK__) -gboolean sndcb_fd_check(GSource * source) +void mm_sound_convert_volume_type_to_stream_type(int volume_type, char *stream_type) { - GSList *fd_list; - fd_list = source->poll_fds; - GPollFD* temp; + switch (volume_type) { + case VOLUME_TYPE_SYSTEM: + MMSOUND_STRNCPY(stream_type, "system", MAX_STREAM_TYPE_LEN); + break; + case VOLUME_TYPE_NOTIFICATION: + MMSOUND_STRNCPY(stream_type, "notification", MAX_STREAM_TYPE_LEN); + break; + case VOLUME_TYPE_ALARM: + MMSOUND_STRNCPY(stream_type, "alarm", MAX_STREAM_TYPE_LEN); + break; + case VOLUME_TYPE_RINGTONE: + MMSOUND_STRNCPY(stream_type, "ringtone-voip", MAX_STREAM_TYPE_LEN); + break; + case VOLUME_TYPE_MEDIA: + MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN); + break; + case VOLUME_TYPE_CALL: + MMSOUND_STRNCPY(stream_type, "call-voice", MAX_STREAM_TYPE_LEN); + break; + case VOLUME_TYPE_VOIP: + MMSOUND_STRNCPY(stream_type, "voip", MAX_STREAM_TYPE_LEN); + break; + case VOLUME_TYPE_VOICE: + MMSOUND_STRNCPY(stream_type, "voice-information", MAX_STREAM_TYPE_LEN); + break; + default: + MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN); + break; + } - do - { - temp = (GPollFD*)fd_list->data; - if (temp->revents & (POLLIN|POLLPRI)) - return TRUE; - fd_list = fd_list->next; - }while(fd_list); + debug_msg("volume type (%d) converted to stream type (%s)", volume_type, stream_type); - return FALSE; /* there is no change in any fd state */ } -gboolean sndcb_fd_prepare(GSource *source, gint *timeout) +/***************************************************************************************** + DBUS SUPPORTED FUNCTIONS +******************************************************************************************/ +#ifdef USE_FOCUS +void _mm_sound_client_focus_signal_callback(mm_sound_signal_name_t signal, int value, void *user_data) { - return FALSE; -} + int ret = MM_ERROR_NONE; -gboolean sndcb_fd_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) -{ - callback(user_data); - return TRUE; + debug_fenter(); + debug_msg("focus signal received, value = %d", value); + + if (value == 1) { + ret = mm_sound_proxy_clear_focus(getpid()); + if (ret) + debug_error("clear focus failed ret = 0x%x", ret); + mm_sound_unsubscribe_signal(g_focus_signal_handle); + g_focus_signal_handle = 0; + } } #endif -gboolean RunCallback(gpointer *data) + +int mm_sound_client_play_tone(int number, int volume_config, double volume, + int time, int *handle, bool enable_session) { - mm_ipc_msg_t* msg = NULL; + int ret = MM_ERROR_NONE; +// int instance = -1; /* instance is unique to communicate with server : client message queue filter type */ + int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(volume_config); + char stream_type[MAX_STREAM_TYPE_LEN] = {0, }; - debug_msg("[Client] execute mm_sound stop callback function\n"); + debug_fenter(); - msg = (mm_ipc_msg_t*)data; - ((mm_sound_stop_callback_func)msg->sound_msg.callback)(msg->sound_msg.cbdata); + /* read session information */ + int session_type = MM_SESSION_TYPE_MEDIA; + int session_options = 0; + int is_focus_registered = 0; - return FALSE; + ret = mm_sound_get_signal_value(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &is_focus_registered); + if (ret) { + debug_error("mm_sound_get_signal_value failed [0x%x]", ret); + return MM_ERROR_POLICY_INTERNAL; + } + + if (is_focus_registered) + enable_session = false; + + if (enable_session) { + if (MM_ERROR_NONE != _mm_session_util_read_information(-1, &session_type, &session_options)) { + debug_warning("Read Session Information failed. use default \"media\" type"); + session_type = MM_SESSION_TYPE_MEDIA; + + if(MM_ERROR_NONE != mm_session_init(session_type)) { + debug_critical("MMSessionInit() failed"); + return MM_ERROR_POLICY_INTERNAL; + } + } + } + + // instance = getpid(); + //debug_log("pid for client ::: [%d]", instance); + + /* Send msg */ + debug_msg("Input number : %d", number); + /* Send req memory */ + + mm_sound_convert_volume_type_to_stream_type(volume_type, stream_type); + ret = mm_sound_proxy_play_tone(number, time, volume, volume_config, + session_type, session_options, getpid(), enable_session, handle, stream_type, -1); +#ifdef USE_FOCUS + if (enable_session && !g_focus_signal_handle) { + ret = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &g_focus_signal_handle, + _mm_sound_client_focus_signal_callback, NULL); + if (ret) { + debug_error("mm_sound_subscribe_signal failed [0x%x]", ret); + return MM_ERROR_POLICY_INTERNAL; + } + } +#endif + + debug_fleave(); + return ret; } -static void* callbackfunc(void *param) +int mm_sound_client_play_tone_with_stream_info(int tone, char *stream_type, int stream_id, + double volume, int duration, int *handle) { - int ret = MM_ERROR_SOUND_INTERNAL; - mm_ipc_msg_t *msgrcv = NULL; - int run = 1; - int instance; + int ret = MM_ERROR_NONE; debug_fenter(); - instance = getpid(); - debug_msg("[Client] callback thread for [%d] is created\n", instance); + ret = mm_sound_proxy_play_tone_with_stream_info(getpid(), tone, stream_type, stream_id, volume, duration, handle); + + debug_fleave(); + return ret; +} + +static void _mm_sound_stop_callback_wrapper_func(int ended_handle, void *userdata) +{ + struct callback_data *cb_data = (struct callback_data*) userdata; + play_sound_end_callback_data_t *end_cb_data; + + debug_log("ended_handle : %d", ended_handle); - msgrcv = (mm_ipc_msg_t*)malloc(sizeof(mm_ipc_msg_t)); - if(NULL == msgrcv) - { - debug_critical("[Client] Failed to memory allocation\n"); - return NULL; + if (cb_data == NULL) { + debug_warning("stop callback data null"); + return; } - while(run) - { -#if defined(__GSOURCE_CALLBACK__) - int eventFd = 0; - gchar* eventFile = NULL; - GSource* cmd_fd_gsrc = NULL; - GSourceFuncs *src_funcs = NULL; // handler function - guint gsource_handle; - GPollFD *g_fd_cmd = NULL; // file descriptor -#endif + end_cb_data = (play_sound_end_callback_data_t*) cb_data->extra_data; - debug_warning("[Client] Waiting message\n"); - ret = __MMIpcCBRecvMsg(instance, msgrcv); - if (ret != MM_ERROR_NONE) - { - debug_error("[Client] Fail to receive msg in callback\n"); - continue; - } + if (ended_handle == end_cb_data->watching_handle) { + debug_log("Interested playing handle end : %d", ended_handle); + ((mm_sound_stop_callback_func)(cb_data->user_cb))(cb_data->user_data, ended_handle); + if (mm_sound_proxy_remove_play_sound_end_callback(end_cb_data->subs_id) != MM_ERROR_NONE) + debug_error("mm_sound_client_dbus_remove_play_file_end_callback failed"); + } else { + debug_log("Not interested playing handle : %d", ended_handle); + } +} - debug_msg("[Client] Receive msgtype : [%d]\n", msgrcv->sound_msg.msgtype); +static void play_end_callback_data_free_func(void *data) +{ + struct callback_data *cb_data = (struct callback_data*) data; - switch (msgrcv->sound_msg.msgtype) - { - case MM_SOUND_MSG_INF_STOP_CB: - debug_msg("[Client] callback : %p\n", msgrcv->sound_msg.callback); - debug_msg("[Client] data : %p\n", msgrcv->sound_msg.cbdata); - - if (msgrcv->sound_msg.callback) - { -#if defined(__DIRECT_CALLBACK__) - ((mm_sound_stop_callback_func)msgrcv->sound_msg.callback)(msgrcv->sound_msg.cbdata); -#elif defined(__GIDLE_CALLBACK__) - guint eventid = 0; - eventid = g_idle_add((GSourceFunc)RunCallback, (gpointer)msgrcv); - debug_msg("[Client] Event Source ID : %d\n", eventid); - -#elif defined(__GSOURCE_CALLBACK__) - char eventBuf[3]="OK"; - //////////////////////// - // 0. Make event source - eventFile = g_strdup_printf("/tmp/%d_0x%08x_0x%08x", instance, (unsigned int)msgrcv->sound_msg.callback, (unsigned int)msgrcv->sound_msg.cbdata); - eventFd = open(eventFile, O_RDWR|O_CREAT); - if(eventFd == -1) - { - debug_critical("Event File creation failed\n"); - break; - } - - // 1. make GSource Object - src_funcs = (GSourceFuncs *)g_malloc(sizeof(GSourceFuncs)); - if(!src_funcs){ - debug_error("MMSoundCallback : g_malloc failed on g_src_funcs"); - break; - } - src_funcs->prepare = sndcb_fd_prepare; - src_funcs->check = sndcb_fd_check; - src_funcs->dispatch = sndcb_fd_dispatch; - src_funcs->finalize = NULL; - cmd_fd_gsrc = g_source_new(src_funcs,sizeof(GSource)); - if(!cmd_fd_gsrc){ - debug_error("MMSoundCallback : g_malloc failed on m_readfd"); - break; - } - - // 2. add file description which used in g_loop() - g_fd_cmd = (GPollFD*)g_malloc(sizeof(GPollFD)); - g_fd_cmd->fd = eventFd; - g_fd_cmd->events = POLLIN|POLLPRI; - - // 3. combine g_source object and file descriptor - g_source_add_poll(cmd_fd_gsrc,g_fd_cmd); - gsource_handle = g_source_attach(cmd_fd_gsrc, NULL); - if(!gsource_handle){ - debug_error("MMSoundCallback : Error: Failed to attach the source to context"); - break; - } - - // 4. set callback - g_source_set_callback(cmd_fd_gsrc,RunCallback,(gpointer)g_fd_cmd,NULL); - debug_msg("MMSoundCallback : g_source_set_callback() done\n") - - // 5. Set Event - write(eventFd, eventBuf, sizeof(eventBuf)); - sleep(1); - // 6. Cleanup - close(eventFd); - unlink(eventFile); - g_source_remove_poll(cmd_fd_gsrc, g_fd_cmd); - g_source_remove(gsource_handle); - if(g_fd_cmd) - free(g_fd_cmd); - if(src_funcs) - free(src_funcs); - if(eventFile) - g_free(eventFile); - //////////////////////// -#endif - } - break; - case MM_SOUND_MSG_INF_DESTROY_CB: - run = 0; - break; + if (cb_data) { + g_free(cb_data->extra_data); + g_free(cb_data); + } +} - case MM_SOUND_MSG_INF_ACTIVE_DEVICE_CB: - debug_msg("[Client] device_in : %p\n", msgrcv->sound_msg.device_in); - debug_msg("[Client] device_out : %p\n", msgrcv->sound_msg.device_out); - debug_msg("[Client] callback : %p\n", msgrcv->sound_msg.callback); - debug_msg("[Client] data : %p\n", msgrcv->sound_msg.cbdata); +int mm_sound_client_play_sound(MMSoundPlayParam *param, int tone, int *handle) +{ + int ret = MM_ERROR_NONE; + int session_type = MM_SESSION_TYPE_MEDIA; + int session_options = 0; + int is_focus_registered = 0; +// int instance = -1; /* instance is unique to communicate with server : client message queue filter type */ + int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(param->volume_config); + char stream_type[MAX_STREAM_TYPE_LEN] = {0, }; + struct callback_data *cb_data = NULL; + play_sound_end_callback_data_t *end_cb_data; - if (msgrcv->sound_msg.callback) - { - ((mm_sound_active_device_changed_cb)msgrcv->sound_msg.callback)(msgrcv->sound_msg.device_in, msgrcv->sound_msg.device_out, msgrcv->sound_msg.cbdata); - } - break; - case MM_SOUND_MSG_INF_AVAILABLE_ROUTE_CB: - debug_msg("[Client] callback : %p\n", msgrcv->sound_msg.callback); - debug_msg("[Client] data : %p\n", msgrcv->sound_msg.cbdata); - - if (msgrcv->sound_msg.callback) - { - int route_index; - mm_sound_route route; - - int list_count = sizeof(msgrcv->sound_msg.route_list) / sizeof(int); - - for (route_index = list_count-1; route_index >= 0; route_index--) { - route = msgrcv->sound_msg.route_list[route_index]; - if (route == 0) - continue; - if (msgrcv->sound_msg.is_available) { - debug_msg("[Client] available route : %d\n", route); - } else { - debug_msg("[Client] unavailable route : %d\n", route); - } - ((mm_sound_available_route_changed_cb)msgrcv->sound_msg.callback)(route, msgrcv->sound_msg.is_available, msgrcv->sound_msg.cbdata); - - if (route == MM_SOUND_ROUTE_INOUT_HEADSET || route == MM_SOUND_ROUTE_IN_MIC_OUT_HEADPHONE) { - debug_msg("[Client] no need to proceed further more....\n"); - break; - } - } + debug_fenter(); + + /* read session information */ + + ret = mm_sound_get_signal_value(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &is_focus_registered); + if (ret) { + debug_error("mm_sound_get_signal_value failed [0x%x]", ret); + return MM_ERROR_POLICY_INTERNAL; + } + + if (is_focus_registered) + param->skip_session = true; + + if (param->skip_session == false) { + if(MM_ERROR_NONE != _mm_session_util_read_information(-1, &session_type, &session_options)) { + debug_warning("Read MMSession Type failed. use default \"media\" type"); + session_type = MM_SESSION_TYPE_MEDIA; + + if(MM_ERROR_NONE != mm_session_init(session_type)) { + debug_critical("MMSessionInit() failed"); + return MM_ERROR_POLICY_INTERNAL; } - break; - default: - /* Unexpected msg */ - debug_msg("Receive wrong msg in callback func\n"); - break; } } - if(msgrcv) - free(msgrcv); - g_exit_thread = 1; - debug_msg("[Client] callback [%d] is leaved\n", instance); + /* Send msg */ + if ((param->mem_ptr && param->mem_size)) { + // Play memory, deprecated + return MM_ERROR_INVALID_ARGUMENT; + } + + mm_sound_convert_volume_type_to_stream_type(volume_type, stream_type); + ret = mm_sound_proxy_play_sound(param->filename, tone, param->loop, param->volume, param->volume_config, + session_type, session_options, getpid(), param->skip_session, handle, stream_type, -1); + if (ret != MM_ERROR_NONE) { + debug_error("Play Sound Failed"); + goto failed; + } + if (param->callback) { + end_cb_data = (play_sound_end_callback_data_t *) g_malloc0(sizeof(play_sound_end_callback_data_t)); + end_cb_data->watching_handle = *handle; + GET_CB_DATA(cb_data, param->callback, param->data, end_cb_data); + + ret = mm_sound_proxy_add_play_sound_end_callback(_mm_sound_stop_callback_wrapper_func, cb_data, + play_end_callback_data_free_func, &end_cb_data->subs_id); + if (ret != MM_ERROR_NONE) { + debug_error("Add callback for play sound(%d) Failed", *handle); + } + } +#ifdef USE_FOCUS + if (!param->skip_session && !g_focus_signal_handle) { + ret = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &g_focus_signal_handle, + _mm_sound_client_focus_signal_callback, NULL); + if (ret) { + debug_error("mm_sound_subscribe_signal failed [0x%x]", ret); + return MM_ERROR_POLICY_INTERNAL; + } + } +#endif + +failed: + debug_fleave(); - return NULL; + return ret; } -static int __mm_sound_client_get_msg_queue(void) +int mm_sound_client_play_sound_with_stream_info(MMSoundPlayParam *param, int *handle, char* stream_type, int stream_id) { int ret = MM_ERROR_NONE; - - if (g_mutex_initted == -1) - { - pthread_mutex_init(&g_thread_mutex, NULL); - debug_msg("[Client] mutex initialized. \n"); - g_mutex_initted = 1; - - /* Get msg queue id */ - ret = __MMSoundGetMsg(); - if(ret != MM_ERROR_NONE) - { - debug_critical("[Client] Fail to get message queue id\n"); + struct callback_data *cb_data = NULL; + play_sound_end_callback_data_t *end_cb_data; + + ret = mm_sound_proxy_play_sound_with_stream_info(param->filename, param->loop, param->volume, + getpid(), handle, stream_type, stream_id); + if (ret != MM_ERROR_NONE) { + debug_error("Play Sound Failed"); + goto failed; + } + if (param->callback) { + end_cb_data = (play_sound_end_callback_data_t *) g_malloc0(sizeof(play_sound_end_callback_data_t)); + end_cb_data->watching_handle = *handle; + GET_CB_DATA(cb_data, param->callback, param->data, end_cb_data); + + ret = mm_sound_proxy_add_play_sound_end_callback(_mm_sound_stop_callback_wrapper_func, cb_data, + play_end_callback_data_free_func, &end_cb_data->subs_id); + if (ret != MM_ERROR_NONE) { + debug_error("Add callback for play sound(%d) Failed", *handle); } } +failed: + + debug_fleave(); return ret; + } -int MMSoundClientPlayTone(int number, int volume_config, double volume, int time, int *handle) +int mm_sound_client_stop_sound(int handle) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; - int ret = MM_ERROR_NONE; - int instance = -1; /* instance is unique to communicate with server : client message queue filter type */ - debug_fenter(); - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) + if (handle < 0 || handle > CLIENT_HANDLE_MAX) { + ret = MM_ERROR_INVALID_ARGUMENT; return ret; + } - /* read mm-session type */ - int sessionType = MM_SESSION_TYPE_SHARE; - if(MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) - { - debug_warning("[Client] Read MMSession Type failed. use default \"share\" type\n"); - sessionType = MM_SESSION_TYPE_SHARE; + ret = mm_sound_proxy_stop_sound(handle); - if(MM_ERROR_NONE != mm_session_init(sessionType)) - { - debug_critical("[Client] MMSessionInit() failed\n"); - return MM_ERROR_POLICY_INTERNAL; + debug_fleave(); + return ret; +} + +static int _mm_sound_client_device_list_dump (GList *device_list) +{ + int ret = MM_ERROR_NONE; + GList *list = NULL; + mm_sound_device_t *device_node = NULL; + int count = 0; + if (!device_list) { + debug_error("Device list NULL, cannot dump list"); + return MM_ERROR_SOUND_INTERNAL; + } + + debug_log("======================== device list : start =========================="); + for (list = device_list; list != NULL; list = list->next) { + device_node = (mm_sound_device_t *)list->data; + if (device_node) { + debug_log(" list idx[%d]: type[%17s], id[%02d], io_direction[%d], state[%d], name[%s]", + count++, device_node->type, device_node->id, device_node->io_direction, + device_node->state, device_node->name); } } + debug_log("======================== device list : end ============================"); - instance = getpid(); - debug_msg("[Client] pid for client ::: [%d]\n", instance); + return ret; +} - pthread_mutex_lock(&g_thread_mutex); +int mm_sound_client_get_current_connected_device_list(int device_flags, mm_sound_device_list_t *device_list) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); - /* Send msg */ - debug_msg("[Client] Input number : %d\n", number); - /* Send req memory */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_DTMF; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.session_type = sessionType;//asm_session_type; - msgsnd.sound_msg.volume = volume;//This does not effect anymore - msgsnd.sound_msg.volume_config = volume_config; - msgsnd.sound_msg.tone = number; - msgsnd.sound_msg.handle = -1; - msgsnd.sound_msg.repeat = time; - - ret = __MMIpcSndMsg(&msgsnd); - if (ret != MM_ERROR_NONE) - { - debug_error("[Client] Fail to send msg\n"); - goto cleanup; + if (!device_list) { + debug_error("Device list NULL"); + ret = MM_ERROR_COMMON_INVALID_ARGUMENT; + goto failed; } - /* Receive */ - ret = __MMIpcRecvMsg(instance, &msgrcv); - if (ret != MM_ERROR_NONE) - { - debug_error("[Client] Fail to recieve msg\n"); - goto cleanup; + if ((ret = mm_sound_proxy_get_current_connected_device_list(device_flags, &device_list->list)) != MM_ERROR_NONE) { + debug_error("failed to get current connected device list with dbus, ret[0x%x]", ret); + goto failed; } - - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_DTMF: - *handle = msgrcv.sound_msg.handle; - if(*handle == -1) - debug_error("[Client] The handle is not get\n"); - - debug_msg("[Client] Success to play sound sound handle : [%d]\n", *handle); - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; + if (!device_list->list) { + debug_error("Got device list null"); + ret = MM_ERROR_SOUND_NO_DATA; + goto failed; } -cleanup: - pthread_mutex_unlock(&g_thread_mutex); + _mm_sound_client_device_list_dump(device_list->list); +failed: debug_fleave(); return ret; } +int mm_sound_client_get_device_by_id(int device_id, mm_sound_device_t **device) +{ + int ret = MM_ERROR_NONE; + + debug_fenter(); + + if ((ret = mm_sound_proxy_get_device_by_id(device_id, device)) != MM_ERROR_NONE) + debug_error("failed to get device by id"); + + debug_fleave(); -int MMSoundClientPlaySound(MMSoundPlayParam *param, int tone, int keytone, int *handle) + return ret; +} + +static bool device_is_match_direction(int direction, int mask) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; - unsigned char* sharedmem = NULL; + if (mask == DEVICE_IO_DIRECTION_FLAGS || mask == 0) + return true; - int ret = MM_ERROR_NONE; - int instance = -1; /* instance is unique to communicate with server : client message queue filter type */ + if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_IN)) + return true; + if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_OUT)) + return true; + if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH)) + return true; - char shm_name[512]; - void *mmap_buf = NULL; - static int keybase = 0; - int shm_fd = -1; + return false; +} - debug_fenter(); - memset(shm_name, 0, sizeof(shm_name)); +static bool device_is_match_state(int state, int mask) +{ + if (mask == DEVICE_STATE_FLAGS || mask == 0) + return true; - ret = __mm_sound_client_get_msg_queue(); - if (ret != MM_ERROR_NONE) - return ret; + if ((mask & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_DEACTIVATED)) + return true; + if ((mask & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_ACTIVATED)) + return true; - /* read mm-session type */ - int sessionType = MM_SESSION_TYPE_SHARE; - if(MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) - { - debug_warning("[Client] Read MMSession Type failed. use default \"share\" type\n"); - sessionType = MM_SESSION_TYPE_SHARE; + return false; +} - if(MM_ERROR_NONE != mm_session_init(sessionType)) - { - debug_critical("[Client] MMSessionInit() failed\n"); - return MM_ERROR_POLICY_INTERNAL; - } - } +static bool device_is_match_type(const char *type, int mask) +{ + bool is_builtin; + const char *builtin_prefix = "builtin"; + if (mask == DEVICE_TYPE_FLAGS || mask == 0) + return true; - instance = getpid(); - debug_msg("[Client] pid for client ::: [%d]\n", instance); + is_builtin = !strncmp(type, builtin_prefix, strlen(builtin_prefix)); - /* callback */ - /* callback thread is created just once & when the callback is exist */ - if (param->callback) - { - if (g_thread_id == -1) - { - g_thread_id = pthread_create(&g_thread, NULL, callbackfunc, NULL); - if (g_thread_id == -1) - { - debug_critical("[Client] Fail to create thread %s\n", strerror(errno)); - return MM_ERROR_SOUND_INTERNAL; - } - } - } + if ((mask & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG) && (is_builtin)) + return true; + if ((mask & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG) && (!is_builtin)) + return true; - pthread_mutex_lock(&g_thread_mutex); + return false; +} - /* Send msg */ - if ((param->mem_ptr && param->mem_size)) - { - debug_msg("The memptr : [%p]\n", param->mem_ptr); - debug_msg("The memptr : [%d]\n", param->mem_size); - /* Limitted memory size */ - if (param->mem_ptr && param->mem_size > MEMTYPE_SUPPORT_MAX) - { - debug_msg("[Client] Memory size is too big. We support size of media to 1MB\n"); - goto cleanup; - } +static bool device_is_match_with_mask(const char *type, int direction, int state, int mask) +{ + if (mask == DEVICE_ALL_FLAG) + return true; - debug_msg("[Client] memory size : %d\n", param->mem_size); - snprintf(shm_name, sizeof(shm_name)-1, "%d_%d", instance, keybase); - debug_msg("[Client] The shm_path : [%s]\n", shm_name); - keybase++; + return (device_is_match_direction(direction, mask & DEVICE_IO_DIRECTION_FLAGS) && + device_is_match_state(state, mask & DEVICE_STATE_FLAGS) && + device_is_match_type(type, mask & DEVICE_TYPE_FLAGS)); +} - shm_fd = shm_open(shm_name, O_RDWR |O_CREAT, 0666); - if(shm_fd < 0) - { - perror("[Client] Fail create shm_open\n"); - debug_error("[Client] Fail to create shm_open\n"); - goto cleanup; - } +static int _fill_sound_device(mm_sound_device_t *device_h, int device_id, const char *device_type, + int direction, int state, const char *name, int vendor_id, int product_id, + int *stream_id, int stream_num) +{ + int i; - if(ftruncate(shm_fd, param->mem_size) == -1) - { - debug_error("[Client] Fail to ftruncate\n"); - goto cleanup; - } + if (stream_num > 0 && stream_id == NULL) { + debug_error("stream_num is %d, but stream_id is NULL", stream_num); + return -1; + } - mmap_buf = mmap (0, MEMTYPE_SUPPORT_MAX, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - if (mmap_buf == MAP_FAILED) - { - debug_error("[Client] MMAP failed \n"); - goto cleanup; - } - - sharedmem = mmap_buf; + if (stream_num > MAX_STREAM_ON_DEVICE) { + debug_error("too many streams on this device"); + return -1; + } - if(ret != MM_ERROR_NONE) - { - debug_error("[Client] Not allocated shared memory"); - goto cleanup; - } - debug_msg("[Client] Sheared mem ptr : %p\n", sharedmem); - debug_msg("[Client] Sheared key : [%d]\n", 1); - /* Send req memory */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_MEMORY; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.callback = (void*)(param->callback); - msgsnd.sound_msg.cbdata = (void*)(param->data); - msgsnd.sound_msg.memptr = (int)sharedmem; - msgsnd.sound_msg.sharedkey = 1; /* In case of shared memory file name */ - msgsnd.sound_msg.session_type = sessionType;//asm_session_type; - msgsnd.sound_msg.priority = param->priority; - - - strncpy(msgsnd.sound_msg.filename, shm_name, 512); - debug_msg("[Client] shm_name : %s\n", msgsnd.sound_msg.filename); - - msgsnd.sound_msg.memsize = param->mem_size; - msgsnd.sound_msg.volume = param->volume; - msgsnd.sound_msg.tone = tone; - msgsnd.sound_msg.handle = -1; - msgsnd.sound_msg.repeat = param->loop; - msgsnd.sound_msg.volume_config = param->volume_config; - msgsnd.sound_msg.keytone = keytone; - msgsnd.sound_msg.handle_route = param->handle_route; - - /* Send req memory */ - debug_msg("[Client] Shared mem ptr %p, %p, size %d\n", sharedmem, param->mem_ptr, param->mem_size); - memcpy(sharedmem, param->mem_ptr, param->mem_size); - - - if (close(shm_fd) == -1) - { - debug_error("[Client] Fail to close file\n"); - ret = MM_ERROR_SOUND_INTERNAL; - goto cleanup; - } - - ret = __MMIpcSndMsg(&msgsnd); - if (ret != MM_ERROR_NONE) - { - debug_error("[Client] Fail to send msg\n"); - goto cleanup; + device_h->id = device_id; + device_h->io_direction = direction; + device_h->state = state; + MMSOUND_STRNCPY(device_h->name, name, MAX_DEVICE_NAME_NUM); + MMSOUND_STRNCPY(device_h->type, device_type, MAX_DEVICE_TYPE_STR_LEN); + device_h->vendor_id = vendor_id; + device_h->product_id = product_id; + + if (stream_num > 0) { + device_h->stream_num = stream_num; + debug_log("%d streams on this device", stream_num); + for (i = 0; i < stream_num; i++) { + debug_log(" stream_id : %d", stream_id[i]); + device_h->stream_id[i] = stream_id[i]; } + } else { + device_h->stream_num = 0; + debug_log("There is no stream on this device"); } - else - { - /* File type set for send msg */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_FILE; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.callback = (void*)(param->callback); - msgsnd.sound_msg.cbdata = (void*)(param->data); - msgsnd.sound_msg.volume = param->volume; - msgsnd.sound_msg.tone = tone; - msgsnd.sound_msg.handle = -1; - msgsnd.sound_msg.repeat = param->loop; - msgsnd.sound_msg.volume_config = param->volume_config; - msgsnd.sound_msg.session_type = sessionType;//asm_session_type; - msgsnd.sound_msg.priority = param->priority; - msgsnd.sound_msg.handle_route = param->handle_route; - - if((strlen(param->filename)) < FILE_PATH) - { - strncpy(msgsnd.sound_msg.filename, param->filename, sizeof(msgsnd.sound_msg.filename)-1); - } - else - { - debug_error("File name is over count\n"); - ret = MM_ERROR_SOUND_INVALID_PATH; - } - - msgsnd.sound_msg.keytone = keytone; - debug_msg("[Client] callback : %p\n", msgsnd.sound_msg.callback); - debug_msg("[Client] cbdata : %p\n", msgsnd.sound_msg.cbdata); + return 0; +} - ret = __MMIpcSndMsg(&msgsnd); - if (ret != MM_ERROR_NONE) - { - debug_error("[Client] Fail to send msg\n"); - goto cleanup; - } +static void _mm_sound_device_connected_callback_wrapper_func(int device_id, const char *device_type, int io_direction, + int state, const char *name, int vendor_id, int product_id, int *stream_id, int stream_num, + gboolean is_connected, void *userdata) +{ + mm_sound_device_t device_h; + struct callback_data *cb_data = (struct callback_data*) userdata; + int device_flags; + + debug_log("[Device %s] id(%d) type(%s) direction(%d) state(%d) name(%s) vendor-id(%04x) product-id(%04x)", + is_connected ? "Connected" : "Disconnected", device_id, device_type, io_direction, + state, name, vendor_id, product_id, is_connected); + + if (cb_data == NULL) { + debug_warning("device connected changed callback data null"); + return; } - - /* Receive */ - ret = __MMIpcRecvMsg(instance, &msgrcv); - if (ret != MM_ERROR_NONE) - { - debug_error("[Client] Fail to recieve msg\n"); - goto cleanup; + device_flags = (int) cb_data->extra_data; + if (!device_is_match_with_mask(device_type, io_direction, state, device_flags)) + return; + + if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name, + vendor_id, product_id, stream_id, stream_num) < 0) { + debug_error("Failed to fill sound device"); + return; } - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_FILE: - *handle = msgrcv.sound_msg.handle; - debug_msg("[Client] Success to play sound sound handle : [%d]\n", *handle); - break; - case MM_SOUND_MSG_RES_MEMORY: - *handle = msgrcv.sound_msg.handle; - if(*handle == -1) - debug_error("[Client] The handle is not get\n"); + ((mm_sound_device_connected_cb)(cb_data->user_cb))(&device_h, is_connected, cb_data->user_data); +} - shm_unlink(shm_name); - if (ret != MM_ERROR_NONE) - { - debug_critical("[Client] Fail to remove shared memory, must be checked\n"); - goto cleanup; - } - debug_msg("[Client] Success to play sound sound handle : [%d]\n", *handle); - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; +int mm_sound_client_add_device_connected_callback(int device_flags, mm_sound_device_connected_cb func, + void* userdata, unsigned int *subs_id) +{ + int ret = MM_ERROR_NONE; + struct callback_data *cb_data = NULL; + + debug_fenter(); + + GET_CB_DATA(cb_data, func, userdata, (void*) device_flags); + + ret = mm_sound_proxy_add_device_connected_callback(device_flags, + _mm_sound_device_connected_callback_wrapper_func, + cb_data, g_free, subs_id); + if (ret == MM_ERROR_NONE) + g_need_emergent_exit = TRUE; + + debug_fleave(); + return ret; +} + +int mm_sound_client_remove_device_connected_callback(unsigned int subs_id) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); + + ret = mm_sound_proxy_remove_device_connected_callback(subs_id); + + debug_fleave(); + return ret; +} + +static void _mm_sound_device_info_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction, + int state, const char *name, int vendor_id, int product_id, int *stream_id, int stream_num, + int changed_device_info_type, void *userdata) +{ + mm_sound_device_t device_h; + struct callback_data *cb_data = (struct callback_data*) userdata; + int device_flags; + + debug_log("[Device Info Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) " + "vendor-id(%04x) product-id(%04x) changed_info_type(%d)", + device_id, device_type, io_direction, state, name, vendor_id, product_id, changed_device_info_type); + + if (cb_data == NULL) { + debug_warning("device info changed callback data null"); + return; + } + + device_flags = (int) cb_data->extra_data; + if (!device_is_match_with_mask(device_type, io_direction, state, device_flags)) + return; + + if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name, + vendor_id, product_id, stream_id, stream_num) < 0) { + debug_error("Failed to fill sound device"); + return; + } + + ((mm_sound_device_info_changed_cb)(cb_data->user_cb))(&device_h, changed_device_info_type, cb_data->user_data); +} + +int mm_sound_client_add_device_info_changed_callback(int device_flags, mm_sound_device_info_changed_cb func, + void *userdata, unsigned int *subs_id) +{ + int ret = MM_ERROR_NONE; + struct callback_data *cb_data = (struct callback_data*) userdata; + + debug_fenter(); + + GET_CB_DATA(cb_data, func, userdata, (void *) device_flags); + + ret = mm_sound_proxy_add_device_info_changed_callback(device_flags, + _mm_sound_device_info_changed_callback_wrapper_func, + cb_data, g_free, subs_id); + + debug_fleave(); + return ret; +} + +int mm_sound_client_remove_device_info_changed_callback(unsigned int subs_id) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); + + ret = mm_sound_proxy_remove_device_info_changed_callback(subs_id); + + debug_fleave(); + return ret; + +} + +static void _mm_sound_device_state_changed_callback_wrapper_func(int device_id, const char *device_type, + int io_direction, int state, const char *name, int vendor_id, int product_id, + int *stream_id, int stream_num, void *userdata) +{ + mm_sound_device_t device_h; + struct callback_data *cb_data = (struct callback_data*) userdata; + int device_flags; + + debug_log("[Device State Changed] id(%d) type(%s) direction(%d) state(%d) name(%s)" + "vendor-id(%04x), product-id(%04x)", + device_id, device_type, io_direction, state, name, vendor_id, product_id); + + if (cb_data == NULL) { + debug_warning("device state changed callback data null"); + return; + } + + device_flags = (int) cb_data->extra_data; + + if (!device_is_match_with_mask(device_type, io_direction, state, device_flags)) + return; + + if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name, + vendor_id, product_id, stream_id, stream_num) < 0) { + debug_error("Failed to fill sound device"); + return; + } + + ((mm_sound_device_state_changed_cb)(cb_data->user_cb))(&device_h, state, cb_data->user_data); +} + +int mm_sound_client_add_device_state_changed_callback(int device_flags, mm_sound_device_state_changed_cb func, + void *userdata, unsigned int *id) +{ + int ret = MM_ERROR_NONE; + struct callback_data *cb_data = (struct callback_data*) userdata; + + debug_fenter(); + + GET_CB_DATA(cb_data, func, userdata, (void *) device_flags); + + ret = mm_sound_proxy_add_device_state_changed_callback(device_flags, + _mm_sound_device_state_changed_callback_wrapper_func, + cb_data, g_free, id); + + debug_fleave(); + return ret; +} + +int mm_sound_client_remove_device_state_changed_callback(unsigned int id) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); + + ret = mm_sound_proxy_remove_device_state_changed_callback(id); + + debug_fleave(); + return ret; +} + +int mm_sound_client_is_stream_on_device(int stream_id, int device_id, bool *is_on) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); + + if (!is_on) { + debug_error("Invalid Parameter"); + ret = MM_ERROR_COMMON_INVALID_ARGUMENT; + goto failed; + } + + if ((ret = mm_sound_proxy_is_stream_on_device(stream_id, device_id, is_on)) != MM_ERROR_NONE) { + debug_error("failed to query is stream on device, ret[0x%x]", ret); + goto failed; + } + +failed: + debug_fleave(); + return ret; +} + +int __convert_volume_type_to_str(int volume_type, char **volume_type_str) +{ + int ret = MM_ERROR_NONE; + + if (!volume_type_str) { + return MM_ERROR_COMMON_INVALID_ARGUMENT; + } + + switch (volume_type) { + case VOLUME_TYPE_SYSTEM: + *volume_type_str = "system"; + break; + case VOLUME_TYPE_NOTIFICATION: + *volume_type_str = "notification"; + break; + case VOLUME_TYPE_ALARM: + *volume_type_str = "alarm"; + break; + case VOLUME_TYPE_RINGTONE: + *volume_type_str = "ringtone"; + break; + case VOLUME_TYPE_MEDIA: + *volume_type_str = "media"; + break; + case VOLUME_TYPE_CALL: + *volume_type_str = "call"; + break; + case VOLUME_TYPE_VOIP: + *volume_type_str = "voip"; + break; + case VOLUME_TYPE_VOICE: + *volume_type_str = "voice"; + break; + } + if (!strncmp(*volume_type_str,"", VOLUME_TYPE_LEN)) { + debug_error("could not find the volume_type[%d] in this switch case statement", volume_type); + ret = MM_ERROR_SOUND_INTERNAL; + } else { + debug_log("volume_type[%s]", *volume_type_str); + } + return ret; +} + +static int __convert_volume_type_to_int(const char *volume_type_str, volume_type_t *volume_type) +{ + int ret = MM_ERROR_NONE; + + if (!volume_type || !volume_type_str) { + return MM_ERROR_COMMON_INVALID_ARGUMENT; + } + + if (!strncmp(volume_type_str, "system", VOLUME_TYPE_LEN)) { + *volume_type = VOLUME_TYPE_SYSTEM; + } else if (!strncmp(volume_type_str, "notification", VOLUME_TYPE_LEN)) { + *volume_type = VOLUME_TYPE_NOTIFICATION; + } else if (!strncmp(volume_type_str, "alarm", VOLUME_TYPE_LEN)) { + *volume_type = VOLUME_TYPE_ALARM; + } else if (!strncmp(volume_type_str, "ringtone", VOLUME_TYPE_LEN)) { + *volume_type = VOLUME_TYPE_RINGTONE; + } else if (!strncmp(volume_type_str, "media", VOLUME_TYPE_LEN)) { + *volume_type = VOLUME_TYPE_MEDIA; + } else if (!strncmp(volume_type_str, "call", VOLUME_TYPE_LEN)) { + *volume_type = VOLUME_TYPE_CALL; + } else if (!strncmp(volume_type_str, "voip", VOLUME_TYPE_LEN)) { + *volume_type = VOLUME_TYPE_VOIP; + } else if (!strncmp(volume_type_str, "voice", VOLUME_TYPE_LEN)) { + *volume_type = VOLUME_TYPE_VOICE; + } else { + debug_log("Invalid volume type : [%s]", volume_type_str); + ret = MM_ERROR_SOUND_INTERNAL; + } + + return ret; +} + +int mm_sound_client_set_volume_by_type(const int volume_type, const unsigned int volume_level) +{ + int ret = MM_ERROR_NONE; + char *type_str = NULL; + debug_fenter(); + + if ((ret = __convert_volume_type_to_str(volume_type, &type_str)) != MM_ERROR_NONE) { + debug_error("volume type convert failed"); + goto failed; + } + + ret = mm_sound_proxy_set_volume_by_type(type_str, volume_level); + +failed: + debug_fleave(); + return ret; +} + +static void _mm_sound_volume_changed_callback_wrapper_func(const char *direction, const char *volume_type_str, + int volume_level, void *userdata) +{ + volume_type_t volume_type = 0; + struct callback_data *cb_data = (struct callback_data *) userdata; + + debug_log("direction : %s, volume_type : %s, volume_level : %d", + direction, volume_type_str, volume_level); + + if (cb_data == NULL) { + debug_warning("volume changed callback data null"); + return; + } + + if (__convert_volume_type_to_int(volume_type_str, &volume_type) != MM_ERROR_NONE) { + debug_error("volume type convert failed"); + return; + } + debug_log("Call volume changed user cb, direction : %s, vol_type : %s(%d), level : %u", + direction, volume_type_str, volume_type, volume_level); + ((mm_sound_volume_changed_cb)(cb_data->user_cb))(volume_type, volume_level, cb_data->user_data); +} + +int mm_sound_client_add_volume_changed_callback(mm_sound_volume_changed_cb func, void* userdata, unsigned int *subs_id) +{ + int ret = MM_ERROR_NONE; + struct callback_data *cb_data = NULL; + + debug_fenter(); + + GET_CB_DATA(cb_data, func, userdata, NULL); + + ret = mm_sound_proxy_add_volume_changed_callback(_mm_sound_volume_changed_callback_wrapper_func, cb_data, g_free, subs_id); + + debug_fleave(); + + return ret; +} + +int mm_sound_client_remove_volume_changed_callback(unsigned int subs_id) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); + + ret = mm_sound_proxy_remove_volume_changed_callback(subs_id); + + debug_fleave(); + return ret; +} + +int mm_sound_client_set_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_parameters, const char *filter_group) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); + + ret = mm_sound_proxy_set_filter_by_type(stream_type, filter_name, filter_parameters, filter_group); + + debug_fleave(); + return ret; +} + +int mm_sound_client_unset_filter_by_type(const char *stream_type) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); + + ret = mm_sound_proxy_unset_filter_by_type(stream_type); + + debug_fleave(); + return ret; +} + +int mm_sound_client_control_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_controls) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); + + ret = mm_sound_proxy_control_filter_by_type(stream_type, filter_name, filter_controls); + + debug_fleave(); + return ret; +} + +#ifdef USE_FOCUS +static gboolean _interrupted_completed(gpointer *data) +{ + if (!data) { + debug_error("data is null"); + return false; + } + if (!g_focus_session_interrupt_info.user_cb) { + debug_error("user_cb is null"); + free(data); + return false; + } + + debug_msg("invoke user_cb(%p)", g_focus_session_interrupt_info.user_cb); + (g_focus_session_interrupt_info.user_cb)(FOCUS_IS_RELEASED, (const char *)data, g_focus_session_interrupt_info.user_data); + debug_msg("invoked"); + + free(data); + return false; +} + +static void _session_interrupted_cb(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e state, + const char *reason_for_change, const char *ext_info, void *user_data) +{ + debug_msg("id(%d), focus_type(%d), state(%d), reason(%s)", id, focus_type, state, reason_for_change); + + if (id != g_focus_session_interrupt_info.watch_cb_id) { + debug_error("id is not valid(param id:%d, g_focus_session_interrupt_watch_cb_id:%d)", + id, g_focus_session_interrupt_info.watch_cb_id); + return; + } + if (!g_focus_session_interrupt_info.user_cb) { + debug_error("user callback is null"); + return; + } + + debug_msg(" >>> invoking session interrupt callback(%p)", g_focus_session_interrupt_info.user_cb); + if (state == FOCUS_IS_RELEASED) + (g_focus_session_interrupt_info.user_cb)(FOCUS_IS_ACQUIRED, reason_for_change, g_focus_session_interrupt_info.user_data); + else { + debug_msg("INTERRUPTED COMPLETED case, append it to idle"); + g_idle_add((GSourceFunc)_interrupted_completed, strdup(reason_for_change)); + } + debug_msg(" <<< session interrupt callback finished"); +} + +int mm_sound_client_set_session_interrupt_callback(mm_sound_focus_session_interrupt_cb callback, void* user_data) +{ + int ret = MM_ERROR_NONE; + + debug_fenter(); + + if (!callback) + return MM_ERROR_INVALID_ARGUMENT; + + /* add internal focus watch callback */ + if (g_focus_session_interrupt_info.watch_cb_id == -1) { + if ((ret = mm_sound_client_set_focus_watch_callback(getpid(), FOCUS_FOR_BOTH, true, true, _session_interrupted_cb, NULL, + &g_focus_session_interrupt_info.watch_cb_id))) { + debug_error("failed to mm_sound_client_set_focus_watch_callback(), ret(0x%x)", ret); + return ret; + } + } + g_focus_session_interrupt_info.user_cb = callback; + g_focus_session_interrupt_info.user_data = user_data; + + debug_fleave(); + return ret; +} + +int mm_sound_client_unset_session_interrupt_callback(void) +{ + int ret = MM_ERROR_NONE; + + debug_fenter(); + + if (!g_focus_session_interrupt_info.user_cb || g_focus_session_interrupt_info.watch_cb_id == -1) { + debug_error("no callback to unset"); + return MM_ERROR_SOUND_INTERNAL; + } + + /* remove internal focus watch callback */ + if ((ret = mm_sound_client_unset_focus_watch_callback(g_focus_session_interrupt_info.watch_cb_id))) { + debug_error("failed to mm_sound_client_unset_focus_watch_callback(), id(%d), ret(0x%x)", + g_focus_session_interrupt_info.watch_cb_id, ret); + return ret; + } + g_focus_session_interrupt_info.watch_cb_id = -1; + g_focus_session_interrupt_info.user_cb = NULL; + g_focus_session_interrupt_info.user_data = NULL; + + debug_fleave(); + return ret; +} + +static gpointer _focus_thread_func(gpointer data) +{ + unsigned int thread_id = (unsigned int)pthread_self(); + GMainLoop *focus_loop = (GMainLoop*)data; + + debug_warning(">>> thread id(%u), mainloop[%p]", thread_id, focus_loop); + if (focus_loop) + g_main_loop_run(focus_loop); + debug_warning("<<< quit : thread id(%u), mainloop[%p]", thread_id, focus_loop); + + return NULL; +} + +static gboolean _focus_fd_prepare(GSource *source, gint *timeout) +{ +#ifdef __DEBUG__ + debug_warning("[ PREPARE : %p, (%p, %d)", source, timeout, timeout? *timeout : -1); +#endif + return FALSE; +} + +static gboolean _focus_fd_check(GSource * source) +{ + FocusSource* fsource = (FocusSource *)source; + + if (!fsource) { + debug_error("GSource is null"); + return FALSE; + } +#ifdef __DEBUG__ + debug_warning("CHECK : %p, 0x%x ]", source, fsource->pollfd.revents); +#endif + if (fsource->poll_fd.revents & (POLLIN | POLLPRI)) + return TRUE; + else + return FALSE; +} + +static gboolean _focus_fd_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) +{ + debug_warning("*** DISPATCH : %p, (%p, %p)", source, callback, user_data); + return callback(user_data); +} + +static void _focus_fd_finalize(GSource *source) +{ + debug_warning("### FINALIZE : %p", source); +} + +static int _focus_find_index_by_handle(int handle) +{ + int i = 0; + for (i = 0; i < FOCUS_HANDLE_MAX; i++) { + if (g_focus_sound_handle[i].focus_callback && handle == g_focus_sound_handle[i].handle) { + /* debug_msg("found index(%d) for handle(%d)", i, handle);*/ + return (handle == FOCUS_HANDLE_INIT_VAL)? -1 : i; + } + } + return -1; +} + +static int _focus_watch_find_index_by_handle(int handle) +{ + int i = 0; + for (i = 0; i < FOCUS_HANDLE_MAX; i++) { + if (g_focus_sound_handle[i].watch_callback && handle == g_focus_sound_handle[i].handle) { + /* debug_msg("found index(%d) for watch handle(%d)", i, handle);*/ + return (handle == FOCUS_HANDLE_INIT_VAL)? -1 : i; + } + } + return -1; +} + +static gboolean _focus_callback_handler(gpointer user_data) +{ + focus_sound_info_t *focus_handle = (focus_sound_info_t *)user_data; + GPollFD *poll_fd; + int count; + int tid = 0; + focus_cb_data_lib cb_data; + + debug_log(">>> thread id(%u)", (unsigned int)pthread_self()); + + if (!focus_handle) { + debug_error("focus_handle is null"); + return G_SOURCE_CONTINUE; + } + poll_fd = &focus_handle->fsrc->poll_fd; + debug_log("focus_handle(%p), poll_fd(%p)", focus_handle, poll_fd); + + memset(&cb_data, 0, sizeof(focus_cb_data_lib)); + + if (poll_fd->revents & (POLLIN | POLLPRI)) { + int changed_state = -1; + + count = read(poll_fd->fd, &cb_data, sizeof(cb_data)); + if (count < 0){ + char str_error[256]; + strerror_r(errno, str_error, sizeof(str_error)); + debug_error("GpollFD read fail, errno=%d(%s)",errno, str_error); + return G_SOURCE_CONTINUE; + } + changed_state = cb_data.state; + + g_mutex_lock(&focus_handle->focus_lock); + + tid = focus_handle->focus_tid; + + if (changed_state != -1) { + debug_msg("Got and start CB : TID(%d), handle(%d), type(%d), state(%d,(DEACTIVATED(0)/ACTIVATED(1)), trigger(%s)", + tid, cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type); + if (focus_handle->focus_callback == NULL) { + debug_error("focus callback is null.."); + g_mutex_unlock(&focus_handle->focus_lock); + return G_SOURCE_CONTINUE; + } + debug_msg("[CALLBACK(%p) START]", focus_handle->focus_callback); + (focus_handle->focus_callback)(cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type, + cb_data.option, cb_data.ext_info, focus_handle->user_data); + debug_msg("[CALLBACK END]"); + } +#ifdef CONFIG_ENABLE_RETCB + { + int rett = 0; + int tmpfd = -1; + unsigned int buf = 0; + char *filename2 = g_strdup_printf("/tmp/FOCUS.%d.%dr", focus_handle->focus_tid, cb_data.handle); + tmpfd = open(filename2, O_WRONLY | O_NONBLOCK); + if (tmpfd < 0) { + char str_error[256]; + strerror_r(errno, str_error, sizeof(str_error)); + debug_warning("[RETCB][Failed(May Server Close First)]tid(%d) fd(%d) %s errno=%d(%s)", + tid, tmpfd, filename2, errno, str_error); + g_free(filename2); + g_mutex_unlock(&focus_handle->focus_lock); + return G_SOURCE_CONTINUE; + } + /* buf contains data as below, + * |<--12bits--><--4bits (reacquisition)--><--16bits (handle)-->| */ + buf = (unsigned int)((0x0000ffff & cb_data.handle) | (focus_handle->auto_reacquire << 16)); + rett = write(tmpfd, &buf, sizeof(buf)); + close(tmpfd); + g_free(filename2); + debug_msg("[RETCB] tid(%d) finishing CB (write=%d)", tid, rett); + } +#endif + } + + g_mutex_unlock(&focus_handle->focus_lock); + + debug_fleave(); + + return G_SOURCE_CONTINUE; +} + +static gboolean _focus_watch_callback_handler(gpointer user_data) +{ + focus_sound_info_t *focus_handle = (focus_sound_info_t *)user_data; + GPollFD *poll_fd; + int count; + int tid = 0; + focus_cb_data_lib cb_data; + + debug_log(">>> thread id(%u)", (unsigned int)pthread_self()); + + if (!focus_handle) { + debug_error("focus_handle is null"); + return G_SOURCE_CONTINUE; + } + poll_fd = &focus_handle->fsrc->poll_fd; + debug_log("focus_handle(%p), poll_fd(%p)", focus_handle, poll_fd); + + memset(&cb_data, 0, sizeof(focus_cb_data_lib)); + + if (poll_fd->revents & (POLLIN | POLLPRI)) { + count = read(poll_fd->fd, &cb_data, sizeof(cb_data)); + if (count < 0){ + char str_error[256]; + strerror_r(errno, str_error, sizeof(str_error)); + debug_error("GpollFD read fail, errno=%d(%s)",errno, str_error); + return G_SOURCE_CONTINUE; + } + + if (!focus_handle->is_used) { + debug_warning("unsetting watch calllback has been already requested"); + goto SKIP_CB_AND_RET; + } + + g_mutex_lock(&focus_handle->focus_lock); + + tid = focus_handle->focus_tid; + + debug_msg("Got and start CB : TID(%d), handle(%d), type(%d), state(%d,(DEACTIVATED(0)/ACTIVATED(1)), trigger(%s)", + tid, cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type); + + if (focus_handle->watch_callback == NULL) { + debug_warning("watch callback is null.."); + goto SKIP_CB_AND_RET; + } + if (focus_handle->unset_watch_callback_requested == true) { + debug_warning("unset_watch_callback_requested.."); + goto SKIP_CB_AND_RET; + } + + debug_msg("[CALLBACK(%p) START]", focus_handle->watch_callback); + (focus_handle->watch_callback)(cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type, + cb_data.ext_info, focus_handle->user_data); + debug_msg("[CALLBACK END]"); + +SKIP_CB_AND_RET: +#ifdef CONFIG_ENABLE_RETCB + { + int rett = 0; + int tmpfd = -1; + int buf = -1; + char *filename2 = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr", focus_handle->focus_tid, cb_data.handle); + tmpfd = open(filename2, O_WRONLY | O_NONBLOCK); + if (tmpfd < 0) { + char str_error[256]; + strerror_r(errno, str_error, sizeof(str_error)); + debug_warning("[RETCB][Failed(May Server Close First)]tid(%d) fd(%d) %s errno=%d(%s)", + tid, tmpfd, filename2, errno, str_error); + g_free(filename2); + g_mutex_unlock(&focus_handle->focus_lock); + return G_SOURCE_CONTINUE; + } + buf = cb_data.handle; + rett = write(tmpfd, &buf, sizeof(buf)); + close(tmpfd); + g_free(filename2); + debug_msg("[RETCB] tid(%d) finishing CB (write=%d)", tid, rett); + } +#endif + } + + if (focus_handle->is_used) { + debug_msg("unlock focus_lock = %p", &focus_handle->focus_lock); + g_mutex_unlock(&focus_handle->focus_lock); + } + + debug_fleave(); + + return G_SOURCE_CONTINUE; +} + +static void _focus_open_callback(int index, bool is_for_watching) +{ + mode_t pre_mask; + char *filename; + + debug_fenter(); + + if (index < 0 || index >= FOCUS_HANDLE_MAX) { + debug_error("Invalid focus handle index [%d]", index); + return; + } + + if (is_for_watching) { + filename = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", + g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle); + } else { + filename = g_strdup_printf("/tmp/FOCUS.%d.%d", + g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle); + } + pre_mask = umask(0); + if (mknod(filename, S_IFIFO|0666, 0)) { + debug_error("mknod() failure, errno(%d)", errno); + } + umask(pre_mask); + g_focus_sound_handle[index].focus_fd = open(filename, O_RDWR|O_NONBLOCK); + if (g_focus_sound_handle[index].focus_fd == -1) { + debug_error("Open fail : index(%d), file open error(%d)", index, errno); + } else { + debug_log("Open success : index(%d), filename(%s), fd(%d)", + index, filename, g_focus_sound_handle[index].focus_fd); + } + g_free(filename); + filename = NULL; + +#ifdef CONFIG_ENABLE_RETCB + char *filename2; + + if (is_for_watching) { + filename2 = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr", + g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle); + } else { + filename2 = g_strdup_printf("/tmp/FOCUS.%d.%dr", + g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle); + } + pre_mask = umask(0); + if (mknod(filename2, S_IFIFO | 0666, 0)) { + debug_error("mknod() failure, errno(%d)", errno); + } + umask(pre_mask); + g_free(filename2); + filename2 = NULL; +#endif + debug_fleave(); + +} + +void _focus_close_callback(int index, bool is_for_watching) +{ + char *filename = NULL; + + debug_fenter(); + + if (index < 0 || index >= FOCUS_HANDLE_MAX) { + debug_error("Invalid focus handle index [%d]", index); + return; + } + + if (g_focus_sound_handle[index].focus_fd < 0) { + debug_error("Close fail : index(%d)", index); + } else { + close(g_focus_sound_handle[index].focus_fd); + debug_log("Close Success : index(%d)", index); + } + + if (is_for_watching) { + filename = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", + g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle); + } else { + filename = g_strdup_printf("/tmp/FOCUS.%d.%d", + g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle); + } + if (remove(filename)) { + debug_warning("remove(%s) failure (focus_server probably removed it in advance), errno(%d)", + filename, errno); + } + g_free(filename); + filename = NULL; + +#ifdef CONFIG_ENABLE_RETCB + char *filename2; + + if (is_for_watching) { + filename2 = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr", + g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle); + } else { + filename2 = g_strdup_printf("/tmp/FOCUS.%d.%dr", + g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle); + } + if (remove(filename2)) { + debug_warning("remove(%s) failure (focus_server probably removed it in advance), errno(%d)", + filename2, errno); + } + g_free(filename2); + filename2 = NULL; + + debug_fleave(); +#endif + +} + +static GSourceFuncs event_funcs = { + .prepare = _focus_fd_prepare, + .check = _focus_fd_check, + .dispatch = _focus_fd_dispatch, + .finalize = _focus_fd_finalize, +}; + +static bool _focus_add_sound_callback(int index, focus_callback_handler_t focus_cb_handler) +{ + FocusSource *fsrc = NULL; + GSource *src = NULL; + guint fsrc_id = 0; + + debug_fenter(); + + g_mutex_init(&g_focus_sound_handle[index].focus_lock); + + src = g_source_new(&event_funcs, sizeof(FocusSource)); + if (!src) { + debug_error("failed to g_source_new for focus source"); + goto ERROR; + } + + fsrc = (FocusSource*) src; + + fsrc->poll_fd.fd = g_focus_sound_handle[index].focus_fd; + fsrc->poll_fd.events = (gushort)(POLLIN | POLLPRI); + g_source_add_poll(src, &fsrc->poll_fd); + + g_source_set_callback(src, focus_cb_handler, (gpointer)&g_focus_sound_handle[index], NULL); + + debug_warning("fsrc(%p), src_funcs(%p), pollfd(%p), fd(%d)", + fsrc, &event_funcs, &fsrc->poll_fd, fsrc->poll_fd.fd); + + fsrc_id = g_source_attach(src, g_main_loop_get_context(g_focus_sound_handle[index].focus_loop)); + if (!fsrc_id) { + debug_error("failed to attach the source to context"); + goto ERROR; + } + g_source_unref(src); + + g_focus_sound_handle[index].fsrc = fsrc; + + debug_fleave(); + return true; + +ERROR: + if (src) + g_source_unref(src); + + return false; +} + +static bool _focus_remove_sound_callback(int index) +{ + focus_sound_info_t *h = NULL; + + debug_fenter(); + + if (index < 0 || index >= FOCUS_HANDLE_MAX) { + debug_error("Invalid focus handle index [%d]", index); + return false; + } + + h = &g_focus_sound_handle[index]; + if (h->fsrc) { + g_source_destroy((GSource *)h->fsrc); + h->fsrc = NULL; + } + + h->focus_callback = NULL; + h->watch_callback = NULL; + + g_mutex_clear(&h->focus_lock); + + debug_fleave(); + + return true; +} + +static void _focus_add_callback(int index, bool is_for_watching) +{ + debug_fenter(); + + if (index < 0 || index >= FOCUS_HANDLE_MAX) { + debug_error("Invalid focus handle index [%d]", index); + return; + } + + if (!is_for_watching) { + if (!_focus_add_sound_callback(index, _focus_callback_handler)) + debug_error("failed to _focus_add_sound_callback(%p)", _focus_callback_handler); + } else { // need to check if it's necessary + if (!_focus_add_sound_callback(index, _focus_watch_callback_handler)) + debug_error("failed to _focus_add_sound_callback(%p)", _focus_watch_callback_handler); + } + debug_fleave(); +} + +static void _focus_remove_callback(int index) +{ + debug_fenter(); + if (!_focus_remove_sound_callback(index)) + debug_error("failed to __focus_remove_sound_callback()"); + debug_fleave(); +} + +static void _focus_init_callback(int index, bool is_for_watching) +{ + debug_fenter(); + _focus_open_callback(index, is_for_watching); + _focus_add_callback(index, is_for_watching); + debug_fleave(); +} + +static void _focus_deinit_callback(int index, bool is_for_watching) +{ + debug_fenter(); + _focus_remove_callback(index); + _focus_close_callback(index, is_for_watching); + debug_fleave(); +} + +#define INTERVAL_MS 20 +static int _focus_loop_is_running_timed_wait(GMainLoop *focus_loop, int timeout_ms) +{ + int reduced_time_ms = timeout_ms; + if (!focus_loop || timeout_ms < 0) { + debug_error("invalid argument, focus_loop(%p), timeout_ms(%d)", focus_loop, timeout_ms); + return MM_ERROR_INVALID_ARGUMENT; + } + + do { + if (g_main_loop_is_running(focus_loop)) + return MM_ERROR_NONE; + + usleep(INTERVAL_MS * 1000); + if (reduced_time_ms < timeout_ms) + debug_warning("reduced_time_ms(%d)", reduced_time_ms); + } while ((reduced_time_ms -= INTERVAL_MS) >= 0); + + debug_error("focus_loop is not running for timeout_ms(%d), focus_loop(%p) ", timeout_ms, focus_loop); + + return MM_ERROR_SOUND_INTERNAL; +} + +#define LOOP_RUNNING_WAIT_TIME_MS 200 +static int _focus_init_context(int index) +{ + int ret = MM_ERROR_NONE; + GMainContext *focus_context; + + debug_fenter(); + + if (index < 0 || index >= FOCUS_HANDLE_MAX) { + debug_error("index(%d) is not valid", index); + return MM_ERROR_INVALID_ARGUMENT; + } + + focus_context = g_main_context_new(); + g_focus_sound_handle[index].focus_loop = g_main_loop_new(focus_context, FALSE); + g_main_context_unref(focus_context); + if (g_focus_sound_handle[index].focus_loop == NULL) { + debug_error("could not create mainloop.."); + goto ERROR; + } + + g_focus_sound_handle[index].focus_cb_thread = g_thread_new("focus-cb-thread", + _focus_thread_func, + g_focus_sound_handle[index].focus_loop); + if (g_focus_sound_handle[index].focus_cb_thread == NULL) { + debug_error("could not create thread.."); + goto ERROR; + } + + debug_warning("focus cb thread[%p] with mainloop[%p] is created for index(%d)", + g_focus_sound_handle[index].focus_cb_thread, g_focus_sound_handle[index].focus_loop, index); + + if ((ret = _focus_loop_is_running_timed_wait(g_focus_sound_handle[index].focus_loop, LOOP_RUNNING_WAIT_TIME_MS))) { + debug_error("failed to _focus_loop_is_running_timed_wait(), ret[0x%x]", ret); + goto ERROR; + } + + debug_fleave(); + + return MM_ERROR_NONE; + +ERROR: + if (g_focus_sound_handle[index].focus_loop) { + g_main_loop_unref(g_focus_sound_handle[index].focus_loop); + g_focus_sound_handle[index].focus_loop = NULL; + } + return MM_ERROR_SOUND_INTERNAL; +} + +static void _focus_deinit_context(int index) +{ + debug_fenter(); + + if (index < 0 || index >= FOCUS_HANDLE_MAX) { + debug_error("index(%d) is not valid", index); + return; + } + + if (!g_focus_sound_handle[index].focus_loop || !g_focus_sound_handle[index].focus_cb_thread) { + debug_error("focus_loop[%p] or focus_cb_thread[%p] is null", + g_focus_sound_handle[index].focus_loop, g_focus_sound_handle[index].focus_cb_thread); + return; + } + + g_main_loop_quit(g_focus_sound_handle[index].focus_loop); + g_thread_join(g_focus_sound_handle[index].focus_cb_thread); + debug_warning("after thread join, thread[%p], mainloop[%p] for index(%d)", + g_focus_sound_handle[index].focus_cb_thread, g_focus_sound_handle[index].focus_loop, index); + g_main_loop_unref(g_focus_sound_handle[index].focus_loop); + g_focus_sound_handle[index].focus_loop = NULL; + g_focus_sound_handle[index].focus_cb_thread = NULL; + + debug_fleave(); +} + +int mm_sound_client_get_unique_id(int *id) +{ + int ret = MM_ERROR_NONE; + + debug_fenter(); + + if (!id) + ret = MM_ERROR_INVALID_ARGUMENT; + else + ret = mm_sound_proxy_get_unique_id(id); + + debug_fleave(); + + return ret; +} + +int mm_sound_client_is_focus_cb_thread(GThread *mine, bool *result) +{ + int ret = MM_ERROR_NONE; + int i = 0; + + if (!mine || !result) + ret = MM_ERROR_INVALID_ARGUMENT; + else { + *result = false; + for (i = 0; i < FOCUS_HANDLE_MAX; i++) { + if (!g_focus_sound_handle[i].is_used) + continue; + if (g_focus_sound_handle[i].focus_cb_thread == mine) { + *result = true; + break; + } + } + } + + return ret; +} + +int mm_sound_client_register_focus(int id, int pid, const char *stream_type, bool is_for_session, + mm_sound_focus_changed_cb callback, void* user_data) +{ + int ret = MM_ERROR_NONE; + int instance; + int index = 0; + + debug_fenter(); + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); + + instance = pid; + + for (index = 0; index < FOCUS_HANDLE_MAX - 1; index++) { + if (g_focus_sound_handle[index].is_used == false) { + g_focus_sound_handle[index].is_used = true; + break; + } + } + + g_focus_sound_handle[index].focus_tid = instance; + g_focus_sound_handle[index].handle = id; + g_focus_sound_handle[index].focus_callback = callback; + g_focus_sound_handle[index].user_data = user_data; + g_focus_sound_handle[index].is_for_session = is_for_session; + g_focus_sound_handle[index].auto_reacquire = true; + + ret = mm_sound_proxy_register_focus(id, pid, stream_type, callback, is_for_session, user_data); + if (ret == MM_ERROR_NONE) { + debug_msg("Success to register focus"); + g_need_emergent_exit = TRUE; + if (_focus_init_context(index)) { + ret = MM_ERROR_SOUND_INTERNAL; + goto cleanup; + } + } else { + debug_error("Error occurred : 0x%x",ret); + goto cleanup; + } + + _focus_init_callback(index, false); + +cleanup: + if (ret) { + g_focus_sound_handle[index].is_used = false; + } + + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); + debug_fleave(); + + return ret; +} + +int mm_sound_client_unregister_focus(int id) +{ + int ret = MM_ERROR_NONE; + int instance; + int index = -1; + + debug_fenter(); + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); + + index = _focus_find_index_by_handle(id); + if (index == -1) { + debug_error("Could not find index"); + ret = MM_ERROR_INVALID_ARGUMENT; + goto cleanup; + } + instance = g_focus_sound_handle[index].focus_tid; + + if (!g_mutex_trylock(&g_focus_sound_handle[index].focus_lock)) { + debug_warning("maybe focus_callback is being called, try one more time.."); + usleep(2500000); // 2.5 sec + if (g_mutex_trylock(&g_focus_sound_handle[index].focus_lock)) { + debug_msg("finally got focus_lock"); + } } -cleanup: - pthread_mutex_unlock(&g_thread_mutex); + ret = mm_sound_proxy_unregister_focus(instance, id, g_focus_sound_handle[index].is_for_session); + if (ret == MM_ERROR_NONE) + debug_msg("Success to unregister focus"); + else + debug_error("Error occurred : 0x%x", ret); + + g_mutex_unlock(&g_focus_sound_handle[index].focus_lock); + + _focus_deinit_callback(index, false); + g_focus_sound_handle[index].focus_fd = 0; + g_focus_sound_handle[index].focus_tid = 0; + g_focus_sound_handle[index].handle = 0; + g_focus_sound_handle[index].is_used = false; + _focus_deinit_context(index); + + +cleanup: + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); debug_fleave(); return ret; } -int MMSoundClientStopSound(int handle) +int mm_sound_client_set_focus_reacquisition(int id, bool reacquisition, bool is_for_session) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; int instance; + int index = -1; + bool result; debug_fenter(); - debug_msg("[Client] The stop audio handle ::: [%d]\n", handle); - instance = getpid(); + /* Since the muse server which uses this library for multiple handles executes requests from clients serially, + * we can skip locking/unlocking the mutex for this case. */ + if (!is_for_session) + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); - if (handle < 0) - { + index = _focus_find_index_by_handle(id); + if (index == -1) { + debug_error("Could not find index"); ret = MM_ERROR_INVALID_ARGUMENT; - return ret; - } - - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; - - pthread_mutex_lock(&g_thread_mutex); - - /* Send req STOP */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_STOP; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.handle = handle; /* handle means audio handle slot id */ - - ret = __MMIpcSndMsg(&msgsnd); - if (ret != MM_ERROR_NONE) - { - debug_error("Fail to send msg\n"); goto cleanup; } + instance = g_focus_sound_handle[index].focus_tid; - /* Recieve */ - ret = __MMIpcRecvMsg(instance, &msgrcv); - if (ret != MM_ERROR_NONE) - { - debug_error("[Client] Fail to recieve msg\n"); - goto cleanup; - } - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_STOP: - debug_msg("[Client] Success to stop sound\n"); - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; + ret = mm_sound_client_is_focus_cb_thread(g_thread_self(), &result); + if (ret) { + debug_error("mm_sound_client_is_focus_cb_thread failed"); goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; + } else if (!result) { + ret = mm_sound_proxy_set_focus_reacquisition(instance, id, reacquisition, is_for_session); + if (ret == MM_ERROR_NONE) { + debug_msg("Success to set focus reacquisition to [%d]", reacquisition); + } else { + debug_error("Error occurred : 0x%x",ret); + goto cleanup; + } + } else { + debug_warning("Inside the focus cb thread, set focus reacquisition to [%d]", reacquisition); } -cleanup: - pthread_mutex_unlock(&g_thread_mutex); - + g_focus_sound_handle[index].auto_reacquire = reacquisition; + debug_msg("set focus reacquisition(%d) for id(%d)", reacquisition, id); +cleanup: + if (!is_for_session) + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); debug_fleave(); return ret; } -int _mm_sound_client_is_route_available(mm_sound_route route, bool *is_available) +int mm_sound_client_get_focus_reacquisition(int id, bool *reacquisition) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; - int instance; + int index = -1; debug_fenter(); - *is_available = FALSE; - - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; - - pthread_mutex_lock(&g_thread_mutex); - - instance = getpid(); - /* Send REQ_IS_ROUTE_AVAILABLE */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_IS_ROUTE_AVAILABLE; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.route = route; - - if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE) - goto cleanup; + if (!reacquisition) { + debug_error("Invalid parameter"); + return MM_ERROR_INVALID_ARGUMENT; + } - /* Recieve */ - if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE) - goto cleanup; + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_IS_ROUTE_AVAILABLE: - *is_available = msgrcv.sound_msg.is_available; - debug_msg("[Client] Success to check given route is available %d\n", *is_available); - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; + index = _focus_find_index_by_handle(id); + if (index == -1) { + debug_error("Could not find index"); + ret = MM_ERROR_INVALID_ARGUMENT; goto cleanup; - break; } -cleanup: - pthread_mutex_unlock(&g_thread_mutex); + *reacquisition = g_focus_sound_handle[index].auto_reacquire; + debug_msg("get focus reacquisition(%d) for id(%d)", *reacquisition, id); +cleanup: + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); debug_fleave(); return ret; } -static int _handle_foreach_callback(mm_ipc_msg_t *msg) +int mm_sound_client_get_acquired_focus_stream_type(int focus_type, char **stream_type, int *option, char **ext_info) { - int route_index; - mm_sound_route route; + int ret = MM_ERROR_NONE; + char *stream_type_str = NULL; + char *ext_info_str = NULL; debug_fenter(); - if (msg->sound_msg.callback == NULL) { - debug_error ("[Client] Foreach callback is [%p], cbdata = %p => exit", - msg->sound_msg.callback, msg->sound_msg.cbdata); - return MM_ERROR_SOUND_INTERNAL; - } - - for (route_index = 0; route_index < MM_SOUND_ROUTE_NUM; route_index++) { - route = msg->sound_msg.route_list[route_index]; - if (route == 0) - break; - debug_msg("[Client] available route : %d\n", route); - if (((mm_sound_available_route_cb)msg->sound_msg.callback)(route, msg->sound_msg.cbdata) == false) { - debug_msg ("[Client] user doesn't want anymore. quit loop!!\n"); - break; - } + ret = mm_sound_proxy_get_acquired_focus_stream_type(focus_type, &stream_type_str, option, &ext_info_str); + if (ret == MM_ERROR_NONE) { + debug_msg("Success to get stream type of acquired focus, stream_type(%s), ext_info(%s)", + stream_type_str, ext_info_str); + *stream_type = strdup(stream_type_str); + *ext_info = strdup(ext_info_str); + g_free(stream_type_str); + g_free(ext_info_str); + } else { + debug_error("Error occurred : 0x%x",ret); } debug_fleave(); - - return MM_ERROR_NONE; + return ret; } -int _mm_sound_client_foreach_available_route_cb(mm_sound_available_route_cb available_route_cb, void *user_data) +int mm_sound_client_acquire_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; int instance; + int index = -1; debug_fenter(); + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; - - pthread_mutex_lock(&g_thread_mutex); - - instance = getpid(); - /* Send REQ_FOREACH_AVAILABLE_ROUTE_CB */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_FOREACH_AVAILABLE_ROUTE_CB; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.callback = (void *)available_route_cb; - msgsnd.sound_msg.cbdata = (void *)user_data; - - if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE) - goto cleanup; - - /* Recieve */ - if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE) - goto cleanup; - - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_FOREACH_AVAILABLE_ROUTE_CB: - debug_msg("[Client] Success to set foreach available route callback\n"); - msgrcv.sound_msg.callback = (void *)available_route_cb; - msgrcv.sound_msg.cbdata = (void *)user_data; - ret = _handle_foreach_callback (&msgrcv); - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; + index = _focus_find_index_by_handle(id); + if (index == -1) { + debug_error("Could not find index"); + ret = MM_ERROR_INVALID_ARGUMENT; goto cleanup; - break; } + instance = g_focus_sound_handle[index].focus_tid; -cleanup: - pthread_mutex_unlock(&g_thread_mutex); + ret = mm_sound_proxy_acquire_focus(instance, id, type, option, ext_info, g_focus_sound_handle[index].is_for_session); + if (ret == MM_ERROR_NONE) + debug_msg("Success to acquire focus"); + else + debug_error("Error occurred : 0x%x", ret); +cleanup: + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); debug_fleave(); return ret; } -int _mm_sound_client_set_active_route(mm_sound_route route) +int mm_sound_client_release_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; int instance; + int index = -1; debug_fenter(); + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; - - pthread_mutex_lock(&g_thread_mutex); - - instance = getpid(); - /* Send REQ_SET_ACTIVE_ROUTE */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_SET_ACTIVE_ROUTE; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.route = route; - - if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE) - goto cleanup; - - /* Recieve */ - if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE) - goto cleanup; - - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_SET_ACTIVE_ROUTE: - debug_msg("[Client] Success to add active device callback\n"); - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; + index = _focus_find_index_by_handle(id); + if (index == -1) { + debug_error("Could not find index"); + ret = MM_ERROR_INVALID_ARGUMENT; goto cleanup; - break; } + instance = g_focus_sound_handle[index].focus_tid; -cleanup: - pthread_mutex_unlock(&g_thread_mutex); + ret = mm_sound_proxy_release_focus(instance, id, type, option, ext_info, g_focus_sound_handle[index].is_for_session); + if (ret == MM_ERROR_NONE) + debug_msg("Success to release focus"); + else + debug_error("Error occurred : 0x%x",ret); +cleanup: + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); debug_fleave(); return ret; } -int _mm_sound_client_get_active_device(mm_sound_device_in *device_in, mm_sound_device_out *device_out) +int mm_sound_client_update_stream_focus_status(int id, unsigned int status) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; - int instance; - debug_fenter(); - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; - - pthread_mutex_lock(&g_thread_mutex); - - instance = getpid(); - /* Send REQ_GET_ACTIVE_DEVICE */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_GET_ACTIVE_DEVICE; - msgsnd.sound_msg.msgid = instance; - - if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE) - goto cleanup; + if ((ret = mm_sound_proxy_update_stream_focus_status(id, status)) != MM_ERROR_NONE) + debug_error("failed to update stream focus status, ret[0x%x]", ret); - /* Recieve */ - if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE) - goto cleanup; + debug_fleave(); + return ret; +} - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_GET_ACTIVE_DEVICE: - *device_in = msgrcv.sound_msg.device_in; - *device_out = msgrcv.sound_msg.device_out; - debug_msg("[Client] Success to get active device %d %d\n", *device_in, *device_out); - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - } +int mm_sound_client_deliver_focus(int pid, int src_id, int dst_id, mm_sound_focus_type_e focus_type) +{ + int ret = MM_ERROR_NONE; + debug_fenter(); -cleanup: - pthread_mutex_unlock(&g_thread_mutex); + if ((ret = mm_sound_proxy_deliver_focus(pid, src_id, dst_id, focus_type)) != MM_ERROR_NONE) + debug_error("failed to deliver focus, ret[0x%x]", ret); debug_fleave(); return ret; } -int _mm_sound_client_add_active_device_changed_callback(mm_sound_active_device_changed_cb func, void* user_data) +int mm_sound_client_set_focus_watch_callback(int pid, mm_sound_focus_type_e focus_type, bool is_for_session, bool is_for_monitor, + mm_sound_focus_changed_watch_cb callback, void* user_data, int *id) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; int instance; + int index = 0; debug_fenter(); - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; + if (!id) + return MM_ERROR_INVALID_ARGUMENT; - pthread_mutex_lock(&g_thread_mutex); + //pthread_mutex_lock(&g_thread_mutex2); - instance = getpid(); - /* Send REQ_ADD_ACTIVE_DEVICE_CB */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_ADD_ACTIVE_DEVICE_CB; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.callback = func; - msgsnd.sound_msg.cbdata = user_data; + instance = pid; - if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE) - goto cleanup; + ret = mm_sound_proxy_get_unique_id(id); + if (ret) + return ret; - /* Recieve */ - if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE) - goto cleanup; + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_ADD_ACTIVE_DEVICE_CB: - debug_msg("[Client] Success to add active device callback\n"); - if (g_thread_id == -1) - { - g_thread_id = pthread_create(&g_thread, NULL, callbackfunc, NULL); - if (g_thread_id == -1) - { - debug_critical("[Client] Fail to create thread %s\n", strerror(errno)); - ret = MM_ERROR_SOUND_INTERNAL; - goto cleanup; - } + for (index = 0; index < FOCUS_HANDLE_MAX - 1; index++) { + if (g_focus_sound_handle[index].is_used == false) { + g_focus_sound_handle[index].is_used = true; + break; } - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; + } + + g_focus_sound_handle[index].focus_tid = instance; + g_focus_sound_handle[index].handle = *id; + g_focus_sound_handle[index].watch_callback = callback; + g_focus_sound_handle[index].user_data = user_data; + g_focus_sound_handle[index].is_for_session = is_for_session; + g_focus_sound_handle[index].is_for_monitor = is_for_monitor; + g_focus_sound_handle[index].unset_watch_callback_requested = false; + + ret = mm_sound_proxy_set_focus_watch_callback(pid, g_focus_sound_handle[index].handle, focus_type, + is_for_session, is_for_monitor, callback, user_data); + + if (ret == MM_ERROR_NONE) { + debug_msg("Success to watch focus"); + g_need_emergent_exit = TRUE; + if (_focus_init_context(index)) { + ret = MM_ERROR_SOUND_INTERNAL; + goto cleanup; + } + } else { + debug_error("Error occurred : 0x%x",ret); goto cleanup; - break; } + _focus_init_callback(index, true); + cleanup: - pthread_mutex_unlock(&g_thread_mutex); + if (ret) { + g_focus_sound_handle[index].is_used = false; + } + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); debug_fleave(); return ret; } -int _mm_sound_client_remove_active_device_changed_callback(void) +int mm_sound_client_request_unset_focus_watch_callback(int id) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; - int instance; + int index = -1; debug_fenter(); + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; - - pthread_mutex_lock(&g_thread_mutex); - - instance = getpid(); - /* Send REQ_REMOVE_ACTIVE_DEVICE_CB */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_REMOVE_ACTIVE_DEVICE_CB; - msgsnd.sound_msg.msgid = instance; - - if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE) - goto cleanup; - - /* Recieve */ - if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE) - goto cleanup; - - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_REMOVE_ACTIVE_DEVICE_CB: - debug_msg("[Client] Success to remove active device callback\n"); - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; + index = _focus_watch_find_index_by_handle(id); + if (index == -1) { + debug_error("Could not find index"); + ret = MM_ERROR_INVALID_ARGUMENT; goto cleanup; - break; } + g_focus_sound_handle[index].unset_watch_callback_requested = true; cleanup: - pthread_mutex_unlock(&g_thread_mutex); - + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); debug_fleave(); return ret; } -int _mm_sound_client_add_available_route_changed_callback(mm_sound_available_route_changed_cb func, void* user_data) +int mm_sound_client_unset_focus_watch_callback(int id) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; - int instance; + int index = -1; debug_fenter(); + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL); - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; + index = _focus_watch_find_index_by_handle(id); + if (index == -1) { + debug_error("Could not find index"); + ret = MM_ERROR_INVALID_ARGUMENT; + goto cleanup; + } - pthread_mutex_lock(&g_thread_mutex); + g_mutex_lock(&g_focus_sound_handle[index].focus_lock); - instance = getpid(); - /* Send REQ_ADD_AVAILABLE_ROUTE_CB */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_ADD_AVAILABLE_ROUTE_CB; - msgsnd.sound_msg.msgid = instance; - msgsnd.sound_msg.callback = func; - msgsnd.sound_msg.cbdata = user_data; + g_focus_sound_handle[index].is_used = false; - if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE) - goto cleanup; + ret = mm_sound_proxy_unset_focus_watch_callback(g_focus_sound_handle[index].focus_tid, + g_focus_sound_handle[index].handle, + g_focus_sound_handle[index].is_for_session); - /* Recieve */ - if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE) - goto cleanup; + if (ret == MM_ERROR_NONE) + debug_msg("Success to unwatch focus"); + else + debug_error("Error occurred : 0x%x",ret); - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_ADD_AVAILABLE_ROUTE_CB: - debug_msg("[Client] Success to add available route callback\n"); - if (g_thread_id == -1) - { - g_thread_id = pthread_create(&g_thread, NULL, callbackfunc, NULL); - if (g_thread_id == -1) - { - debug_critical("[Client] Fail to create thread %s\n", strerror(errno)); - ret = MM_ERROR_SOUND_INTERNAL; - goto cleanup; - } - } - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - } -cleanup: - pthread_mutex_unlock(&g_thread_mutex); + g_mutex_unlock(&g_focus_sound_handle[index].focus_lock); + _focus_deinit_callback(index, true); + g_focus_sound_handle[index].focus_fd = 0; + g_focus_sound_handle[index].focus_tid = 0; + g_focus_sound_handle[index].handle = 0; + _focus_deinit_context(index); + +cleanup: + MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex); debug_fleave(); return ret; } -int _mm_sound_client_remove_available_route_changed_callback(void) +static gboolean _idle_event_callback(void *data) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; + focus_idle_event_t *idle_event_data = (focus_idle_event_t*)data; int ret = MM_ERROR_NONE; - int instance; - - debug_fenter(); - - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; - - pthread_mutex_lock(&g_thread_mutex); - instance = getpid(); - /* Send REQ_REMOVE_AVAILABLE_ROUTE_CB */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_REMOVE_AVAILABLE_ROUTE_CB; - msgsnd.sound_msg.msgid = instance; - - if (__MMIpcSndMsg(&msgsnd) != MM_ERROR_NONE) - goto cleanup; + if (data == NULL) { + debug_error("data is null"); + return FALSE; + } - /* Recieve */ - if (__MMIpcRecvMsg(instance, &msgrcv) != MM_ERROR_NONE) - goto cleanup; + debug_msg("idle_event_data(%p): type(%d), data(%d)", + idle_event_data, idle_event_data->type, idle_event_data->data); - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_REMOVE_AVAILABLE_ROUTE_CB: - debug_msg("[Client] Success to remove available route callback\n"); + switch (idle_event_data->type) { + case IDLE_EVENT_TYPE_UNSET_FOCUS_WATCH_CB: + if ((ret = mm_sound_client_unset_focus_watch_callback(idle_event_data->data))) + debug_error("Could not unset focus watch callback, id(%d), ret = %x", idle_event_data->data, ret); break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("[Client] Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; + case IDLE_EVENT_TYPE_UNREGISTER_FOCUS: + if ((ret = mm_sound_client_unregister_focus(idle_event_data->data))) + debug_error("Could not unregister focus, id(%d), ret = %x", idle_event_data->data, ret); break; default: - debug_critical("[Client] Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; + debug_warning("invalid type(%d)", idle_event_data->type); break; } -cleanup: - pthread_mutex_unlock(&g_thread_mutex); - - debug_fleave(); - return ret; -} + g_free(idle_event_data); -static int __MMIpcCBSndMsg(mm_ipc_msg_t *msg) -{ - /* rcv message */ - msg->msg_type = msg->sound_msg.msgid; - if (msgsnd(g_msg_sccb, msg,DSIZE, 0)== -1) - { - if(errno == EACCES) - { - debug_warning("[Client] Not acces.\n"); - } - else if(errno == EAGAIN) - { - debug_warning("[Client] Blocked process [msgflag & IPC_NOWAIT != 0]\n"); - } - else if(errno == EIDRM) - { - debug_warning("[Client] Removed msgid from system\n"); - } - else if(errno == EINTR) - { - debug_warning("[Client] Iterrrupted by singnal\n"); - } - else if(errno == EINVAL) - { - debug_warning("[Client] Invalid msgid or msgtype < 1 or out of data size \n"); - } - debug_critical("[Client] Fail to callback send message msgid : [%d] \n", g_msg_sccb); - return MM_ERROR_COMMON_UNKNOWN; - } - return MM_ERROR_NONE; -} + g_idle_event_src = 0; -static int __MMIpcCBRecvMsg(int msgtype, mm_ipc_msg_t *msg) -{ - /* rcv message */ - if(msgrcv(g_msg_sccb, msg, DSIZE, msgtype, 0) == -1) - { - if(errno == E2BIG) - { - debug_warning("[Client] Not acces.\n"); - } - else if(errno == EACCES) - { - debug_warning("[Client] Access denied\n"); - } - else if(errno == ENOMSG) - { - debug_warning("[Client] Blocked process [msgflag & IPC_NOWAIT != 0]\n"); - } - else if(errno == EIDRM) - { - debug_warning("[Client] Removed msgid from system\n"); - } - else if(errno == EINTR) - { - debug_warning("[Client] Iterrrupted by singnal\n"); - } - else if(errno == EINVAL) - { - debug_warning("[Client] Invalid msgid \n"); - } + MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex); - debug_error("[Client] Fail to callback receive msgid : [%d] \n", g_msg_sccb); - return MM_ERROR_COMMON_UNKNOWN; - } - return MM_ERROR_NONE; + return FALSE; } -static int __MMIpcRecvMsg(int msgtype, mm_ipc_msg_t *msg) +int mm_sound_client_execute_focus_func_in_main_context(focus_idle_event_type_e type, int data) { - int retry_count = 0; + focus_idle_event_t *idle_event_data = NULL; - /* rcv message */ - while (msgrcv(g_msg_scrcv, msg, DSIZE, msgtype, IPC_NOWAIT) == -1) { - if (errno == ENOMSG) { - if (retry_count < 20000) { /* usec is 10^-6 sec so, 5ms * 20000 = 10sec. */ - usleep(5000); - retry_count++; - continue; - } else { - return MM_ERROR_SOUND_INTERNAL; - } - } else if (errno == E2BIG) { - debug_warning("[Client] Not acces.\n"); - } else if (errno == EACCES) { - debug_warning("[Client] Access denied\n"); - } else if (errno == EIDRM) { - debug_warning("[Client] Removed msgid from system\n"); - } else if (errno == EINTR) { - debug_warning("[Client] Iterrrupted by singnal\n"); - continue; - } else if (errno == EINVAL) { - debug_warning("[Client] Invalid msgid \n"); - } + if (IDLE_EVENT_TYPE_MAX < type) + return MM_ERROR_INVALID_ARGUMENT; - debug_error("[Client] Fail to recive msgid : [%d] \n", g_msg_scrcv); - return MM_ERROR_COMMON_UNKNOWN; - } - debug_log("[Client] Retry %d times when receive msg\n", retry_count); - return MM_ERROR_NONE; -} + MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL); -static int __MMIpcSndMsg(mm_ipc_msg_t *msg) -{ - /* rcv message */ - msg->msg_type = msg->sound_msg.msgid; - if (msgsnd(g_msg_scsnd, msg,DSIZE, 0) == -1) - { - if (errno == EACCES) { - debug_warning("[Client] Not access.\n"); - } else if (errno == EAGAIN) { - debug_warning("[Client] Blocked process msgflag & IPC_NOWAIT != 0]\n"); - } else if (errno == EIDRM) { - debug_warning("[Client] Removed msgid from system\n"); - } else if (errno == EINTR) { - debug_warning("[Client] Iterrrupted by singnal\n"); - } else if (errno == EINVAL) { - debug_warning("Invalid msgid or msgtype < 1 or out of data size \n"); - } else if (errno == EFAULT) { - debug_warning("[Client] The address pointed to by msgp isn't accessible \n"); - } else if (errno == ENOMEM) { - debug_warning("[Client] The system does not have enough memory to make a copy of the message pointed to by msgp\n"); - } + idle_event_data = g_new0(focus_idle_event_t, 1); + idle_event_data->type = type; + idle_event_data->data = data; + + g_idle_event_src = g_idle_add_full(G_PRIORITY_HIGH, + (GSourceFunc)_idle_event_callback, + (gpointer)idle_event_data, + NULL); - debug_critical("[Client] Fail to send message msgid : [%d] \n", g_msg_scsnd); - return MM_ERROR_SOUND_INTERNAL; - } return MM_ERROR_NONE; } +#endif -static int __MMSoundGetMsg(void) + +int mm_sound_client_add_test_callback(mm_sound_test_cb func, void* user_data, unsigned int *subs_id) { - /* Init message queue, generate msgid for communication to server */ - /* The key value to get msgid is defined "mm_sound_msg.h". Shared with server */ - + int ret = MM_ERROR_NONE; + debug_fenter(); - - /* get msg queue rcv, snd, cb */ - g_msg_scsnd = msgget(ftok(KEY_BASE_PATH, RCV_MSG), 0666); - g_msg_scrcv = msgget(ftok(KEY_BASE_PATH, SND_MSG), 0666); - g_msg_sccb = msgget(ftok(KEY_BASE_PATH, CB_MSG), 0666); - - if ((g_msg_scsnd == -1 || g_msg_scrcv == -1 || g_msg_sccb == -1) != MM_ERROR_NONE) { - if (errno == EACCES) { - debug_warning("Require ROOT permission.\n"); - } else if (errno == ENOMEM) { - debug_warning("System memory is empty.\n"); - } else if(errno == ENOSPC) { - debug_warning("Resource is empty.\n"); - } - debug_error("Fail to GET msgid\n"); - return MM_ERROR_SOUND_INTERNAL; - } - - debug_msg("Get msg queue id from server : [%d]\n", g_msg_scsnd); - debug_msg("Get msg queue id from server : [%d]\n", g_msg_scrcv); - debug_msg("Get msg queue id from server : [%d]\n", g_msg_sccb); - + + ret = mm_sound_proxy_add_test_callback(func, user_data, g_free, subs_id); + debug_fleave(); - return MM_ERROR_NONE; + return ret; } -#ifdef PULSE_CLIENT - -int MMSoundClientIsBtA2dpOn (bool *connected, char** bt_name) +int mm_sound_client_remove_test_callback(unsigned int subs_id) { - mm_ipc_msg_t msgrcv = {0,}; - mm_ipc_msg_t msgsnd = {0,}; int ret = MM_ERROR_NONE; - int instance; - debug_fenter(); - instance = getpid(); - - if (__mm_sound_client_get_msg_queue() != MM_ERROR_NONE) - return ret; + ret = mm_sound_proxy_remove_test_callback(subs_id); - pthread_mutex_lock(&g_thread_mutex); + debug_fleave(); + return ret; +} - /* Send req */ - msgsnd.sound_msg.msgtype = MM_SOUND_MSG_REQ_IS_BT_A2DP_ON; - msgsnd.sound_msg.msgid = instance; - ret = __MMIpcSndMsg(&msgsnd); - if (ret != MM_ERROR_NONE) - { - debug_error("Fail to send msg\n"); - goto cleanup; - } +int mm_sound_client_test(int a, int b, int* getv) +{ + int ret = MM_ERROR_NONE; - /* Recieve */ - ret = __MMIpcRecvMsg(instance, &msgrcv); - if (ret != MM_ERROR_NONE) - { - debug_error("Fail to recieve msg\n"); - goto cleanup; - } - switch (msgrcv.sound_msg.msgtype) - { - case MM_SOUND_MSG_RES_IS_BT_A2DP_ON: - debug_msg("Success to get IS_BT_A2DP_ON [%d][%s]\n", msgrcv.sound_msg.code, msgrcv.sound_msg.filename); - *connected = (bool)msgrcv.sound_msg.code; - if (*connected) - *bt_name = strdup (msgrcv.sound_msg.filename); - else - *bt_name = NULL; - break; - case MM_SOUND_MSG_RES_ERROR: - debug_error("Error occurred \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - default: - debug_critical("Unexpected state with communication \n"); - ret = msgrcv.sound_msg.code; - goto cleanup; - break; - } + debug_fenter(); -cleanup: - pthread_mutex_unlock(&g_thread_mutex); + ret = mm_sound_proxy_test(a, b, getv); + debug_log("%d * %d -> result : %d", a, b, *getv); debug_fleave(); + return ret; } - -#endif // PULSE_CLIENT