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
41 #define VOLUME_MAX_MULTIMEDIA 16
42 #define VOLUME_MAX_BASIC 8
44 #define VCONF_KEY_VOLUME_PREFIX "file/private/sound/volume"
45 #define VCONF_KEY_VOLUME_TYPE_SYSTEM VCONF_KEY_VOLUME_PREFIX"/system"
46 #define VCONF_KEY_VOLUME_TYPE_NOTIFICATION VCONF_KEY_VOLUME_PREFIX"/notification"
47 #define VCONF_KEY_VOLUME_TYPE_ALARM VCONF_KEY_VOLUME_PREFIX"/alarm"
48 #define VCONF_KEY_VOLUME_TYPE_RINGTONE VCONF_KEY_VOLUME_PREFIX"/ringtone"
49 #define VCONF_KEY_VOLUME_TYPE_MEDIA VCONF_KEY_VOLUME_PREFIX"/media"
50 #define VCONF_KEY_VOLUME_TYPE_CALL VCONF_KEY_VOLUME_PREFIX"/call"
51 #define VCONF_KEY_VOLUME_TYPE_VOIP VCONF_KEY_VOLUME_PREFIX"/voip"
52 #define VCONF_KEY_VOLUME_TYPE_VOICE VCONF_KEY_VOLUME_PREFIX"/voice"
53 #define VCONF_KEY_VOLUME_TYPE_ANDROID VCONF_KEY_VOLUME_PREFIX"/fixed"
55 #define VCONF_KEY_MUTE_PREFIX "file/private/sound/mute"
56 #define VCONF_KEY_MUTE_TYPE_SYSTEM VCONF_KEY_MUTE_PREFIX"/system"
57 #define VCONF_KEY_MUTE_TYPE_NOTIFICATION VCONF_KEY_MUTE_PREFIX"/notification"
58 #define VCONF_KEY_MUTE_TYPE_ALARM VCONF_KEY_MUTE_PREFIX"/alarm"
59 #define VCONF_KEY_MUTE_TYPE_RINGTONE VCONF_KEY_MUTE_PREFIX"/ringtone"
60 #define VCONF_KEY_MUTE_TYPE_MEDIA VCONF_KEY_MUTE_PREFIX"/media"
61 #define VCONF_KEY_MUTE_TYPE_CALL VCONF_KEY_MUTE_PREFIX"/call"
62 #define VCONF_KEY_MUTE_TYPE_VOIP VCONF_KEY_MUTE_PREFIX"/voip"
63 #define VCONF_KEY_MUTE_TYPE_VOICE VCONF_KEY_MUTE_PREFIX"/voice"
65 static char *g_volume_vconf[VOLUME_TYPE_MAX] = {
66 VCONF_KEY_VOLUME_TYPE_SYSTEM, /* VOLUME_TYPE_SYSTEM */
67 VCONF_KEY_VOLUME_TYPE_NOTIFICATION, /* VOLUME_TYPE_NOTIFICATION */
68 VCONF_KEY_VOLUME_TYPE_ALARM, /* VOLUME_TYPE_ALARM */
69 VCONF_KEY_VOLUME_TYPE_RINGTONE, /* VOLUME_TYPE_RINGTONE */
70 VCONF_KEY_VOLUME_TYPE_MEDIA, /* VOLUME_TYPE_MEDIA */
71 VCONF_KEY_VOLUME_TYPE_CALL, /* VOLUME_TYPE_CALL */
72 VCONF_KEY_VOLUME_TYPE_VOIP, /* VOLUME_TYPE_VOIP */
73 VCONF_KEY_VOLUME_TYPE_VOICE, /* VOLUME_TYPE_VOICE */
74 VCONF_KEY_VOLUME_TYPE_ANDROID /* VOLUME_TYPE_FIXED */
77 static char *g_mute_vconf[] = {
78 VCONF_KEY_MUTE_TYPE_SYSTEM, /* MUTE_TYPE_SYSTEM */
79 VCONF_KEY_MUTE_TYPE_NOTIFICATION, /* MUTE_TYPE_NOTIFICATION */
80 VCONF_KEY_MUTE_TYPE_ALARM, /* MUTE_TYPE_ALARM */
81 VCONF_KEY_MUTE_TYPE_RINGTONE, /* MUTE_TYPE_RINGTONE */
82 VCONF_KEY_MUTE_TYPE_MEDIA, /* MUTE_TYPE_MEDIA */
83 VCONF_KEY_MUTE_TYPE_CALL, /* MUTE_TYPE_CALL */
84 VCONF_KEY_MUTE_TYPE_VOIP, /* MUTE_TYPE_VOIP */
85 VCONF_KEY_MUTE_TYPE_VOICE, /* MUTE_TYPE_VOICE */
88 static char *g_volume_str[VOLUME_TYPE_MAX] = {
100 struct callback_data {
107 #define GET_CB_DATA(_cb_data, _func, _userdata, _extradata) \
109 _cb_data = (struct callback_data*) g_malloc0(sizeof(struct callback_data)); \
110 _cb_data->user_cb = _func; \
111 _cb_data->user_data = _userdata; \
112 _cb_data->extra_data = _extradata; \
115 static pthread_mutex_t g_index_mutex = PTHREAD_MUTEX_INITIALIZER;
116 static pthread_mutex_t g_event_mutex = PTHREAD_MUTEX_INITIALIZER;
117 guint g_idle_event_src;
120 /* handle to watch end of playing */
122 /* subscription id to unsubscribe when handle ended */
124 } play_sound_end_callback_data_t;
126 typedef struct _focus_idle_event {
127 focus_idle_event_type_e type;
129 } focus_idle_event_t;
131 static int _validate_volume(volume_type_t type, int level)
137 case VOLUME_TYPE_CALL:
138 case VOLUME_TYPE_VOIP:
139 if (level >= VOLUME_MAX_BASIC) {
143 case VOLUME_TYPE_SYSTEM:
144 case VOLUME_TYPE_MEDIA:
145 case VOLUME_TYPE_ALARM:
146 case VOLUME_TYPE_NOTIFICATION:
147 case VOLUME_TYPE_RINGTONE:
148 case VOLUME_TYPE_VOICE:
149 if (level >= VOLUME_MAX_MULTIMEDIA) {
160 int mm_sound_client_initialize(void)
162 int ret = MM_ERROR_NONE;
166 mm_sound_proxy_initialize();
167 g_idle_event_src = 0;
173 int mm_sound_client_finalize(void)
175 int ret = MM_ERROR_NONE;
179 ret = mm_sound_proxy_finalize();
181 if (g_idle_event_src > 0) {
182 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL);
183 g_source_remove(g_idle_event_src);
184 MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex);
191 void mm_sound_convert_volume_type_to_stream_type(int volume_type, char *stream_type)
193 switch (volume_type) {
194 case VOLUME_TYPE_SYSTEM:
195 MMSOUND_STRNCPY(stream_type, "system", MAX_STREAM_TYPE_LEN);
197 case VOLUME_TYPE_NOTIFICATION:
198 MMSOUND_STRNCPY(stream_type, "notification", MAX_STREAM_TYPE_LEN);
200 case VOLUME_TYPE_ALARM:
201 MMSOUND_STRNCPY(stream_type, "alarm", MAX_STREAM_TYPE_LEN);
203 case VOLUME_TYPE_RINGTONE:
204 MMSOUND_STRNCPY(stream_type, "ringtone-voip", MAX_STREAM_TYPE_LEN);
206 case VOLUME_TYPE_MEDIA:
207 MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN);
209 case VOLUME_TYPE_CALL:
210 MMSOUND_STRNCPY(stream_type, "call-voice", MAX_STREAM_TYPE_LEN);
212 case VOLUME_TYPE_VOIP:
213 MMSOUND_STRNCPY(stream_type, "voip", MAX_STREAM_TYPE_LEN);
215 case VOLUME_TYPE_VOICE:
216 MMSOUND_STRNCPY(stream_type, "voice-information", MAX_STREAM_TYPE_LEN);
219 MMSOUND_STRNCPY(stream_type, "media", MAX_STREAM_TYPE_LEN);
223 debug_msg("volume type (%d) converted to stream type (%s)", volume_type, stream_type);
227 /*****************************************************************************************
228 DBUS SUPPORTED FUNCTIONS
229 ******************************************************************************************/
230 int mm_sound_client_play_tone_with_stream_info(int tone, char *stream_type, int stream_id,
231 double volume, int duration, int *handle)
233 int ret = MM_ERROR_NONE;
237 ret = mm_sound_proxy_play_tone_with_stream_info(getpid(), tone, stream_type, stream_id, volume, duration, handle);
243 static void _mm_sound_stop_callback_wrapper_func(int ended_handle, void *userdata)
245 struct callback_data *cb_data = (struct callback_data*) userdata;
246 play_sound_end_callback_data_t *end_cb_data;
248 debug_log("ended_handle : %d", ended_handle);
250 if (cb_data == NULL) {
251 debug_warning("stop callback data null");
255 end_cb_data = (play_sound_end_callback_data_t*) cb_data->extra_data;
257 if (ended_handle == end_cb_data->watching_handle) {
258 debug_log("Interested playing handle end : %d", ended_handle);
259 ((mm_sound_stop_callback_func)(cb_data->user_cb))(cb_data->user_data, ended_handle);
260 if (mm_sound_proxy_remove_play_sound_end_callback(end_cb_data->subs_id) != MM_ERROR_NONE)
261 debug_error("mm_sound_client_dbus_remove_play_file_end_callback failed");
263 debug_log("Not interested playing handle : %d", ended_handle);
267 static void play_end_callback_data_free_func(void *data)
269 struct callback_data *cb_data = (struct callback_data*) data;
272 g_free(cb_data->extra_data);
277 int mm_sound_client_play_sound_with_stream_info(MMSoundPlayParam *param, int *handle, char* stream_type, int stream_id)
279 int ret = MM_ERROR_NONE;
280 struct callback_data *cb_data = NULL;
281 play_sound_end_callback_data_t *end_cb_data;
283 ret = mm_sound_proxy_play_sound_with_stream_info(param->filename, param->loop, param->volume,
284 getpid(), handle, stream_type, stream_id);
285 if (ret != MM_ERROR_NONE) {
286 debug_error("Play Sound Failed");
289 if (param->callback) {
290 end_cb_data = (play_sound_end_callback_data_t *) g_malloc0(sizeof(play_sound_end_callback_data_t));
291 end_cb_data->watching_handle = *handle;
292 GET_CB_DATA(cb_data, param->callback, param->data, end_cb_data);
294 ret = mm_sound_proxy_add_play_sound_end_callback(_mm_sound_stop_callback_wrapper_func, cb_data,
295 play_end_callback_data_free_func, &end_cb_data->subs_id);
296 if (ret != MM_ERROR_NONE)
297 debug_error("Add callback for play sound(%d) Failed", *handle);
307 int mm_sound_client_stop_sound(int handle)
309 int ret = MM_ERROR_NONE;
312 if (handle < 0 || handle > CLIENT_HANDLE_MAX) {
313 ret = MM_ERROR_INVALID_ARGUMENT;
317 ret = mm_sound_proxy_stop_sound(handle);
323 static int _mm_sound_client_device_list_dump(GList *device_list)
325 int ret = MM_ERROR_NONE;
327 mm_sound_device_t *device_node = NULL;
330 debug_error("Device list NULL, cannot dump list");
331 return MM_ERROR_SOUND_INTERNAL;
334 debug_log("======================== device list : start ==========================");
335 for (list = device_list; list != NULL; list = list->next) {
336 device_node = (mm_sound_device_t *)list->data;
338 debug_log(" list idx[%d]: type[%17s], id[%02d], io_direction[%d], state[%d], name[%s]",
339 count++, device_node->type, device_node->id, device_node->io_direction,
340 device_node->state, device_node->name);
343 debug_log("======================== device list : end ============================");
348 int mm_sound_client_get_current_connected_device_list(int device_flags, mm_sound_device_list_t *device_list)
350 int ret = MM_ERROR_NONE;
354 debug_error("Device list NULL");
355 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
359 if ((ret = mm_sound_proxy_get_current_connected_device_list(device_flags, &device_list->list)) != MM_ERROR_NONE) {
360 debug_error("failed to get current connected device list with dbus, ret[0x%x]", ret);
363 if (!device_list->list) {
364 debug_error("Got device list null");
365 ret = MM_ERROR_SOUND_NO_DATA;
368 _mm_sound_client_device_list_dump(device_list->list);
375 int mm_sound_client_get_device_by_id(int device_id, mm_sound_device_t **device)
377 int ret = MM_ERROR_NONE;
381 if ((ret = mm_sound_proxy_get_device_by_id(device_id, device)) != MM_ERROR_NONE)
382 debug_error("failed to get device by id");
389 static bool device_is_match_direction(int direction, int mask)
391 if (mask == DEVICE_IO_DIRECTION_FLAGS || mask == 0)
394 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_IN))
396 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG) && (direction & MM_SOUND_DEVICE_IO_DIRECTION_OUT))
398 if ((mask & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG) && (direction == MM_SOUND_DEVICE_IO_DIRECTION_BOTH))
404 static bool device_is_match_state(int state, int mask)
406 if (mask == DEVICE_STATE_FLAGS || mask == 0)
409 if ((mask & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_DEACTIVATED))
411 if ((mask & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG) && (state == MM_SOUND_DEVICE_STATE_ACTIVATED))
417 static bool device_is_match_type(const char *type, int mask)
420 const char *builtin_prefix = "builtin";
422 if (mask == DEVICE_TYPE_FLAGS || mask == 0)
425 is_builtin = !strncmp(type, builtin_prefix, strlen(builtin_prefix));
427 if ((mask & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG) && (is_builtin))
429 if ((mask & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG) && (!is_builtin))
435 static bool device_is_match_with_mask(const char *type, int direction, int state, int mask)
437 if (mask == DEVICE_ALL_FLAG)
440 return (device_is_match_direction(direction, mask & DEVICE_IO_DIRECTION_FLAGS) &&
441 device_is_match_state(state, mask & DEVICE_STATE_FLAGS) &&
442 device_is_match_type(type, mask & DEVICE_TYPE_FLAGS));
445 static int _fill_sound_device(mm_sound_device_t *device_h, int device_id, const char *device_type,
446 int direction, int state, const char *name, int vendor_id, int product_id,
447 int *stream_id, int stream_num, bool is_running)
451 if (stream_num > 0 && stream_id == NULL) {
452 debug_error("stream_num is %d, but stream_id is NULL", stream_num);
456 if (stream_num > MAX_STREAM_ON_DEVICE) {
457 debug_error("too many streams on this device");
461 device_h->id = device_id;
462 device_h->io_direction = direction;
463 device_h->state = state;
464 MMSOUND_STRNCPY(device_h->name, name, MAX_DEVICE_NAME_NUM);
465 MMSOUND_STRNCPY(device_h->type, device_type, MAX_DEVICE_TYPE_STR_LEN);
466 device_h->vendor_id = vendor_id;
467 device_h->product_id = product_id;
468 device_h->is_running = is_running;
470 if (stream_num > 0) {
471 device_h->stream_num = stream_num;
472 debug_log("%d streams on this device", stream_num);
473 for (i = 0; i < stream_num; i++) {
474 debug_log(" stream_id : %d", stream_id[i]);
475 device_h->stream_id[i] = stream_id[i];
478 device_h->stream_num = 0;
479 debug_log("There is no stream on this device");
485 static void _mm_sound_device_connected_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
486 int state, const char *name, int vendor_id, int product_id, bool is_running,
487 int *stream_id, int stream_num, bool is_connected, void *userdata)
489 mm_sound_device_t device_h;
490 struct callback_data *cb_data = (struct callback_data*) userdata;
493 debug_log("[Device %s] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x) product-id(%04x)",
494 is_connected ? "Connected" : "Disconnected", device_id, device_type, io_direction, state, name,
495 is_running, vendor_id, product_id);
497 if (cb_data == NULL) {
498 debug_warning("device connected changed callback data null");
502 device_flags = (int) cb_data->extra_data;
503 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
506 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
507 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
508 debug_error("Failed to fill sound device");
512 ((mm_sound_device_connected_cb)(cb_data->user_cb))(&device_h, is_connected, cb_data->user_data);
515 int mm_sound_client_add_device_connected_callback(int device_flags, mm_sound_device_connected_cb func,
516 void* userdata, unsigned int *subs_id)
518 int ret = MM_ERROR_NONE;
519 struct callback_data *cb_data = NULL;
523 GET_CB_DATA(cb_data, func, userdata, (void*) device_flags);
525 ret = mm_sound_proxy_add_device_connected_callback(_mm_sound_device_connected_callback_wrapper_func,
526 cb_data, g_free, subs_id);
532 int mm_sound_client_remove_device_connected_callback(unsigned int subs_id)
534 int ret = MM_ERROR_NONE;
537 ret = mm_sound_proxy_remove_device_connected_callback(subs_id);
543 static void _mm_sound_device_info_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
544 int state, const char *name, int vendor_id, int product_id, bool is_running,
545 int *stream_id, int stream_num, int changed_device_info_type, void *userdata)
547 mm_sound_device_t device_h;
548 struct callback_data *cb_data = (struct callback_data*) userdata;
551 debug_log("[Device Info Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) "
552 "vendor-id(%04x) product-id(%04x) changed_info_type(%d)",
553 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id, changed_device_info_type);
555 if (cb_data == NULL) {
556 debug_warning("device info changed callback data null");
560 device_flags = (int) cb_data->extra_data;
561 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
564 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
565 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
566 debug_error("Failed to fill sound device");
570 ((mm_sound_device_info_changed_cb)(cb_data->user_cb))(&device_h, changed_device_info_type, cb_data->user_data);
573 int mm_sound_client_add_device_info_changed_callback(int device_flags, mm_sound_device_info_changed_cb func,
574 void *userdata, unsigned int *subs_id)
576 int ret = MM_ERROR_NONE;
577 struct callback_data *cb_data = (struct callback_data*) userdata;
581 GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
583 ret = mm_sound_proxy_add_device_info_changed_callback(_mm_sound_device_info_changed_callback_wrapper_func,
584 cb_data, g_free, subs_id);
590 int mm_sound_client_remove_device_info_changed_callback(unsigned int subs_id)
592 int ret = MM_ERROR_NONE;
595 ret = mm_sound_proxy_remove_device_info_changed_callback(subs_id);
602 static void _mm_sound_device_state_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
603 int state, const char *name, int vendor_id, int product_id,
604 bool is_running, int *stream_id, int stream_num, void *userdata)
606 mm_sound_device_t device_h;
607 struct callback_data *cb_data = (struct callback_data*) userdata;
610 debug_log("[Device State Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x) product-id(%04x)",
611 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id);
613 if (cb_data == NULL) {
614 debug_warning("device state changed callback data null");
618 device_flags = (int) cb_data->extra_data;
620 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
623 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
624 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
625 debug_error("Failed to fill sound device");
629 ((mm_sound_device_state_changed_cb)(cb_data->user_cb))(&device_h, state, cb_data->user_data);
632 int mm_sound_client_add_device_state_changed_callback(int device_flags, mm_sound_device_state_changed_cb func,
633 void *userdata, unsigned int *id)
635 int ret = MM_ERROR_NONE;
636 struct callback_data *cb_data = (struct callback_data*) userdata;
640 GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
642 ret = mm_sound_proxy_add_device_state_changed_callback(_mm_sound_device_state_changed_callback_wrapper_func,
643 cb_data, g_free, id);
649 int mm_sound_client_remove_device_state_changed_callback(unsigned int id)
651 int ret = MM_ERROR_NONE;
654 ret = mm_sound_proxy_remove_device_state_changed_callback(id);
660 static void _mm_sound_device_running_changed_callback_wrapper_func(int device_id, const char *device_type, int io_direction,
661 int state, const char *name, int vendor_id, int product_id,
662 bool is_running, int *stream_id, int stream_num, void *userdata)
664 mm_sound_device_t device_h;
665 struct callback_data *cb_data = (struct callback_data*) userdata;
668 debug_log("[Device Running Changed] id(%d) type(%s) direction(%d) state(%d) name(%s) is_running(%d) vendor-id(%04x), product-id(%04x)",
669 device_id, device_type, io_direction, state, name, is_running, vendor_id, product_id);
671 if (cb_data == NULL) {
672 debug_warning("device running changed callback data null");
676 device_flags = (int) cb_data->extra_data;
678 if (!device_is_match_with_mask(device_type, io_direction, state, device_flags))
681 if (_fill_sound_device(&device_h, device_id, device_type, io_direction, state, name,
682 vendor_id, product_id, stream_id, stream_num, is_running) < 0) {
683 debug_error("Failed to fill sound device");
687 ((mm_sound_device_running_changed_cb)(cb_data->user_cb))(&device_h, is_running, cb_data->user_data);
690 int mm_sound_client_add_device_running_changed_callback(int device_flags, mm_sound_device_running_changed_cb func,
691 void *userdata, unsigned int *id)
693 int ret = MM_ERROR_NONE;
694 struct callback_data *cb_data = (struct callback_data*) userdata;
698 GET_CB_DATA(cb_data, func, userdata, (void *) device_flags);
700 ret = mm_sound_proxy_add_device_running_changed_callback(_mm_sound_device_running_changed_callback_wrapper_func,
701 cb_data, g_free, id);
707 int mm_sound_client_remove_device_running_changed_callback(unsigned int id)
709 int ret = MM_ERROR_NONE;
712 ret = mm_sound_proxy_remove_device_running_changed_callback(id);
718 int mm_sound_client_is_stream_on_device(int stream_id, int device_id, bool *is_on)
720 int ret = MM_ERROR_NONE;
724 debug_error("Invalid Parameter");
725 ret = MM_ERROR_COMMON_INVALID_ARGUMENT;
729 if ((ret = mm_sound_proxy_is_stream_on_device(stream_id, device_id, is_on)) != MM_ERROR_NONE) {
730 debug_error("failed to query is stream on device, ret[0x%x]", ret);
739 int __convert_volume_type_to_str(int volume_type, char **volume_type_str)
741 int ret = MM_ERROR_NONE;
743 if (!volume_type_str)
744 return MM_ERROR_COMMON_INVALID_ARGUMENT;
746 switch (volume_type) {
747 case VOLUME_TYPE_SYSTEM:
748 *volume_type_str = "system";
750 case VOLUME_TYPE_NOTIFICATION:
751 *volume_type_str = "notification";
753 case VOLUME_TYPE_ALARM:
754 *volume_type_str = "alarm";
756 case VOLUME_TYPE_RINGTONE:
757 *volume_type_str = "ringtone";
759 case VOLUME_TYPE_MEDIA:
760 *volume_type_str = "media";
762 case VOLUME_TYPE_CALL:
763 *volume_type_str = "call";
765 case VOLUME_TYPE_VOIP:
766 *volume_type_str = "voip";
768 case VOLUME_TYPE_VOICE:
769 *volume_type_str = "voice";
772 debug_error("unexpected volume type [%d]", volume_type);
773 return MM_ERROR_SOUND_INTERNAL;
775 if (!strncmp(*volume_type_str, "", VOLUME_TYPE_LEN)) {
776 debug_error("could not find the volume_type[%d] in this switch case statement", volume_type);
777 ret = MM_ERROR_SOUND_INTERNAL;
779 debug_log("volume_type[%s]", *volume_type_str);
784 static int __convert_volume_type_to_int(const char *volume_type_str, volume_type_t *volume_type)
786 int ret = MM_ERROR_NONE;
788 if (!volume_type || !volume_type_str)
789 return MM_ERROR_COMMON_INVALID_ARGUMENT;
791 if (!strncmp(volume_type_str, "system", VOLUME_TYPE_LEN)) {
792 *volume_type = VOLUME_TYPE_SYSTEM;
793 } else if (!strncmp(volume_type_str, "notification", VOLUME_TYPE_LEN)) {
794 *volume_type = VOLUME_TYPE_NOTIFICATION;
795 } else if (!strncmp(volume_type_str, "alarm", VOLUME_TYPE_LEN)) {
796 *volume_type = VOLUME_TYPE_ALARM;
797 } else if (!strncmp(volume_type_str, "ringtone", VOLUME_TYPE_LEN)) {
798 *volume_type = VOLUME_TYPE_RINGTONE;
799 } else if (!strncmp(volume_type_str, "media", VOLUME_TYPE_LEN)) {
800 *volume_type = VOLUME_TYPE_MEDIA;
801 } else if (!strncmp(volume_type_str, "call", VOLUME_TYPE_LEN)) {
802 *volume_type = VOLUME_TYPE_CALL;
803 } else if (!strncmp(volume_type_str, "voip", VOLUME_TYPE_LEN)) {
804 *volume_type = VOLUME_TYPE_VOIP;
805 } else if (!strncmp(volume_type_str, "voice", VOLUME_TYPE_LEN)) {
806 *volume_type = VOLUME_TYPE_VOICE;
808 debug_log("Invalid volume type : [%s]", volume_type_str);
809 ret = MM_ERROR_SOUND_INTERNAL;
815 int mm_sound_client_set_volume_by_type(volume_type_t type, const unsigned int level)
817 int ret = MM_ERROR_NONE;
818 char *type_str = NULL;
821 if (type >= VOLUME_TYPE_MAX) {
822 debug_error("invalid volume type %d", type);
823 return MM_ERROR_INVALID_ARGUMENT;
826 /* Check input param */
827 if (0 > _validate_volume(type, (int)level)) {
828 debug_error("invalid level %u of %s", level, g_volume_str[type]);
829 return MM_ERROR_INVALID_ARGUMENT;
832 if ((ret = __convert_volume_type_to_str(type, &type_str)) != MM_ERROR_NONE) {
833 debug_error("volume type convert failed");
837 ret = mm_sound_proxy_set_volume_by_type(type_str, level);
844 int mm_sound_client_get_volume_by_type(volume_type_t type, unsigned int *level)
846 int ret = MM_ERROR_NONE;
850 debug_error("invalid argument, level is null");
851 return MM_ERROR_INVALID_ARGUMENT;
854 if (type >= VOLUME_TYPE_MAX) {
855 debug_error("invalid volume type %d", type);
856 return MM_ERROR_INVALID_ARGUMENT;
859 /* Get volume value from VCONF */
860 if (vconf_get_int(g_volume_vconf[type], &vconf_value)) {
861 debug_error("vconf_get_int(%s) failed..\n", g_volume_vconf[type]);
862 return MM_ERROR_SOUND_INTERNAL;
865 *level = vconf_value;
870 static void _mm_sound_volume_changed_callback_wrapper_func(const char *direction, const char *volume_type_str,
871 int volume_level, void *userdata)
873 volume_type_t volume_type = 0;
874 struct callback_data *cb_data = (struct callback_data *) userdata;
876 debug_log("direction : %s, volume_type : %s, volume_level : %d",
877 direction, volume_type_str, volume_level);
879 if (cb_data == NULL) {
880 debug_warning("volume changed callback data null");
884 if (__convert_volume_type_to_int(volume_type_str, &volume_type) != MM_ERROR_NONE) {
885 debug_error("volume type convert failed");
888 debug_log("Call volume changed user cb, direction : %s, vol_type : %s(%d), level : %u",
889 direction, volume_type_str, volume_type, volume_level);
890 ((mm_sound_volume_changed_cb)(cb_data->user_cb))(volume_type, volume_level, cb_data->user_data);
893 int mm_sound_client_add_volume_changed_callback(mm_sound_volume_changed_cb func, void* userdata, unsigned int *subs_id)
895 int ret = MM_ERROR_NONE;
896 struct callback_data *cb_data = NULL;
900 GET_CB_DATA(cb_data, func, userdata, NULL);
902 ret = mm_sound_proxy_add_volume_changed_callback(_mm_sound_volume_changed_callback_wrapper_func, cb_data, g_free, subs_id);
909 int mm_sound_client_remove_volume_changed_callback(unsigned int subs_id)
911 int ret = MM_ERROR_NONE;
914 ret = mm_sound_proxy_remove_volume_changed_callback(subs_id);
920 int mm_sound_client_set_mute_by_type(volume_type_t type, bool mute)
922 int ret = MM_ERROR_NONE;
923 char *type_str = NULL;
927 if (type > VOLUME_TYPE_VOICE) {
928 debug_error("invalid volume type %d", type);
929 return MM_ERROR_INVALID_ARGUMENT;
932 if ((ret = __convert_volume_type_to_str(type, &type_str)) != MM_ERROR_NONE) {
933 debug_error("volume type convert failed");
937 ret = mm_sound_proxy_set_mute_by_type(type_str, mute);
944 int mm_sound_client_get_mute_by_type(volume_type_t type, bool *muted)
946 int ret = MM_ERROR_NONE;
951 if (type > VOLUME_TYPE_VOICE) {
952 debug_error("invalid volume type %d", type);
953 return MM_ERROR_INVALID_ARGUMENT;
956 /* Get mute state from VCONF */
957 if (vconf_get_bool(g_mute_vconf[type], &vconf_value)) {
958 debug_error("vconf_get_int(%s) failed..\n", g_mute_vconf[type]);
959 return MM_ERROR_SOUND_INTERNAL;
962 *muted = (bool)vconf_value;
968 int mm_sound_client_set_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_parameters, const char *filter_group)
970 int ret = MM_ERROR_NONE;
973 ret = mm_sound_proxy_set_filter_by_type(stream_type, filter_name, filter_parameters, filter_group);
979 int mm_sound_client_unset_filter_by_type(const char *stream_type)
981 int ret = MM_ERROR_NONE;
984 ret = mm_sound_proxy_unset_filter_by_type(stream_type);
990 int mm_sound_client_control_filter_by_type(const char *stream_type, const char *filter_name, const char *filter_controls)
992 int ret = MM_ERROR_NONE;
995 ret = mm_sound_proxy_control_filter_by_type(stream_type, filter_name, filter_controls);
1001 int mm_sound_client_is_focus_cb_thread(GThread *mine, bool *result)
1003 int ret = MM_ERROR_NONE;
1006 if (!mine || !result)
1007 ret = MM_ERROR_INVALID_ARGUMENT;
1010 for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
1011 if (!g_focus_sound_handle[i].is_used)
1013 if (g_focus_sound_handle[i].focus_cb_thread == mine) {
1023 int mm_sound_client_register_focus(int pid, const char *stream_type,
1024 mm_sound_focus_changed_cb callback, void* user_data, int *id)
1026 int ret = MM_ERROR_NONE;
1030 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1032 if (focus_find_empty_index(&index)) {
1033 ret = MM_ERROR_SOUND_INTERNAL;
1037 g_focus_sound_handle[index].focus_pid = pid;
1038 g_focus_sound_handle[index].focus_callback = callback;
1039 g_focus_sound_handle[index].user_data = user_data;
1040 g_focus_sound_handle[index].auto_reacquire = true;
1042 ret = mm_sound_proxy_register_focus(index, stream_type, id);
1043 if (ret == MM_ERROR_NONE) {
1044 debug_msg("Success to register focus, client_fd[%d], id[%d]", g_focus_sound_handle[index].client_fd, *id);
1045 if (focus_init_context(index)) {
1046 ret = MM_ERROR_SOUND_INTERNAL;
1050 debug_error("Error occurred : 0x%x", ret);
1054 focus_init_callback(index, false);
1058 g_focus_sound_handle[index].is_used = false;
1060 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1066 int mm_sound_client_unregister_focus(int id)
1068 int ret = MM_ERROR_NONE;
1072 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1074 index = focus_find_index_by_handle(id);
1076 debug_error("Could not find index");
1077 ret = MM_ERROR_INVALID_ARGUMENT;
1081 if (!g_mutex_trylock(&g_focus_sound_handle[index].focus_lock)) {
1082 debug_warning("maybe focus_callback is being called, try one more time..");
1083 usleep(2500000); /* 2.5 sec */
1084 if (g_mutex_trylock(&g_focus_sound_handle[index].focus_lock))
1085 debug_msg("finally got focus_lock");
1088 ret = mm_sound_proxy_unregister_focus(index);
1089 if (ret == MM_ERROR_NONE)
1090 debug_msg("Success to unregister focus");
1092 debug_error("Error occurred : 0x%x", ret);
1094 g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1096 focus_deinit_callback(index, false);
1097 g_focus_sound_handle[index].focus_fd = 0;
1098 g_focus_sound_handle[index].focus_pid = 0;
1099 g_focus_sound_handle[index].client_fd = 0;
1100 g_focus_sound_handle[index].handle = 0;
1101 g_focus_sound_handle[index].is_used = false;
1102 focus_deinit_context(index);
1105 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1110 int mm_sound_client_set_focus_reacquisition(int id, bool reacquisition)
1112 int ret = MM_ERROR_NONE;
1118 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1120 index = focus_find_index_by_handle(id);
1122 debug_error("Could not find index");
1123 ret = MM_ERROR_INVALID_ARGUMENT;
1127 ret = mm_sound_client_is_focus_cb_thread(g_thread_self(), &result);
1129 debug_error("mm_sound_client_is_focus_cb_thread failed");
1131 } else if (!result) {
1132 ret = mm_sound_proxy_set_focus_reacquisition(index, reacquisition);
1133 if (ret == MM_ERROR_NONE) {
1134 debug_msg("Success to set focus reacquisition to [%d]", reacquisition);
1136 debug_error("Error occurred : 0x%x", ret);
1140 debug_warning("Inside the focus cb thread, set focus reacquisition to [%d]", reacquisition);
1143 g_focus_sound_handle[index].auto_reacquire = reacquisition;
1144 debug_msg("set focus reacquisition(%d) for id(%d)", reacquisition, id);
1147 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1152 int mm_sound_client_get_focus_reacquisition(int id, bool *reacquisition)
1154 int ret = MM_ERROR_NONE;
1159 if (!reacquisition) {
1160 debug_error("Invalid parameter");
1161 return MM_ERROR_INVALID_ARGUMENT;
1164 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1166 index = focus_find_index_by_handle(id);
1168 debug_error("Could not find index");
1169 ret = MM_ERROR_INVALID_ARGUMENT;
1173 *reacquisition = g_focus_sound_handle[index].auto_reacquire;
1174 debug_msg("get focus reacquisition(%d) for id(%d)", *reacquisition, id);
1177 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1182 int mm_sound_client_get_acquired_focus_stream_type(int focus_type, char **stream_type, int *option, char **ext_info)
1184 int ret = MM_ERROR_NONE;
1188 ret = mm_sound_proxy_get_acquired_focus_stream_type(focus_type, stream_type, option, ext_info);
1189 if (ret == MM_ERROR_NONE)
1190 debug_msg("Success to get stream type of acquired focus, stream_type(%s), ext_info(%s)",
1191 *stream_type, *ext_info);
1193 debug_error("Error occurred : 0x%x", ret);
1200 int mm_sound_client_acquire_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1202 int ret = MM_ERROR_NONE;
1206 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1208 index = focus_find_index_by_handle(id);
1210 debug_error("Could not find index");
1211 ret = MM_ERROR_INVALID_ARGUMENT;
1215 ret = mm_sound_proxy_acquire_focus(index, type, option, ext_info);
1216 if (ret == MM_ERROR_NONE)
1217 debug_msg("Success to acquire focus");
1219 debug_error("Error occurred : 0x%x", ret);
1222 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1227 int mm_sound_client_release_focus(int id, mm_sound_focus_type_e type, int option, const char *ext_info)
1229 int ret = MM_ERROR_NONE;
1233 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1235 index = focus_find_index_by_handle(id);
1237 debug_error("Could not find index");
1238 ret = MM_ERROR_INVALID_ARGUMENT;
1242 ret = mm_sound_proxy_release_focus(index, type, option, ext_info);
1243 if (ret == MM_ERROR_NONE)
1244 debug_msg("Success to release focus");
1246 debug_error("Error occurred : 0x%x", ret);
1249 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1254 int mm_sound_client_update_stream_focus_status(int id, unsigned int status)
1256 int ret = MM_ERROR_NONE;
1259 if ((ret = mm_sound_proxy_update_stream_focus_status(id, status)) != MM_ERROR_NONE)
1260 debug_error("failed to update stream focus status, ret[0x%x]", ret);
1266 int mm_sound_client_deliver_focus(int src_id, int dst_id, mm_sound_focus_type_e focus_type)
1268 int ret = MM_ERROR_NONE;
1274 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1276 src_index = focus_find_index_by_handle(src_id);
1277 if (src_index == -1) {
1278 debug_error("Could not find src index");
1279 ret = MM_ERROR_INVALID_ARGUMENT;
1282 dst_index = focus_find_index_by_handle(dst_id);
1283 if (dst_index == -1) {
1284 debug_error("Could not find dst index");
1285 ret = MM_ERROR_INVALID_ARGUMENT;
1288 if (g_focus_sound_handle[src_index].focus_pid != g_focus_sound_handle[dst_index].focus_pid) {
1289 debug_error("pid[%d/%d] are not same for dst/src",
1290 g_focus_sound_handle[src_index].focus_pid,
1291 g_focus_sound_handle[dst_index].focus_pid);
1292 ret = MM_ERROR_SOUND_INTERNAL;
1296 if ((ret = mm_sound_proxy_deliver_focus(src_index, dst_index, focus_type)) != MM_ERROR_NONE)
1297 debug_error("failed to deliver focus, ret[0x%x]", ret);
1300 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1305 int mm_sound_client_set_focus_watch_callback(int pid, mm_sound_focus_type_e focus_type,
1306 mm_sound_focus_changed_watch_cb callback, void* user_data, int *id)
1308 int ret = MM_ERROR_NONE;
1314 return MM_ERROR_INVALID_ARGUMENT;
1316 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1318 if (focus_find_empty_index(&index)) {
1319 ret = MM_ERROR_SOUND_INTERNAL;
1323 g_focus_sound_handle[index].focus_pid = pid;
1324 g_focus_sound_handle[index].watch_callback = callback;
1325 g_focus_sound_handle[index].user_data = user_data;
1326 g_focus_sound_handle[index].unset_watch_callback_requested = false;
1328 ret = mm_sound_proxy_add_focus_watch_callback(index, focus_type);
1329 if (ret == MM_ERROR_NONE) {
1330 *id = g_focus_sound_handle[index].handle;
1331 debug_msg("Success to add watch focus cb, id(%d)", *id);
1332 if (focus_init_context(index)) {
1333 ret = MM_ERROR_SOUND_INTERNAL;
1337 debug_error("Error occurred : 0x%x", ret);
1341 focus_init_callback(index, true);
1345 g_focus_sound_handle[index].is_used = false;
1347 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1352 int mm_sound_client_request_unset_focus_watch_callback(int id)
1354 int ret = MM_ERROR_NONE;
1358 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1360 index = focus_watch_find_index_by_handle(id);
1362 debug_error("Could not find index");
1363 ret = MM_ERROR_INVALID_ARGUMENT;
1366 g_focus_sound_handle[index].unset_watch_callback_requested = true;
1369 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1374 int mm_sound_client_unset_focus_watch_callback(int id)
1376 int ret = MM_ERROR_NONE;
1380 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_index_mutex, MM_ERROR_SOUND_INTERNAL);
1382 index = focus_watch_find_index_by_handle(id);
1384 debug_error("Could not find index");
1385 ret = MM_ERROR_INVALID_ARGUMENT;
1389 g_mutex_lock(&g_focus_sound_handle[index].focus_lock);
1391 g_focus_sound_handle[index].is_used = false;
1393 ret = mm_sound_proxy_remove_focus_watch_callback(index);
1394 if (ret == MM_ERROR_NONE)
1395 debug_msg("Success to remove watch focus cb, id(%d)", g_focus_sound_handle[index].handle);
1397 debug_error("Error occurred : 0x%x", ret);
1400 g_mutex_unlock(&g_focus_sound_handle[index].focus_lock);
1402 focus_deinit_callback(index, true);
1403 g_focus_sound_handle[index].focus_fd = 0;
1404 g_focus_sound_handle[index].focus_pid = 0;
1405 g_focus_sound_handle[index].client_fd = 0;
1406 g_focus_sound_handle[index].handle = 0;
1407 focus_deinit_context(index);
1410 MMSOUND_LEAVE_CRITICAL_SECTION(&g_index_mutex);
1415 static gboolean _idle_event_callback(void *data)
1417 focus_idle_event_t *idle_event_data = (focus_idle_event_t*)data;
1418 int ret = MM_ERROR_NONE;
1421 debug_error("data is null");
1425 debug_msg("idle_event_data(%p): type(%d), data(%d)",
1426 idle_event_data, idle_event_data->type, idle_event_data->data);
1428 switch (idle_event_data->type) {
1429 case IDLE_EVENT_TYPE_UNSET_FOCUS_WATCH_CB:
1430 if ((ret = mm_sound_client_unset_focus_watch_callback(idle_event_data->data)))
1431 debug_error("Could not unset focus watch callback, id(%d), ret = %x", idle_event_data->data, ret);
1433 case IDLE_EVENT_TYPE_UNREGISTER_FOCUS:
1434 if ((ret = mm_sound_client_unregister_focus(idle_event_data->data)))
1435 debug_error("Could not unregister focus, id(%d), ret = %x", idle_event_data->data, ret);
1438 debug_warning("invalid type(%d)", idle_event_data->type);
1442 g_free(idle_event_data);
1444 g_idle_event_src = 0;
1446 MMSOUND_LEAVE_CRITICAL_SECTION(&g_event_mutex);
1451 int mm_sound_client_execute_focus_func_in_main_context(focus_idle_event_type_e type, int data)
1453 focus_idle_event_t *idle_event_data = NULL;
1455 if (IDLE_EVENT_TYPE_MAX < type)
1456 return MM_ERROR_INVALID_ARGUMENT;
1458 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_event_mutex, MM_ERROR_SOUND_INTERNAL);
1460 idle_event_data = g_new0(focus_idle_event_t, 1);
1461 idle_event_data->type = type;
1462 idle_event_data->data = data;
1464 g_idle_event_src = g_idle_add_full(G_PRIORITY_HIGH,
1465 (GSourceFunc)_idle_event_callback,
1466 (gpointer)idle_event_data,
1469 return MM_ERROR_NONE;
1472 int mm_sound_client_add_test_callback(mm_sound_test_cb func, void* user_data, unsigned int *subs_id)
1474 int ret = MM_ERROR_NONE;
1478 ret = mm_sound_proxy_add_test_callback(func, user_data, g_free, subs_id);
1484 int mm_sound_client_remove_test_callback(unsigned int subs_id)
1486 int ret = MM_ERROR_NONE;
1489 ret = mm_sound_proxy_remove_test_callback(subs_id);
1495 int mm_sound_client_test(int a, int b, int* getv)
1497 int ret = MM_ERROR_NONE;
1501 ret = mm_sound_proxy_test(a, b, getv);
1502 debug_log("%d * %d -> result : %d", a, b, *getv);