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