4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Seungbae Shin <seungbae.shin@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
39 #define CLIENT_HANDLE_MAX 256
40 #define VOLUME_TYPE_LEN 64
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"
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"
63 /* For internal use */
64 #define VCONF_KEY_VOLUME_TYPE_BIXBY VCONF_KEY_VOLUME_PREFIX"/bixby"
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 */
78 static char *g_volume_vconf_internal[] = {
79 VCONF_KEY_VOLUME_TYPE_BIXBY, /* VOLUME_TYPE_BIXBY */
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 */
93 struct callback_data {
100 #define GET_CB_DATA(_cb_data, _func, _userdata, _extradata) \
102 _cb_data = (struct callback_data*) g_try_malloc0(sizeof(struct callback_data)); \
104 debug_error("failed to allocate callback_data"); \
105 return MM_ERROR_OUT_OF_MEMORY; \
107 _cb_data->user_cb = _func; \
108 _cb_data->user_data = _userdata; \
109 _cb_data->extra_data = _extradata; \
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;
117 /* handle to watch end of playing */
119 /* subscription id to unsubscribe when handle ended */
121 } play_sound_end_callback_data_t;
123 typedef struct _focus_idle_event {
124 focus_idle_event_type_e type;
126 } focus_idle_event_t;
128 int mm_sound_client_initialize(void)
130 int ret = MM_ERROR_NONE;
134 mm_sound_proxy_initialize();
135 g_idle_event_src = 0;
141 int mm_sound_client_finalize(void)
143 int ret = MM_ERROR_NONE;
147 ret = mm_sound_proxy_finalize();
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);
159 void mm_sound_convert_volume_type_to_stream_type(int volume_type, char *stream_type)
161 switch (volume_type) {
162 case VOLUME_TYPE_SYSTEM:
163 MMSOUND_STRNCPY(stream_type, "system", MAX_STREAM_TYPE_LEN);
165 case VOLUME_TYPE_NOTIFICATION:
166 MMSOUND_STRNCPY(stream_type, "notification", MAX_STREAM_TYPE_LEN);
168 case VOLUME_TYPE_ALARM:
169 MMSOUND_STRNCPY(stream_type, "alarm", MAX_STREAM_TYPE_LEN);
171 case VOLUME_TYPE_RINGTONE:
172 MMSOUND_STRNCPY(stream_type, "ringtone-voip", MAX_STREAM_TYPE_LEN);
174 case VOLUME_TYPE_MEDIA:
175 MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN);
177 case VOLUME_TYPE_CALL:
178 MMSOUND_STRNCPY(stream_type, "call-voice", MAX_STREAM_TYPE_LEN);
180 case VOLUME_TYPE_VOIP:
181 MMSOUND_STRNCPY(stream_type, "voip", MAX_STREAM_TYPE_LEN);
183 case VOLUME_TYPE_VOICE:
184 MMSOUND_STRNCPY(stream_type, "voice-information", MAX_STREAM_TYPE_LEN);
187 MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN);
191 debug_msg("volume type (%d) converted to stream type (%s)", volume_type, stream_type);
195 /*****************************************************************************************
196 DBUS SUPPORTED FUNCTIONS
197 ******************************************************************************************/
198 static int _mm_sound_client_device_list_dump(GList *device_list)
200 int ret = MM_ERROR_NONE;
202 mm_sound_device_t *device_node = NULL;
205 debug_error("Device list NULL, cannot dump list");
206 return MM_ERROR_SOUND_INTERNAL;
209 debug_log("======================== device list : start ==========================");
210 for (list = device_list; list != NULL; list = list->next) {
211 device_node = (mm_sound_device_t *)list->data;
213 debug_log(" list idx[%d]: type[%17s], id[%02d], io_direction[%d], state[%d], name[%s]",
214 count++, device_node->type, device_node->id, device_node->io_direction,
215 device_node->state, device_node->name);
218 debug_log("======================== device list : end ============================");
223 int mm_sound_client_get_current_connected_device_list(int device_flags, mm_sound_device_list_t *device_list)
225 int ret = MM_ERROR_NONE;
229 debug_error("Device list NULL");
230 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
234 if ((ret = mm_sound_proxy_get_current_connected_device_list(device_flags, &device_list->list)) != MM_ERROR_NONE) {
235 debug_error("failed to get current connected device list with dbus, ret[0x%x]", ret);
238 if (!device_list->list) {
239 debug_error("Got device list null");
240 ret = MM_ERROR_SOUND_NO_DATA;
243 _mm_sound_client_device_list_dump(device_list->list);
250 int mm_sound_client_get_device_by_id(int device_id, mm_sound_device_t **device)
252 int ret = MM_ERROR_NONE;
256 if ((ret = mm_sound_proxy_get_device_by_id(device_id, device)) != MM_ERROR_NONE)
257 debug_error("failed to get device by id");
264 static bool device_is_match_direction(int direction, int mask)
266 if (mask == DEVICE_IO_DIRECTION_FLAGS || mask == 0)
269 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_IN))
271 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_OUT))
273 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH))
279 static bool device_is_match_state(int state, int mask)
281 if (mask == DEVICE_STATE_FLAGS || mask == 0)
284 if ((mask & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_DEACTIVATED))
286 if ((mask & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_ACTIVATED))
292 static bool device_is_match_type(const char *type, int mask)
295 const char *builtin_prefix = "builtin";
297 if (mask == DEVICE_TYPE_FLAGS || mask == 0)
300 is_builtin = !strncmp(type, builtin_prefix, strlen(builtin_prefix));
302 if ((mask & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG) && (is_builtin))
304 if ((mask & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG) && (!is_builtin))
310 static bool device_is_match_with_mask(const char *type, int direction, int state, int mask)
312 if (mask == DEVICE_ALL_FLAG)
315 return (device_is_match_direction(direction, mask & DEVICE_IO_DIRECTION_FLAGS) &&
316 device_is_match_state(state, mask & DEVICE_STATE_FLAGS) &&
317 device_is_match_type(type, mask & DEVICE_TYPE_FLAGS));
320 static int _fill_sound_device(mm_sound_device_t *device_h, int device_id, const char *device_type,
321 int direction, int state, const char *name, int vendor_id, int product_id,
322 int *stream_id, int stream_num, bool is_running)
326 if (stream_num > 0 && stream_id == NULL) {
327 debug_error("stream_num is %d, but stream_id is NULL", stream_num);
331 if (stream_num > MAX_STREAM_ON_DEVICE) {
332 debug_error("too many streams on this device");
336 device_h->id = device_id;
337 device_h->io_direction = direction;
338 device_h->state = state;
339 MMSOUND_STRNCPY(device_h->name, name, MAX_DEVICE_NAME_NUM);
340 MMSOUND_STRNCPY(device_h->type, device_type, MAX_DEVICE_TYPE_STR_LEN);
341 device_h->vendor_id = vendor_id;
342 device_h->product_id = product_id;
343 device_h->is_running = is_running;
345 if (stream_num > 0) {
346 device_h->stream_num = stream_num;
347 debug_log("%d streams on this device", stream_num);
348 for (i = 0; i < stream_num; i++) {
349 debug_log(" stream_id : %d", stream_id[i]);
350 device_h->stream_id[i] = stream_id[i];
353 device_h->stream_num = 0;
354 debug_log("There is no stream on this device");
360 static void _mm_sound_device_connected_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
361 int state, const char *name, int vendor_id, int product_id, bool is_running,
362 int *stream_id, int stream_num, bool is_connected, void *userdata)
364 mm_sound_device_t device_h;
365 struct callback_data *cb_data = (struct callback_data*) userdata;
368 debug_log("[Device %s] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x) product-id(%04x)",
369 is_connected ? "Connected" : "Disconnected", device_id, device_type, io_direction, state, name,
370 is_running, vendor_id, product_id);
372 if (cb_data == NULL) {
373 debug_warning("device connected changed callback data null");
377 device_flags = (int) cb_data->extra_data;
378 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
381 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
382 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
383 debug_error("Failed to fill sound device");
387 ((mm_sound_device_connected_cb)(cb_data->user_cb))(&device_h, is_connected, cb_data->user_data);
390 int mm_sound_client_add_device_connected_callback(int device_flags, mm_sound_device_connected_cb func,
391 void* userdata, unsigned int *subs_id)
393 int ret = MM_ERROR_NONE;
394 struct callback_data *cb_data = NULL;
398 GET_CB_DATA(cb_data, func, userdata, (void*) device_flags);
400 ret = mm_sound_proxy_add_device_connected_callback(_mm_sound_device_connected_callback_wrapper_func,
401 cb_data, g_free, subs_id);
407 int mm_sound_client_remove_device_connected_callback(unsigned int subs_id)
409 int ret = MM_ERROR_NONE;
412 ret = mm_sound_proxy_remove_device_connected_callback(subs_id);
418 static void _mm_sound_device_info_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
419 int state, const char *name, int vendor_id, int product_id, bool is_running,
420 int *stream_id, int stream_num, int changed_device_info_type, void *userdata)
422 mm_sound_device_t device_h;
423 struct callback_data *cb_data = (struct callback_data*) userdata;
426 debug_log("[Device Info Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) "
427 "vendor-id(%04x) product-id(%04x) changed_info_type(%d)",
428 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id, changed_device_info_type);
430 if (cb_data == NULL) {
431 debug_warning("device info changed callback data null");
435 device_flags = (int) cb_data->extra_data;
436 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
439 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
440 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
441 debug_error("Failed to fill sound device");
445 ((mm_sound_device_info_changed_cb)(cb_data->user_cb))(&device_h, changed_device_info_type, cb_data->user_data);
448 int mm_sound_client_add_device_info_changed_callback(int device_flags, mm_sound_device_info_changed_cb func,
449 void *userdata, unsigned int *subs_id)
451 int ret = MM_ERROR_NONE;
452 struct callback_data *cb_data = (struct callback_data*) userdata;
456 GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
458 ret = mm_sound_proxy_add_device_info_changed_callback(_mm_sound_device_info_changed_callback_wrapper_func,
459 cb_data, g_free, subs_id);
465 int mm_sound_client_remove_device_info_changed_callback(unsigned int subs_id)
467 int ret = MM_ERROR_NONE;
470 ret = mm_sound_proxy_remove_device_info_changed_callback(subs_id);
477 static void _mm_sound_device_state_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
478 int state, const char *name, int vendor_id, int product_id,
479 bool is_running, int *stream_id, int stream_num, void *userdata)
481 mm_sound_device_t device_h;
482 struct callback_data *cb_data = (struct callback_data*) userdata;
485 debug_log("[Device State Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x) product-id(%04x)",
486 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id);
488 if (cb_data == NULL) {
489 debug_warning("device state changed callback data null");
493 device_flags = (int) cb_data->extra_data;
495 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
498 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
499 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
500 debug_error("Failed to fill sound device");
504 ((mm_sound_device_state_changed_cb)(cb_data->user_cb))(&device_h, state, cb_data->user_data);
507 int mm_sound_client_add_device_state_changed_callback(int device_flags, mm_sound_device_state_changed_cb func,
508 void *userdata, unsigned int *id)
510 int ret = MM_ERROR_NONE;
511 struct callback_data *cb_data = (struct callback_data*) userdata;
515 GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
517 ret = mm_sound_proxy_add_device_state_changed_callback(_mm_sound_device_state_changed_callback_wrapper_func,
518 cb_data, g_free, id);
524 int mm_sound_client_remove_device_state_changed_callback(unsigned int id)
526 int ret = MM_ERROR_NONE;
529 ret = mm_sound_proxy_remove_device_state_changed_callback(id);
535 static void _mm_sound_device_running_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
536 int state, const char *name, int vendor_id, int product_id,
537 bool is_running, int *stream_id, int stream_num, void *userdata)
539 mm_sound_device_t device_h;
540 struct callback_data *cb_data = (struct callback_data*) userdata;
543 debug_log("[Device Running Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x), product-id(%04x)",
544 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id);
546 if (cb_data == NULL) {
547 debug_warning("device running changed callback data null");
551 device_flags = (int) cb_data->extra_data;
553 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
556 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
557 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
558 debug_error("Failed to fill sound device");
562 ((mm_sound_device_running_changed_cb)(cb_data->user_cb))(&device_h, is_running, cb_data->user_data);
565 int mm_sound_client_add_device_running_changed_callback(int device_flags, mm_sound_device_running_changed_cb func,
566 void *userdata, unsigned int *id)
568 int ret = MM_ERROR_NONE;
569 struct callback_data *cb_data = (struct callback_data*) userdata;
573 GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
575 ret = mm_sound_proxy_add_device_running_changed_callback(_mm_sound_device_running_changed_callback_wrapper_func,
576 cb_data, g_free, id);
582 int mm_sound_client_remove_device_running_changed_callback(unsigned int id)
584 int ret = MM_ERROR_NONE;
587 ret = mm_sound_proxy_remove_device_running_changed_callback(id);
593 int mm_sound_client_is_stream_on_device(int stream_id, int device_id, bool *is_on)
595 int ret = MM_ERROR_NONE;
599 debug_error("Invalid Parameter");
600 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
604 if ((ret = mm_sound_proxy_is_stream_on_device(stream_id, device_id, is_on)) != MM_ERROR_NONE) {
605 debug_error("failed to query is stream on device, ret[0x%x]", ret);
614 int __convert_volume_type_to_str(volume_type_t volume_type, char **volume_type_str)
616 int ret = MM_ERROR_NONE;
618 if (!volume_type_str)
619 return MM_ERROR_COMMON_INVALID_ARGUMENT;
621 switch (volume_type) {
622 case VOLUME_TYPE_SYSTEM:
623 *volume_type_str = "system";
625 case VOLUME_TYPE_NOTIFICATION:
626 *volume_type_str = "notification";
628 case VOLUME_TYPE_ALARM:
629 *volume_type_str = "alarm";
631 case VOLUME_TYPE_RINGTONE:
632 *volume_type_str = "ringtone";
634 case VOLUME_TYPE_MEDIA:
635 *volume_type_str = "media";
637 case VOLUME_TYPE_CALL:
638 *volume_type_str = "call";
640 case VOLUME_TYPE_VOIP:
641 *volume_type_str = "voip";
643 case VOLUME_TYPE_VOICE:
644 *volume_type_str = "voice";
647 debug_error("unexpected volume type [%d]", volume_type);
648 return MM_ERROR_SOUND_INTERNAL;
650 debug_log("volume_type[%s]", *volume_type_str);
654 int __convert_volume_type_internal_to_str(volume_type_internal_t volume_type, char **volume_type_str)
656 int ret = MM_ERROR_NONE;
658 if (!volume_type_str)
659 return MM_ERROR_COMMON_INVALID_ARGUMENT;
661 switch (volume_type) {
662 case VOLUME_TYPE_BIXBY:
663 *volume_type_str = "bixby";
666 debug_error("unexpected volume type [%d]", volume_type);
667 return MM_ERROR_SOUND_INTERNAL;
669 debug_log("volume_type[%s]", *volume_type_str);
673 static int __convert_volume_type_to_int(const char *volume_type_str, int *volume_type, bool *is_for_internal)
675 int ret = MM_ERROR_NONE;
677 if (!volume_type || !volume_type_str || !is_for_internal)
678 return MM_ERROR_COMMON_INVALID_ARGUMENT;
680 if (!strncmp(volume_type_str, "system", VOLUME_TYPE_LEN)) {
681 *volume_type = VOLUME_TYPE_SYSTEM;
682 *is_for_internal = false;
683 } else if (!strncmp(volume_type_str, "notification", VOLUME_TYPE_LEN)) {
684 *volume_type = VOLUME_TYPE_NOTIFICATION;
685 *is_for_internal = false;
686 } else if (!strncmp(volume_type_str, "alarm", VOLUME_TYPE_LEN)) {
687 *volume_type = VOLUME_TYPE_ALARM;
688 *is_for_internal = false;
689 } else if (!strncmp(volume_type_str, "ringtone", VOLUME_TYPE_LEN)) {
690 *volume_type = VOLUME_TYPE_RINGTONE;
691 *is_for_internal = false;
692 } else if (!strncmp(volume_type_str, "media", VOLUME_TYPE_LEN)) {
693 *volume_type = VOLUME_TYPE_MEDIA;
694 *is_for_internal = false;
695 } else if (!strncmp(volume_type_str, "call", VOLUME_TYPE_LEN)) {
696 *volume_type = VOLUME_TYPE_CALL;
697 *is_for_internal = false;
698 } else if (!strncmp(volume_type_str, "voip", VOLUME_TYPE_LEN)) {
699 *volume_type = VOLUME_TYPE_VOIP;
700 *is_for_internal = false;
701 } else if (!strncmp(volume_type_str, "voice", VOLUME_TYPE_LEN)) {
702 *volume_type = VOLUME_TYPE_VOICE;
703 *is_for_internal = false;
704 /* else-if statements below are for internal use */
705 } else if (!strncmp(volume_type_str, "bixby", VOLUME_TYPE_LEN)) {
706 *volume_type = VOLUME_TYPE_BIXBY;
707 *is_for_internal = true;
709 debug_log("Invalid volume type : [%s]", volume_type_str);
710 ret = MM_ERROR_SOUND_INTERNAL;
716 int mm_sound_client_set_volume_by_type(volume_type_t type, const unsigned int level)
718 int ret = MM_ERROR_NONE;
719 char *type_str = NULL;
722 if (type >= VOLUME_TYPE_MAX) {
723 debug_error("invalid volume type %d", type);
724 return MM_ERROR_INVALID_ARGUMENT;
727 if ((ret = __convert_volume_type_to_str(type, &type_str)) != MM_ERROR_NONE) {
728 debug_error("volume type convert failed");
732 ret = mm_sound_proxy_set_volume_by_type(type_str, level);
739 int mm_sound_client_get_volume_by_type(volume_type_t type, unsigned int *level)
741 int ret = MM_ERROR_NONE;
745 debug_error("invalid argument, level is null");
746 return MM_ERROR_INVALID_ARGUMENT;
749 if (type >= VOLUME_TYPE_MAX) {
750 debug_error("invalid volume type %d", type);
751 return MM_ERROR_INVALID_ARGUMENT;
754 /* Get volume value from VCONF */
755 if (vconf_get_int(g_volume_vconf[type], &vconf_value)) {
756 debug_error("vconf_get_int(%s) failed..\n", g_volume_vconf[type]);
757 return MM_ERROR_SOUND_INTERNAL;
760 *level = vconf_value;
765 int mm_sound_client_set_volume_by_internal_type(volume_type_internal_t type, const unsigned int level)
767 int ret = MM_ERROR_NONE;
768 char *type_str = NULL;
772 if ((ret = __convert_volume_type_internal_to_str(type, &type_str)) != MM_ERROR_NONE) {
773 debug_error("volume type convert failed");
777 ret = mm_sound_proxy_set_volume_by_type(type_str, level);
784 int mm_sound_client_get_volume_by_internal_type(volume_type_internal_t type, unsigned int *level)
786 int ret = MM_ERROR_NONE;
790 debug_error("invalid argument, level is null");
791 return MM_ERROR_INVALID_ARGUMENT;
794 /* Get volume value from VCONF */
795 if (vconf_get_int(g_volume_vconf_internal[type], &vconf_value)) {
796 debug_error("vconf_get_int(%s) failed..\n", g_volume_vconf_internal[type]);
797 return MM_ERROR_SOUND_INTERNAL;
800 *level = vconf_value;
805 static void _mm_sound_volume_changed_callback_wrapper_func(const char *direction, const char *volume_type_str,
806 int volume_level, void *userdata)
809 bool is_for_internal = false;
810 struct callback_data *cb_data = (struct callback_data *) userdata;
812 debug_log("direction : %s, volume_type : %s, volume_level : %d",
813 direction, volume_type_str, volume_level);
815 if (cb_data == NULL) {
816 debug_warning("volume changed callback data null");
820 if (__convert_volume_type_to_int(volume_type_str, &volume_type, &is_for_internal) != MM_ERROR_NONE) {
821 debug_error("volume type convert failed");
825 if (!is_for_internal && !cb_data->extra_data) {
826 debug_log("Invoke volume changed cb, direction : %s, vol_type : %s(%d), level : %u",
827 direction, volume_type_str, volume_type, volume_level);
828 ((mm_sound_volume_changed_cb)(cb_data->user_cb))((volume_type_t)volume_type, volume_level, cb_data->user_data);
829 } else if (is_for_internal && (cb_data->extra_data && (bool)(cb_data->extra_data))) {
830 debug_log("Invoke internal volume changed cb, direction : %s, vol_type : %s(%d), level : %u",
831 direction, volume_type_str, volume_type, volume_level);
832 ((mm_sound_volume_changed_cb_internal)(cb_data->user_cb))((volume_type_internal_t)volume_type, volume_level, cb_data->user_data);
836 int mm_sound_client_add_volume_changed_callback(mm_sound_volume_changed_cb func, void* userdata, unsigned int *subs_id)
838 int ret = MM_ERROR_NONE;
839 struct callback_data *cb_data = NULL;
843 GET_CB_DATA(cb_data, func, userdata, NULL);
845 ret = mm_sound_proxy_add_volume_changed_callback(_mm_sound_volume_changed_callback_wrapper_func, cb_data, g_free, subs_id);
852 int mm_sound_client_add_volume_changed_callback_internal(mm_sound_volume_changed_cb_internal func, void* userdata, unsigned int *subs_id)
854 int ret = MM_ERROR_NONE;
855 struct callback_data *cb_data = NULL;
856 gboolean is_for_internal = true;
860 GET_CB_DATA(cb_data, func, userdata, (void*)is_for_internal);
862 ret = mm_sound_proxy_add_volume_changed_callback(_mm_sound_volume_changed_callback_wrapper_func, cb_data, g_free, subs_id);
869 int mm_sound_client_remove_volume_changed_callback(unsigned int subs_id)
871 int ret = MM_ERROR_NONE;
874 ret = mm_sound_proxy_remove_volume_changed_callback(subs_id);
880 int mm_sound_client_set_mute_by_type(volume_type_t type, bool mute)
882 int ret = MM_ERROR_NONE;
883 char *type_str = NULL;
887 if (type > VOLUME_TYPE_VOICE) {
888 debug_error("invalid volume type %d", type);
889 return MM_ERROR_INVALID_ARGUMENT;
892 if ((ret = __convert_volume_type_to_str(type, &type_str)) != MM_ERROR_NONE) {
893 debug_error("volume type convert failed");
897 ret = mm_sound_proxy_set_mute_by_type(type_str, mute);
904 int mm_sound_client_get_mute_by_type(volume_type_t type, bool *muted)
906 int ret = MM_ERROR_NONE;
911 if (type > VOLUME_TYPE_VOICE) {
912 debug_error("invalid volume type %d", type);
913 return MM_ERROR_INVALID_ARGUMENT;
916 /* Get mute state from VCONF */
917 if (vconf_get_bool(g_mute_vconf[type], &vconf_value)) {
918 debug_error("vconf_get_int(%s) failed..\n", g_mute_vconf[type]);
919 return MM_ERROR_SOUND_INTERNAL;
922 *muted = (bool)vconf_value;
928 int mm_sound_client_set_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_parameters, const char *filter_group)
930 int ret = MM_ERROR_NONE;
933 ret = mm_sound_proxy_set_filter_by_type(stream_type, filter_name, filter_parameters, filter_group);
939 int mm_sound_client_unset_filter_by_type(const char *stream_type)
941 int ret = MM_ERROR_NONE;
944 ret = mm_sound_proxy_unset_filter_by_type(stream_type);
950 int mm_sound_client_control_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_controls)
952 int ret = MM_ERROR_NONE;
955 ret = mm_sound_proxy_control_filter_by_type(stream_type, filter_name, filter_controls);
961 int mm_sound_client_is_focus_cb_thread(GThread *mine, bool *result, bool *is_for_watching)
963 int ret = MM_ERROR_NONE;
966 if (!mine || !result)
967 ret = MM_ERROR_INVALID_ARGUMENT;
970 for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
971 if (!g_focus_sound_handle[i].is_used)
973 if (g_focus_sound_handle[i].focus_cb_thread == mine) {
976 *is_for_watching = false;
979 if (g_focus_sound_handle[i].focus_watch_cb_thread == mine) {
982 *is_for_watching = true;
991 int mm_sound_client_register_focus(int pid, const char *stream_type,
992 mm_sound_focus_changed_cb callback, void* user_data, int *id)
994 int ret = MM_ERROR_NONE;
998 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1000 if (focus_find_empty_index(&index)) {
1001 ret = MM_ERROR_SOUND_INTERNAL;
1005 g_focus_sound_handle[index].focus_pid = pid;
1006 g_focus_sound_handle[index].focus_callback = callback;
1007 g_focus_sound_handle[index].user_data = user_data;
1008 g_focus_sound_handle[index].auto_reacquire = true;
1010 ret = mm_sound_proxy_register_focus(index, stream_type, id);
1011 if (ret == MM_ERROR_NONE) {
1012 debug_msg("Success to register focus, client_fd[%d], id[%d]", g_focus_sound_handle[index].client_fd, *id);
1013 if (focus_init_context(index, false)) {
1014 ret = MM_ERROR_SOUND_INTERNAL;
1018 debug_error("Error occurred : 0x%x", ret);
1022 focus_init_callback(index, false);
1025 if (ret != MM_ERROR_NONE && index >= 0)
1026 g_focus_sound_handle[index].is_used = false;
1028 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1034 int mm_sound_client_unregister_focus(int id)
1036 int ret = MM_ERROR_NONE;
1040 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1042 index = focus_find_index_by_handle(id);
1044 debug_error("Could not find index");
1045 ret = MM_ERROR_INVALID_ARGUMENT;
1049 if (!g_mutex_trylock(&g_focus_sound_handle[index].focus_lock)) {
1050 debug_warning("maybe focus_callback is being called, try one more time..");
1051 usleep(2500000); /* 2.5 sec */
1052 if (g_mutex_trylock(&g_focus_sound_handle[index].focus_lock))
1053 debug_msg("finally got focus_lock");
1056 ret = mm_sound_proxy_unregister_focus(index);
1057 if (ret == MM_ERROR_NONE)
1058 debug_msg("Success to unregister focus");
1060 debug_error("Error occurred : 0x%x", ret);
1062 g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1064 focus_deinit_callback(index, false);
1065 g_focus_sound_handle[index].focus_fd = 0;
1066 g_focus_sound_handle[index].focus_pid = 0;
1067 g_focus_sound_handle[index].client_fd = 0;
1068 g_focus_sound_handle[index].handle = 0;
1069 g_focus_sound_handle[index].is_used = false;
1070 focus_deinit_context(index, false);
1073 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1078 int mm_sound_client_set_focus_reacquisition(int id, bool reacquisition)
1080 int ret = MM_ERROR_NONE;
1086 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1088 index = focus_find_index_by_handle(id);
1090 debug_error("Could not find index");
1091 ret = MM_ERROR_INVALID_ARGUMENT;
1095 ret = mm_sound_client_is_focus_cb_thread(g_thread_self(), &result, NULL);
1097 debug_error("mm_sound_client_is_focus_cb_thread failed");
1099 } else if (!result) {
1100 ret = mm_sound_proxy_set_focus_reacquisition(index, reacquisition);
1101 if (ret == MM_ERROR_NONE) {
1102 debug_msg("Success to set focus reacquisition to [%d]", reacquisition);
1104 debug_error("Error occurred : 0x%x", ret);
1108 debug_warning("Inside the focus cb thread, set focus reacquisition to [%d]", reacquisition);
1111 g_focus_sound_handle[index].auto_reacquire = reacquisition;
1112 debug_msg("set focus reacquisition(%d) for id(%d)", reacquisition, id);
1115 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1120 int mm_sound_client_get_focus_reacquisition(int id, bool *reacquisition)
1122 int ret = MM_ERROR_NONE;
1127 if (!reacquisition) {
1128 debug_error("Invalid parameter");
1129 return MM_ERROR_INVALID_ARGUMENT;
1132 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1134 index = focus_find_index_by_handle(id);
1136 debug_error("Could not find index");
1137 ret = MM_ERROR_INVALID_ARGUMENT;
1141 *reacquisition = g_focus_sound_handle[index].auto_reacquire;
1142 debug_msg("get focus reacquisition(%d) for id(%d)", *reacquisition, id);
1145 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1150 int mm_sound_client_get_acquired_focus_stream_type(int focus_type, char **stream_type, int *option, char **ext_info)
1152 int ret = MM_ERROR_NONE;
1156 ret = mm_sound_proxy_get_acquired_focus_stream_type(focus_type, stream_type, option, ext_info);
1157 if (ret == MM_ERROR_NONE)
1158 debug_msg("Success to get stream type of acquired focus, stream_type(%s), ext_info(%s)",
1159 *stream_type, *ext_info);
1161 debug_error("Error occurred : 0x%x", ret);
1168 int mm_sound_client_acquire_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1170 int ret = MM_ERROR_NONE;
1174 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1176 index = focus_find_index_by_handle(id);
1178 debug_error("Could not find index");
1179 ret = MM_ERROR_INVALID_ARGUMENT;
1183 ret = mm_sound_proxy_acquire_focus(index, type, option, ext_info);
1184 if (ret == MM_ERROR_NONE)
1185 debug_msg("Success to acquire focus");
1187 debug_error("Error occurred : 0x%x", ret);
1190 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1195 int mm_sound_client_release_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1197 int ret = MM_ERROR_NONE;
1201 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1203 index = focus_find_index_by_handle(id);
1205 debug_error("Could not find index");
1206 ret = MM_ERROR_INVALID_ARGUMENT;
1210 ret = mm_sound_proxy_release_focus(index, type, option, ext_info);
1211 if (ret == MM_ERROR_NONE)
1212 debug_msg("Success to release focus");
1214 debug_error("Error occurred : 0x%x", ret);
1217 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1222 int mm_sound_client_update_stream_focus_status(int id, unsigned int status)
1224 int ret = MM_ERROR_NONE;
1227 if ((ret = mm_sound_proxy_update_stream_focus_status(id, status)) != MM_ERROR_NONE)
1228 debug_error("failed to update stream focus status, ret[0x%x]", ret);
1234 int mm_sound_client_deliver_focus(int src_id, int dst_id, mm_sound_focus_type_e focus_type)
1236 int ret = MM_ERROR_NONE;
1242 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1244 src_index = focus_find_index_by_handle(src_id);
1245 if (src_index == -1) {
1246 debug_error("Could not find src index");
1247 ret = MM_ERROR_INVALID_ARGUMENT;
1250 dst_index = focus_find_index_by_handle(dst_id);
1251 if (dst_index == -1) {
1252 debug_error("Could not find dst index");
1253 ret = MM_ERROR_INVALID_ARGUMENT;
1256 if (g_focus_sound_handle[src_index].focus_pid != g_focus_sound_handle[dst_index].focus_pid) {
1257 debug_error("pid[%d/%d] are not same for dst/src",
1258 g_focus_sound_handle[src_index].focus_pid,
1259 g_focus_sound_handle[dst_index].focus_pid);
1260 ret = MM_ERROR_SOUND_INTERNAL;
1264 if ((ret = mm_sound_proxy_deliver_focus(src_index, dst_index, focus_type)) != MM_ERROR_NONE)
1265 debug_error("failed to deliver focus, ret[0x%x]", ret);
1268 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1273 int mm_sound_client_set_focus_watch_callback(int pid, mm_sound_focus_type_e focus_type,
1274 mm_sound_focus_changed_watch_cb callback, void* user_data, int *id)
1276 int ret = MM_ERROR_NONE;
1282 return MM_ERROR_INVALID_ARGUMENT;
1284 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1286 if (focus_find_empty_index(&index)) {
1287 ret = MM_ERROR_SOUND_INTERNAL;
1291 g_focus_sound_handle[index].focus_pid = pid;
1292 g_focus_sound_handle[index].watch_callback = callback;
1293 g_focus_sound_handle[index].user_data = user_data;
1294 g_focus_sound_handle[index].unset_watch_callback_requested = false;
1296 ret = mm_sound_proxy_add_focus_watch_callback(index, focus_type);
1297 if (ret == MM_ERROR_NONE) {
1298 *id = g_focus_sound_handle[index].handle;
1299 debug_msg("Success to add watch focus cb, id(%d)", *id);
1300 if (focus_init_context(index, true)) {
1301 ret = MM_ERROR_SOUND_INTERNAL;
1305 debug_error("Error occurred : 0x%x", ret);
1309 focus_init_callback(index, true);
1312 if (ret != MM_ERROR_NONE && index >= 0)
1313 g_focus_sound_handle[index].is_used = false;
1315 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1320 int mm_sound_client_request_unset_focus_watch_callback(int id)
1322 int ret = MM_ERROR_NONE;
1326 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1328 index = focus_watch_find_index_by_handle(id);
1330 debug_error("Could not find index");
1331 ret = MM_ERROR_INVALID_ARGUMENT;
1334 g_focus_sound_handle[index].unset_watch_callback_requested = true;
1337 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1342 int mm_sound_client_unset_focus_watch_callback(int id)
1344 int ret = MM_ERROR_NONE;
1348 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1350 index = focus_watch_find_index_by_handle(id);
1352 debug_error("Could not find index");
1353 ret = MM_ERROR_INVALID_ARGUMENT;
1357 g_mutex_lock(&g_focus_sound_handle[index].focus_lock);
1359 g_focus_sound_handle[index].is_used = false;
1361 ret = mm_sound_proxy_remove_focus_watch_callback(index);
1362 if (ret == MM_ERROR_NONE)
1363 debug_msg("Success to remove watch focus cb, id(%d)", g_focus_sound_handle[index].handle);
1365 debug_error("Error occurred : 0x%x", ret);
1368 g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1370 focus_deinit_callback(index, true);
1371 g_focus_sound_handle[index].focus_fd = 0;
1372 g_focus_sound_handle[index].focus_pid = 0;
1373 g_focus_sound_handle[index].client_fd = 0;
1374 g_focus_sound_handle[index].handle = 0;
1375 focus_deinit_context(index, true);
1378 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1383 static gboolean _idle_event_callback(void *data)
1385 focus_idle_event_t *idle_event_data = (focus_idle_event_t*)data;
1386 int ret = MM_ERROR_NONE;
1389 debug_error("data is null");
1393 debug_msg("idle_event_data(%p): type(%d), data(%d)",
1394 idle_event_data, idle_event_data->type, idle_event_data->data);
1396 switch (idle_event_data->type) {
1397 case IDLE_EVENT_TYPE_UNSET_FOCUS_WATCH_CB:
1398 if ((ret = mm_sound_client_unset_focus_watch_callback(idle_event_data->data)))
1399 debug_error("Could not unset focus watch callback, id(%d), ret = %x", idle_event_data->data, ret);
1401 case IDLE_EVENT_TYPE_UNREGISTER_FOCUS:
1402 if ((ret = mm_sound_client_unregister_focus(idle_event_data->data)))
1403 debug_error("Could not unregister focus, id(%d), ret = %x", idle_event_data->data, ret);
1406 debug_warning("invalid type(%d)", idle_event_data->type);
1410 g_free(idle_event_data);
1412 g_idle_event_src = 0;
1414 MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex);
1419 int mm_sound_client_execute_focus_func_in_main_context(focus_idle_event_type_e type, int data)
1421 focus_idle_event_t *idle_event_data = NULL;
1423 if (IDLE_EVENT_TYPE_MAX < type)
1424 return MM_ERROR_INVALID_ARGUMENT;
1426 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL);
1428 idle_event_data = g_new0(focus_idle_event_t, 1);
1429 idle_event_data->type = type;
1430 idle_event_data->data = data;
1432 g_idle_event_src = g_idle_add_full(G_PRIORITY_HIGH,
1433 (GSourceFunc)_idle_event_callback,
1434 (gpointer)idle_event_data,
1437 return MM_ERROR_NONE;
1440 int mm_sound_client_add_ducking_state_changed_callback(mm_sound_ducking_state_changed_cb func, void* userdata, unsigned int *subs_id)
1442 int ret = MM_ERROR_NONE;
1443 struct callback_data *cb_data = NULL;
1447 GET_CB_DATA(cb_data, func, userdata, NULL);
1449 ret = mm_sound_proxy_add_ducking_state_changed_callback((mm_sound_ducking_state_changed_wrapper_cb)func,
1450 cb_data, g_free, subs_id);
1457 int mm_sound_client_remove_ducking_state_changed_callback(unsigned int subs_id)
1459 int ret = MM_ERROR_NONE;
1462 ret = mm_sound_proxy_remove_ducking_state_changed_callback(subs_id);
1468 int mm_sound_client_add_test_callback(mm_sound_test_cb func, void* user_data, unsigned int *subs_id)
1470 int ret = MM_ERROR_NONE;
1474 ret = mm_sound_proxy_add_test_callback(func, user_data, g_free, subs_id);
1480 int mm_sound_client_remove_test_callback(unsigned int subs_id)
1482 int ret = MM_ERROR_NONE;
1485 ret = mm_sound_proxy_remove_test_callback(subs_id);
1491 int mm_sound_client_test(int a, int b, int* getv)
1493 int ret = MM_ERROR_NONE;
1497 ret = mm_sound_proxy_test(a, b, getv);
1498 debug_log("%d * %d -> result : %d", a, b, *getv);