4 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Sangchul Lee <sc11.lee@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.
27 #include "include/mm_sound.h"
28 #include "include/mm_sound_device.h"
29 #include "include/mm_sound_client.h"
31 #define VOLUME_TYPE_LEN 64
33 static mm_sound_device_list_t g_device_list;
34 static pthread_mutex_t g_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
36 static int _check_for_valid_mask(int flags)
38 int ret = MM_ERROR_NONE;
39 bool at_least_cond = false;
41 if (flags > 0 && flags <= MM_SOUND_DEVICE_ALL_FLAG) {
42 if (flags & MM_SOUND_DEVICE_IO_DIRECTION_IN_FLAG)
44 if (!at_least_cond && (flags & MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG))
46 if (!at_least_cond && (flags & MM_SOUND_DEVICE_IO_DIRECTION_BOTH_FLAG))
48 if (!at_least_cond && (flags & MM_SOUND_DEVICE_TYPE_INTERNAL_FLAG))
50 if (!at_least_cond && (flags & MM_SOUND_DEVICE_TYPE_EXTERNAL_FLAG))
52 if (!at_least_cond && (flags & MM_SOUND_DEVICE_STATE_DEACTIVATED_FLAG))
54 if (!at_least_cond && (flags & MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG))
57 ret = MM_ERROR_INVALID_ARGUMENT;
61 ret = MM_ERROR_INVALID_ARGUMENT;
64 debug_error("flags[0x%x] is not valid", flags);
69 static int __convert_device_type_to_enum(char *device_type, mm_sound_device_type_e *device_type_enum)
71 int ret = MM_ERROR_NONE;
73 if (!device_type || !device_type_enum)
74 return MM_ERROR_INVALID_ARGUMENT;
76 if (!strncmp(device_type, "builtin-speaker", VOLUME_TYPE_LEN)) {
77 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
78 } else if (!strncmp(device_type, "builtin-receiver", VOLUME_TYPE_LEN)) {
79 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_RECEIVER;
80 } else if (!strncmp(device_type, "builtin-mic", VOLUME_TYPE_LEN)) {
81 *device_type_enum = MM_SOUND_DEVICE_TYPE_BUILTIN_MIC;
82 } else if (!strncmp(device_type, "audio-jack", VOLUME_TYPE_LEN)) {
83 *device_type_enum = MM_SOUND_DEVICE_TYPE_AUDIOJACK;
84 } else if (!strncmp(device_type, "bt-a2dp", VOLUME_TYPE_LEN)) {
85 *device_type_enum = MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP;
86 } else if (!strncmp(device_type, "bt-sco", VOLUME_TYPE_LEN)) {
87 *device_type_enum = MM_SOUND_DEVICE_TYPE_BLUETOOTH_SCO;
88 } else if (!strncmp(device_type, "hdmi", VOLUME_TYPE_LEN)) {
89 *device_type_enum = MM_SOUND_DEVICE_TYPE_HDMI;
90 } else if (!strncmp(device_type, "forwarding", VOLUME_TYPE_LEN)) {
91 *device_type_enum = MM_SOUND_DEVICE_TYPE_MIRRORING;
92 } else if (!strncmp(device_type, "usb-audio", VOLUME_TYPE_LEN)) {
93 *device_type_enum = MM_SOUND_DEVICE_TYPE_USB_AUDIO;
94 } else if (!strncmp(device_type, "network", VOLUME_TYPE_LEN)) {
95 *device_type_enum = MM_SOUND_DEVICE_TYPE_NETWORK;
97 ret = MM_ERROR_INVALID_ARGUMENT;
98 debug_error("not supported device_type(%s), err(0x%08x)", device_type, ret);
104 static int __free_device_list(mm_sound_device_list_t *device_list_t)
107 return MM_ERROR_INVALID_ARGUMENT;
109 debug_log("free device list %p", device_list_t);
110 g_list_free_full(g_list_first(device_list_t->list), g_free);
111 g_free(device_list_t);
113 return MM_ERROR_NONE;
117 int mm_sound_add_device_connected_callback(int flags, mm_sound_device_connected_cb func, void *user_data, unsigned int *id)
119 int ret = MM_ERROR_NONE;
121 if (func == NULL || id == NULL) {
122 debug_error("argument is not valid");
123 return MM_ERROR_INVALID_ARGUMENT;
125 ret = _check_for_valid_mask(flags);
126 if (ret == MM_ERROR_NONE) {
127 ret = mm_sound_client_add_device_connected_callback(flags, func, user_data, id);
129 debug_error("Could not add device connected callback, ret = %x", ret);
136 int mm_sound_remove_device_connected_callback(unsigned int id)
138 int ret = MM_ERROR_NONE;
140 ret = mm_sound_client_remove_device_connected_callback(id);
142 debug_error("Could not remove device connected callback, ret = %x", ret);
148 int mm_sound_add_device_information_changed_callback(int flags, mm_sound_device_info_changed_cb func, void *user_data, unsigned int *id)
150 int ret = MM_ERROR_NONE;
152 if (func == NULL || id == NULL) {
153 debug_error("argument is not valid");
154 return MM_ERROR_INVALID_ARGUMENT;
156 ret = _check_for_valid_mask(flags);
157 if (ret == MM_ERROR_NONE) {
158 ret = mm_sound_client_add_device_info_changed_callback(flags, func, user_data, id);
160 debug_error("Could not add device information changed callback, ret = %x", ret);
167 int mm_sound_remove_device_information_changed_callback(unsigned int id)
169 int ret = MM_ERROR_NONE;
171 ret = mm_sound_client_remove_device_info_changed_callback(id);
173 debug_error("Could not remove device information changed callback, ret = %x", ret);
179 int mm_sound_add_device_state_changed_callback(int flags, mm_sound_device_state_changed_cb func, void *user_data, unsigned int *id)
181 int ret = MM_ERROR_NONE;
183 if (func == NULL || id == NULL) {
184 debug_error("argument is not valid");
185 return MM_ERROR_INVALID_ARGUMENT;
187 ret = _check_for_valid_mask(flags);
188 if (ret == MM_ERROR_NONE) {
189 ret = mm_sound_client_add_device_state_changed_callback(flags, func, user_data, id);
191 debug_error("Could not add device state changed callback, ret = %x", ret);
198 int mm_sound_remove_device_state_changed_callback(unsigned int id)
200 int ret = MM_ERROR_NONE;
202 ret = mm_sound_client_remove_device_state_changed_callback(id);
204 debug_error("Could not remove device state changed callback, ret = %x", ret);
210 int mm_sound_add_device_running_changed_callback(int flags, mm_sound_device_running_changed_cb func, void *user_data, unsigned int *id)
212 int ret = MM_ERROR_NONE;
214 if (func == NULL || id == NULL) {
215 debug_error("argument is not valid");
216 return MM_ERROR_INVALID_ARGUMENT;
218 ret = _check_for_valid_mask(flags);
219 if (ret == MM_ERROR_NONE) {
220 ret = mm_sound_client_add_device_running_changed_callback(flags, func, user_data, id);
222 debug_error("Could not add device running changed callback, ret = %x", ret);
230 int mm_sound_remove_device_running_changed_callback(unsigned int id)
232 int ret = MM_ERROR_NONE;
234 ret = mm_sound_client_remove_device_running_changed_callback(id);
236 debug_error("Could not remove device running changed callback, ret = %x", ret);
243 int mm_sound_get_current_device_list(mm_sound_device_flags_e flags, MMSoundDeviceList_t *device_list)
245 int ret = MM_ERROR_NONE;
248 return MM_ERROR_INVALID_ARGUMENT;
250 ret = _check_for_valid_mask(flags);
251 if (ret != MM_ERROR_NONE) {
252 debug_error("mask[0x%x] is invalid, ret=0x%x", flags, ret);
256 pthread_mutex_lock(&g_thread_mutex);
258 if (g_device_list.list != NULL) {
259 g_list_free_full(g_device_list.list, g_free);
260 g_device_list.list = NULL;
263 g_device_list.is_new_device_list = true;
265 ret = mm_sound_client_get_current_connected_device_list(flags, &g_device_list);
267 debug_error("Could not get current connected device list, ret = %x", ret);
268 g_device_list.list = NULL;
270 *device_list = &g_device_list;
273 pthread_mutex_unlock(&g_thread_mutex);
279 int mm_sound_get_device_list(int flags, MMSoundDeviceList_t *device_list)
281 int ret = MM_ERROR_NONE;
282 mm_sound_device_list_t *_device_list;
285 return MM_ERROR_INVALID_ARGUMENT;
287 ret = _check_for_valid_mask(flags);
288 if (ret != MM_ERROR_NONE) {
289 debug_error("mask[0x%x] is invalid, ret=0x%x", flags, ret);
293 if (!(_device_list = g_malloc0(sizeof(mm_sound_device_list_t)))) {
294 debug_error("Allocate device list failed");
295 return MM_ERROR_SOUND_INTERNAL;
298 _device_list->is_new_device_list = true;
300 ret = mm_sound_client_get_current_connected_device_list(flags, _device_list);
302 debug_error("Could not get current connected device list, ret = %x", ret);
303 g_free(_device_list);
305 *device_list = _device_list;
312 int mm_sound_free_device_list(MMSoundDeviceList_t device_list)
314 return __free_device_list((mm_sound_device_list_t*) device_list);
318 int mm_sound_free_device(MMSoundDevice_t device_h)
320 if (device_h == NULL)
321 return MM_ERROR_INVALID_ARGUMENT;
325 return MM_ERROR_NONE;
329 int mm_sound_get_device_by_id(int device_id, MMSoundDevice_t *device_h)
331 int ret = MM_ERROR_NONE;
332 mm_sound_device_t *device = NULL;
334 if (device_id < 1 || device_h == NULL)
335 return MM_ERROR_INVALID_ARGUMENT;
337 ret = mm_sound_client_get_device_by_id(device_id, &device);
339 debug_error("Could not get device by id, ret = %x", ret);
347 int mm_sound_get_next_device(MMSoundDeviceList_t device_list, MMSoundDevice_t *device)
349 int ret = MM_ERROR_NONE;
350 mm_sound_device_list_t *device_list_t = NULL;
353 if (!device_list || !device)
354 return MM_ERROR_INVALID_ARGUMENT;
356 device_list_t = (mm_sound_device_list_t*) device_list;
357 if (device_list_t->is_new_device_list)
358 node = g_list_first(device_list_t->list);
360 node = g_list_next(device_list_t->list);
363 ret = MM_ERROR_SOUND_NO_DATA;
365 if (device_list_t->is_new_device_list)
366 device_list_t->is_new_device_list = false;
368 device_list_t->list = node;
370 *device = (mm_sound_device_t*)node->data;
371 debug_log("next device[%p]", *device);
377 int mm_sound_get_prev_device(MMSoundDeviceList_t device_list, MMSoundDevice_t *device)
379 int ret = MM_ERROR_NONE;
380 mm_sound_device_list_t *device_list_t = NULL;
383 if (!device_list || !device)
384 return MM_ERROR_INVALID_ARGUMENT;
386 device_list_t = (mm_sound_device_list_t*) device_list;
387 node = g_list_previous(device_list_t->list);
389 ret = MM_ERROR_SOUND_NO_DATA;
390 debug_error("Could not get previous device, ret = %x", ret);
392 device_list_t->list = node;
393 *device = (mm_sound_device_t*)node->data;
394 debug_log("previous device[%p]", *device);
400 int mm_sound_get_device_type(MMSoundDevice_t device_h, mm_sound_device_type_e *type)
402 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
403 if (!device || !type) {
404 debug_error("invalid argument");
405 return MM_ERROR_INVALID_ARGUMENT;
407 __convert_device_type_to_enum(device->type, type);
408 debug_log("device_handle:%p, type:%d", device, *type);
410 return MM_ERROR_NONE;
414 int mm_sound_get_device_io_direction(MMSoundDevice_t device_h, mm_sound_device_io_direction_e *io_direction)
416 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
418 debug_error("invalid handle");
419 return MM_ERROR_INVALID_ARGUMENT;
421 *io_direction = device->io_direction;
422 debug_log("device_handle:%p, io_direction:%d (1:IN,2:OUT,3:INOUT)", device, *io_direction);
424 return MM_ERROR_NONE;
428 int mm_sound_get_device_id(MMSoundDevice_t device_h, int *id)
430 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
432 debug_error("invalid handle");
433 return MM_ERROR_INVALID_ARGUMENT;
436 debug_log("device_handle:%p, id:%d", device, *id);
438 return MM_ERROR_NONE;
442 int mm_sound_get_device_state(MMSoundDevice_t device_h, mm_sound_device_state_e *state)
444 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
446 debug_error("invalid handle");
447 return MM_ERROR_INVALID_ARGUMENT;
449 *state = device->state;
450 debug_log("device_handle:%p, state:%d (0:INACTIVATED,1:ACTIVATED)", device, *state);
452 return MM_ERROR_NONE;
456 int mm_sound_get_device_name(MMSoundDevice_t device_h, char **name)
458 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
460 debug_error("invalid handle");
461 return MM_ERROR_INVALID_ARGUMENT;
463 *name = device->name;
464 debug_log("device_handle:%p, name:%s", device, *name);
466 return MM_ERROR_NONE;
470 int mm_sound_get_device_vendor_id(MMSoundDevice_t device_h, int *vendor_id)
472 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
474 debug_error("invalid handle");
475 return MM_ERROR_INVALID_ARGUMENT;
477 *vendor_id = device->vendor_id;
478 debug_log("device_handle:%p, vendor id:%04x", device, *vendor_id);
480 return MM_ERROR_NONE;
484 int mm_sound_get_device_product_id(MMSoundDevice_t device_h, int *product_id)
486 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
488 debug_error("invalid handle");
489 return MM_ERROR_INVALID_ARGUMENT;
491 *product_id = device->product_id;
492 debug_log("device_handle:%p, product id:%04x", device, *product_id);
494 return MM_ERROR_NONE;
498 int mm_sound_is_stream_on_device(int stream_id, MMSoundDevice_t device_h, bool *is_on)
500 int ret = MM_ERROR_NONE;
502 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
505 if (!device || !is_on) {
506 debug_error("invalid argument");
507 return MM_ERROR_INVALID_ARGUMENT;
510 if (device->stream_num >= 0) {
511 debug_log("device_handle has stream id");
512 for (i = 0; i < device->stream_num; i++) {
513 if (device->stream_id[i] == stream_id) {
519 debug_log("device_handle dosn't have stream id");
520 /* No information about stream in client-side, should ask to server-side */
521 if ((ret = mm_sound_client_is_stream_on_device(stream_id, device->id, &_is_on)) < 0) {
522 debug_error("Failed to query is stream on");
523 return MM_ERROR_SOUND_INTERNAL;
527 debug_log("device(%d) %s stream(%d)", device->id, _is_on ? "has" : "doesn't have", stream_id);
534 int mm_sound_is_stream_on_device_by_id(int stream_id, int device_id, bool *is_on)
536 int ret = MM_ERROR_NONE;
540 debug_error("invalid argument");
541 return MM_ERROR_INVALID_ARGUMENT;
544 if ((ret = mm_sound_client_is_stream_on_device(stream_id, device_id, &_is_on)) < 0) {
545 debug_error("Failed to query is stream on");
546 return MM_ERROR_SOUND_INTERNAL;
549 debug_log("device(%d) %s stream(%d)", device_id, _is_on ? "has" : "doesn't have", stream_id);
556 int mm_sound_is_device_running(MMSoundDevice_t device_h, bool *is_running)
558 mm_sound_device_t *device = (mm_sound_device_t*)device_h;
559 if (!device || !is_running) {
560 debug_error("invalid argument");
561 return MM_ERROR_INVALID_ARGUMENT;
563 *is_running = device->is_running;
564 debug_log("device_handle:0x%p, running:%d", device, *is_running);
566 return MM_ERROR_NONE;