Manage focus cb thread and focus watch cb thread separately
[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 <unistd.h>
24 #include <errno.h>
25 #include <pthread.h>
26 #include <glib.h>
27 #include <mm_error.h>
28 #include <mm_debug.h>
29 #include <vconf.h>
30
31 #include "include/mm_sound.h"
32 #include "include/mm_sound_client.h"
33 #include "include/mm_sound_proxy.h"
34 #include "include/mm_sound_common.h"
35 #include "include/mm_sound_device.h"
36 #include "include/mm_sound_stream.h"
37 #include "include/mm_sound_focus_private.h"
38
39 #define CLIENT_HANDLE_MAX 256
40 #define VOLUME_TYPE_LEN 64
41 #define VOLUME_MAX_MULTIMEDIA   16
42 #define VOLUME_MAX_BASIC                8
43
44 #define VCONF_KEY_VOLUME_PREFIX                         "file/private/sound/volume"
45 #define VCONF_KEY_VOLUME_TYPE_SYSTEM            VCONF_KEY_VOLUME_PREFIX"/system"
46 #define VCONF_KEY_VOLUME_TYPE_NOTIFICATION      VCONF_KEY_VOLUME_PREFIX"/notification"
47 #define VCONF_KEY_VOLUME_TYPE_ALARM                     VCONF_KEY_VOLUME_PREFIX"/alarm"
48 #define VCONF_KEY_VOLUME_TYPE_RINGTONE          VCONF_KEY_VOLUME_PREFIX"/ringtone"
49 #define VCONF_KEY_VOLUME_TYPE_MEDIA                     VCONF_KEY_VOLUME_PREFIX"/media"
50 #define VCONF_KEY_VOLUME_TYPE_CALL                      VCONF_KEY_VOLUME_PREFIX"/call"
51 #define VCONF_KEY_VOLUME_TYPE_VOIP                      VCONF_KEY_VOLUME_PREFIX"/voip"
52 #define VCONF_KEY_VOLUME_TYPE_VOICE             VCONF_KEY_VOLUME_PREFIX"/voice"
53 #define VCONF_KEY_VOLUME_TYPE_ANDROID           VCONF_KEY_VOLUME_PREFIX"/fixed"
54
55 #define VCONF_KEY_MUTE_PREFIX                           "file/private/sound/mute"
56 #define VCONF_KEY_MUTE_TYPE_SYSTEM              VCONF_KEY_MUTE_PREFIX"/system"
57 #define VCONF_KEY_MUTE_TYPE_NOTIFICATION        VCONF_KEY_MUTE_PREFIX"/notification"
58 #define VCONF_KEY_MUTE_TYPE_ALARM                       VCONF_KEY_MUTE_PREFIX"/alarm"
59 #define VCONF_KEY_MUTE_TYPE_RINGTONE            VCONF_KEY_MUTE_PREFIX"/ringtone"
60 #define VCONF_KEY_MUTE_TYPE_MEDIA                       VCONF_KEY_MUTE_PREFIX"/media"
61 #define VCONF_KEY_MUTE_TYPE_CALL                        VCONF_KEY_MUTE_PREFIX"/call"
62 #define VCONF_KEY_MUTE_TYPE_VOIP                        VCONF_KEY_MUTE_PREFIX"/voip"
63 #define VCONF_KEY_MUTE_TYPE_VOICE               VCONF_KEY_MUTE_PREFIX"/voice"
64
65 static char *g_volume_vconf[VOLUME_TYPE_MAX] = {
66         VCONF_KEY_VOLUME_TYPE_SYSTEM,           /* VOLUME_TYPE_SYSTEM */
67         VCONF_KEY_VOLUME_TYPE_NOTIFICATION,     /* VOLUME_TYPE_NOTIFICATION */
68         VCONF_KEY_VOLUME_TYPE_ALARM,            /* VOLUME_TYPE_ALARM */
69         VCONF_KEY_VOLUME_TYPE_RINGTONE,         /* VOLUME_TYPE_RINGTONE */
70         VCONF_KEY_VOLUME_TYPE_MEDIA,            /* VOLUME_TYPE_MEDIA */
71         VCONF_KEY_VOLUME_TYPE_CALL,                     /* VOLUME_TYPE_CALL */
72         VCONF_KEY_VOLUME_TYPE_VOIP,                     /* VOLUME_TYPE_VOIP */
73         VCONF_KEY_VOLUME_TYPE_VOICE,            /* VOLUME_TYPE_VOICE */
74         VCONF_KEY_VOLUME_TYPE_ANDROID           /* VOLUME_TYPE_FIXED */
75 };
76
77 static char *g_mute_vconf[] = {
78         VCONF_KEY_MUTE_TYPE_SYSTEM,             /* MUTE_TYPE_SYSTEM */
79         VCONF_KEY_MUTE_TYPE_NOTIFICATION,       /* MUTE_TYPE_NOTIFICATION */
80         VCONF_KEY_MUTE_TYPE_ALARM,              /* MUTE_TYPE_ALARM */
81         VCONF_KEY_MUTE_TYPE_RINGTONE,           /* MUTE_TYPE_RINGTONE */
82         VCONF_KEY_MUTE_TYPE_MEDIA,              /* MUTE_TYPE_MEDIA */
83         VCONF_KEY_MUTE_TYPE_CALL,                       /* MUTE_TYPE_CALL */
84         VCONF_KEY_MUTE_TYPE_VOIP,                       /* MUTE_TYPE_VOIP */
85         VCONF_KEY_MUTE_TYPE_VOICE,              /* MUTE_TYPE_VOICE */
86 };
87
88 static char *g_volume_str[VOLUME_TYPE_MAX] = {
89         "SYSTEM",
90         "NOTIFICATION",
91         "ALARM",
92         "RINGTONE",
93         "MEDIA",
94         "CALL",
95         "VOIP",
96         "VOICE",
97         "FIXED",
98 };
99
100 struct callback_data {
101         void *user_cb;
102         void *user_data;
103         void *extra_data;
104         guint subs_id;
105 };
106
107 #define GET_CB_DATA(_cb_data, _func, _userdata, _extradata) \
108         do { \
109                 _cb_data = (struct callback_data*) g_malloc0(sizeof(struct callback_data)); \
110                 _cb_data->user_cb = _func; \
111                 _cb_data->user_data = _userdata; \
112                 _cb_data->extra_data = _extradata; \
113         } while (0)
114
115 static pthread_mutex_t g_index_mutex = PTHREAD_MUTEX_INITIALIZER;
116 static pthread_mutex_t g_event_mutex = PTHREAD_MUTEX_INITIALIZER;
117 guint g_idle_event_src;
118
119 typedef struct {
120         /* handle to watch end of playing */
121         int watching_handle;
122         /* subscription id to unsubscribe when handle ended */
123         unsigned subs_id;
124 } play_sound_end_callback_data_t;
125
126 typedef struct _focus_idle_event {
127         focus_idle_event_type_e type;
128         int data;
129 } focus_idle_event_t;
130
131 static int _validate_volume(volume_type_t type, int level)
132 {
133         if (level < 0)
134                 return -1;
135
136         switch (type) {
137         case VOLUME_TYPE_CALL:
138         case VOLUME_TYPE_VOIP:
139                 if (level >= VOLUME_MAX_BASIC) {
140                         return -1;
141                 }
142                 break;
143         case VOLUME_TYPE_SYSTEM:
144         case VOLUME_TYPE_MEDIA:
145         case VOLUME_TYPE_ALARM:
146         case VOLUME_TYPE_NOTIFICATION:
147         case VOLUME_TYPE_RINGTONE:
148         case VOLUME_TYPE_VOICE:
149                 if (level >= VOLUME_MAX_MULTIMEDIA) {
150                         return -1;
151                 }
152                 break;
153         default:
154                 return -1;
155                 break;
156         }
157         return 0;
158 }
159
160 int mm_sound_client_initialize(void)
161 {
162         int ret = MM_ERROR_NONE;
163
164         debug_fenter();
165
166         mm_sound_proxy_initialize();
167         g_idle_event_src = 0;
168
169         debug_fleave();
170         return ret;
171 }
172
173 int mm_sound_client_finalize(void)
174 {
175         int ret = MM_ERROR_NONE;
176
177         debug_fenter();
178
179         ret = mm_sound_proxy_finalize();
180
181         if (g_idle_event_src > 0) {
182                 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL);
183                 g_source_remove(g_idle_event_src);
184                 MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex);
185         }
186
187         debug_fleave();
188         return ret;
189 }
190
191 void mm_sound_convert_volume_type_to_stream_type(int volume_type, char *stream_type)
192 {
193         switch (volume_type) {
194         case VOLUME_TYPE_SYSTEM:
195                 MMSOUND_STRNCPY(stream_type, "system", MAX_STREAM_TYPE_LEN);
196                 break;
197         case VOLUME_TYPE_NOTIFICATION:
198                 MMSOUND_STRNCPY(stream_type, "notification", MAX_STREAM_TYPE_LEN);
199                 break;
200         case VOLUME_TYPE_ALARM:
201                 MMSOUND_STRNCPY(stream_type, "alarm", MAX_STREAM_TYPE_LEN);
202                 break;
203         case VOLUME_TYPE_RINGTONE:
204                 MMSOUND_STRNCPY(stream_type, "ringtone-voip", MAX_STREAM_TYPE_LEN);
205                 break;
206         case VOLUME_TYPE_MEDIA:
207                 MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN);
208                 break;
209         case VOLUME_TYPE_CALL:
210                 MMSOUND_STRNCPY(stream_type, "call-voice", MAX_STREAM_TYPE_LEN);
211                 break;
212         case VOLUME_TYPE_VOIP:
213                 MMSOUND_STRNCPY(stream_type, "voip", MAX_STREAM_TYPE_LEN);
214                 break;
215         case VOLUME_TYPE_VOICE:
216                 MMSOUND_STRNCPY(stream_type, "voice-information", MAX_STREAM_TYPE_LEN);
217                 break;
218         default:
219                 MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN);
220                 break;
221         }
222
223         debug_msg("volume type (%d) converted to stream type (%s)", volume_type, stream_type);
224
225 }
226
227 /*****************************************************************************************
228                             DBUS SUPPORTED FUNCTIONS
229 ******************************************************************************************/
230 int mm_sound_client_play_tone_with_stream_info(int tone, char *stream_type, int stream_id,
231                                                                                         double volume, int duration, int *handle)
232 {
233         int ret = MM_ERROR_NONE;
234
235         debug_fenter();
236
237         ret = mm_sound_proxy_play_tone_with_stream_info(getpid(), tone, stream_type, stream_id, volume, duration, handle);
238
239         debug_fleave();
240         return ret;
241 }
242
243 static void _mm_sound_stop_callback_wrapper_func(int ended_handle, void *userdata)
244 {
245         struct callback_data *cb_data = (struct callback_data*) userdata;
246         play_sound_end_callback_data_t *end_cb_data;
247
248         debug_log("ended_handle : %d", ended_handle);
249
250         if (cb_data == NULL) {
251                 debug_warning("stop callback data null");
252                 return;
253         }
254
255         end_cb_data = (play_sound_end_callback_data_t*) cb_data->extra_data;
256
257         if (ended_handle == end_cb_data->watching_handle) {
258                 debug_log("Interested playing handle end : %d", ended_handle);
259                 ((mm_sound_stop_callback_func)(cb_data->user_cb))(cb_data->user_data, ended_handle);
260                 if (mm_sound_proxy_remove_play_sound_end_callback(end_cb_data->subs_id) != MM_ERROR_NONE)
261                         debug_error("mm_sound_client_dbus_remove_play_file_end_callback failed");
262         } else {
263                 debug_log("Not interested playing handle : %d", ended_handle);
264         }
265 }
266
267 static void play_end_callback_data_free_func(void *data)
268 {
269         struct callback_data *cb_data = (struct callback_data*) data;
270
271         if (cb_data) {
272                 g_free(cb_data->extra_data);
273                 g_free(cb_data);
274         }
275 }
276
277 int mm_sound_client_play_sound_with_stream_info(MMSoundPlayParam *param, int *handle, char* stream_type, int stream_id)
278 {
279         int ret = MM_ERROR_NONE;
280         struct callback_data *cb_data = NULL;
281         play_sound_end_callback_data_t *end_cb_data;
282
283         ret = mm_sound_proxy_play_sound_with_stream_info(param->filename, param->loop, param->volume,
284                                                                                                         getpid(), handle, stream_type, stream_id);
285         if (ret != MM_ERROR_NONE) {
286                 debug_error("Play Sound Failed");
287                 goto failed;
288         }
289         if (param->callback) {
290                 end_cb_data = (play_sound_end_callback_data_t *) g_malloc0(sizeof(play_sound_end_callback_data_t));
291                 end_cb_data->watching_handle = *handle;
292                 GET_CB_DATA(cb_data, param->callback, param->data, end_cb_data);
293
294                 ret = mm_sound_proxy_add_play_sound_end_callback(_mm_sound_stop_callback_wrapper_func, cb_data,
295                                                                                                                 play_end_callback_data_free_func, &end_cb_data->subs_id);
296                 if (ret != MM_ERROR_NONE)
297                         debug_error("Add callback for play sound(%d) Failed", *handle);
298         }
299
300 failed:
301
302         debug_fleave();
303         return ret;
304
305 }
306
307 int mm_sound_client_stop_sound(int handle)
308 {
309         int ret = MM_ERROR_NONE;
310         debug_fenter();
311
312         if (handle < 0 || handle > CLIENT_HANDLE_MAX) {
313                 ret = MM_ERROR_INVALID_ARGUMENT;
314                 return ret;
315         }
316
317         ret = mm_sound_proxy_stop_sound(handle);
318
319         debug_fleave();
320         return ret;
321 }
322
323 static int _mm_sound_client_device_list_dump(GList *device_list)
324 {
325         int ret = MM_ERROR_NONE;
326         GList *list = NULL;
327         mm_sound_device_t *device_node = NULL;
328         int count = 0;
329         if (!device_list) {
330                 debug_error("Device list NULL, cannot dump list");
331                 return MM_ERROR_SOUND_INTERNAL;
332         }
333
334         debug_log("======================== device list : start ==========================");
335         for (list = device_list; list != NULL; list = list->next) {
336                 device_node = (mm_sound_device_t *)list->data;
337                 if (device_node) {
338                         debug_log(" list idx[%d]: type[%17s], id[%02d], io_direction[%d], state[%d], name[%s]",
339                                                 count++, device_node->type, device_node->id, device_node->io_direction,
340                                                 device_node->state, device_node->name);
341                 }
342         }
343         debug_log("======================== device list : end ============================");
344
345         return ret;
346 }
347
348 int mm_sound_client_get_current_connected_device_list(int device_flags, mm_sound_device_list_t *device_list)
349 {
350         int ret = MM_ERROR_NONE;
351         debug_fenter();
352
353         if (!device_list) {
354                 debug_error("Device list NULL");
355                 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
356                 goto failed;
357         }
358
359         if ((ret = mm_sound_proxy_get_current_connected_device_list(device_flags, &device_list->list)) != MM_ERROR_NONE) {
360                 debug_error("failed to get current connected device list with dbus, ret[0x%x]", ret);
361                 goto failed;
362         }
363         if (!device_list->list) {
364                 debug_error("Got device list null");
365                 ret = MM_ERROR_SOUND_NO_DATA;
366                 goto failed;
367         }
368         _mm_sound_client_device_list_dump(device_list->list);
369
370 failed:
371         debug_fleave();
372         return ret;
373 }
374
375 int mm_sound_client_get_device_by_id(int device_id, mm_sound_device_t **device)
376 {
377         int ret = MM_ERROR_NONE;
378
379         debug_fenter();
380
381         if ((ret = mm_sound_proxy_get_device_by_id(device_id, device)) != MM_ERROR_NONE)
382                 debug_error("failed to get device by id");
383
384         debug_fleave();
385
386         return ret;
387 }
388
389 static bool device_is_match_direction(int direction, int mask)
390 {
391         if (mask == DEVICE_IO_DIRECTION_FLAGS || mask == 0)
392                 return true;
393
394         if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_IN))
395                 return true;
396         if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_OUT))
397                 return true;
398         if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH))
399                 return true;
400
401         return false;
402 }
403
404 static bool device_is_match_state(int state, int mask)
405 {
406         if (mask == DEVICE_STATE_FLAGS || mask == 0)
407                 return true;
408
409         if ((mask & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_DEACTIVATED))
410                 return true;
411         if ((mask & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_ACTIVATED))
412                 return true;
413
414         return false;
415 }
416
417 static bool device_is_match_type(const char *type, int mask)
418 {
419         bool is_builtin;
420         const char *builtin_prefix = "builtin";
421
422         if (mask == DEVICE_TYPE_FLAGS || mask == 0)
423                 return true;
424
425         is_builtin = !strncmp(type, builtin_prefix, strlen(builtin_prefix));
426
427         if ((mask & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG) && (is_builtin))
428                 return true;
429         if ((mask & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG) && (!is_builtin))
430                 return true;
431
432         return false;
433 }
434
435 static bool device_is_match_with_mask(const char *type, int direction, int state, int mask)
436 {
437         if (mask == DEVICE_ALL_FLAG)
438                 return true;
439
440         return (device_is_match_direction(direction, mask & DEVICE_IO_DIRECTION_FLAGS) &&
441                         device_is_match_state(state, mask & DEVICE_STATE_FLAGS) &&
442                         device_is_match_type(type, mask & DEVICE_TYPE_FLAGS));
443 }
444
445 static int _fill_sound_device(mm_sound_device_t *device_h, int device_id, const char *device_type,
446                 int direction, int state, const char *name, int vendor_id, int product_id,
447                 int *stream_id, int stream_num, bool is_running)
448 {
449         int i;
450
451         if (stream_num > 0 && stream_id == NULL) {
452                 debug_error("stream_num is %d, but stream_id is NULL", stream_num);
453                 return -1;
454         }
455
456         if (stream_num > MAX_STREAM_ON_DEVICE) {
457                 debug_error("too many streams on this device");
458                 return -1;
459         }
460
461         device_h->id = device_id;
462         device_h->io_direction = direction;
463         device_h->state = state;
464         MMSOUND_STRNCPY(device_h->name, name, MAX_DEVICE_NAME_NUM);
465         MMSOUND_STRNCPY(device_h->type, device_type, MAX_DEVICE_TYPE_STR_LEN);
466         device_h->vendor_id = vendor_id;
467         device_h->product_id = product_id;
468         device_h->is_running = is_running;
469
470         if (stream_num > 0) {
471                 device_h->stream_num = stream_num;
472                 debug_log("%d streams on this device", stream_num);
473                 for (i = 0; i < stream_num; i++) {
474                         debug_log("  stream_id : %d", stream_id[i]);
475                         device_h->stream_id[i] = stream_id[i];
476                 }
477         } else {
478                 device_h->stream_num = 0;
479                 debug_log("There is no stream on this device");
480         }
481
482         return 0;
483 }
484
485 static void _mm_sound_device_connected_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
486                                                                                                                         int state, const char *name, int vendor_id, int product_id, bool is_running,
487                                                                                                                         int *stream_id, int stream_num, bool is_connected, void *userdata)
488 {
489         mm_sound_device_t device_h;
490         struct callback_data *cb_data = (struct callback_data*) userdata;
491         int device_flags;
492
493         debug_log("[Device %s] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x) product-id(%04x)",
494                                 is_connected ? "Connected" : "Disconnected", device_id, device_type, io_direction, state, name,
495                                 is_running, vendor_id, product_id);
496
497         if (cb_data == NULL) {
498                 debug_warning("device connected changed callback data null");
499                 return;
500         }
501
502         device_flags = (int) cb_data->extra_data;
503         if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
504                 return;
505
506         if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
507                                                         vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
508                 debug_error("Failed to fill sound device");
509                 return;
510         }
511
512         ((mm_sound_device_connected_cb)(cb_data->user_cb))(&device_h, is_connected, cb_data->user_data);
513 }
514
515 int mm_sound_client_add_device_connected_callback(int device_flags, mm_sound_device_connected_cb func,
516                                                                                                 void* userdata, unsigned int *subs_id)
517 {
518         int ret = MM_ERROR_NONE;
519         struct callback_data *cb_data = NULL;
520
521         debug_fenter();
522
523         GET_CB_DATA(cb_data, func, userdata, (void*) device_flags);
524
525         ret = mm_sound_proxy_add_device_connected_callback(_mm_sound_device_connected_callback_wrapper_func,
526                                                                                                         cb_data, g_free, subs_id);
527
528         debug_fleave();
529         return ret;
530 }
531
532 int mm_sound_client_remove_device_connected_callback(unsigned int subs_id)
533 {
534         int ret = MM_ERROR_NONE;
535         debug_fenter();
536
537         ret = mm_sound_proxy_remove_device_connected_callback(subs_id);
538
539         debug_fleave();
540         return ret;
541 }
542
543 static void _mm_sound_device_info_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
544                                                                                                                                 int state, const char *name, int vendor_id, int product_id, bool is_running,
545                                                                                                                                 int *stream_id, int stream_num, int changed_device_info_type, void *userdata)
546 {
547         mm_sound_device_t device_h;
548         struct callback_data *cb_data = (struct callback_data*) userdata;
549         int device_flags;
550
551         debug_log("[Device Info Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) "
552                         "vendor-id(%04x) product-id(%04x) changed_info_type(%d)",
553                         device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id, changed_device_info_type);
554
555         if (cb_data == NULL) {
556                 debug_warning("device info changed callback data null");
557                 return;
558         }
559
560         device_flags = (int) cb_data->extra_data;
561         if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
562                 return;
563
564         if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
565                                 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
566                 debug_error("Failed to fill sound device");
567                 return;
568         }
569
570         ((mm_sound_device_info_changed_cb)(cb_data->user_cb))(&device_h, changed_device_info_type, cb_data->user_data);
571 }
572
573 int mm_sound_client_add_device_info_changed_callback(int device_flags, mm_sound_device_info_changed_cb func,
574                                                                                                         void *userdata, unsigned int *subs_id)
575 {
576         int ret = MM_ERROR_NONE;
577         struct callback_data *cb_data = (struct callback_data*) userdata;
578
579         debug_fenter();
580
581         GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
582
583         ret = mm_sound_proxy_add_device_info_changed_callback(_mm_sound_device_info_changed_callback_wrapper_func,
584                                                                                                                 cb_data, g_free, subs_id);
585
586         debug_fleave();
587         return ret;
588 }
589
590 int mm_sound_client_remove_device_info_changed_callback(unsigned int subs_id)
591 {
592         int ret = MM_ERROR_NONE;
593         debug_fenter();
594
595         ret =  mm_sound_proxy_remove_device_info_changed_callback(subs_id);
596
597         debug_fleave();
598         return ret;
599
600 }
601
602 static void _mm_sound_device_state_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
603                                                                                                                                 int state, const char *name, int vendor_id, int product_id,
604                                                                                                                                 bool is_running, int *stream_id, int stream_num, void *userdata)
605 {
606         mm_sound_device_t device_h;
607         struct callback_data *cb_data = (struct callback_data*) userdata;
608         int device_flags;
609
610         debug_log("[Device State Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x) product-id(%04x)",
611                                 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id);
612
613         if (cb_data == NULL) {
614                 debug_warning("device state changed callback data null");
615                 return;
616         }
617
618         device_flags = (int) cb_data->extra_data;
619
620         if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
621                 return;
622
623         if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
624                                 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
625                 debug_error("Failed to fill sound device");
626                 return;
627         }
628
629         ((mm_sound_device_state_changed_cb)(cb_data->user_cb))(&device_h, state, cb_data->user_data);
630 }
631
632 int mm_sound_client_add_device_state_changed_callback(int device_flags, mm_sound_device_state_changed_cb func,
633                                                                                                         void *userdata, unsigned int *id)
634 {
635         int ret = MM_ERROR_NONE;
636         struct callback_data *cb_data = (struct callback_data*) userdata;
637
638         debug_fenter();
639
640         GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
641
642         ret = mm_sound_proxy_add_device_state_changed_callback(_mm_sound_device_state_changed_callback_wrapper_func,
643                                                                                                                 cb_data, g_free, id);
644
645         debug_fleave();
646         return ret;
647 }
648
649 int mm_sound_client_remove_device_state_changed_callback(unsigned int id)
650 {
651         int ret = MM_ERROR_NONE;
652         debug_fenter();
653
654         ret =  mm_sound_proxy_remove_device_state_changed_callback(id);
655
656         debug_fleave();
657         return ret;
658 }
659
660 static void _mm_sound_device_running_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
661                                                                                                                                 int state, const char *name, int vendor_id, int product_id,
662                                                                                                                                 bool is_running, int *stream_id, int stream_num, void *userdata)
663 {
664         mm_sound_device_t device_h;
665         struct callback_data *cb_data = (struct callback_data*) userdata;
666         int device_flags;
667
668         debug_log("[Device Running Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x), product-id(%04x)",
669                         device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id);
670
671         if (cb_data == NULL) {
672                 debug_warning("device running changed callback data null");
673                 return;
674         }
675
676         device_flags = (int) cb_data->extra_data;
677
678         if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
679                 return;
680
681         if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
682                                                         vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
683                 debug_error("Failed to fill sound device");
684                 return;
685         }
686
687         ((mm_sound_device_running_changed_cb)(cb_data->user_cb))(&device_h, is_running, cb_data->user_data);
688 }
689
690 int mm_sound_client_add_device_running_changed_callback(int device_flags, mm_sound_device_running_changed_cb func,
691                                                                                                                 void *userdata, unsigned int *id)
692 {
693         int ret = MM_ERROR_NONE;
694         struct callback_data *cb_data = (struct callback_data*) userdata;
695
696         debug_fenter();
697
698         GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
699
700         ret = mm_sound_proxy_add_device_running_changed_callback(_mm_sound_device_running_changed_callback_wrapper_func,
701                                                                                                                         cb_data, g_free, id);
702
703         debug_fleave();
704         return ret;
705 }
706
707 int mm_sound_client_remove_device_running_changed_callback(unsigned int id)
708 {
709         int ret = MM_ERROR_NONE;
710         debug_fenter();
711
712         ret =  mm_sound_proxy_remove_device_running_changed_callback(id);
713
714         debug_fleave();
715         return ret;
716 }
717
718 int mm_sound_client_is_stream_on_device(int stream_id, int device_id, bool *is_on)
719 {
720         int ret = MM_ERROR_NONE;
721         debug_fenter();
722
723         if (!is_on) {
724                 debug_error("Invalid Parameter");
725                 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
726                 goto failed;
727         }
728
729         if ((ret = mm_sound_proxy_is_stream_on_device(stream_id, device_id, is_on)) != MM_ERROR_NONE) {
730                 debug_error("failed to query is stream on device, ret[0x%x]", ret);
731                 goto failed;
732         }
733
734 failed:
735         debug_fleave();
736         return ret;
737 }
738
739 int __convert_volume_type_to_str(int volume_type, char **volume_type_str)
740 {
741         int ret = MM_ERROR_NONE;
742
743         if (!volume_type_str)
744                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
745
746         switch (volume_type) {
747         case VOLUME_TYPE_SYSTEM:
748                 *volume_type_str = "system";
749                 break;
750         case VOLUME_TYPE_NOTIFICATION:
751                 *volume_type_str = "notification";
752                 break;
753         case VOLUME_TYPE_ALARM:
754                 *volume_type_str = "alarm";
755                 break;
756         case VOLUME_TYPE_RINGTONE:
757                 *volume_type_str = "ringtone";
758                 break;
759         case VOLUME_TYPE_MEDIA:
760                 *volume_type_str = "media";
761                 break;
762         case VOLUME_TYPE_CALL:
763                 *volume_type_str = "call";
764                 break;
765         case VOLUME_TYPE_VOIP:
766                 *volume_type_str = "voip";
767                 break;
768         case VOLUME_TYPE_VOICE:
769                 *volume_type_str = "voice";
770                 break;
771         default:
772                 debug_error("unexpected volume type [%d]", volume_type);
773                 return MM_ERROR_SOUND_INTERNAL;
774         }
775         if (!strncmp(*volume_type_str, "", VOLUME_TYPE_LEN)) {
776                 debug_error("could not find the volume_type[%d] in this switch case statement", volume_type);
777                 ret = MM_ERROR_SOUND_INTERNAL;
778         } else {
779                 debug_log("volume_type[%s]", *volume_type_str);
780         }
781         return ret;
782 }
783
784 static int __convert_volume_type_to_int(const char *volume_type_str, volume_type_t *volume_type)
785 {
786         int ret = MM_ERROR_NONE;
787
788         if (!volume_type || !volume_type_str)
789                 return MM_ERROR_COMMON_INVALID_ARGUMENT;
790
791         if (!strncmp(volume_type_str, "system", VOLUME_TYPE_LEN)) {
792                 *volume_type = VOLUME_TYPE_SYSTEM;
793         } else if (!strncmp(volume_type_str, "notification", VOLUME_TYPE_LEN)) {
794                 *volume_type = VOLUME_TYPE_NOTIFICATION;
795         } else if (!strncmp(volume_type_str, "alarm", VOLUME_TYPE_LEN)) {
796                 *volume_type = VOLUME_TYPE_ALARM;
797         } else if (!strncmp(volume_type_str, "ringtone", VOLUME_TYPE_LEN)) {
798                 *volume_type = VOLUME_TYPE_RINGTONE;
799         } else if (!strncmp(volume_type_str, "media", VOLUME_TYPE_LEN)) {
800                 *volume_type = VOLUME_TYPE_MEDIA;
801         } else if (!strncmp(volume_type_str, "call", VOLUME_TYPE_LEN)) {
802                 *volume_type = VOLUME_TYPE_CALL;
803         } else if (!strncmp(volume_type_str, "voip", VOLUME_TYPE_LEN)) {
804                 *volume_type = VOLUME_TYPE_VOIP;
805         } else if (!strncmp(volume_type_str, "voice", VOLUME_TYPE_LEN)) {
806                 *volume_type = VOLUME_TYPE_VOICE;
807         } else {
808                 debug_log("Invalid volume type : [%s]", volume_type_str);
809                 ret = MM_ERROR_SOUND_INTERNAL;
810         }
811
812         return ret;
813 }
814
815 int mm_sound_client_set_volume_by_type(volume_type_t type, const unsigned int level)
816 {
817         int ret = MM_ERROR_NONE;
818         char *type_str = NULL;
819         debug_fenter();
820
821         if (type >= VOLUME_TYPE_MAX) {
822                 debug_error("invalid volume type %d", type);
823                 return MM_ERROR_INVALID_ARGUMENT;
824         }
825
826         /* Check input param */
827         if (0 > _validate_volume(type, (int)level)) {
828                 debug_error("invalid level %u of %s", level, g_volume_str[type]);
829                 return MM_ERROR_INVALID_ARGUMENT;
830         }
831
832         if ((ret = __convert_volume_type_to_str(type, &type_str)) != MM_ERROR_NONE) {
833                 debug_error("volume type convert failed");
834                 goto failed;
835         }
836
837         ret = mm_sound_proxy_set_volume_by_type(type_str, level);
838
839 failed:
840         debug_fleave();
841         return ret;
842 }
843
844 int mm_sound_client_get_volume_by_type(volume_type_t type, unsigned int *level)
845 {
846         int ret = MM_ERROR_NONE;
847         int vconf_value = 0;
848
849         if (level == NULL) {
850                 debug_error("invalid argument, level is null");
851                 return MM_ERROR_INVALID_ARGUMENT;
852         }
853
854         if (type >= VOLUME_TYPE_MAX) {
855                 debug_error("invalid volume type %d", type);
856                 return MM_ERROR_INVALID_ARGUMENT;
857         }
858
859         /* Get volume value from VCONF */
860         if (vconf_get_int(g_volume_vconf[type], &vconf_value)) {
861                 debug_error("vconf_get_int(%s) failed..\n", g_volume_vconf[type]);
862                 return MM_ERROR_SOUND_INTERNAL;
863         }
864
865         *level = vconf_value;
866
867         return ret;
868 }
869
870 static void _mm_sound_volume_changed_callback_wrapper_func(const char *direction, const char *volume_type_str,
871                                                                                                                 int volume_level, void *userdata)
872 {
873         volume_type_t volume_type = 0;
874         struct callback_data *cb_data = (struct callback_data *) userdata;
875
876         debug_log("direction : %s, volume_type : %s, volume_level : %d",
877                         direction, volume_type_str, volume_level);
878
879         if (cb_data == NULL) {
880                 debug_warning("volume changed callback data null");
881                 return;
882         }
883
884         if (__convert_volume_type_to_int(volume_type_str, &volume_type) != MM_ERROR_NONE) {
885                 debug_error("volume type convert failed");
886                 return;
887         }
888         debug_log("Call volume changed user cb, direction : %s, vol_type : %s(%d), level : %u",
889                         direction, volume_type_str, volume_type, volume_level);
890         ((mm_sound_volume_changed_cb)(cb_data->user_cb))(volume_type, volume_level, cb_data->user_data);
891 }
892
893 int mm_sound_client_add_volume_changed_callback(mm_sound_volume_changed_cb func, void* userdata, unsigned int *subs_id)
894 {
895         int ret = MM_ERROR_NONE;
896         struct callback_data *cb_data = NULL;
897
898         debug_fenter();
899
900         GET_CB_DATA(cb_data, func, userdata, NULL);
901
902         ret = mm_sound_proxy_add_volume_changed_callback(_mm_sound_volume_changed_callback_wrapper_func, cb_data, g_free, subs_id);
903
904         debug_fleave();
905
906         return ret;
907 }
908
909 int mm_sound_client_remove_volume_changed_callback(unsigned int subs_id)
910 {
911         int ret = MM_ERROR_NONE;
912         debug_fenter();
913
914         ret = mm_sound_proxy_remove_volume_changed_callback(subs_id);
915
916         debug_fleave();
917         return ret;
918 }
919
920 int mm_sound_client_set_mute_by_type(volume_type_t type, bool mute)
921 {
922         int ret = MM_ERROR_NONE;
923         char *type_str = NULL;
924
925         debug_fenter();
926
927         if (type > VOLUME_TYPE_VOICE) {
928                 debug_error("invalid volume type %d", type);
929                 return MM_ERROR_INVALID_ARGUMENT;
930         }
931
932         if ((ret = __convert_volume_type_to_str(type, &type_str)) != MM_ERROR_NONE) {
933                 debug_error("volume type convert failed");
934                 goto failed;
935         }
936
937         ret = mm_sound_proxy_set_mute_by_type(type_str, mute);
938
939 failed:
940         debug_fleave();
941         return ret;
942 }
943
944 int mm_sound_client_get_mute_by_type(volume_type_t type, bool *muted)
945 {
946         int ret = MM_ERROR_NONE;
947         int vconf_value = 0;
948
949         debug_fenter();
950
951         if (type > VOLUME_TYPE_VOICE) {
952                 debug_error("invalid volume type %d", type);
953                 return MM_ERROR_INVALID_ARGUMENT;
954         }
955
956         /* Get mute state from VCONF */
957         if (vconf_get_bool(g_mute_vconf[type], &vconf_value)) {
958                 debug_error("vconf_get_int(%s) failed..\n", g_mute_vconf[type]);
959                 return MM_ERROR_SOUND_INTERNAL;
960         }
961
962         *muted = (bool)vconf_value;
963
964         debug_fleave();
965         return ret;
966 }
967
968 int mm_sound_client_set_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_parameters, const char *filter_group)
969 {
970         int ret = MM_ERROR_NONE;
971         debug_fenter();
972
973         ret = mm_sound_proxy_set_filter_by_type(stream_type, filter_name, filter_parameters, filter_group);
974
975         debug_fleave();
976         return ret;
977 }
978
979 int mm_sound_client_unset_filter_by_type(const char *stream_type)
980 {
981         int ret = MM_ERROR_NONE;
982         debug_fenter();
983
984         ret = mm_sound_proxy_unset_filter_by_type(stream_type);
985
986         debug_fleave();
987         return ret;
988 }
989
990 int mm_sound_client_control_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_controls)
991 {
992         int ret = MM_ERROR_NONE;
993         debug_fenter();
994
995         ret = mm_sound_proxy_control_filter_by_type(stream_type, filter_name, filter_controls);
996
997         debug_fleave();
998         return ret;
999 }
1000
1001 int mm_sound_client_is_focus_cb_thread(GThread *mine, bool *result, bool *is_for_watching)
1002 {
1003         int ret = MM_ERROR_NONE;
1004         int i = 0;
1005
1006         if (!mine || !result)
1007                 ret = MM_ERROR_INVALID_ARGUMENT;
1008         else {
1009                 *result = false;
1010                 for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
1011                         if (!g_focus_sound_handle[i].is_used)
1012                                 continue;
1013                         if (g_focus_sound_handle[i].focus_cb_thread == mine) {
1014                                 *result = true;
1015                                 if (is_for_watching)
1016                                         *is_for_watching = false;
1017                                 break;
1018                         }
1019                         if (g_focus_sound_handle[i].focus_watch_cb_thread == mine) {
1020                                 *result = true;
1021                                 if (is_for_watching)
1022                                         *is_for_watching = true;
1023                                 break;
1024                         }
1025                 }
1026         }
1027
1028         return ret;
1029 }
1030
1031 int mm_sound_client_register_focus(int pid, const char *stream_type,
1032                                                                 mm_sound_focus_changed_cb callback, void* user_data, int *id)
1033 {
1034         int ret = MM_ERROR_NONE;
1035         int index = -1;
1036
1037         debug_fenter();
1038         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1039
1040         if (focus_find_empty_index(&index)) {
1041                 ret = MM_ERROR_SOUND_INTERNAL;
1042                 goto cleanup;
1043         }
1044
1045         g_focus_sound_handle[index].focus_pid = pid;
1046         g_focus_sound_handle[index].focus_callback = callback;
1047         g_focus_sound_handle[index].user_data = user_data;
1048         g_focus_sound_handle[index].auto_reacquire = true;
1049
1050         ret = mm_sound_proxy_register_focus(index, stream_type, id);
1051         if (ret == MM_ERROR_NONE) {
1052                 debug_msg("Success to register focus, client_fd[%d], id[%d]", g_focus_sound_handle[index].client_fd, *id);
1053                 if (focus_init_context(index, false)) {
1054                         ret = MM_ERROR_SOUND_INTERNAL;
1055                         goto cleanup;
1056                 }
1057         } else {
1058                 debug_error("Error occurred : 0x%x", ret);
1059                 goto cleanup;
1060         }
1061
1062         focus_init_callback(index, false);
1063
1064 cleanup:
1065         if (ret)
1066                 g_focus_sound_handle[index].is_used = false;
1067
1068         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1069         debug_fleave();
1070
1071         return ret;
1072 }
1073
1074 int mm_sound_client_unregister_focus(int id)
1075 {
1076         int ret = MM_ERROR_NONE;
1077         int index = -1;
1078
1079         debug_fenter();
1080         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1081
1082         index = focus_find_index_by_handle(id);
1083         if (index == -1) {
1084                 debug_error("Could not find index");
1085                 ret = MM_ERROR_INVALID_ARGUMENT;
1086                 goto cleanup;
1087         }
1088
1089         if (!g_mutex_trylock(&g_focus_sound_handle[index].focus_lock)) {
1090                 debug_warning("maybe focus_callback is being called, try one more time..");
1091                 usleep(2500000); /* 2.5 sec */
1092                 if (g_mutex_trylock(&g_focus_sound_handle[index].focus_lock))
1093                         debug_msg("finally got focus_lock");
1094         }
1095
1096         ret = mm_sound_proxy_unregister_focus(index);
1097         if (ret == MM_ERROR_NONE)
1098                 debug_msg("Success to unregister focus");
1099         else
1100                 debug_error("Error occurred : 0x%x", ret);
1101
1102         g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1103
1104         focus_deinit_callback(index, false);
1105         g_focus_sound_handle[index].focus_fd = 0;
1106         g_focus_sound_handle[index].focus_pid = 0;
1107         g_focus_sound_handle[index].client_fd = 0;
1108         g_focus_sound_handle[index].handle = 0;
1109         g_focus_sound_handle[index].is_used = false;
1110         focus_deinit_context(index, false);
1111
1112 cleanup:
1113         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1114         debug_fleave();
1115         return ret;
1116 }
1117
1118 int mm_sound_client_set_focus_reacquisition(int id, bool reacquisition)
1119 {
1120         int ret = MM_ERROR_NONE;
1121         int index = -1;
1122         bool result;
1123
1124         debug_fenter();
1125
1126         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1127
1128         index = focus_find_index_by_handle(id);
1129         if (index == -1) {
1130                 debug_error("Could not find index");
1131                 ret = MM_ERROR_INVALID_ARGUMENT;
1132                 goto cleanup;
1133         }
1134
1135         ret = mm_sound_client_is_focus_cb_thread(g_thread_self(), &result, NULL);
1136         if (ret) {
1137                 debug_error("mm_sound_client_is_focus_cb_thread failed");
1138                 goto cleanup;
1139         } else if (!result) {
1140                 ret = mm_sound_proxy_set_focus_reacquisition(index, reacquisition);
1141                 if (ret == MM_ERROR_NONE) {
1142                         debug_msg("Success to set focus reacquisition to [%d]", reacquisition);
1143                 } else {
1144                         debug_error("Error occurred : 0x%x", ret);
1145                         goto cleanup;
1146                 }
1147         } else {
1148                 debug_warning("Inside the focus cb thread, set focus reacquisition to [%d]", reacquisition);
1149         }
1150
1151         g_focus_sound_handle[index].auto_reacquire = reacquisition;
1152         debug_msg("set focus reacquisition(%d) for id(%d)", reacquisition, id);
1153
1154 cleanup:
1155         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1156         debug_fleave();
1157         return ret;
1158 }
1159
1160 int mm_sound_client_get_focus_reacquisition(int id, bool *reacquisition)
1161 {
1162         int ret = MM_ERROR_NONE;
1163         int index = -1;
1164
1165         debug_fenter();
1166
1167         if (!reacquisition) {
1168                 debug_error("Invalid parameter");
1169                 return MM_ERROR_INVALID_ARGUMENT;
1170         }
1171
1172         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1173
1174         index = focus_find_index_by_handle(id);
1175         if (index == -1) {
1176                 debug_error("Could not find index");
1177                 ret = MM_ERROR_INVALID_ARGUMENT;
1178                 goto cleanup;
1179         }
1180
1181         *reacquisition = g_focus_sound_handle[index].auto_reacquire;
1182         debug_msg("get focus reacquisition(%d) for id(%d)", *reacquisition, id);
1183
1184 cleanup:
1185         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1186         debug_fleave();
1187         return ret;
1188 }
1189
1190 int mm_sound_client_get_acquired_focus_stream_type(int focus_type, char **stream_type, int *option, char **ext_info)
1191 {
1192         int ret = MM_ERROR_NONE;
1193
1194         debug_fenter();
1195
1196         ret = mm_sound_proxy_get_acquired_focus_stream_type(focus_type, stream_type, option, ext_info);
1197         if (ret == MM_ERROR_NONE)
1198                 debug_msg("Success to get stream type of acquired focus, stream_type(%s), ext_info(%s)",
1199                                 *stream_type, *ext_info);
1200         else
1201                 debug_error("Error occurred : 0x%x", ret);
1202
1203         debug_fleave();
1204
1205         return ret;
1206 }
1207
1208 int mm_sound_client_acquire_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1209 {
1210         int ret = MM_ERROR_NONE;
1211         int index = -1;
1212
1213         debug_fenter();
1214         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1215
1216         index = focus_find_index_by_handle(id);
1217         if (index == -1) {
1218                 debug_error("Could not find index");
1219                 ret = MM_ERROR_INVALID_ARGUMENT;
1220                 goto cleanup;
1221         }
1222
1223         ret = mm_sound_proxy_acquire_focus(index, type, option, ext_info);
1224         if (ret == MM_ERROR_NONE)
1225                 debug_msg("Success to acquire focus");
1226         else
1227                 debug_error("Error occurred : 0x%x", ret);
1228
1229 cleanup:
1230         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1231         debug_fleave();
1232         return ret;
1233 }
1234
1235 int mm_sound_client_release_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1236 {
1237         int ret = MM_ERROR_NONE;
1238         int index = -1;
1239
1240         debug_fenter();
1241         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1242
1243         index = focus_find_index_by_handle(id);
1244         if (index == -1) {
1245                 debug_error("Could not find index");
1246                 ret = MM_ERROR_INVALID_ARGUMENT;
1247                 goto cleanup;
1248         }
1249
1250         ret = mm_sound_proxy_release_focus(index, type, option, ext_info);
1251         if (ret == MM_ERROR_NONE)
1252                 debug_msg("Success to release focus");
1253         else
1254                 debug_error("Error occurred : 0x%x", ret);
1255
1256 cleanup:
1257         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1258         debug_fleave();
1259         return ret;
1260 }
1261
1262 int mm_sound_client_update_stream_focus_status(int id, unsigned int status)
1263 {
1264         int ret = MM_ERROR_NONE;
1265         debug_fenter();
1266
1267         if ((ret = mm_sound_proxy_update_stream_focus_status(id, status)) != MM_ERROR_NONE)
1268                 debug_error("failed to update stream focus status, ret[0x%x]", ret);
1269
1270         debug_fleave();
1271         return ret;
1272 }
1273
1274 int mm_sound_client_deliver_focus(int src_id, int dst_id, mm_sound_focus_type_e focus_type)
1275 {
1276         int ret = MM_ERROR_NONE;
1277         int src_index;
1278         int dst_index;
1279
1280         debug_fenter();
1281
1282         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1283
1284         src_index = focus_find_index_by_handle(src_id);
1285         if (src_index == -1) {
1286                 debug_error("Could not find src index");
1287                 ret = MM_ERROR_INVALID_ARGUMENT;
1288                 goto cleanup;
1289         }
1290         dst_index = focus_find_index_by_handle(dst_id);
1291         if (dst_index == -1) {
1292                 debug_error("Could not find dst index");
1293                 ret = MM_ERROR_INVALID_ARGUMENT;
1294                 goto cleanup;
1295         }
1296         if (g_focus_sound_handle[src_index].focus_pid != g_focus_sound_handle[dst_index].focus_pid) {
1297                 debug_error("pid[%d/%d] are not same for dst/src",
1298                                         g_focus_sound_handle[src_index].focus_pid,
1299                                         g_focus_sound_handle[dst_index].focus_pid);
1300                 ret = MM_ERROR_SOUND_INTERNAL;
1301                 goto cleanup;
1302         }
1303
1304         if ((ret = mm_sound_proxy_deliver_focus(src_index, dst_index, focus_type)) != MM_ERROR_NONE)
1305                 debug_error("failed to deliver focus, ret[0x%x]", ret);
1306
1307 cleanup:
1308         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1309         debug_fleave();
1310         return ret;
1311 }
1312
1313 int mm_sound_client_set_focus_watch_callback(int pid, mm_sound_focus_type_e focus_type,
1314                                                                                         mm_sound_focus_changed_watch_cb callback, void* user_data, int *id)
1315 {
1316         int ret = MM_ERROR_NONE;
1317         int index = -1;
1318
1319         debug_fenter();
1320
1321         if (!id)
1322                 return MM_ERROR_INVALID_ARGUMENT;
1323
1324         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1325
1326         if (focus_find_empty_index(&index)) {
1327                 ret = MM_ERROR_SOUND_INTERNAL;
1328                 goto cleanup;
1329         }
1330
1331         g_focus_sound_handle[index].focus_pid = pid;
1332         g_focus_sound_handle[index].watch_callback = callback;
1333         g_focus_sound_handle[index].user_data = user_data;
1334         g_focus_sound_handle[index].unset_watch_callback_requested = false;
1335
1336         ret = mm_sound_proxy_add_focus_watch_callback(index, focus_type);
1337         if (ret == MM_ERROR_NONE) {
1338                 *id = g_focus_sound_handle[index].handle;
1339                 debug_msg("Success to add watch focus cb, id(%d)", *id);
1340                 if (focus_init_context(index, true)) {
1341                         ret = MM_ERROR_SOUND_INTERNAL;
1342                         goto cleanup;
1343                 }
1344         } else {
1345                 debug_error("Error occurred : 0x%x", ret);
1346                 goto cleanup;
1347         }
1348
1349         focus_init_callback(index, true);
1350
1351 cleanup:
1352         if (ret)
1353                 g_focus_sound_handle[index].is_used = false;
1354
1355         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1356         debug_fleave();
1357         return ret;
1358 }
1359
1360 int mm_sound_client_request_unset_focus_watch_callback(int id)
1361 {
1362         int ret = MM_ERROR_NONE;
1363         int index = -1;
1364
1365         debug_fenter();
1366         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1367
1368         index = focus_watch_find_index_by_handle(id);
1369         if (index == -1) {
1370                 debug_error("Could not find index");
1371                 ret = MM_ERROR_INVALID_ARGUMENT;
1372                 goto cleanup;
1373         }
1374         g_focus_sound_handle[index].unset_watch_callback_requested = true;
1375
1376 cleanup:
1377         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1378         debug_fleave();
1379         return ret;
1380 }
1381
1382 int mm_sound_client_unset_focus_watch_callback(int id)
1383 {
1384         int ret = MM_ERROR_NONE;
1385         int index = -1;
1386
1387         debug_fenter();
1388         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1389
1390         index = focus_watch_find_index_by_handle(id);
1391         if (index == -1) {
1392                 debug_error("Could not find index");
1393                 ret = MM_ERROR_INVALID_ARGUMENT;
1394                 goto cleanup;
1395         }
1396
1397         g_mutex_lock(&g_focus_sound_handle[index].focus_lock);
1398
1399         g_focus_sound_handle[index].is_used = false;
1400
1401         ret = mm_sound_proxy_remove_focus_watch_callback(index);
1402         if (ret == MM_ERROR_NONE)
1403                 debug_msg("Success to remove watch focus cb, id(%d)", g_focus_sound_handle[index].handle);
1404         else
1405                 debug_error("Error occurred : 0x%x", ret);
1406
1407
1408         g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1409
1410         focus_deinit_callback(index, true);
1411         g_focus_sound_handle[index].focus_fd = 0;
1412         g_focus_sound_handle[index].focus_pid = 0;
1413         g_focus_sound_handle[index].client_fd = 0;
1414         g_focus_sound_handle[index].handle = 0;
1415         focus_deinit_context(index, true);
1416
1417 cleanup:
1418         MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1419         debug_fleave();
1420         return ret;
1421 }
1422
1423 static gboolean _idle_event_callback(void *data)
1424 {
1425         focus_idle_event_t *idle_event_data = (focus_idle_event_t*)data;
1426         int ret = MM_ERROR_NONE;
1427
1428         if (data == NULL) {
1429                 debug_error("data is null");
1430                 return FALSE;
1431         }
1432
1433         debug_msg("idle_event_data(%p): type(%d), data(%d)",
1434                 idle_event_data, idle_event_data->type, idle_event_data->data);
1435
1436         switch (idle_event_data->type) {
1437         case IDLE_EVENT_TYPE_UNSET_FOCUS_WATCH_CB:
1438                 if ((ret = mm_sound_client_unset_focus_watch_callback(idle_event_data->data)))
1439                         debug_error("Could not unset focus watch callback, id(%d), ret = %x", idle_event_data->data, ret);
1440                 break;
1441         case IDLE_EVENT_TYPE_UNREGISTER_FOCUS:
1442                 if ((ret = mm_sound_client_unregister_focus(idle_event_data->data)))
1443                         debug_error("Could not unregister focus, id(%d), ret = %x", idle_event_data->data, ret);
1444                 break;
1445         default:
1446                 debug_warning("invalid type(%d)", idle_event_data->type);
1447                 break;
1448         }
1449
1450         g_free(idle_event_data);
1451
1452         g_idle_event_src = 0;
1453
1454         MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex);
1455
1456         return FALSE;
1457 }
1458
1459 int mm_sound_client_execute_focus_func_in_main_context(focus_idle_event_type_e type, int data)
1460 {
1461         focus_idle_event_t *idle_event_data = NULL;
1462
1463         if (IDLE_EVENT_TYPE_MAX < type)
1464                 return MM_ERROR_INVALID_ARGUMENT;
1465
1466         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL);
1467
1468         idle_event_data = g_new0(focus_idle_event_t, 1);
1469         idle_event_data->type = type;
1470         idle_event_data->data = data;
1471
1472         g_idle_event_src = g_idle_add_full(G_PRIORITY_HIGH,
1473                                 (GSourceFunc)_idle_event_callback,
1474                                 (gpointer)idle_event_data,
1475                                 NULL);
1476
1477         return MM_ERROR_NONE;
1478 }
1479
1480 int mm_sound_client_add_test_callback(mm_sound_test_cb func, void* user_data, unsigned int *subs_id)
1481 {
1482         int ret = MM_ERROR_NONE;
1483
1484         debug_fenter();
1485
1486         ret = mm_sound_proxy_add_test_callback(func, user_data, g_free, subs_id);
1487
1488         debug_fleave();
1489         return ret;
1490 }
1491
1492 int mm_sound_client_remove_test_callback(unsigned int subs_id)
1493 {
1494         int ret = MM_ERROR_NONE;
1495         debug_fenter();
1496
1497         ret = mm_sound_proxy_remove_test_callback(subs_id);
1498
1499         debug_fleave();
1500         return ret;
1501 }
1502
1503 int mm_sound_client_test(int a, int b, int* getv)
1504 {
1505         int ret = MM_ERROR_NONE;
1506
1507         debug_fenter();
1508
1509         ret = mm_sound_proxy_test(a, b, getv);
1510         debug_log("%d * %d -> result : %d", a, b, *getv);
1511
1512         debug_fleave();
1513
1514         return ret;
1515 }