Fix memory leak : valgrind
[platform/core/multimedia/libmm-sound.git] / mm_sound_client.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <poll.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <signal.h>
31
32 #include <pthread.h>
33 #include <semaphore.h>
34
35 #include <mm_error.h>
36 #include <mm_debug.h>
37
38 #include "include/mm_sound.h"
39 #include "include/mm_sound_client.h"
40 #include "include/mm_sound_proxy.h"
41 #include "include/mm_sound_common.h"
42 #include "include/mm_sound_device.h"
43 #include "include/mm_sound_stream.h"
44
45 #include <mm_session.h>
46 #include <mm_session_private.h>
47
48 #include <glib.h>
49 #if defined(__GSOURCE_CALLBACK__)
50 #include <sys/poll.h>
51 #endif
52
53 #define CLIENT_HANDLE_MAX 256
54
55 #define FOCUS_HANDLE_MAX 512
56 #define FOCUS_HANDLE_INIT_VAL -1
57 #define CONFIG_ENABLE_RETCB
58
59 #define VOLUME_TYPE_LEN 64
60
61 struct sigaction system_int_old_action;
62 struct sigaction system_abrt_old_action;
63 struct sigaction system_segv_old_action;
64 struct sigaction system_term_old_action;
65 struct sigaction system_sys_old_action;
66 struct sigaction system_xcpu_old_action;
67
68 struct callback_data {
69         void *user_cb;
70         void *user_data;
71         void *extra_data;
72         guint subs_id;
73 };
74
75 #define GET_CB_DATA(_cb_data, _func, _userdata, _extradata) \
76         do { \
77                 _cb_data = (struct callback_data*) g_malloc0(sizeof(struct callback_data)); \
78                 _cb_data->user_cb = _func; \
79                 _cb_data->user_data = _userdata; \
80                 _cb_data->extra_data = _extradata; \
81         } while (0)
82
83 #ifdef USE_FOCUS
84 typedef struct {
85         int focus_tid;
86         int handle;
87         int focus_fd;
88         GSourceFuncs* g_src_funcs;
89         GPollFD* g_poll_fd;
90         GSource* focus_src;
91         bool is_used;
92         bool auto_reacquire;
93         GMutex focus_lock;
94         mm_sound_focus_changed_cb focus_callback;
95         mm_sound_focus_changed_watch_cb watch_callback;
96         void* user_data;
97
98         bool is_for_session;    /* will be removed when the session concept is completely left out*/
99 } focus_sound_info_t;
100
101 typedef struct {
102         int pid;
103         int handle;
104         int type;
105         int state;
106         char stream_type[MAX_STREAM_TYPE_LEN];
107         char ext_info[MM_SOUND_NAME_NUM];
108         int option;
109 } focus_cb_data_lib;
110
111 typedef struct {
112         mm_sound_focus_session_interrupt_cb user_cb;
113         void* user_data;
114 } focus_session_interrupt_info_t;
115
116 typedef gboolean (*focus_gLoopPollHandler_t)(gpointer d);
117
118 GThread *g_focus_thread;
119 GMainLoop *g_focus_loop;
120 focus_sound_info_t g_focus_sound_handle[FOCUS_HANDLE_MAX];
121 focus_session_interrupt_info_t g_focus_session_interrupt_info = {NULL, NULL};
122 static pthread_mutex_t g_index_mutex = PTHREAD_MUTEX_INITIALIZER;
123 guint g_focus_signal_handle = 0;
124 #endif
125
126 gboolean g_need_emergent_exit = FALSE;
127
128 typedef struct {
129         /* handle to watch end of playing */
130         int watching_handle;
131         /* subscription id to unsubscribe when handle ended */
132         unsigned subs_id;
133 } play_sound_end_callback_data_t;
134
135 void _system_signal_handler(int signo)
136 {
137         int ret = MM_ERROR_NONE;
138         sigset_t old_mask, all_mask;
139
140         debug_warning("Got signal : signo(%d)", signo);
141
142         /* signal block */
143
144         sigfillset(&all_mask);
145         sigprocmask(SIG_BLOCK, &all_mask, &old_mask);
146
147         if (g_need_emergent_exit) {
148                 ret = mm_sound_proxy_emergent_exit(getpid());
149                 if (ret == MM_ERROR_NONE)
150                         debug_msg("[Client] Success to emergnet_exit\n");
151                 else
152                         debug_error("[Client] Error occurred : 0x%x \n",ret);
153         }
154
155         sigprocmask(SIG_SETMASK, &old_mask, NULL);
156         /* signal unblock */
157
158         switch (signo) {
159         case SIGINT:
160                 sigaction(SIGINT, &system_int_old_action, NULL);
161                 raise( signo);
162                 break;
163         case SIGABRT:
164                 sigaction(SIGABRT, &system_abrt_old_action, NULL);
165                 raise( signo);
166                 break;
167         case SIGSEGV:
168                 sigaction(SIGSEGV, &system_segv_old_action, NULL);
169                 raise( signo);
170                 break;
171         case SIGTERM:
172                 sigaction(SIGTERM, &system_term_old_action, NULL);
173                 raise( signo);
174                 break;
175         case SIGSYS:
176                 sigaction(SIGSYS, &system_sys_old_action, NULL);
177                 raise( signo);
178                 break;
179         case SIGXCPU:
180                 sigaction(SIGXCPU, &system_xcpu_old_action, NULL);
181                 raise( signo);
182                 break;
183         default:
184                 break;
185         }
186
187         debug_warning("signal handling end");
188 }
189
190 int mm_sound_client_initialize(void)
191 {
192         int ret = MM_ERROR_NONE;
193         debug_fenter();
194
195         mm_sound_proxy_initialize();
196
197
198         struct sigaction system_action;
199         system_action.sa_handler = _system_signal_handler;
200         system_action.sa_flags = SA_NOCLDSTOP;
201
202         sigemptyset(&system_action.sa_mask);
203
204         sigaction(SIGINT, &system_action, &system_int_old_action);
205         sigaction(SIGABRT, &system_action, &system_abrt_old_action);
206         sigaction(SIGSEGV, &system_action, &system_segv_old_action);
207         sigaction(SIGTERM, &system_action, &system_term_old_action);
208         sigaction(SIGSYS, &system_action, &system_sys_old_action);
209         sigaction(SIGXCPU, &system_action, &system_xcpu_old_action);
210
211         debug_fleave();
212         return ret;
213 }
214
215 int mm_sound_client_finalize(void)
216 {
217         int ret = MM_ERROR_NONE;
218
219         debug_fenter();
220
221         if (g_need_emergent_exit) {
222                 ret = mm_sound_proxy_emergent_exit(getpid());
223                 if (ret == MM_ERROR_NONE)
224                         debug_msg("[Client] Success to emergnet_exit\n");
225                 else
226                         debug_error("[Client] Error occurred : 0x%x \n",ret);
227         }
228
229         sigaction(SIGINT, &system_int_old_action, NULL);
230         sigaction(SIGABRT, &system_abrt_old_action, NULL);
231         sigaction(SIGSEGV, &system_segv_old_action, NULL);
232         sigaction(SIGTERM, &system_term_old_action, NULL);
233         sigaction(SIGSYS, &system_sys_old_action, NULL);
234         sigaction(SIGXCPU, &system_xcpu_old_action, NULL);
235
236         ret = mm_sound_proxy_finalize();
237
238
239 #ifdef USE_FOCUS
240
241         if (g_focus_thread) {
242                 g_main_loop_quit(g_focus_loop);
243                 g_thread_join(g_focus_thread);
244                 debug_log("after thread join");
245                 g_main_loop_unref(g_focus_loop);
246                 g_focus_thread = NULL;
247         }
248
249 #endif
250
251         debug_fleave();
252         return ret;
253 }
254
255 void mm_sound_convert_volume_type_to_stream_type(int volume_type, char *stream_type)
256 {
257         switch (volume_type) {
258         case VOLUME_TYPE_SYSTEM:
259                 MMSOUND_STRNCPY(stream_type, "system", MM_SOUND_STREAM_TYPE_LEN);
260                 break;
261         case VOLUME_TYPE_NOTIFICATION:
262                 MMSOUND_STRNCPY(stream_type, "notification", MM_SOUND_STREAM_TYPE_LEN);
263                 break;
264         case VOLUME_TYPE_ALARM:
265                 MMSOUND_STRNCPY(stream_type, "alarm", MM_SOUND_STREAM_TYPE_LEN);
266                 break;
267         case VOLUME_TYPE_RINGTONE:
268                 MMSOUND_STRNCPY(stream_type, "ringtone-voip", MM_SOUND_STREAM_TYPE_LEN);
269                 break;
270         case VOLUME_TYPE_MEDIA:
271                 MMSOUND_STRNCPY(stream_type, "media", MM_SOUND_STREAM_TYPE_LEN);
272                 break;
273         case VOLUME_TYPE_CALL:
274                 MMSOUND_STRNCPY(stream_type, "call-voice", MM_SOUND_STREAM_TYPE_LEN);
275                 break;
276         case VOLUME_TYPE_VOIP:
277                 MMSOUND_STRNCPY(stream_type, "voip", MM_SOUND_STREAM_TYPE_LEN);
278                 break;
279         case VOLUME_TYPE_VOICE:
280                 MMSOUND_STRNCPY(stream_type, "voice-recognition", MM_SOUND_STREAM_TYPE_LEN);
281                 break;
282         default:
283                 MMSOUND_STRNCPY(stream_type, "media", MM_SOUND_STREAM_TYPE_LEN);
284                 break;
285         }
286
287         debug_msg("volume type (%d) converted to stream type (%s)", volume_type, stream_type);
288
289 }
290
291 /*****************************************************************************************
292                             DBUS SUPPORTED FUNCTIONS
293 ******************************************************************************************/
294 #ifdef USE_FOCUS
295 void _mm_sound_client_focus_signal_callback(mm_sound_signal_name_t signal, int value, void *user_data)
296 {
297         int ret = MM_ERROR_NONE;
298
299         debug_fenter();
300         debug_msg("focus signal received, value = %d", value);
301
302         if (value == 1) {
303                 ret = mm_sound_proxy_clear_focus(getpid());
304                 if (ret)
305                         debug_error("clear focus failed ret = 0x%x", ret);
306                 mm_sound_unsubscribe_signal(g_focus_signal_handle);
307                 g_focus_signal_handle = 0;
308         }
309 }
310 #endif
311
312 int mm_sound_client_play_tone(int number, int volume_config, double volume, int time, int *handle, bool enable_session)
313 {
314         int ret = MM_ERROR_NONE;
315 //       int instance = -1;     /* instance is unique to communicate with server : client message queue filter type */
316         int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(volume_config);
317         char stream_type[MM_SOUND_STREAM_TYPE_LEN] = {0, };
318
319          debug_fenter();
320
321         /* read session information */
322         int session_type = MM_SESSION_TYPE_MEDIA;
323         int session_options = 0;
324         int is_focus_registered = 0;
325
326         ret = mm_sound_get_signal_value(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &is_focus_registered);
327         if (ret) {
328                 debug_error("mm_sound_get_signal_value failed [0x%x]", ret);
329                 return MM_ERROR_POLICY_INTERNAL;
330         }
331
332         if (is_focus_registered)
333                 enable_session = false;
334
335         if (enable_session) {
336                 if (MM_ERROR_NONE != _mm_session_util_read_information(-1, &session_type, &session_options)) {
337                         debug_warning("[Client] Read Session Information failed. use default \"media\" type\n");
338                         session_type = MM_SESSION_TYPE_MEDIA;
339
340                         if(MM_ERROR_NONE != mm_session_init(session_type)) {
341                                 debug_critical("[Client] MMSessionInit() failed\n");
342                                 return MM_ERROR_POLICY_INTERNAL;
343                         }
344                 }
345         }
346
347          // instance = getpid();
348          //debug_log("[Client] pid for client ::: [%d]\n", instance);
349
350          /* Send msg */
351          debug_msg("[Client] Input number : %d\n", number);
352          /* Send req memory */
353
354         mm_sound_convert_volume_type_to_stream_type(volume_type, stream_type);
355         ret = mm_sound_proxy_play_tone(number, time, volume, volume_config,
356                                         session_type, session_options, getpid(), enable_session, handle, stream_type, -1);
357 #ifdef USE_FOCUS
358         if (enable_session && !g_focus_signal_handle) {
359                 ret = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &g_focus_signal_handle, _mm_sound_client_focus_signal_callback, NULL);
360                 if (ret) {
361                         debug_error("mm_sound_subscribe_signal failed [0x%x]", ret);
362                         return MM_ERROR_POLICY_INTERNAL;
363                 }
364         }
365 #endif
366
367         debug_fleave();
368         return ret;
369 }
370
371 int mm_sound_client_play_tone_with_stream_info(int tone, char *stream_type, int stream_id, double volume, int duration, int *handle)
372 {
373         int ret = MM_ERROR_NONE;
374
375         debug_fenter();
376
377         ret = mm_sound_proxy_play_tone_with_stream_info(getpid(), tone, stream_type, stream_id, volume, duration, handle);
378
379         debug_fleave();
380         return ret;
381 }
382
383 static void _mm_sound_stop_callback_wrapper_func(int ended_handle, void *userdata)
384 {
385         struct callback_data *cb_data = (struct callback_data*) userdata;
386         play_sound_end_callback_data_t *end_cb_data;
387
388         debug_log("[Wrapper CB][Play Stop] ended_handle : %d", ended_handle);
389
390         if (cb_data == NULL) {
391                 debug_warning("stop callback data null");
392                 return;
393         }
394
395         end_cb_data = (play_sound_end_callback_data_t*) cb_data->extra_data;
396
397         if (ended_handle == end_cb_data->watching_handle) {
398                 debug_log("Interested playing handle end : %d", ended_handle);
399                 ((mm_sound_stop_callback_func)(cb_data->user_cb))(cb_data->user_data, ended_handle);
400                 if (mm_sound_proxy_remove_play_sound_end_callback(end_cb_data->subs_id) != MM_ERROR_NONE)
401                         debug_error("mm_sound_client_dbus_remove_play_file_end_callback failed");
402         } else {
403                 debug_log("Not interested playing handle : %d", ended_handle);
404         }
405 }
406
407 static void play_end_callback_data_free_func(void *data)
408 {
409         struct callback_data *cb_data = (struct callback_data*) data;
410
411         if (cb_data) {
412                 g_free(cb_data->extra_data);
413                 g_free(cb_data);
414         }
415 }
416
417 int mm_sound_client_play_sound(MMSoundPlayParam *param, int tone, int *handle)
418 {
419         int ret = MM_ERROR_NONE;
420         int session_type = MM_SESSION_TYPE_MEDIA;
421         int session_options = 0;
422         int is_focus_registered = 0;
423 //      int instance = -1;      /* instance is unique to communicate with server : client message queue filter type */
424         int volume_type = MM_SOUND_VOLUME_CONFIG_TYPE(param->volume_config);
425         char stream_type[MM_SOUND_STREAM_TYPE_LEN] = {0, };
426         struct callback_data *cb_data = NULL;
427         play_sound_end_callback_data_t *end_cb_data;
428
429         debug_fenter();
430
431         /* read session information */
432
433         ret = mm_sound_get_signal_value(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &is_focus_registered);
434         if (ret) {
435                 debug_error("mm_sound_get_signal_value failed [0x%x]", ret);
436                 return MM_ERROR_POLICY_INTERNAL;
437         }
438
439         if (is_focus_registered)
440                 param->skip_session = true;
441
442         if (param->skip_session == false) {
443                 if(MM_ERROR_NONE != _mm_session_util_read_information(-1, &session_type, &session_options)) {
444                         debug_warning("[Client] Read MMSession Type failed. use default \"media\" type\n");
445                         session_type = MM_SESSION_TYPE_MEDIA;
446
447                         if(MM_ERROR_NONE != mm_session_init(session_type)) {
448                                 debug_critical("[Client] MMSessionInit() failed\n");
449                                 return MM_ERROR_POLICY_INTERNAL;
450                         }
451                 }
452         }
453
454         /* Send msg */
455         if ((param->mem_ptr && param->mem_size)) {
456                 // Play memory, deprecated
457                 return MM_ERROR_INVALID_ARGUMENT;
458         }
459
460         mm_sound_convert_volume_type_to_stream_type(volume_type, stream_type);
461         ret = mm_sound_proxy_play_sound(param->filename, tone, param->loop, param->volume, param->volume_config,
462                                          param->priority, session_type, session_options, getpid(), param->handle_route,
463                                          !param->skip_session, handle, stream_type, -1);
464         if (ret != MM_ERROR_NONE) {
465                 debug_error("Play Sound Failed");
466                 goto failed;
467         }
468         if (param->callback) {
469                 end_cb_data = (play_sound_end_callback_data_t *) g_malloc0(sizeof(play_sound_end_callback_data_t));
470                 end_cb_data->watching_handle = *handle;
471                 GET_CB_DATA(cb_data, param->callback, param->data, end_cb_data);
472
473                 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);
474                 if (ret != MM_ERROR_NONE) {
475                         debug_error("Add callback for play sound(%d) Failed", *handle);
476                 }
477         }
478 #ifdef USE_FOCUS
479         if (!param->skip_session && !g_focus_signal_handle) {
480                 ret = mm_sound_subscribe_signal(MM_SOUND_SIGNAL_RELEASE_INTERNAL_FOCUS, &g_focus_signal_handle, _mm_sound_client_focus_signal_callback, NULL);
481                 if (ret) {
482                         debug_error("mm_sound_subscribe_signal failed [0x%x]", ret);
483                         return MM_ERROR_POLICY_INTERNAL;
484                 }
485         }
486 #endif
487
488 failed:
489
490         debug_fleave();
491         return ret;
492 }
493
494 int mm_sound_client_play_sound_with_stream_info(MMSoundPlayParam *param, int *handle, char* stream_type, int stream_id)
495 {
496         int ret = MM_ERROR_NONE;
497         struct callback_data *cb_data = NULL;
498         play_sound_end_callback_data_t *end_cb_data;
499
500         ret = mm_sound_proxy_play_sound_with_stream_info(param->filename, param->loop, param->volume,
501                                          param->priority, getpid(), param->handle_route, handle, stream_type, stream_id);
502         if (ret != MM_ERROR_NONE) {
503                 debug_error("Play Sound Failed");
504                 goto failed;
505         }
506         if (param->callback) {
507                 end_cb_data = (play_sound_end_callback_data_t *) g_malloc0(sizeof(play_sound_end_callback_data_t));
508                 end_cb_data->watching_handle = *handle;
509                 GET_CB_DATA(cb_data, param->callback, param->data, end_cb_data);
510
511                 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);
512                 if (ret != MM_ERROR_NONE) {
513                         debug_error("Add callback for play sound(%d) Failed", *handle);
514                 }
515         }
516
517 failed:
518
519         debug_fleave();
520         return ret;
521
522 }
523
524 int mm_sound_client_stop_sound(int handle)
525 {
526         int ret = MM_ERROR_NONE;
527         debug_fenter();
528
529         if (handle < 0 || handle > CLIENT_HANDLE_MAX) {
530                 ret = MM_ERROR_INVALID_ARGUMENT;
531                 return ret;
532         }
533
534         ret = mm_sound_proxy_stop_sound(handle);
535
536         debug_fleave();
537         return ret;
538 }
539
540 static int _mm_sound_client_device_list_dump (GList *device_list)
541 {
542         int ret = MM_ERROR_NONE;
543         GList *list = NULL;
544         mm_sound_device_t *device_node = NULL;
545         int count = 0;
546         if (!device_list) {
547                 debug_error("Device list NULL, cannot dump list");
548                 return MM_ERROR_SOUND_INTERNAL;
549         }
550
551         debug_log("======================== device list : start ==========================\n");
552         for (list = device_list; list != NULL; list = list->next) {
553                 device_node = (mm_sound_device_t *)list->data;
554                 if (device_node) {
555                         debug_log(" list idx[%d]: type[%17s], id[%02d], io_direction[%d], state[%d], name[%s]\n",
556                                                 count++, device_node->type, device_node->id, device_node->io_direction, device_node->state, device_node->name);
557                 }
558         }
559         debug_log("======================== device list : end ============================\n");
560
561         return ret;
562 }
563
564 int mm_sound_client_get_current_connected_device_list(int device_flags, mm_sound_device_list_t *device_list)
565 {
566         int ret = MM_ERROR_NONE;
567         debug_fenter();
568
569         if (!device_list) {
570                 debug_error("Device list NULL");
571                 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
572                 goto failed;
573         }
574
575         if ((ret = mm_sound_proxy_get_current_connected_device_list(device_flags, &device_list->list)) != MM_ERROR_NONE) {
576                 debug_error("[Client] failed to get current connected device list with dbus, ret[0x%x]", ret);
577                 goto failed;
578         }
579         if (!device_list->list) {
580                 debug_error("Got device list null");
581                 ret = MM_ERROR_SOUND_NO_DATA;
582                 goto failed;
583         }
584         _mm_sound_client_device_list_dump(device_list->list);
585
586 failed:
587         debug_fleave();
588         return ret;
589 }
590
591 static bool device_is_match_direction(int direction, int mask)
592 {
593         if (mask == DEVICE_IO_DIRECTION_FLAGS || mask == 0)
594                 return true;
595
596         if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_IN))
597                 return true;
598         if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_OUT))
599                 return true;
600         if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH))
601                 return true;
602
603         return false;
604 }
605
606 static bool device_is_match_state(int state, int mask)
607 {
608         if (mask == DEVICE_STATE_FLAGS || mask == 0)
609                 return true;
610
611         if ((mask & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_DEACTIVATED))
612                 return true;
613         if ((mask & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_ACTIVATED))
614                 return true;
615
616         return false;
617 }
618
619 static bool device_is_match_type(const char *type, int mask)
620 {
621         bool is_builtin;
622         const char *builtin_prefix = "builtin";
623
624         if (mask == DEVICE_TYPE_FLAGS || mask == 0)
625                 return true;
626
627         is_builtin = !strncmp(type, builtin_prefix, strlen(builtin_prefix));
628
629         if ((mask & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG) && (is_builtin))
630                 return true;
631         if ((mask & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG) && (!is_builtin))
632                 return true;
633
634         return false;
635 }
636
637 static bool device_is_match_with_mask(const char *type, int direction, int state, int mask)
638 {
639         if (mask == DEVICE_ALL_FLAG)
640                 return true;
641
642         return (device_is_match_direction(direction, mask & DEVICE_IO_DIRECTION_FLAGS) &&
643                         device_is_match_state(state, mask & DEVICE_STATE_FLAGS) &&
644                         device_is_match_type(type, mask & DEVICE_TYPE_FLAGS));
645 }
646
647 static int _fill_sound_device(mm_sound_device_t *device_h, int device_id, const char *device_type,
648                 int direction, int state, const char *name, int *stream_id, int stream_num)
649 {
650         int i;
651
652         if (stream_num > 0 && stream_id == NULL) {
653                 debug_error("stream_num is %d, but stream_id is NULL", stream_num);
654                 return -1;
655         }
656
657         if (stream_num > MAX_STREAM_ON_DEVICE) {
658                 debug_error("too many streams on this device");
659                 return -1;
660         }
661
662         device_h->id = device_id;
663         device_h->io_direction = direction;
664         device_h->state = state;
665         MMSOUND_STRNCPY(device_h->name, name, MAX_DEVICE_NAME_NUM);
666         MMSOUND_STRNCPY(device_h->type, device_type, MAX_DEVICE_TYPE_STR_LEN);
667
668         if (stream_num > 0) {
669                 device_h->stream_num = stream_num;
670                 debug_log("%d streams on this device", stream_num);
671                 for (i = 0; i < stream_num; i++) {
672                         debug_log("  stream_id : %d", stream_id[i]);
673                         device_h->stream_id[i] = stream_id[i];
674                 }
675         } else {
676                 device_h->stream_num = 0;
677                 debug_log("There is no stream on this device");
678         }
679
680         return 0;
681 }
682
683 static void _mm_sound_device_connected_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
684                 int state, const char *name, int *stream_id, int stream_num, gboolean is_connected, void *userdata)
685 {
686         mm_sound_device_t device_h;
687         struct callback_data *cb_data = (struct callback_data*) userdata;
688         int device_flags;
689
690         debug_log("[Device %s] id(%d) type(%s) direction(%d) state(%d) name(%s)",
691                           is_connected ? "Connected" : "Disconnected", device_id, device_type, io_direction,
692                           state, name, is_connected);
693
694         if (cb_data == NULL) {
695                 debug_warning("device connected changed callback data null");
696                 return;
697         }
698
699         device_flags = (int) cb_data->extra_data;
700         if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
701                 return;
702
703         if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name, stream_id, stream_num) < 0) {
704                 debug_error("Failed to fill sound device");
705                 return;
706         }
707
708         ((mm_sound_device_connected_cb)(cb_data->user_cb))(&device_h, is_connected, cb_data->user_data);
709 }
710
711 int mm_sound_client_add_device_connected_callback(int device_flags, mm_sound_device_connected_cb func, void* userdata, unsigned int *subs_id)
712 {
713         int ret = MM_ERROR_NONE;
714         struct callback_data *cb_data = NULL;
715
716         debug_fenter();
717
718         GET_CB_DATA(cb_data, func, userdata, (void*) device_flags);
719
720         ret = mm_sound_proxy_add_device_connected_callback(device_flags, _mm_sound_device_connected_callback_wrapper_func, cb_data, g_free, subs_id);
721         if (ret == MM_ERROR_NONE)
722                 g_need_emergent_exit = TRUE;
723
724         debug_fleave();
725         return ret;
726 }
727
728 int mm_sound_client_remove_device_connected_callback(unsigned int subs_id)
729 {
730         int ret = MM_ERROR_NONE;
731         debug_fenter();
732
733         ret = mm_sound_proxy_remove_device_connected_callback(subs_id);
734
735         debug_fleave();
736         return ret;
737 }
738
739 static void _mm_sound_device_info_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
740                 int state, const char *name, int *stream_id, int stream_num, int changed_device_info_type, void *userdata)
741 {
742         mm_sound_device_t device_h;
743         struct callback_data *cb_data = (struct callback_data*) userdata;
744         int device_flags;
745
746         debug_log("[Device Info Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) changed_info_type(%d)",
747                           device_id, device_type, io_direction, state, name, changed_device_info_type);
748
749         if (cb_data == NULL) {
750                 debug_warning("device info changed callback data null");
751                 return;
752         }
753
754         device_flags = (int) cb_data->extra_data;
755         if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
756                 return;
757
758         if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name, stream_id, stream_num) < 0) {
759                 debug_error("Failed to fill sound device");
760                 return;
761         }
762
763         ((mm_sound_device_info_changed_cb)(cb_data->user_cb))(&device_h, changed_device_info_type, cb_data->user_data);
764 }
765
766 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)
767 {
768         int ret = MM_ERROR_NONE;
769         struct callback_data *cb_data = (struct callback_data*) userdata;
770
771         debug_fenter();
772
773         GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
774
775         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);
776
777         debug_fleave();
778         return ret;
779 }
780
781 int mm_sound_client_remove_device_info_changed_callback(unsigned int subs_id)
782 {
783         int ret = MM_ERROR_NONE;
784         debug_fenter();
785
786         ret =  mm_sound_proxy_remove_device_info_changed_callback(subs_id);
787
788         debug_fleave();
789         return ret;
790
791 }
792
793 static void _mm_sound_device_state_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
794                 int state, const char *name, int *stream_id, int stream_num, void *userdata)
795 {
796         mm_sound_device_t device_h;
797         struct callback_data *cb_data = (struct callback_data*) userdata;
798         int device_flags;
799
800         debug_log("[Device State Changed] id(%d) type(%s) direction(%d) state(%d) name(%s)",
801                           device_id, device_type, io_direction, state, name);
802
803         if (cb_data == NULL) {
804                 debug_warning("device state changed callback data null");
805                 return;
806         }
807
808         device_flags = (int) cb_data->extra_data;
809
810         if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
811                 return;
812
813         if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name, stream_id, stream_num) < 0) {
814                 debug_error("Failed to fill sound device");
815                 return;
816         }
817
818         ((mm_sound_device_state_changed_cb)(cb_data->user_cb))(&device_h, state, cb_data->user_data);
819 }
820
821 int mm_sound_client_add_device_state_changed_callback(int device_flags, mm_sound_device_state_changed_cb func, void *userdata, unsigned int *id)
822 {
823         int ret = MM_ERROR_NONE;
824         struct callback_data *cb_data = (struct callback_data*) userdata;
825
826         debug_fenter();
827
828         GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
829
830         ret = mm_sound_proxy_add_device_state_changed_callback(device_flags, _mm_sound_device_state_changed_callback_wrapper_func, cb_data, g_free, id);
831
832         debug_fleave();
833         return ret;
834 }
835
836 int mm_sound_client_remove_device_state_changed_callback(unsigned int id)
837 {
838         int ret = MM_ERROR_NONE;
839         debug_fenter();
840
841         ret =  mm_sound_proxy_remove_device_state_changed_callback(id);
842
843         debug_fleave();
844         return ret;
845 }
846
847 int mm_sound_client_is_stream_on_device(int stream_id, int device_id, bool *is_on)
848 {
849         int ret = MM_ERROR_NONE;
850         debug_fenter();
851
852         if (!is_on) {
853                 debug_error("Invalid Parameter");
854                 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
855                 goto failed;
856         }
857
858         if ((ret = mm_sound_proxy_is_stream_on_device(stream_id, device_id, is_on)) != MM_ERROR_NONE) {
859                 debug_error("[Client] failed to query is stream on device, ret[0x%x]", ret);
860                 goto failed;
861         }
862
863 failed:
864         debug_fleave();
865         return ret;
866 }
867
868 int __convert_volume_type_to_str(int volume_type, char **volume_type_str)
869 {
870         int ret = MM_ERROR_NONE;
871
872         if (!volume_type_str) {
873                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
874         }
875
876         switch (volume_type) {
877         case VOLUME_TYPE_SYSTEM:
878                 *volume_type_str = "system";
879                 break;
880         case VOLUME_TYPE_NOTIFICATION:
881                 *volume_type_str = "notification";
882                 break;
883         case VOLUME_TYPE_ALARM:
884                 *volume_type_str = "alarm";
885                 break;
886         case VOLUME_TYPE_RINGTONE:
887                 *volume_type_str = "ringtone";
888                 break;
889         case VOLUME_TYPE_MEDIA:
890                 *volume_type_str = "media";
891                 break;
892         case VOLUME_TYPE_CALL:
893                 *volume_type_str = "call";
894                 break;
895         case VOLUME_TYPE_VOIP:
896                 *volume_type_str = "voip";
897                 break;
898         case VOLUME_TYPE_VOICE:
899                 *volume_type_str = "voice";
900                 break;
901         }
902         if (!strncmp(*volume_type_str,"", VOLUME_TYPE_LEN)) {
903                 debug_error("could not find the volume_type[%d] in this switch case statement", volume_type);
904                 ret = MM_ERROR_SOUND_INTERNAL;
905         } else {
906                 debug_log("volume_type[%s]", *volume_type_str);
907         }
908         return ret;
909 }
910
911 static int __convert_volume_type_to_int(const char *volume_type_str, volume_type_t *volume_type)
912 {
913         int ret = MM_ERROR_NONE;
914
915         if (!volume_type || !volume_type_str) {
916                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
917         }
918
919         if (!strncmp(volume_type_str, "system", VOLUME_TYPE_LEN)) {
920                 *volume_type = VOLUME_TYPE_SYSTEM;
921         } else if (!strncmp(volume_type_str, "notification", VOLUME_TYPE_LEN)) {
922                 *volume_type = VOLUME_TYPE_NOTIFICATION;
923         } else if (!strncmp(volume_type_str, "alarm", VOLUME_TYPE_LEN)) {
924                 *volume_type = VOLUME_TYPE_ALARM;
925         } else if (!strncmp(volume_type_str, "ringtone", VOLUME_TYPE_LEN)) {
926                 *volume_type = VOLUME_TYPE_RINGTONE;
927         } else if (!strncmp(volume_type_str, "media", VOLUME_TYPE_LEN)) {
928                 *volume_type = VOLUME_TYPE_MEDIA;
929         } else if (!strncmp(volume_type_str, "call", VOLUME_TYPE_LEN)) {
930                 *volume_type = VOLUME_TYPE_CALL;
931         } else if (!strncmp(volume_type_str, "voip", VOLUME_TYPE_LEN)) {
932                 *volume_type = VOLUME_TYPE_VOIP;
933         } else if (!strncmp(volume_type_str, "voice", VOLUME_TYPE_LEN)) {
934                 *volume_type = VOLUME_TYPE_VOICE;
935         } else {
936                 debug_log("Invalid volume type : [%s]", volume_type_str);
937                 ret = MM_ERROR_SOUND_INTERNAL;
938         }
939
940         return ret;
941 }
942
943 int mm_sound_client_set_volume_by_type(const int volume_type, const unsigned int volume_level)
944 {
945         int ret = MM_ERROR_NONE;
946         char *type_str = NULL;
947         debug_fenter();
948
949         if ((ret = __convert_volume_type_to_str(volume_type, &type_str)) != MM_ERROR_NONE) {
950                 debug_error("volume type convert failed");
951                 goto failed;
952         }
953
954         ret = mm_sound_proxy_set_volume_by_type(type_str, volume_level);
955
956 failed:
957         debug_fleave();
958         return ret;
959 }
960
961 static void _mm_sound_volume_changed_callback_wrapper_func(const char *direction, const char *volume_type_str, int volume_level, void *userdata)
962 {
963         volume_type_t volume_type = 0;
964         struct callback_data *cb_data = (struct callback_data *) userdata;
965
966         debug_log("[Wrapper CB][Volume Changed] direction : %s, volume_type : %s, volume_level : %d", direction, volume_type_str, volume_level);
967
968         if (cb_data == NULL) {
969                 debug_warning("volume changed callback data null");
970                 return;
971         }
972
973         if (__convert_volume_type_to_int(volume_type_str, &volume_type) != MM_ERROR_NONE) {
974                 debug_error("volume type convert failed");
975                 return;
976         }
977         debug_log("Call volume changed user cb, direction : %s, vol_type : %s(%d), level : %u", direction, volume_type_str, volume_type, volume_level);
978         ((mm_sound_volume_changed_cb)(cb_data->user_cb))(volume_type, volume_level, cb_data->user_data);
979 }
980
981 int mm_sound_client_add_volume_changed_callback(mm_sound_volume_changed_cb func, void* userdata, unsigned int *subs_id)
982 {
983         int ret = MM_ERROR_NONE;
984         struct callback_data *cb_data = NULL;
985
986         debug_fenter();
987
988         GET_CB_DATA(cb_data, func, userdata, NULL);
989
990         ret = mm_sound_proxy_add_volume_changed_callback(_mm_sound_volume_changed_callback_wrapper_func, cb_data, g_free, subs_id);
991
992         debug_fleave();
993
994         return ret;
995 }
996
997 int mm_sound_client_remove_volume_changed_callback(unsigned int subs_id)
998 {
999         int ret = MM_ERROR_NONE;
1000         debug_fenter();
1001
1002         ret = mm_sound_proxy_remove_volume_changed_callback(subs_id);
1003
1004         debug_fleave();
1005         return ret;
1006 }
1007
1008 #ifdef USE_FOCUS
1009 int mm_sound_client_set_session_interrupt_callback(mm_sound_focus_session_interrupt_cb callback, void* user_data)
1010 {
1011         int ret = MM_ERROR_NONE;
1012
1013         debug_fenter();
1014
1015         if (!callback)
1016                 return MM_ERROR_INVALID_ARGUMENT;
1017
1018         g_focus_session_interrupt_info.user_cb = callback;
1019         g_focus_session_interrupt_info.user_data = user_data;
1020
1021         debug_fleave();
1022         return ret;
1023 }
1024
1025 int mm_sound_client_unset_session_interrupt_callback(void)
1026 {
1027         int ret = MM_ERROR_NONE;
1028
1029         debug_fenter();
1030
1031         if (!g_focus_session_interrupt_info.user_cb) {
1032                 debug_error("no callback to unset");
1033                 return MM_ERROR_SOUND_INTERNAL;
1034         }
1035
1036         g_focus_session_interrupt_info.user_cb = NULL;
1037         g_focus_session_interrupt_info.user_data = NULL;
1038
1039         debug_fleave();
1040         return ret;
1041 }
1042
1043 static gpointer _focus_thread_func(gpointer data)
1044 {
1045         unsigned int thread_id = (unsigned int)pthread_self();
1046         debug_warning(">>> thread func..ID of this thread(%u), mainloop(%p)", thread_id, g_focus_loop);
1047         if (g_focus_loop)
1048                 g_main_loop_run(g_focus_loop);
1049
1050         debug_warning("<<< quit thread func..(%u), mainloop(%p)", thread_id, g_focus_loop);
1051         return NULL;
1052 }
1053
1054 static gboolean _focus_fd_check(GSource * source)
1055 {
1056         GSList *fd_list;
1057         GPollFD *temp;
1058
1059         if (!source) {
1060                 debug_error("GSource is null");
1061                 return FALSE;
1062         }
1063         fd_list = source->poll_fds;
1064         if (!fd_list) {
1065                 debug_error("fd_list is null");
1066                 return FALSE;
1067         }
1068         do {
1069                 temp = (GPollFD*)fd_list->data;
1070                 if (!temp) {
1071                         debug_error("fd_list->data is null");
1072                         return FALSE;
1073                 }
1074                 if (temp->revents & (POLLIN | POLLPRI)) {
1075                         return TRUE;
1076                 }
1077                 fd_list = fd_list->next;
1078         } while (fd_list);
1079
1080         return FALSE; /* there is no change in any fd state */
1081 }
1082
1083 static gboolean _focus_fd_prepare(GSource *source, gint *timeout)
1084 {
1085         return FALSE;
1086 }
1087
1088 static gboolean _focus_fd_dispatch(GSource *source,     GSourceFunc callback, gpointer user_data)
1089 {
1090         callback(user_data);
1091         return TRUE;
1092 }
1093
1094 static int _focus_find_index_by_handle(int handle)
1095 {
1096         int i = 0;
1097         for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
1098                 if (g_focus_sound_handle[i].focus_callback && handle == g_focus_sound_handle[i].handle) {
1099                         /* debug_msg("found index(%d) for handle(%d)", i, handle);*/
1100                         return (handle == FOCUS_HANDLE_INIT_VAL)? -1 : i;
1101                 }
1102         }
1103         return -1;
1104 }
1105
1106 static int _focus_watch_find_index_by_handle(int handle)
1107 {
1108         int i = 0;
1109         for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
1110                 if (g_focus_sound_handle[i].watch_callback && handle == g_focus_sound_handle[i].handle) {
1111                         /* debug_msg("found index(%d) for watch handle(%d)", i, handle);*/
1112                         return (handle == FOCUS_HANDLE_INIT_VAL)? -1 : i;
1113                 }
1114         }
1115         return -1;
1116 }
1117
1118 static gboolean _focus_callback_handler(gpointer d)
1119 {
1120         GPollFD *data = (GPollFD*)d;
1121         int count;
1122         int tid = 0;
1123         int focus_index = 0;
1124         focus_cb_data_lib cb_data;
1125         debug_log(">>> focus_callback_handler()..ID of this thread(%u)\n", (unsigned int)pthread_self());
1126
1127         memset(&cb_data, 0, sizeof(focus_cb_data_lib));
1128
1129         if (!data) {
1130                 debug_error("GPollFd is null");
1131                 return FALSE;
1132         }
1133         if (data->revents & (POLLIN | POLLPRI)) {
1134                 int changed_state = -1;
1135
1136                 count = read(data->fd, &cb_data, sizeof(cb_data));
1137                 if (count < 0){
1138                         char str_error[256];
1139                         strerror_r(errno, str_error, sizeof(str_error));
1140                         debug_error("GpollFD read fail, errno=%d(%s)",errno, str_error);
1141                         return FALSE;
1142                 }
1143                 changed_state = cb_data.state;
1144                 focus_index = _focus_find_index_by_handle(cb_data.handle);
1145                 if (focus_index == -1) {
1146                         debug_error("Could not find index");
1147                         return FALSE;
1148                 }
1149
1150                 g_mutex_lock(&g_focus_sound_handle[focus_index].focus_lock);
1151
1152                 tid = g_focus_sound_handle[focus_index].focus_tid;
1153
1154                 if (changed_state != -1) {
1155                         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);
1156                         if (g_focus_sound_handle[focus_index].focus_callback == NULL) {
1157                                         debug_error("callback is null..");
1158                                         g_mutex_unlock(&g_focus_sound_handle[focus_index].focus_lock);
1159                                         return FALSE;
1160                         }
1161                         debug_msg("[CALLBACK(%p) START]",g_focus_sound_handle[focus_index].focus_callback);
1162                         (g_focus_sound_handle[focus_index].focus_callback)(cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type, cb_data.option, cb_data.ext_info, g_focus_sound_handle[focus_index].user_data);
1163                         debug_msg("[CALLBACK END]");
1164                         if (g_focus_session_interrupt_info.user_cb) {
1165                                 debug_msg("sending session interrupt callback(%p)", g_focus_session_interrupt_info.user_cb);
1166                                 (g_focus_session_interrupt_info.user_cb)(cb_data.state, cb_data.stream_type, false, g_focus_session_interrupt_info.user_data);
1167                         }
1168                 }
1169 #ifdef CONFIG_ENABLE_RETCB
1170                 {
1171                         int rett = 0;
1172                         int tmpfd = -1;
1173                         unsigned int buf = 0;
1174                         char *filename2 = g_strdup_printf("/tmp/FOCUS.%d.%dr", g_focus_sound_handle[focus_index].focus_tid, cb_data.handle);
1175                         tmpfd = open(filename2, O_WRONLY | O_NONBLOCK);
1176                         if (tmpfd < 0) {
1177                                 char str_error[256];
1178                                 strerror_r(errno, str_error, sizeof(str_error));
1179                                 debug_warning("[RETCB][Failed(May Server Close First)]tid(%d) fd(%d) %s errno=%d(%s)\n", tid, tmpfd, filename2, errno, str_error);
1180                                 g_free(filename2);
1181                                 g_mutex_unlock(&g_focus_sound_handle[focus_index].focus_lock);
1182                                 return FALSE;
1183                         }
1184                         /* buf contains data as below,
1185                          * |<--12bits--><--4bits (reacquisition)--><--16bits (handle)-->| */
1186                         buf = (unsigned int)((0x0000ffff & cb_data.handle) | (g_focus_sound_handle[focus_index].auto_reacquire << 16));
1187                         rett = write(tmpfd, &buf, sizeof(buf));
1188                         close(tmpfd);
1189                         g_free(filename2);
1190                         debug_msg("[RETCB] tid(%d) finishing CB (write=%d)\n", tid, rett);
1191                 }
1192 #endif
1193         }
1194
1195         g_mutex_unlock(&g_focus_sound_handle[focus_index].focus_lock);
1196
1197         return TRUE;
1198 }
1199
1200 static gboolean _focus_watch_callback_handler(gpointer d)
1201 {
1202         GPollFD *data = (GPollFD*)d;
1203         int count;
1204         int tid = 0;
1205         int focus_index = 0;
1206         focus_cb_data_lib cb_data;
1207
1208         debug_fenter();
1209
1210         memset(&cb_data, 0, sizeof(focus_cb_data_lib));
1211
1212         if (!data) {
1213                 debug_error("GPollFd is null");
1214                 return FALSE;
1215         }
1216         if (data->revents & (POLLIN | POLLPRI)) {
1217                 count = read(data->fd, &cb_data, sizeof(cb_data));
1218                 if (count < 0){
1219                         char str_error[256];
1220                         strerror_r(errno, str_error, sizeof(str_error));
1221                         debug_error("GpollFD read fail, errno=%d(%s)",errno, str_error);
1222                         return FALSE;
1223                 }
1224
1225                 focus_index = _focus_watch_find_index_by_handle(cb_data.handle);
1226                 if (focus_index == -1) {
1227                         debug_error("Could not find index");
1228                         return FALSE;
1229                 }
1230
1231                 if (!g_focus_sound_handle[focus_index].is_used) {
1232                         debug_warning("unsetting watch calllback has been already requested");
1233                         goto SKIP_CB_AND_RET;
1234                 }
1235
1236                 debug_msg("lock focus_lock = %p", &g_focus_sound_handle[focus_index].focus_lock);
1237                 g_mutex_lock(&g_focus_sound_handle[focus_index].focus_lock);
1238
1239                 tid = g_focus_sound_handle[focus_index].focus_tid;
1240
1241                 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);
1242
1243                 if (g_focus_sound_handle[focus_index].watch_callback == NULL) {
1244                         debug_msg("callback is null..");
1245                 } else {
1246                         debug_msg("[CALLBACK(%p) START]",g_focus_sound_handle[focus_index].watch_callback);
1247                         (g_focus_sound_handle[focus_index].watch_callback)(cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type, cb_data.ext_info, g_focus_sound_handle[focus_index].user_data);
1248                         debug_msg("[CALLBACK END]");
1249                         if (g_focus_session_interrupt_info.user_cb) {
1250                                 debug_msg("sending session interrupt callback(%p)", g_focus_session_interrupt_info.user_cb);
1251                                 (g_focus_session_interrupt_info.user_cb)(cb_data.state, cb_data.stream_type, true, g_focus_session_interrupt_info.user_data);
1252                         }
1253                 }
1254
1255 SKIP_CB_AND_RET:
1256 #ifdef CONFIG_ENABLE_RETCB
1257                 {
1258                         int rett = 0;
1259                         int tmpfd = -1;
1260                         int buf = -1;
1261                         char *filename2 = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr", g_focus_sound_handle[focus_index].focus_tid, cb_data.handle);
1262                         tmpfd = open(filename2, O_WRONLY | O_NONBLOCK);
1263                         if (tmpfd < 0) {
1264                                 char str_error[256];
1265                                 strerror_r(errno, str_error, sizeof(str_error));
1266                                 debug_warning("[RETCB][Failed(May Server Close First)]tid(%d) fd(%d) %s errno=%d(%s)\n", tid, tmpfd, filename2, errno, str_error);
1267                                 g_free(filename2);
1268                                 g_mutex_unlock(&g_focus_sound_handle[focus_index].focus_lock);
1269                                 return FALSE;
1270                         }
1271                         buf = cb_data.handle;
1272                         rett = write(tmpfd, &buf, sizeof(buf));
1273                         close(tmpfd);
1274                         g_free(filename2);
1275                         debug_msg("[RETCB] tid(%d) finishing CB (write=%d)\n", tid, rett);
1276                 }
1277 #endif
1278         }
1279
1280         if (g_focus_sound_handle[focus_index].is_used) {
1281                 debug_msg("unlock focus_lock = %p", &g_focus_sound_handle[focus_index].focus_lock);
1282                 g_mutex_unlock(&g_focus_sound_handle[focus_index].focus_lock);
1283         }
1284
1285         debug_fleave();
1286
1287         return TRUE;
1288 }
1289
1290 static void _focus_open_callback(int index, bool is_for_watching)
1291 {
1292         mode_t pre_mask;
1293         char *filename;
1294
1295         debug_fenter();
1296
1297         if (is_for_watching) {
1298                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", g_focus_sound_handle[index].focus_tid, g_focus_sound_handle[index].handle);
1299         } else {
1300                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d", g_focus_sound_handle[index].focus_tid, g_focus_sound_handle[index].handle);
1301         }
1302         pre_mask = umask(0);
1303         if (mknod(filename, S_IFIFO|0666, 0)) {
1304                 debug_error("mknod() failure, errno(%d)", errno);
1305         }
1306         umask(pre_mask);
1307         g_focus_sound_handle[index].focus_fd = open(filename, O_RDWR|O_NONBLOCK);
1308         if (g_focus_sound_handle[index].focus_fd == -1) {
1309                 debug_error("Open fail : index(%d), file open error(%d)", index, errno);
1310         } else {
1311                 debug_log("Open success : index(%d), filename(%s), fd(%d)", index, filename, g_focus_sound_handle[index].focus_fd);
1312         }
1313         g_free(filename);
1314         filename = NULL;
1315
1316 #ifdef CONFIG_ENABLE_RETCB
1317         char *filename2;
1318
1319         if (is_for_watching) {
1320                 filename2 = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr", g_focus_sound_handle[index].focus_tid, g_focus_sound_handle[index].handle);
1321         } else {
1322                 filename2 = g_strdup_printf("/tmp/FOCUS.%d.%dr", g_focus_sound_handle[index].focus_tid, g_focus_sound_handle[index].handle);
1323         }
1324         pre_mask = umask(0);
1325         if (mknod(filename2, S_IFIFO | 0666, 0)) {
1326                 debug_error("mknod() failure, errno(%d)", errno);
1327         }
1328         umask(pre_mask);
1329         g_free(filename2);
1330         filename2 = NULL;
1331 #endif
1332         debug_fleave();
1333
1334 }
1335
1336 void _focus_close_callback(int index, bool is_for_watching)
1337 {
1338         char *filename = NULL;
1339
1340         debug_fenter();
1341
1342         if (g_focus_sound_handle[index].focus_fd < 0) {
1343                 debug_error("Close fail : index(%d)", index);
1344         } else {
1345                 close(g_focus_sound_handle[index].focus_fd);
1346                 debug_log("Close Success : index(%d)", index);
1347         }
1348
1349         if (is_for_watching) {
1350                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", g_focus_sound_handle[index].focus_tid, g_focus_sound_handle[index].handle);
1351         } else {
1352                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d", g_focus_sound_handle[index].focus_tid, g_focus_sound_handle[index].handle);
1353         }
1354         if (remove(filename)) {
1355                 debug_warning("remove(%s) failure (focus_server probably removed it in advance), errno(%d)", filename, errno);
1356         }
1357         g_free(filename);
1358         filename = NULL;
1359
1360 #ifdef CONFIG_ENABLE_RETCB
1361         char *filename2;
1362
1363         if (is_for_watching) {
1364                 filename2 = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr", g_focus_sound_handle[index].focus_tid, g_focus_sound_handle[index].handle);
1365         } else {
1366                 filename2 = g_strdup_printf("/tmp/FOCUS.%d.%dr", g_focus_sound_handle[index].focus_tid, g_focus_sound_handle[index].handle);
1367         }
1368         if (remove(filename2)) {
1369                 debug_warning("remove(%s) failure (focus_server probably removed it in advance), errno(%d)", filename2, errno);
1370         }
1371         g_free(filename2);
1372         filename2 = NULL;
1373
1374         debug_fleave();
1375 #endif
1376
1377 }
1378
1379 static bool _focus_add_sound_callback(int index, int fd, gushort events, focus_gLoopPollHandler_t p_gloop_poll_handler )
1380 {
1381         GSource* g_src = NULL;
1382         GSourceFuncs *g_src_funcs = NULL;               /* handler function */
1383         guint g_src_id = 0;
1384         GPollFD *g_poll_fd = NULL;                      /* file descriptor */
1385
1386         debug_fenter();
1387
1388         g_mutex_init(&g_focus_sound_handle[index].focus_lock);
1389
1390         /* 1. make GSource Object */
1391         g_src_funcs = (GSourceFuncs *)g_malloc(sizeof(GSourceFuncs));
1392         if (!g_src_funcs) {
1393                 debug_error("failed to g_malloc for g_src_funcs");
1394                 goto ERROR;
1395         }
1396
1397         g_src_funcs->prepare = _focus_fd_prepare;
1398         g_src_funcs->check = _focus_fd_check;
1399         g_src_funcs->dispatch = _focus_fd_dispatch;
1400         g_src_funcs->finalize = NULL;
1401         g_src = g_source_new(g_src_funcs, sizeof(GSource));
1402         if (!g_src) {
1403                 debug_error("failed to g_source_new for g_src");
1404                 goto ERROR;
1405         }
1406
1407         /* 2. add file description which used in g_loop() */
1408         g_poll_fd = (GPollFD *)g_malloc(sizeof(GPollFD));
1409         if (!g_poll_fd) {
1410                 debug_error("failed to g_malloc for g_poll_fd");
1411                 goto ERROR;
1412         }
1413         g_poll_fd->fd = fd;
1414         g_poll_fd->events = events;
1415
1416         /* 3. combine g_source object and file descriptor */
1417         g_source_add_poll(g_src, g_poll_fd);
1418         g_src_id = g_source_attach(g_src, g_main_loop_get_context(g_focus_loop));
1419         if (!g_src_id) {
1420                 debug_error("failed to attach the source to context");
1421                 goto ERROR;
1422         }
1423
1424         /* 4. set callback */
1425         g_source_set_callback(g_src, p_gloop_poll_handler,(gpointer)g_poll_fd, NULL);
1426
1427         debug_log("g_malloc : g_src_funcs(%p), g_poll_fd(%p)", g_src_funcs, g_poll_fd);
1428
1429         /* 5. store to global handle */
1430         g_focus_sound_handle[index].focus_src = g_src;
1431         g_focus_sound_handle[index].g_src_funcs = g_src_funcs;
1432         g_focus_sound_handle[index].g_poll_fd = g_poll_fd;
1433
1434         debug_fleave();
1435         return true;
1436
1437 ERROR:
1438         g_free(g_src_funcs);
1439         g_free(g_poll_fd);
1440         if (g_src)
1441                 g_source_unref(g_src);
1442
1443         return false;
1444 }
1445
1446 static bool _focus_remove_sound_callback(int index)
1447 {
1448         bool ret = true;
1449         focus_sound_info_t *h = NULL;
1450
1451         debug_fenter();
1452
1453         h = &g_focus_sound_handle[index];
1454         if (h == NULL) {
1455                 debug_error("g_focus_sound_handle[%d] is NULL", index);
1456                 return false;
1457         }
1458
1459         if (h->focus_src && h->g_poll_fd) {
1460                 debug_log("g_source_remove_poll : fd(%d), event(0x%x)",
1461                                 h->g_poll_fd->fd, h->g_poll_fd->events);
1462                 g_source_remove_poll(h->focus_src, h->g_poll_fd);
1463         } else {
1464                 debug_error("[%d] focus_src[%p], g_poll_fd[%p]",
1465                                         index, h->focus_src, h->g_poll_fd);
1466                 ret = false;
1467         }
1468
1469         if (h->focus_src) {
1470                 g_source_destroy(h->focus_src);
1471                 g_source_unref(h->focus_src);
1472                 h->focus_src = NULL;
1473         }
1474
1475         debug_log("g_free : g_src_funcs(%p), g_poll_fd(%p)",
1476                         h->g_src_funcs, h->g_poll_fd);
1477
1478         g_free(h->g_src_funcs);
1479         h->g_src_funcs = NULL;
1480
1481         g_free(h->g_poll_fd);
1482         h->g_poll_fd = NULL;
1483
1484         h->focus_callback = NULL;
1485         h->watch_callback = NULL;
1486
1487         g_mutex_clear(&h->focus_lock);
1488
1489         debug_fleave();
1490
1491         return ret;
1492 }
1493
1494
1495 static void _focus_add_callback(int index, bool is_for_watching)
1496 {
1497         debug_fenter();
1498         if (!is_for_watching) {
1499                 if (!_focus_add_sound_callback(index, g_focus_sound_handle[index].focus_fd,
1500                                                                         (gushort)POLLIN | POLLPRI, _focus_callback_handler))
1501                         debug_error("failed to _focus_add_sound_callback(%p)", _focus_callback_handler);
1502         } else { // need to check if it's necessary
1503                 if (!_focus_add_sound_callback(index, g_focus_sound_handle[index].focus_fd,
1504                                                                         (gushort)POLLIN | POLLPRI, _focus_watch_callback_handler))
1505                         debug_error("failed to _focus_add_sound_callback(%p)", _focus_watch_callback_handler);
1506         }
1507         debug_fleave();
1508 }
1509
1510 static void _focus_remove_callback(int index)
1511 {
1512         debug_fenter();
1513         if (!_focus_remove_sound_callback(index))
1514                 debug_error("failed to __focus_remove_sound_callback()");
1515         debug_fleave();
1516 }
1517
1518 static void _focus_init_callback(int index, bool is_for_watching)
1519 {
1520         debug_fenter();
1521         _focus_open_callback(index, is_for_watching);
1522         _focus_add_callback(index, is_for_watching);
1523         debug_fleave();
1524 }
1525
1526 static void _focus_destroy_callback(int index, bool is_for_watching)
1527 {
1528         debug_fenter();
1529         _focus_remove_callback(index);
1530         _focus_close_callback(index, is_for_watching);
1531         debug_fleave();
1532 }
1533
1534 int mm_sound_client_get_unique_id(int *id)
1535 {
1536         int ret = MM_ERROR_NONE;
1537
1538         debug_fenter();
1539
1540         if (!id)
1541                 ret = MM_ERROR_INVALID_ARGUMENT;
1542         else
1543                 ret = mm_sound_proxy_get_unique_id(id);
1544
1545         debug_fleave();
1546
1547         return ret;
1548 }
1549
1550 int mm_sound_client_is_focus_cb_thread(GThread *mine, bool *result)
1551 {
1552         int ret = MM_ERROR_NONE;
1553
1554         if (!mine || !result)
1555                 ret = MM_ERROR_INVALID_ARGUMENT;
1556         else {
1557                 if (mine == g_focus_thread)
1558                         *result = true;
1559                 else
1560                         *result = false;
1561         }
1562
1563         return ret;
1564 }
1565
1566 int mm_sound_client_register_focus(int id, int pid, const char *stream_type, mm_sound_focus_changed_cb callback, bool is_for_session, void* user_data)
1567 {
1568         int ret = MM_ERROR_NONE;
1569         int instance;
1570         int index = 0;
1571
1572         debug_fenter();
1573         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1574
1575         instance = pid;
1576
1577         for (index = 0; index < FOCUS_HANDLE_MAX - 1; index++) {
1578                 if (g_focus_sound_handle[index].is_used == false) {
1579                         g_focus_sound_handle[index].is_used = true;
1580                         break;
1581                 }
1582         }
1583
1584         g_focus_sound_handle[index].focus_tid = instance;
1585         g_focus_sound_handle[index].handle = id;
1586         g_focus_sound_handle[index].focus_callback = callback;
1587         g_focus_sound_handle[index].user_data = user_data;
1588         g_focus_sound_handle[index].is_for_session = is_for_session;
1589         g_focus_sound_handle[index].auto_reacquire = true;
1590
1591         ret = mm_sound_proxy_register_focus(id, pid, stream_type, callback, is_for_session, user_data);
1592
1593         if (ret == MM_ERROR_NONE) {
1594                 debug_msg("[Client] Success to register focus\n");
1595                 g_need_emergent_exit = TRUE;
1596                 if (!g_focus_thread) {
1597                         GMainContext* focus_context = g_main_context_new ();
1598                         g_focus_loop = g_main_loop_new (focus_context, FALSE);
1599                         g_main_context_unref(focus_context);
1600                         if (g_focus_loop == NULL) {
1601                                 debug_error("could not create mainloop..");
1602                                 ret = MM_ERROR_SOUND_INTERNAL;
1603                                 goto cleanup;
1604                         }
1605
1606                         g_focus_thread = g_thread_new("focus-cb-thread", _focus_thread_func, NULL);
1607                         if (g_focus_thread == NULL) {
1608                                 debug_error("could not create thread..");
1609                                 g_main_loop_unref(g_focus_loop);
1610                                 ret = MM_ERROR_SOUND_INTERNAL;
1611                                 goto cleanup;
1612                         }
1613                 } else {
1614                         debug_warning("focus thread(%p) with mainloop(%p) exists, skip thread creation",
1615                                                 g_focus_thread, g_focus_loop);
1616                 }
1617         } else {
1618                 debug_error("[Client] Error occurred : 0x%x \n",ret);
1619                 goto cleanup;
1620         }
1621
1622         _focus_init_callback(index, false);
1623
1624 cleanup:
1625
1626         if (ret) {
1627                 g_focus_sound_handle[index].is_used = false;
1628         }
1629
1630         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1631         debug_fleave();
1632
1633         return ret;
1634 }
1635
1636 int mm_sound_client_unregister_focus(int id)
1637 {
1638         int ret = MM_ERROR_NONE;
1639         int instance;
1640         int index = -1;
1641
1642         debug_fenter();
1643         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1644
1645         index = _focus_find_index_by_handle(id);
1646         if (index == -1) {
1647                 debug_error("Could not find index");
1648                 ret = MM_ERROR_INVALID_ARGUMENT;
1649                 goto cleanup;
1650         }
1651         instance = g_focus_sound_handle[index].focus_tid;
1652
1653         if (!g_mutex_trylock(&g_focus_sound_handle[index].focus_lock)) {
1654                 debug_warning("maybe focus_callback is being called, try one more time..");
1655                 usleep(2500000); // 2.5 sec
1656                 if (g_mutex_trylock(&g_focus_sound_handle[index].focus_lock)) {
1657                         debug_msg("finally got focus_lock");
1658                 }
1659         }
1660
1661         ret = mm_sound_proxy_unregister_focus(instance, id, g_focus_sound_handle[index].is_for_session);
1662
1663         if (ret == MM_ERROR_NONE)
1664                 debug_msg("[Client] Success to unregister focus\n");
1665         else
1666                 debug_error("[Client] Error occurred : 0x%x \n",ret);
1667
1668         g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1669
1670         _focus_destroy_callback(index, false);
1671         g_focus_sound_handle[index].focus_fd = 0;
1672         g_focus_sound_handle[index].focus_tid = 0;
1673         g_focus_sound_handle[index].handle = 0;
1674         g_focus_sound_handle[index].is_used = false;
1675 cleanup:
1676         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1677         debug_fleave();
1678         return ret;
1679 }
1680
1681 int mm_sound_client_set_focus_reacquisition(int id, bool reacquisition)
1682 {
1683         int ret = MM_ERROR_NONE;
1684         int instance;
1685         int index = -1;
1686         bool result;
1687
1688         debug_fenter();
1689         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1690
1691         index = _focus_find_index_by_handle(id);
1692         if (index == -1) {
1693                 debug_error("Could not find index");
1694                 ret = MM_ERROR_INVALID_ARGUMENT;
1695                 goto cleanup;
1696         }
1697         instance = g_focus_sound_handle[index].focus_tid;
1698
1699         ret = mm_sound_client_is_focus_cb_thread(g_thread_self(), &result);
1700         if (ret) {
1701                 debug_error("[Client] mm_sound_client_is_focus_cb_thread failed");
1702                 goto cleanup;
1703         } else if (!result) {
1704                 ret = mm_sound_proxy_set_foucs_reacquisition(instance, id, reacquisition);
1705                 if (ret == MM_ERROR_NONE) {
1706                         debug_msg("[Client] Success to set focus reacquisition to [%d]\n", reacquisition);
1707                 } else {
1708                         debug_error("[Client] Error occurred : 0x%x \n",ret);
1709                         goto cleanup;
1710                 }
1711         } else {
1712                 debug_warning("[Client] Inside the focus cb thread, set focus reacquisition to [%d]\n", reacquisition);
1713         }
1714
1715         g_focus_sound_handle[index].auto_reacquire = reacquisition;
1716
1717 cleanup:
1718         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1719         debug_fleave();
1720         return ret;
1721 }
1722
1723 int mm_sound_client_get_focus_reacquisition(int id, bool *reacquisition)
1724 {
1725         int ret = MM_ERROR_NONE;
1726         int index = -1;
1727
1728         debug_fenter();
1729
1730         if (!reacquisition) {
1731                 debug_error("Invalid parameter");
1732                 return MM_ERROR_INVALID_ARGUMENT;
1733         }
1734
1735         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1736
1737         index = _focus_find_index_by_handle(id);
1738         if (index == -1) {
1739                 debug_error("Could not find index");
1740                 ret = MM_ERROR_INVALID_ARGUMENT;
1741                 goto cleanup;
1742         }
1743
1744         *reacquisition = g_focus_sound_handle[index].auto_reacquire;
1745
1746 cleanup:
1747         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1748         debug_fleave();
1749         return ret;
1750 }
1751
1752 int mm_sound_client_get_acquired_focus_stream_type(int focus_type, char **stream_type, int *option, char **ext_info)
1753 {
1754         int ret = MM_ERROR_NONE;
1755         char *ext_str = NULL;
1756
1757         debug_fenter();
1758
1759         ret = mm_sound_proxy_get_acquired_focus_stream_type(focus_type, stream_type, option, &ext_str);
1760         if (ret == MM_ERROR_NONE) {
1761                 debug_msg("[Client] Success to get stream type of acquired focus, stream_type(%s), ext_info(%s)\n", *stream_type, ext_str);
1762                 *ext_info = strdup(ext_str);
1763                 g_free(ext_str);
1764         } else {
1765                 debug_error("[Client] Error occurred : 0x%x \n",ret);
1766         }
1767
1768         debug_fleave();
1769         return ret;
1770 }
1771
1772 int mm_sound_client_acquire_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1773 {
1774         int ret = MM_ERROR_NONE;
1775         int instance;
1776         int index = -1;
1777
1778         debug_fenter();
1779         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1780
1781         index = _focus_find_index_by_handle(id);
1782         if (index == -1) {
1783                 debug_error("Could not find index");
1784                 ret = MM_ERROR_INVALID_ARGUMENT;
1785                 goto cleanup;
1786         }
1787         instance = g_focus_sound_handle[index].focus_tid;
1788
1789         ret = mm_sound_proxy_acquire_focus(instance, id, type, option, ext_info, g_focus_sound_handle[index].is_for_session);
1790         if (ret == MM_ERROR_NONE)
1791                 debug_msg("[Client] Success to acquire focus\n");
1792         else
1793                 debug_error("[Client] Error occurred : 0x%x \n",ret);
1794
1795 cleanup:
1796         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1797         debug_fleave();
1798         return ret;
1799 }
1800
1801 int mm_sound_client_release_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1802 {
1803         int ret = MM_ERROR_NONE;
1804         int instance;
1805         int index = -1;
1806
1807         debug_fenter();
1808         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1809
1810         index = _focus_find_index_by_handle(id);
1811         if (index == -1) {
1812                 debug_error("Could not find index");
1813                 ret = MM_ERROR_INVALID_ARGUMENT;
1814                 goto cleanup;
1815         }
1816         instance = g_focus_sound_handle[index].focus_tid;
1817
1818         ret = mm_sound_proxy_release_focus(instance, id, type, option, ext_info, g_focus_sound_handle[index].is_for_session);
1819         if (ret == MM_ERROR_NONE)
1820                 debug_msg("[Client] Success to release focus\n");
1821         else
1822                 debug_error("[Client] Error occurred : 0x%x \n",ret);
1823
1824 cleanup:
1825         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1826         debug_fleave();
1827         return ret;
1828 }
1829
1830 int mm_sound_client_set_focus_watch_callback(int pid, mm_sound_focus_type_e focus_type, mm_sound_focus_changed_watch_cb callback, bool is_for_session, void* user_data, int *id)
1831 {
1832         int ret = MM_ERROR_NONE;
1833         int instance;
1834         int index = 0;
1835
1836         debug_fenter();
1837
1838         if (!id)
1839                 return MM_ERROR_INVALID_ARGUMENT;
1840
1841         //pthread_mutex_lock(&g_thread_mutex2);
1842
1843         instance = pid;
1844
1845         ret = mm_sound_proxy_get_unique_id(id);
1846         if (ret)
1847                 return ret;
1848
1849         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1850
1851         for (index = 0; index < FOCUS_HANDLE_MAX - 1; index++) {
1852                 if (g_focus_sound_handle[index].is_used == false) {
1853                         g_focus_sound_handle[index].is_used = true;
1854                         break;
1855                 }
1856         }
1857
1858         g_focus_sound_handle[index].focus_tid = instance;
1859         g_focus_sound_handle[index].handle = *id;
1860         g_focus_sound_handle[index].watch_callback = callback;
1861         g_focus_sound_handle[index].user_data = user_data;
1862         g_focus_sound_handle[index].is_for_session = is_for_session;
1863
1864         ret = mm_sound_proxy_set_focus_watch_callback(pid, g_focus_sound_handle[index].handle, focus_type, callback, is_for_session, user_data);
1865
1866         if (ret == MM_ERROR_NONE) {
1867                 debug_msg("[Client] Success to watch focus");
1868                 g_need_emergent_exit = TRUE;
1869                 if (!g_focus_thread) {
1870                         GMainContext* focus_context = g_main_context_new ();
1871                         g_focus_loop = g_main_loop_new (focus_context, FALSE);
1872                         g_main_context_unref(focus_context);
1873                         if (g_focus_loop == NULL) {
1874                                 debug_error("could not create mainloop..");
1875                                 ret = MM_ERROR_SOUND_INTERNAL;
1876                                 goto cleanup;
1877                         }
1878
1879                         g_focus_thread = g_thread_new("focus-cb-thread", _focus_thread_func, NULL);
1880                         if (g_focus_thread == NULL) {
1881                                 debug_error ("could not create thread..");
1882                                 g_main_loop_unref(g_focus_loop);
1883                                 ret = MM_ERROR_SOUND_INTERNAL;
1884                                 goto cleanup;
1885                         }
1886                 } else {
1887                         debug_warning("focus thread(%p) with mainloop(%p) exists, skip thread creation",
1888                                                 g_focus_thread, g_focus_loop);
1889                 }
1890         } else {
1891                 debug_error("[Client] Error occurred : 0x%x",ret);
1892                 goto cleanup;
1893         }
1894
1895         _focus_init_callback(index, true);
1896
1897 cleanup:
1898
1899         if (ret) {
1900                 g_focus_sound_handle[index].is_used = false;
1901         }
1902
1903         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1904         debug_fleave();
1905         return ret;
1906 }
1907
1908 int mm_sound_client_unset_focus_watch_callback(int id)
1909 {
1910         int ret = MM_ERROR_NONE;
1911         int index = -1;
1912         debug_fenter();
1913         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1914
1915         index = _focus_watch_find_index_by_handle(id);
1916         if (index == -1) {
1917                 debug_error("Could not find index");
1918                 ret = MM_ERROR_INVALID_ARGUMENT;
1919                 goto cleanup;
1920         }
1921
1922         g_mutex_lock(&g_focus_sound_handle[index].focus_lock);
1923
1924         g_focus_sound_handle[index].is_used = false;
1925
1926         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);
1927
1928         if (ret == MM_ERROR_NONE)
1929                 debug_msg("[Client] Success to unwatch focus\n");
1930         else
1931                 debug_error("[Client] Error occurred : 0x%x \n",ret);
1932
1933
1934         g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1935
1936         _focus_destroy_callback(index, true);
1937         g_focus_sound_handle[index].focus_fd = 0;
1938         g_focus_sound_handle[index].focus_tid = 0;
1939         g_focus_sound_handle[index].handle = 0;
1940 cleanup:
1941         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1942         debug_fleave();
1943         return ret;
1944 }
1945 #endif
1946
1947
1948 int mm_sound_client_add_test_callback(mm_sound_test_cb func, void* user_data, unsigned int *subs_id)
1949 {
1950         int ret = MM_ERROR_NONE;
1951
1952         debug_fenter();
1953
1954         ret = mm_sound_proxy_add_test_callback(func, user_data, g_free, subs_id);
1955
1956         debug_fleave();
1957         return ret;
1958 }
1959
1960 int mm_sound_client_remove_test_callback(unsigned int subs_id)
1961 {
1962         int ret = MM_ERROR_NONE;
1963         debug_fenter();
1964
1965         ret = mm_sound_proxy_remove_test_callback(subs_id);
1966
1967         debug_fleave();
1968         return ret;
1969 }
1970
1971
1972 int mm_sound_client_test(int a, int b, int* getv)
1973 {
1974         int ret = MM_ERROR_NONE;
1975
1976         debug_fenter();
1977
1978         ret = mm_sound_proxy_test(a, b, getv);
1979         debug_log("%d * %d -> result : %d", a, b, *getv);
1980
1981         debug_fleave();
1982
1983         return ret;
1984 }