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.
32 #include "include/mm_sound.h"
33 #include "include/mm_sound_client.h"
34 #include "include/mm_sound_proxy.h"
35 #include "include/mm_sound_common.h"
36 #include "include/mm_sound_device.h"
37 #include "include/mm_sound_stream.h"
38 #include "include/mm_sound_focus_private.h"
40 #define CLIENT_HANDLE_MAX 256
41 #define VOLUME_TYPE_LEN 64
43 #define VCONF_KEY_VOLUME_PREFIX "file/private/sound/volume"
44 #define VCONF_KEY_VOLUME_TYPE_SYSTEM VCONF_KEY_VOLUME_PREFIX"/system"
45 #define VCONF_KEY_VOLUME_TYPE_NOTIFICATION VCONF_KEY_VOLUME_PREFIX"/notification"
46 #define VCONF_KEY_VOLUME_TYPE_ALARM VCONF_KEY_VOLUME_PREFIX"/alarm"
47 #define VCONF_KEY_VOLUME_TYPE_RINGTONE VCONF_KEY_VOLUME_PREFIX"/ringtone"
48 #define VCONF_KEY_VOLUME_TYPE_MEDIA VCONF_KEY_VOLUME_PREFIX"/media"
49 #define VCONF_KEY_VOLUME_TYPE_CALL VCONF_KEY_VOLUME_PREFIX"/call"
50 #define VCONF_KEY_VOLUME_TYPE_VOIP VCONF_KEY_VOLUME_PREFIX"/voip"
51 #define VCONF_KEY_VOLUME_TYPE_VOICE VCONF_KEY_VOLUME_PREFIX"/voice"
52 #define VCONF_KEY_VOLUME_TYPE_ANDROID VCONF_KEY_VOLUME_PREFIX"/fixed"
54 #define VCONF_KEY_MUTE_PREFIX "file/private/sound/mute"
55 #define VCONF_KEY_MUTE_TYPE_SYSTEM VCONF_KEY_MUTE_PREFIX"/system"
56 #define VCONF_KEY_MUTE_TYPE_NOTIFICATION VCONF_KEY_MUTE_PREFIX"/notification"
57 #define VCONF_KEY_MUTE_TYPE_ALARM VCONF_KEY_MUTE_PREFIX"/alarm"
58 #define VCONF_KEY_MUTE_TYPE_RINGTONE VCONF_KEY_MUTE_PREFIX"/ringtone"
59 #define VCONF_KEY_MUTE_TYPE_MEDIA VCONF_KEY_MUTE_PREFIX"/media"
60 #define VCONF_KEY_MUTE_TYPE_CALL VCONF_KEY_MUTE_PREFIX"/call"
61 #define VCONF_KEY_MUTE_TYPE_VOIP VCONF_KEY_MUTE_PREFIX"/voip"
62 #define VCONF_KEY_MUTE_TYPE_VOICE VCONF_KEY_MUTE_PREFIX"/voice"
64 /* For internal use */
65 #define VCONF_KEY_VOLUME_TYPE_BIXBY VCONF_KEY_VOLUME_PREFIX"/bixby"
67 static char *g_volume_vconf[VOLUME_TYPE_MAX] = {
68 VCONF_KEY_VOLUME_TYPE_SYSTEM, /* VOLUME_TYPE_SYSTEM */
69 VCONF_KEY_VOLUME_TYPE_NOTIFICATION, /* VOLUME_TYPE_NOTIFICATION */
70 VCONF_KEY_VOLUME_TYPE_ALARM, /* VOLUME_TYPE_ALARM */
71 VCONF_KEY_VOLUME_TYPE_RINGTONE, /* VOLUME_TYPE_RINGTONE */
72 VCONF_KEY_VOLUME_TYPE_MEDIA, /* VOLUME_TYPE_MEDIA */
73 VCONF_KEY_VOLUME_TYPE_CALL, /* VOLUME_TYPE_CALL */
74 VCONF_KEY_VOLUME_TYPE_VOIP, /* VOLUME_TYPE_VOIP */
75 VCONF_KEY_VOLUME_TYPE_VOICE, /* VOLUME_TYPE_VOICE */
76 VCONF_KEY_VOLUME_TYPE_ANDROID /* VOLUME_TYPE_FIXED */
79 static char *g_volume_vconf_internal[] = {
80 VCONF_KEY_VOLUME_TYPE_BIXBY, /* VOLUME_TYPE_BIXBY */
83 static char *g_mute_vconf[] = {
84 VCONF_KEY_MUTE_TYPE_SYSTEM, /* MUTE_TYPE_SYSTEM */
85 VCONF_KEY_MUTE_TYPE_NOTIFICATION, /* MUTE_TYPE_NOTIFICATION */
86 VCONF_KEY_MUTE_TYPE_ALARM, /* MUTE_TYPE_ALARM */
87 VCONF_KEY_MUTE_TYPE_RINGTONE, /* MUTE_TYPE_RINGTONE */
88 VCONF_KEY_MUTE_TYPE_MEDIA, /* MUTE_TYPE_MEDIA */
89 VCONF_KEY_MUTE_TYPE_CALL, /* MUTE_TYPE_CALL */
90 VCONF_KEY_MUTE_TYPE_VOIP, /* MUTE_TYPE_VOIP */
91 VCONF_KEY_MUTE_TYPE_VOICE, /* MUTE_TYPE_VOICE */
94 struct callback_data {
101 #define GET_CB_DATA(_cb_data, _func, _userdata, _extradata) \
103 _cb_data = (struct callback_data*) g_try_malloc0(sizeof(struct callback_data)); \
105 debug_error("failed to allocate callback_data"); \
106 return MM_ERROR_OUT_OF_MEMORY; \
108 _cb_data->user_cb = _func; \
109 _cb_data->user_data = _userdata; \
110 _cb_data->extra_data = _extradata; \
113 static pthread_mutex_t g_index_mutex = PTHREAD_MUTEX_INITIALIZER;
114 static pthread_mutex_t g_event_mutex = PTHREAD_MUTEX_INITIALIZER;
115 static guint g_idle_event_src;
118 /* handle to watch end of playing */
120 /* subscription id to unsubscribe when handle ended */
122 } play_sound_end_callback_data_t;
124 typedef struct _focus_idle_event {
125 focus_idle_event_type_e type;
127 } focus_idle_event_t;
129 int mm_sound_client_initialize(void)
131 int ret = MM_ERROR_NONE;
135 mm_sound_proxy_initialize();
136 g_idle_event_src = 0;
142 int mm_sound_client_finalize(void)
144 int ret = MM_ERROR_NONE;
148 ret = mm_sound_proxy_finalize();
150 if (g_idle_event_src > 0) {
151 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL);
152 g_source_remove(g_idle_event_src);
153 MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex);
160 void mm_sound_convert_volume_type_to_stream_type(int volume_type, char *stream_type)
162 switch (volume_type) {
163 case VOLUME_TYPE_SYSTEM:
164 MMSOUND_STRNCPY(stream_type, "system", MAX_STREAM_TYPE_LEN);
166 case VOLUME_TYPE_NOTIFICATION:
167 MMSOUND_STRNCPY(stream_type, "notification", MAX_STREAM_TYPE_LEN);
169 case VOLUME_TYPE_ALARM:
170 MMSOUND_STRNCPY(stream_type, "alarm", MAX_STREAM_TYPE_LEN);
172 case VOLUME_TYPE_RINGTONE:
173 MMSOUND_STRNCPY(stream_type, "ringtone-voip", MAX_STREAM_TYPE_LEN);
175 case VOLUME_TYPE_MEDIA:
176 MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN);
178 case VOLUME_TYPE_CALL:
179 MMSOUND_STRNCPY(stream_type, "call-voice", MAX_STREAM_TYPE_LEN);
181 case VOLUME_TYPE_VOIP:
182 MMSOUND_STRNCPY(stream_type, "voip", MAX_STREAM_TYPE_LEN);
184 case VOLUME_TYPE_VOICE:
185 MMSOUND_STRNCPY(stream_type, "voice-information", MAX_STREAM_TYPE_LEN);
188 MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN);
192 debug_msg("volume type (%d) converted to stream type (%s)", volume_type, stream_type);
196 /*****************************************************************************************
197 DBUS SUPPORTED FUNCTIONS
198 ******************************************************************************************/
199 static int _mm_sound_client_device_list_dump(GList *device_list)
201 int ret = MM_ERROR_NONE;
203 mm_sound_device_t *device_node = NULL;
206 debug_error("Device list NULL, cannot dump list");
207 return MM_ERROR_SOUND_INTERNAL;
210 debug_log("======================== device list : start ==========================");
211 for (list = device_list; list != NULL; list = list->next) {
212 device_node = (mm_sound_device_t *)list->data;
214 debug_log(" list idx[%d]: type[%17s], id[%02d], io_direction[%d], state[%d], name[%s]",
215 count++, device_node->type, device_node->id, device_node->io_direction,
216 device_node->state, device_node->name);
219 debug_log("======================== device list : end ============================");
224 int mm_sound_client_get_current_connected_device_list(int device_flags, mm_sound_device_list_t *device_list)
226 int ret = MM_ERROR_NONE;
230 debug_error("Device list NULL");
231 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
235 if ((ret = mm_sound_proxy_get_current_connected_device_list(device_flags, &device_list->list)) != MM_ERROR_NONE) {
236 debug_error("failed to get current connected device list with dbus, ret[0x%x]", ret);
239 if (!device_list->list) {
240 debug_error("Got device list null");
241 ret = MM_ERROR_SOUND_NO_DATA;
244 _mm_sound_client_device_list_dump(device_list->list);
251 int mm_sound_client_get_device_by_id(int device_id, mm_sound_device_t **device)
253 int ret = MM_ERROR_NONE;
257 if ((ret = mm_sound_proxy_get_device_by_id(device_id, device)) != MM_ERROR_NONE)
258 debug_error("failed to get device by id");
265 static bool device_is_match_direction(int direction, int mask)
267 if (mask == DEVICE_IO_DIRECTION_FLAGS || mask == 0)
270 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_IN))
272 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_OUT))
274 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH))
280 static bool device_is_match_state(int state, int mask)
282 if (mask == DEVICE_STATE_FLAGS || mask == 0)
285 if ((mask & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_DEACTIVATED))
287 if ((mask & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_ACTIVATED))
293 static bool device_is_match_type(const char *type, int mask)
296 const char *builtin_prefix = "builtin";
298 if (mask == DEVICE_TYPE_FLAGS || mask == 0)
301 is_builtin = !strncmp(type, builtin_prefix, strlen(builtin_prefix));
303 if ((mask & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG) && (is_builtin))
305 if ((mask & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG) && (!is_builtin))
311 static bool device_is_match_with_mask(const char *type, int direction, int state, int mask)
313 if (mask == DEVICE_ALL_FLAG)
316 return (device_is_match_direction(direction, mask & DEVICE_IO_DIRECTION_FLAGS) &&
317 device_is_match_state(state, mask & DEVICE_STATE_FLAGS) &&
318 device_is_match_type(type, mask & DEVICE_TYPE_FLAGS));
321 static int _fill_sound_device(mm_sound_device_t *device_h, int device_id, const char *device_type,
322 int direction, int state, const char *name, int vendor_id, int product_id,
323 int *stream_id, int stream_num, bool is_running)
327 if (stream_num > 0 && stream_id == NULL) {
328 debug_error("stream_num is %d, but stream_id is NULL", stream_num);
332 if (stream_num > MAX_STREAM_ON_DEVICE) {
333 debug_error("too many streams on this device");
337 device_h->id = device_id;
338 device_h->io_direction = direction;
339 device_h->state = state;
340 MMSOUND_STRNCPY(device_h->name, name, MAX_DEVICE_NAME_NUM);
341 MMSOUND_STRNCPY(device_h->type, device_type, MAX_DEVICE_TYPE_STR_LEN);
342 device_h->vendor_id = vendor_id;
343 device_h->product_id = product_id;
344 device_h->is_running = is_running;
346 if (stream_num > 0) {
347 device_h->stream_num = stream_num;
348 debug_log("%d streams on this device", stream_num);
349 for (i = 0; i < stream_num; i++) {
350 debug_log(" stream_id : %d", stream_id[i]);
351 device_h->stream_id[i] = stream_id[i];
354 device_h->stream_num = 0;
355 debug_log("There is no stream on this device");
361 static void _mm_sound_device_connected_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
362 int state, const char *name, int vendor_id, int product_id, bool is_running,
363 int *stream_id, int stream_num, bool is_connected, void *userdata)
365 mm_sound_device_t device_h;
366 struct callback_data *cb_data = (struct callback_data*) userdata;
369 debug_log("[Device %s] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x) product-id(%04x)",
370 is_connected ? "Connected" : "Disconnected", device_id, device_type, io_direction, state, name,
371 is_running, vendor_id, product_id);
373 if (cb_data == NULL) {
374 debug_warning("device connected changed callback data null");
378 device_flags = (int)(uintptr_t)cb_data->extra_data;
379 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
382 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
383 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
384 debug_error("Failed to fill sound device");
388 ((mm_sound_device_connected_cb)(cb_data->user_cb))(&device_h, is_connected, cb_data->user_data);
391 int mm_sound_client_add_device_connected_callback(int device_flags, mm_sound_device_connected_cb func,
392 void* userdata, unsigned int *subs_id)
394 int ret = MM_ERROR_NONE;
395 struct callback_data *cb_data = NULL;
399 GET_CB_DATA(cb_data, func, userdata, (void*)(uintptr_t)device_flags);
401 ret = mm_sound_proxy_add_device_connected_callback(_mm_sound_device_connected_callback_wrapper_func,
402 cb_data, g_free, subs_id);
408 int mm_sound_client_remove_device_connected_callback(unsigned int subs_id)
410 int ret = MM_ERROR_NONE;
413 ret = mm_sound_proxy_remove_device_connected_callback(subs_id);
419 static void _mm_sound_device_info_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
420 int state, const char *name, int vendor_id, int product_id, bool is_running,
421 int *stream_id, int stream_num, int changed_device_info_type, void *userdata)
423 mm_sound_device_t device_h;
424 struct callback_data *cb_data = (struct callback_data*) userdata;
427 debug_log("[Device Info Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) "
428 "vendor-id(%04x) product-id(%04x) changed_info_type(%d)",
429 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id, changed_device_info_type);
431 if (cb_data == NULL) {
432 debug_warning("device info changed callback data null");
436 device_flags = (int)(uintptr_t)cb_data->extra_data;
437 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
440 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
441 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
442 debug_error("Failed to fill sound device");
446 ((mm_sound_device_info_changed_cb)(cb_data->user_cb))(&device_h, changed_device_info_type, cb_data->user_data);
449 int mm_sound_client_add_device_info_changed_callback(int device_flags, mm_sound_device_info_changed_cb func,
450 void *userdata, unsigned int *subs_id)
452 int ret = MM_ERROR_NONE;
453 struct callback_data *cb_data = (struct callback_data*) userdata;
457 GET_CB_DATA(cb_data, func, userdata, (void *)(uintptr_t)device_flags);
459 ret = mm_sound_proxy_add_device_info_changed_callback(_mm_sound_device_info_changed_callback_wrapper_func,
460 cb_data, g_free, subs_id);
466 int mm_sound_client_remove_device_info_changed_callback(unsigned int subs_id)
468 int ret = MM_ERROR_NONE;
471 ret = mm_sound_proxy_remove_device_info_changed_callback(subs_id);
478 static void _mm_sound_device_state_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
479 int state, const char *name, int vendor_id, int product_id,
480 bool is_running, int *stream_id, int stream_num, void *userdata)
482 mm_sound_device_t device_h;
483 struct callback_data *cb_data = (struct callback_data*) userdata;
486 debug_log("[Device State Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x) product-id(%04x)",
487 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id);
489 if (cb_data == NULL) {
490 debug_warning("device state changed callback data null");
494 device_flags = (int)(uintptr_t)cb_data->extra_data;
496 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
499 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
500 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
501 debug_error("Failed to fill sound device");
505 ((mm_sound_device_state_changed_cb)(cb_data->user_cb))(&device_h, state, cb_data->user_data);
508 int mm_sound_client_add_device_state_changed_callback(int device_flags, mm_sound_device_state_changed_cb func,
509 void *userdata, unsigned int *id)
511 int ret = MM_ERROR_NONE;
512 struct callback_data *cb_data = (struct callback_data*) userdata;
516 GET_CB_DATA(cb_data, func, userdata, (void *)(uintptr_t)device_flags);
518 ret = mm_sound_proxy_add_device_state_changed_callback(_mm_sound_device_state_changed_callback_wrapper_func,
519 cb_data, g_free, id);
525 int mm_sound_client_remove_device_state_changed_callback(unsigned int id)
527 int ret = MM_ERROR_NONE;
530 ret = mm_sound_proxy_remove_device_state_changed_callback(id);
536 static void _mm_sound_device_running_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
537 int state, const char *name, int vendor_id, int product_id,
538 bool is_running, int *stream_id, int stream_num, void *userdata)
540 mm_sound_device_t device_h;
541 struct callback_data *cb_data = (struct callback_data*) userdata;
544 debug_log("[Device Running Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x), product-id(%04x)",
545 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id);
547 if (cb_data == NULL) {
548 debug_warning("device running changed callback data null");
552 device_flags = (int)(uintptr_t)cb_data->extra_data;
554 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
557 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
558 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
559 debug_error("Failed to fill sound device");
563 ((mm_sound_device_running_changed_cb)(cb_data->user_cb))(&device_h, is_running, cb_data->user_data);
566 int mm_sound_client_add_device_running_changed_callback(int device_flags, mm_sound_device_running_changed_cb func,
567 void *userdata, unsigned int *id)
569 int ret = MM_ERROR_NONE;
570 struct callback_data *cb_data = (struct callback_data*) userdata;
574 GET_CB_DATA(cb_data, func, userdata, (void *)(uintptr_t)device_flags);
576 ret = mm_sound_proxy_add_device_running_changed_callback(_mm_sound_device_running_changed_callback_wrapper_func,
577 cb_data, g_free, id);
583 int mm_sound_client_remove_device_running_changed_callback(unsigned int id)
585 int ret = MM_ERROR_NONE;
588 ret = mm_sound_proxy_remove_device_running_changed_callback(id);
594 int mm_sound_client_is_stream_on_device(int stream_id, int device_id, bool *is_on)
596 int ret = MM_ERROR_NONE;
600 debug_error("Invalid Parameter");
601 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
605 if ((ret = mm_sound_proxy_is_stream_on_device(stream_id, device_id, is_on)) != MM_ERROR_NONE) {
606 debug_error("failed to query is stream on device, ret[0x%x]", ret);
615 int __convert_volume_type_to_str(volume_type_t volume_type, char **volume_type_str)
617 int ret = MM_ERROR_NONE;
619 if (!volume_type_str)
620 return MM_ERROR_COMMON_INVALID_ARGUMENT;
622 switch (volume_type) {
623 case VOLUME_TYPE_SYSTEM:
624 *volume_type_str = "system";
626 case VOLUME_TYPE_NOTIFICATION:
627 *volume_type_str = "notification";
629 case VOLUME_TYPE_ALARM:
630 *volume_type_str = "alarm";
632 case VOLUME_TYPE_RINGTONE:
633 *volume_type_str = "ringtone";
635 case VOLUME_TYPE_MEDIA:
636 *volume_type_str = "media";
638 case VOLUME_TYPE_CALL:
639 *volume_type_str = "call";
641 case VOLUME_TYPE_VOIP:
642 *volume_type_str = "voip";
644 case VOLUME_TYPE_VOICE:
645 *volume_type_str = "voice";
648 debug_error("unexpected volume type [%d]", volume_type);
649 return MM_ERROR_SOUND_INTERNAL;
651 debug_log("volume_type[%s]", *volume_type_str);
655 int __convert_volume_type_internal_to_str(volume_type_internal_t volume_type, char **volume_type_str)
657 int ret = MM_ERROR_NONE;
659 if (!volume_type_str)
660 return MM_ERROR_COMMON_INVALID_ARGUMENT;
662 switch (volume_type) {
663 case VOLUME_TYPE_BIXBY:
664 *volume_type_str = "bixby";
667 debug_error("unexpected volume type [%d]", volume_type);
668 return MM_ERROR_SOUND_INTERNAL;
670 debug_log("volume_type[%s]", *volume_type_str);
674 static int __convert_volume_type_to_int(const char *volume_type_str, int *volume_type, bool *is_for_internal)
676 int ret = MM_ERROR_NONE;
678 if (!volume_type || !volume_type_str || !is_for_internal)
679 return MM_ERROR_COMMON_INVALID_ARGUMENT;
681 if (!strncmp(volume_type_str, "system", VOLUME_TYPE_LEN)) {
682 *volume_type = VOLUME_TYPE_SYSTEM;
683 *is_for_internal = false;
684 } else if (!strncmp(volume_type_str, "notification", VOLUME_TYPE_LEN)) {
685 *volume_type = VOLUME_TYPE_NOTIFICATION;
686 *is_for_internal = false;
687 } else if (!strncmp(volume_type_str, "alarm", VOLUME_TYPE_LEN)) {
688 *volume_type = VOLUME_TYPE_ALARM;
689 *is_for_internal = false;
690 } else if (!strncmp(volume_type_str, "ringtone", VOLUME_TYPE_LEN)) {
691 *volume_type = VOLUME_TYPE_RINGTONE;
692 *is_for_internal = false;
693 } else if (!strncmp(volume_type_str, "media", VOLUME_TYPE_LEN)) {
694 *volume_type = VOLUME_TYPE_MEDIA;
695 *is_for_internal = false;
696 } else if (!strncmp(volume_type_str, "call", VOLUME_TYPE_LEN)) {
697 *volume_type = VOLUME_TYPE_CALL;
698 *is_for_internal = false;
699 } else if (!strncmp(volume_type_str, "voip", VOLUME_TYPE_LEN)) {
700 *volume_type = VOLUME_TYPE_VOIP;
701 *is_for_internal = false;
702 } else if (!strncmp(volume_type_str, "voice", VOLUME_TYPE_LEN)) {
703 *volume_type = VOLUME_TYPE_VOICE;
704 *is_for_internal = false;
705 /* else-if statements below are for internal use */
706 } else if (!strncmp(volume_type_str, "bixby", VOLUME_TYPE_LEN)) {
707 *volume_type = VOLUME_TYPE_BIXBY;
708 *is_for_internal = true;
710 debug_log("Invalid volume type : [%s]", volume_type_str);
711 ret = MM_ERROR_SOUND_INTERNAL;
717 int mm_sound_client_set_volume_by_type(volume_type_t type, const unsigned int level)
719 int ret = MM_ERROR_NONE;
720 char *type_str = NULL;
723 if (type >= VOLUME_TYPE_MAX) {
724 debug_error("invalid volume type %d", type);
725 return MM_ERROR_INVALID_ARGUMENT;
728 if ((ret = __convert_volume_type_to_str(type, &type_str)) != MM_ERROR_NONE) {
729 debug_error("volume type convert failed");
733 ret = mm_sound_proxy_set_volume_by_type(type_str, level);
740 int mm_sound_client_get_volume_by_type(volume_type_t type, unsigned int *level)
742 int ret = MM_ERROR_NONE;
746 debug_error("invalid argument, level is null");
747 return MM_ERROR_INVALID_ARGUMENT;
750 if (type >= VOLUME_TYPE_MAX) {
751 debug_error("invalid volume type %d", type);
752 return MM_ERROR_INVALID_ARGUMENT;
755 /* Get volume value from VCONF */
756 if (vconf_get_int(g_volume_vconf[type], &vconf_value)) {
757 debug_error("vconf_get_int(%s) failed..\n", g_volume_vconf[type]);
758 return MM_ERROR_SOUND_INTERNAL;
761 *level = vconf_value;
766 int mm_sound_client_set_volume_by_internal_type(volume_type_internal_t type, const unsigned int level)
768 int ret = MM_ERROR_NONE;
769 char *type_str = NULL;
773 if ((ret = __convert_volume_type_internal_to_str(type, &type_str)) != MM_ERROR_NONE) {
774 debug_error("volume type convert failed");
778 ret = mm_sound_proxy_set_volume_by_type(type_str, level);
785 int mm_sound_client_get_volume_by_internal_type(volume_type_internal_t type, unsigned int *level)
787 int ret = MM_ERROR_NONE;
791 debug_error("invalid argument, level is null");
792 return MM_ERROR_INVALID_ARGUMENT;
795 /* Get volume value from VCONF */
796 if (vconf_get_int(g_volume_vconf_internal[type], &vconf_value)) {
797 debug_error("vconf_get_int(%s) failed..\n", g_volume_vconf_internal[type]);
798 return MM_ERROR_SOUND_INTERNAL;
801 *level = vconf_value;
806 static void _mm_sound_volume_changed_callback_wrapper_func(const char *direction, const char *volume_type_str,
807 int volume_level, void *userdata)
810 bool is_for_internal = false;
811 struct callback_data *cb_data = (struct callback_data *) userdata;
813 debug_log("direction : %s, volume_type : %s, volume_level : %d",
814 direction, volume_type_str, volume_level);
816 if (cb_data == NULL) {
817 debug_warning("volume changed callback data null");
821 if (__convert_volume_type_to_int(volume_type_str, &volume_type, &is_for_internal) != MM_ERROR_NONE) {
822 debug_error("volume type convert failed");
826 if (!is_for_internal && !cb_data->extra_data) {
827 debug_log("Invoke volume changed cb, direction : %s, vol_type : %s(%d), level : %u",
828 direction, volume_type_str, volume_type, volume_level);
829 ((mm_sound_volume_changed_cb)(cb_data->user_cb))((volume_type_t)volume_type, volume_level, cb_data->user_data);
830 } else if (is_for_internal && (cb_data->extra_data && (bool)(cb_data->extra_data))) {
831 debug_log("Invoke internal volume changed cb, direction : %s, vol_type : %s(%d), level : %u",
832 direction, volume_type_str, volume_type, volume_level);
833 ((mm_sound_volume_changed_cb_internal)(cb_data->user_cb))((volume_type_internal_t)volume_type, volume_level, cb_data->user_data);
837 int mm_sound_client_add_volume_changed_callback(mm_sound_volume_changed_cb func, void* userdata, unsigned int *subs_id)
839 int ret = MM_ERROR_NONE;
840 struct callback_data *cb_data = NULL;
844 GET_CB_DATA(cb_data, func, userdata, NULL);
846 ret = mm_sound_proxy_add_volume_changed_callback(_mm_sound_volume_changed_callback_wrapper_func, cb_data, g_free, subs_id);
853 int mm_sound_client_add_volume_changed_callback_internal(mm_sound_volume_changed_cb_internal func, void* userdata, unsigned int *subs_id)
855 int ret = MM_ERROR_NONE;
856 struct callback_data *cb_data = NULL;
857 gboolean is_for_internal = true;
861 GET_CB_DATA(cb_data, func, userdata, (void*)(uintptr_t)is_for_internal);
863 ret = mm_sound_proxy_add_volume_changed_callback(_mm_sound_volume_changed_callback_wrapper_func, cb_data, g_free, subs_id);
870 int mm_sound_client_remove_volume_changed_callback(unsigned int subs_id)
872 int ret = MM_ERROR_NONE;
875 ret = mm_sound_proxy_remove_volume_changed_callback(subs_id);
881 int mm_sound_client_set_mute_by_type(volume_type_t type, bool mute)
883 int ret = MM_ERROR_NONE;
884 char *type_str = NULL;
888 if (type > VOLUME_TYPE_VOICE) {
889 debug_error("invalid volume type %d", type);
890 return MM_ERROR_INVALID_ARGUMENT;
893 if ((ret = __convert_volume_type_to_str(type, &type_str)) != MM_ERROR_NONE) {
894 debug_error("volume type convert failed");
898 ret = mm_sound_proxy_set_mute_by_type(type_str, mute);
905 int mm_sound_client_get_mute_by_type(volume_type_t type, bool *muted)
907 int ret = MM_ERROR_NONE;
912 if (type > VOLUME_TYPE_VOICE) {
913 debug_error("invalid volume type %d", type);
914 return MM_ERROR_INVALID_ARGUMENT;
917 /* Get mute state from VCONF */
918 if (vconf_get_bool(g_mute_vconf[type], &vconf_value)) {
919 debug_error("vconf_get_int(%s) failed..\n", g_mute_vconf[type]);
920 return MM_ERROR_SOUND_INTERNAL;
923 *muted = (bool)vconf_value;
929 int mm_sound_client_set_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_parameters, const char *filter_group)
931 int ret = MM_ERROR_NONE;
934 ret = mm_sound_proxy_set_filter_by_type(stream_type, filter_name, filter_parameters, filter_group);
940 int mm_sound_client_unset_filter_by_type(const char *stream_type)
942 int ret = MM_ERROR_NONE;
945 ret = mm_sound_proxy_unset_filter_by_type(stream_type);
951 int mm_sound_client_control_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_controls)
953 int ret = MM_ERROR_NONE;
956 ret = mm_sound_proxy_control_filter_by_type(stream_type, filter_name, filter_controls);
962 int mm_sound_client_is_focus_cb_thread(GThread *mine, bool *result, bool *is_for_watching)
964 int ret = MM_ERROR_NONE;
967 if (!mine || !result)
968 ret = MM_ERROR_INVALID_ARGUMENT;
971 for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
972 if (!g_focus_sound_handle[i].is_used)
974 if (g_focus_sound_handle[i].focus_cb_thread == mine) {
977 *is_for_watching = false;
980 if (g_focus_sound_handle[i].focus_watch_cb_thread == mine) {
983 *is_for_watching = true;
992 int mm_sound_client_register_focus(int pid, const char *stream_type,
993 mm_sound_focus_changed_cb callback, void* user_data, int *id)
995 int ret = MM_ERROR_NONE;
999 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1001 if (focus_find_empty_index(&index)) {
1002 ret = MM_ERROR_SOUND_INTERNAL;
1006 g_focus_sound_handle[index].focus_pid = pid;
1007 g_focus_sound_handle[index].focus_callback = callback;
1008 g_focus_sound_handle[index].user_data = user_data;
1009 g_focus_sound_handle[index].auto_reacquire = true;
1011 ret = mm_sound_proxy_register_focus(index, stream_type, id);
1012 if (ret == MM_ERROR_NONE) {
1013 debug_msg("Success to register focus, client_fd[%d], id[%d]", g_focus_sound_handle[index].client_fd, *id);
1014 if (focus_init_context(index, false)) {
1015 ret = MM_ERROR_SOUND_INTERNAL;
1019 debug_error("Error occurred : 0x%x", ret);
1023 g_mutex_init(&g_focus_sound_handle[index].focus_lock);
1024 focus_init_callback(index, false);
1027 if (ret != MM_ERROR_NONE && index >= 0)
1028 g_focus_sound_handle[index].is_used = false;
1030 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1036 int mm_sound_client_unregister_focus(int id)
1038 int ret = MM_ERROR_NONE;
1042 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1044 index = focus_find_index_by_handle(id);
1046 debug_error("Could not find index");
1047 ret = MM_ERROR_INVALID_ARGUMENT;
1051 g_mutex_lock(&g_focus_sound_handle[index].focus_lock);
1053 g_focus_sound_handle[index].is_destroying = true;
1055 ret = mm_sound_proxy_unregister_focus(index);
1056 if (ret == MM_ERROR_NONE)
1057 debug_msg("Success to unregister focus");
1059 debug_error("Error occurred : 0x%x", ret);
1061 focus_deinit_callback(index, false);
1062 g_focus_sound_handle[index].focus_fd = 0;
1063 g_focus_sound_handle[index].focus_pid = 0;
1064 g_focus_sound_handle[index].client_fd = 0;
1065 g_focus_sound_handle[index].handle = 0;
1066 g_focus_sound_handle[index].is_used = false;
1067 focus_deinit_context(index, false);
1069 g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1070 g_mutex_clear(&g_focus_sound_handle[index].focus_lock);
1072 g_focus_sound_handle[index].is_destroying = false;
1074 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1079 int mm_sound_client_set_focus_reacquisition(int id, bool reacquisition)
1081 int ret = MM_ERROR_NONE;
1087 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1089 index = focus_find_index_by_handle(id);
1091 debug_error("Could not find index");
1092 ret = MM_ERROR_INVALID_ARGUMENT;
1096 ret = mm_sound_client_is_focus_cb_thread(g_thread_self(), &result, NULL);
1098 debug_error("mm_sound_client_is_focus_cb_thread failed");
1100 } else if (!result) {
1101 ret = mm_sound_proxy_set_focus_reacquisition(index, reacquisition);
1102 if (ret == MM_ERROR_NONE) {
1103 debug_msg("Success to set focus reacquisition to [%d]", reacquisition);
1105 debug_error("Error occurred : 0x%x", ret);
1109 debug_warning("Inside the focus cb thread, set focus reacquisition to [%d]", reacquisition);
1112 g_focus_sound_handle[index].auto_reacquire = reacquisition;
1113 debug_msg("set focus reacquisition(%d) for id(%d)", reacquisition, id);
1116 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1121 int mm_sound_client_get_focus_reacquisition(int id, bool *reacquisition)
1123 int ret = MM_ERROR_NONE;
1128 if (!reacquisition) {
1129 debug_error("Invalid parameter");
1130 return MM_ERROR_INVALID_ARGUMENT;
1133 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1135 index = focus_find_index_by_handle(id);
1137 debug_error("Could not find index");
1138 ret = MM_ERROR_INVALID_ARGUMENT;
1142 *reacquisition = g_focus_sound_handle[index].auto_reacquire;
1143 debug_msg("get focus reacquisition(%d) for id(%d)", *reacquisition, id);
1146 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1151 int mm_sound_client_get_acquired_focus_stream_type(int focus_type, char **stream_type, int *option, char **ext_info)
1153 int ret = MM_ERROR_NONE;
1157 ret = mm_sound_proxy_get_acquired_focus_stream_type(focus_type, stream_type, option, ext_info);
1158 if (ret == MM_ERROR_NONE)
1159 debug_msg("Success to get stream type of acquired focus, stream_type(%s), ext_info(%s)",
1160 *stream_type, *ext_info);
1162 debug_error("Error occurred : 0x%x", ret);
1169 int mm_sound_client_acquire_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1171 int ret = MM_ERROR_NONE;
1175 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1177 index = focus_find_index_by_handle(id);
1179 debug_error("Could not find index");
1180 ret = MM_ERROR_INVALID_ARGUMENT;
1184 ret = mm_sound_proxy_acquire_focus(index, type, option, ext_info);
1185 if (ret == MM_ERROR_NONE)
1186 debug_msg("Success to acquire focus");
1188 debug_error("Error occurred : 0x%x", ret);
1191 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1196 int mm_sound_client_release_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1198 int ret = MM_ERROR_NONE;
1202 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1204 index = focus_find_index_by_handle(id);
1206 debug_error("Could not find index");
1207 ret = MM_ERROR_INVALID_ARGUMENT;
1211 ret = mm_sound_proxy_release_focus(index, type, option, ext_info);
1212 if (ret == MM_ERROR_NONE)
1213 debug_msg("Success to release focus");
1215 debug_error("Error occurred : 0x%x", ret);
1218 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1223 int mm_sound_client_update_stream_focus_status(int id, unsigned int status)
1225 int ret = MM_ERROR_NONE;
1228 if ((ret = mm_sound_proxy_update_stream_focus_status(id, status)) != MM_ERROR_NONE)
1229 debug_error("failed to update stream focus status, ret[0x%x]", ret);
1235 int mm_sound_client_deliver_focus(int src_id, int dst_id, mm_sound_focus_type_e focus_type)
1237 int ret = MM_ERROR_NONE;
1243 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1245 src_index = focus_find_index_by_handle(src_id);
1246 if (src_index == -1) {
1247 debug_error("Could not find src index");
1248 ret = MM_ERROR_INVALID_ARGUMENT;
1251 dst_index = focus_find_index_by_handle(dst_id);
1252 if (dst_index == -1) {
1253 debug_error("Could not find dst index");
1254 ret = MM_ERROR_INVALID_ARGUMENT;
1257 if (g_focus_sound_handle[src_index].focus_pid != g_focus_sound_handle[dst_index].focus_pid) {
1258 debug_error("pid[%d/%d] are not same for dst/src",
1259 g_focus_sound_handle[src_index].focus_pid,
1260 g_focus_sound_handle[dst_index].focus_pid);
1261 ret = MM_ERROR_SOUND_INTERNAL;
1265 if ((ret = mm_sound_proxy_deliver_focus(src_index, dst_index, focus_type)) != MM_ERROR_NONE)
1266 debug_error("failed to deliver focus, ret[0x%x]", ret);
1269 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1274 int mm_sound_client_set_focus_watch_callback(int pid, mm_sound_focus_type_e focus_type,
1275 mm_sound_focus_changed_watch_cb callback, void* user_data, int *id)
1277 int ret = MM_ERROR_NONE;
1283 return MM_ERROR_INVALID_ARGUMENT;
1285 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1287 if (focus_find_empty_index(&index)) {
1288 ret = MM_ERROR_SOUND_INTERNAL;
1292 g_focus_sound_handle[index].focus_pid = pid;
1293 g_focus_sound_handle[index].watch_callback = callback;
1294 g_focus_sound_handle[index].user_data = user_data;
1295 g_focus_sound_handle[index].unset_watch_callback_requested = false;
1297 ret = mm_sound_proxy_add_focus_watch_callback(index, focus_type);
1298 if (ret == MM_ERROR_NONE) {
1299 *id = g_focus_sound_handle[index].handle;
1300 debug_msg("Success to add watch focus cb, id(%d)", *id);
1301 if (focus_init_context(index, true)) {
1302 ret = MM_ERROR_SOUND_INTERNAL;
1306 debug_error("Error occurred : 0x%x", ret);
1310 focus_init_callback(index, true);
1313 if (ret != MM_ERROR_NONE && index >= 0)
1314 g_focus_sound_handle[index].is_used = false;
1316 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1321 int mm_sound_client_request_unset_focus_watch_callback(int id)
1323 int ret = MM_ERROR_NONE;
1327 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1329 index = focus_watch_find_index_by_handle(id);
1331 debug_error("Could not find index");
1332 ret = MM_ERROR_INVALID_ARGUMENT;
1335 g_focus_sound_handle[index].unset_watch_callback_requested = true;
1338 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1343 int mm_sound_client_unset_focus_watch_callback(int id)
1345 int ret = MM_ERROR_NONE;
1349 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1351 index = focus_watch_find_index_by_handle(id);
1353 debug_error("Could not find index");
1354 ret = MM_ERROR_INVALID_ARGUMENT;
1358 g_mutex_lock(&g_focus_sound_handle[index].focus_lock);
1360 g_focus_sound_handle[index].is_used = false;
1362 ret = mm_sound_proxy_remove_focus_watch_callback(index);
1363 if (ret == MM_ERROR_NONE)
1364 debug_msg("Success to remove watch focus cb, id(%d)", g_focus_sound_handle[index].handle);
1366 debug_error("Error occurred : 0x%x", ret);
1369 g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1371 focus_deinit_callback(index, true);
1372 g_focus_sound_handle[index].focus_fd = 0;
1373 g_focus_sound_handle[index].focus_pid = 0;
1374 g_focus_sound_handle[index].client_fd = 0;
1375 g_focus_sound_handle[index].handle = 0;
1376 focus_deinit_context(index, true);
1379 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1384 static gboolean _idle_event_callback(void *data)
1386 focus_idle_event_t *idle_event_data = (focus_idle_event_t*)data;
1387 int ret = MM_ERROR_NONE;
1390 debug_error("data is null");
1394 debug_msg("idle_event_data(%p): type(%d), data(%d)",
1395 idle_event_data, idle_event_data->type, idle_event_data->data);
1397 switch (idle_event_data->type) {
1398 case IDLE_EVENT_TYPE_UNSET_FOCUS_WATCH_CB:
1399 if ((ret = mm_sound_client_unset_focus_watch_callback(idle_event_data->data)))
1400 debug_error("Could not unset focus watch callback, id(%d), ret = %x", idle_event_data->data, ret);
1402 case IDLE_EVENT_TYPE_UNREGISTER_FOCUS:
1403 if ((ret = mm_sound_client_unregister_focus(idle_event_data->data)))
1404 debug_error("Could not unregister focus, id(%d), ret = %x", idle_event_data->data, ret);
1407 debug_warning("invalid type(%d)", idle_event_data->type);
1411 g_free(idle_event_data);
1413 g_idle_event_src = 0;
1415 MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex);
1420 int mm_sound_client_execute_focus_func_in_main_context(focus_idle_event_type_e type, int data)
1422 focus_idle_event_t *idle_event_data = NULL;
1424 if (IDLE_EVENT_TYPE_MAX < type)
1425 return MM_ERROR_INVALID_ARGUMENT;
1427 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL);
1429 idle_event_data = g_new0(focus_idle_event_t, 1);
1430 idle_event_data->type = type;
1431 idle_event_data->data = data;
1433 g_idle_event_src = g_idle_add_full(G_PRIORITY_HIGH,
1434 (GSourceFunc)_idle_event_callback,
1435 (gpointer)idle_event_data,
1438 return MM_ERROR_NONE;
1441 int mm_sound_client_add_ducking_state_changed_callback(mm_sound_ducking_state_changed_cb func, void* userdata, unsigned int *subs_id)
1443 int ret = MM_ERROR_NONE;
1444 struct callback_data *cb_data = NULL;
1448 GET_CB_DATA(cb_data, func, userdata, NULL);
1450 ret = mm_sound_proxy_add_ducking_state_changed_callback((mm_sound_ducking_state_changed_wrapper_cb)func,
1451 cb_data, g_free, subs_id);
1458 int mm_sound_client_remove_ducking_state_changed_callback(unsigned int subs_id)
1460 int ret = MM_ERROR_NONE;
1463 ret = mm_sound_proxy_remove_ducking_state_changed_callback(subs_id);