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