4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
27 #ifdef ALSA_UCM_DEBUG_TIME
32 #include "tizen-audio-internal.h"
34 #ifdef ALSA_UCM_DEBUG_TIME
35 #define SND_USE_CASE_SET __set_use_case_with_time
37 #define SND_USE_CASE_SET snd_use_case_set
40 audio_return_t _audio_ucm_init (audio_mgr_t *am)
42 snd_use_case_mgr_open(&am->ucm.uc_mgr, ALSA_DEFAULT_CARD);
44 if (!am->ucm.uc_mgr) {
45 AUDIO_LOG_ERROR("uc_mgr open failed");
46 return AUDIO_ERR_RESOURCE;
51 audio_return_t _audio_ucm_deinit (audio_mgr_t *am)
53 if (am->ucm.uc_mgr != NULL) {
54 snd_use_case_mgr_close(am->ucm.uc_mgr);
55 am->ucm.uc_mgr = NULL;
61 void _audio_ucm_get_device_name (audio_mgr_t *am, const char *use_case, audio_direction_t direction, const char **value)
63 char identifier[70] = {0};
65 if (direction == AUDIO_DIRECTION_IN) {
66 sprintf(identifier, "CapturePCM//%s", use_case);
68 sprintf(identifier, "PlaybackPCM//%s", use_case);
70 snd_use_case_get(am->ucm.uc_mgr, identifier, value);
73 static inline void __add_ucm_device_info (audio_mgr_t *am, const char *use_case, audio_direction_t direction, audio_device_info_t *device_info_list, int *device_info_count)
75 audio_device_info_t *device_info;
76 const char *device_name = NULL;
79 _audio_ucm_get_device_name(am, use_case, direction, &device_name);
81 device_info = &device_info_list[(*device_info_count)++];
83 memset(device_info, 0x00, sizeof(audio_device_info_t));
84 device_info->api = AUDIO_DEVICE_API_ALSA;
85 device_info->direction = direction;
86 needle = strstr(&device_name[3], ",");
88 device_info->alsa.device_idx = *(needle+1) - '0';
89 device_info->alsa.card_name = strndup(&device_name[3], needle - (device_name+3));
90 device_info->alsa.card_idx = snd_card_get_index(device_info->alsa.card_name);
91 AUDIO_LOG_DEBUG("Card name: %s", device_info->alsa.card_name);
94 free((void *)device_name);
98 int _audio_ucm_fill_device_info_list (audio_mgr_t *am, audio_device_info_t *device_info_list, const char *verb)
100 int device_info_count = 0;
101 const char *curr_verb = NULL;
104 snd_use_case_get(am->ucm.uc_mgr, "_verb", &curr_verb);
109 __add_ucm_device_info(am, verb, AUDIO_DIRECTION_IN, device_info_list, &device_info_count);
110 __add_ucm_device_info(am, verb, AUDIO_DIRECTION_OUT, device_info_list, &device_info_count);
113 free((void *)curr_verb);
116 return device_info_count;
119 static void __dump_use_case(const char *verb, const char *devices[], int dev_count, const char *modifiers[], int mod_count, char *dump)
123 len = sprintf(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
127 for (i = 0; i < dev_count; i++) {
128 if (i != dev_count - 1) {
129 len = sprintf(dump, "%s, ", devices[i]);
131 len = sprintf(dump, "%s", devices[i]);
137 len = sprintf(dump, " ] Modifier [ ");
141 for (i = 0; i < mod_count; i++) {
142 if (i != mod_count - 1) {
143 len = sprintf(dump, "%s, ", modifiers[i]);
145 len = sprintf(dump, "%s", modifiers[i]);
151 len = sprintf(dump, " ]");
158 #ifdef ALSA_UCM_DEBUG_TIME
159 static inline int __set_use_case_with_time(snd_use_case_mgr_t *uc_mgr, const char *identifier, const char *value)
162 struct timeval t_start, t_stop;
163 unsigned long long t_diff = 0;
165 gettimeofday(&t_start, NULL);
166 ret = snd_use_case_set(uc_mgr, identifier, value);
167 gettimeofday(&t_stop, NULL);
168 if (t_start.tv_sec < t_stop.tv_sec)
169 t_diff = (t_stop.tv_sec - t_start.tv_sec) * 1000000;
170 t_diff += (t_stop.tv_usec - t_start.tv_usec);
171 AUDIO_LOG_DEBUG("identifier %s value %s takes %lluusec", identifier, value, t_diff);
178 1) If verb is null or verb is not changed
179 1-1) If device is changed
180 (If there is request for same device, it will be ignored)
181 -> Set "Inactive" verb, disable modifiers & devices, set current verb again, enable devices & modifiers
182 (playback/capture device will be enabled again if there is no request for playback/capture device)
183 1-2) If device is not changed
184 1-2-1) If modifier is changed
185 (If there is request for same modifier, it will be ignored)
186 -> Disable modifiers, enable modifiers
187 2) If verb is changed
188 -> Reset, set new verb, enable devices & modifiers
190 audio_return_t _audio_ucm_set_use_case (audio_mgr_t *am, const char *verb, const char *devices[], const char *modifiers[])
192 audio_return_t audio_ret = AUDIO_RET_OK;
193 int is_verb_changed = 0, is_dev_changed = 0, is_mod_changed = 0;
194 const char *old_verb = NULL, **old_dev_list = NULL, **old_mod_list = NULL;
195 int old_dev_count = 0, dev_count = 0;
196 int old_mod_count = 0, mod_count = 0;
197 const char **dis_dev_list = NULL, **ena_dev_list = NULL;
198 const char **dis_mod_list = NULL, **ena_mod_list = NULL;
199 int dis_dev_count = 0, ena_dev_count = 0;
200 int dis_mod_count = 0, ena_mod_count = 0;
204 if (!am->ucm.uc_mgr || !verb)
205 return AUDIO_ERR_PARAMETER;
207 snd_use_case_get(am->ucm.uc_mgr, "_verb", &old_verb);
208 old_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &old_dev_list);
209 old_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &old_mod_list);
210 __dump_use_case(old_verb, old_dev_list, old_dev_count, old_mod_list, old_mod_count, &dump_str[0]);
211 AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
214 for (dev_count = 0; devices[dev_count]; dev_count++);
217 for (mod_count = 0; modifiers[mod_count]; mod_count++);
220 __dump_use_case(verb, devices, dev_count, modifiers, mod_count, &dump_str[0]);
221 AUDIO_LOG_INFO("> UCM requested %s", dump_str);
223 if (old_verb && streq(verb, old_verb)) {
224 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
226 if (old_dev_count > 0) {
227 dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
228 for (i = 0; i < old_dev_count; i++) {
229 dis_dev_list[i] = NULL;
233 ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
234 for (i = 0; i < dev_count; i++) {
235 ena_dev_list[i] = NULL;
238 if (old_mod_count > 0) {
239 dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
240 for (i = 0; i < old_mod_count; i++) {
241 dis_mod_list[i] = NULL;
245 ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
246 for (i = 0; i < mod_count; i++) {
247 ena_mod_list[i] = NULL;
251 /* update disable modifiers list which are not present in new modifier list */
252 for (i = 0; i < old_mod_count; i++) {
253 int need_disable_mod = 1;
255 for (j = 0; j < mod_count; j++) {
256 if (streq(old_mod_list[i], modifiers[j])) {
257 need_disable_mod = 0;
261 if (need_disable_mod) {
262 if (is_mod_changed == 0)
264 dis_mod_list[dis_mod_count++] = old_mod_list[i];
268 /* update disable devices list which are not present in new device list */
269 for (i = 0; i < old_dev_count; i++) {
270 int need_disable_dev = 1;
272 for (j = 0; j < dev_count; j++) {
273 if (streq(old_dev_list[i], devices[j])) {
274 need_disable_dev = 0;
278 if (need_disable_dev) {
279 if (is_dev_changed == 0)
281 dis_dev_list[dis_dev_count++] = old_dev_list[i];
285 /* update enable devices list which are not present in old device list */
286 for (i = 0; i < dev_count; i++) {
287 int need_enable_dev = 1;
289 for (j = 0; j < old_dev_count; j++) {
290 if (streq(devices[i], old_dev_list[j])) {
295 if (need_enable_dev) {
296 if (is_dev_changed == 0)
298 ena_dev_list[ena_dev_count++] = devices[i];
302 /* update enable modifiers list which are not present in old modifier list */
303 for (i = 0; i < mod_count; i++) {
304 int need_enable_mod = 1;
306 for (j = 0; j < old_mod_count; j++) {
307 if (streq(modifiers[i], old_mod_list[j])) {
312 if (need_enable_mod) {
313 if (is_mod_changed == 0)
315 ena_mod_list[ena_mod_count++] = modifiers[i];
319 /* disable modifiers */
320 for (i = 0; i < dis_mod_count; i++) {
321 AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
322 if (snd_use_case_set(am->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
323 AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
326 /* disable devices */
327 for (i = 0; i < dis_dev_count; i++) {
328 AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
329 if (snd_use_case_set(am->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
330 AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
334 for (i = 0; i < ena_dev_count; i++) {
335 AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
336 if (snd_use_case_set(am->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
337 AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
340 /* enable modifiers */
341 for (i = 0; i < ena_mod_count; i++) {
342 AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
343 if (snd_use_case_set(am->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
344 AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
349 AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
351 if (snd_use_case_set(am->ucm.uc_mgr, "_verb", verb) < 0) {
352 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
353 audio_ret = AUDIO_ERR_UNDEFINED;
357 for (i = 0; i < dev_count; i++) {
358 AUDIO_LOG_DEBUG("Enable device : %s", devices[i]);
359 if(snd_use_case_set(am->ucm.uc_mgr, "_enadev", devices[i]) < 0)
360 AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
362 /* enable modifiers */
363 for (i = 0; i < mod_count; i++) {
364 AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
365 if(snd_use_case_set(am->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
366 AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
372 free((void *)old_verb);
374 snd_use_case_free_list(old_dev_list, old_dev_count);
376 snd_use_case_free_list(old_mod_list, old_mod_count);
378 free((void *)dis_dev_list);
380 free((void *)ena_dev_list);
382 free((void *)dis_mod_list);
384 free((void *)ena_mod_list);
386 if (is_verb_changed == 1 || is_dev_changed == 1 || is_mod_changed == 1) {
387 const char *new_verb = NULL, **new_dev_list = NULL, **new_mod_list = NULL;
388 int new_dev_count = 0, new_mod_count = 0;
390 snd_use_case_get(am->ucm.uc_mgr, "_verb", &new_verb);
391 new_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &new_dev_list);
392 new_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &new_mod_list);
393 __dump_use_case(new_verb, new_dev_list, new_dev_count, new_mod_list, new_mod_count, &dump_str[0]);
394 AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
397 free((void *)new_verb);
399 snd_use_case_free_list(new_dev_list, new_dev_count);
401 snd_use_case_free_list(new_mod_list, new_mod_count);
407 audio_return_t _audio_ucm_set_devices (audio_mgr_t *am, const char *verb, const char *devices[])
409 audio_return_t audio_ret = AUDIO_RET_OK;
410 int is_verb_changed = 0, is_dev_changed = 0;
411 const char *old_verb = NULL, **old_dev_list = NULL;
412 int old_dev_count = 0, dev_count = 0;
413 const char **dis_dev_list = NULL, **ena_dev_list = NULL;
414 int dis_dev_count = 0, ena_dev_count = 0;
418 if (!am->ucm.uc_mgr || !verb)
419 return AUDIO_ERR_PARAMETER;
421 snd_use_case_get(am->ucm.uc_mgr, "_verb", &old_verb);
422 old_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &old_dev_list);
423 __dump_use_case(old_verb, old_dev_list, old_dev_count, NULL, 0, &dump_str[0]);
424 AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
427 for (dev_count = 0; devices[dev_count]; dev_count++);
430 __dump_use_case(verb, devices, dev_count, NULL, 0, &dump_str[0]);
431 AUDIO_LOG_INFO("> UCM requested %s", dump_str);
433 if (old_verb && streq(verb, old_verb)) {
434 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
436 if (old_dev_count > 0) {
437 dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
438 for (i = 0; i < old_dev_count; i++) {
439 dis_dev_list[i] = NULL;
443 ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
444 for (i = 0; i < dev_count; i++) {
445 ena_dev_list[i] = NULL;
449 /* update disable devices list which are not present in new device list */
450 for (i = 0; i < old_dev_count; i++) {
451 int need_disable_dev = 1;
453 for (j = 0; j < dev_count; j++) {
454 if (streq(old_dev_list[i], devices[j])) {
455 need_disable_dev = 0;
459 if (need_disable_dev) {
460 if (is_dev_changed == 0)
462 dis_dev_list[dis_dev_count++] = old_dev_list[i];
466 /* update enable devices list which are not present in old device list */
467 for (i = 0; i < dev_count; i++) {
468 int need_enable_dev = 1;
470 for (j = 0; j < old_dev_count; j++) {
471 if (streq(devices[i], old_dev_list[j])) {
476 if (need_enable_dev) {
477 if (is_dev_changed == 0)
479 ena_dev_list[ena_dev_count++] = devices[i];
483 /* disable devices */
484 for (i = 0; i < dis_dev_count; i++) {
485 AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
486 if (snd_use_case_set(am->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
487 AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
491 for (i = 0; i < ena_dev_count; i++) {
492 AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
493 if (snd_use_case_set(am->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
494 AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
500 AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
502 if (snd_use_case_set(am->ucm.uc_mgr, "_verb", verb) < 0) {
503 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
504 audio_ret = AUDIO_ERR_UNDEFINED;
508 for (i = 0; i < dev_count; i++) {
509 AUDIO_LOG_DEBUG("Enable device : %s", devices[i]);
510 if(snd_use_case_set(am->ucm.uc_mgr, "_enadev", devices[i]) < 0)
511 AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
517 free((void *)old_verb);
519 snd_use_case_free_list(old_dev_list, old_dev_count);
521 free((void *)dis_dev_list);
523 free((void *)ena_dev_list);
525 if (is_verb_changed == 1 || is_dev_changed == 1) {
526 const char *new_verb = NULL, **new_dev_list = NULL;
527 int new_dev_count = 0;
529 snd_use_case_get(am->ucm.uc_mgr, "_verb", &new_verb);
530 new_dev_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enadevs", &new_dev_list);
531 __dump_use_case(new_verb, new_dev_list, new_dev_count, NULL, 0, &dump_str[0]);
532 AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
535 free((void *)new_verb);
537 snd_use_case_free_list(new_dev_list, new_dev_count);
544 audio_return_t _audio_ucm_set_modifiers (audio_mgr_t *am, const char *verb, const char *modifiers[])
546 audio_return_t audio_ret = AUDIO_RET_OK;
547 int is_verb_changed = 0, is_mod_changed = 0;
548 const char *old_verb = NULL, **old_mod_list = NULL;
549 int old_mod_count = 0, mod_count = 0;
550 const char **dis_mod_list = NULL, **ena_mod_list = NULL;
551 int dis_mod_count = 0, ena_mod_count = 0;
555 if (!am->ucm.uc_mgr || !verb)
556 return AUDIO_ERR_PARAMETER;
558 snd_use_case_get(am->ucm.uc_mgr, "_verb", &old_verb);
559 old_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &old_mod_list);
560 __dump_use_case(old_verb, NULL, 0, old_mod_list, old_mod_count, &dump_str[0]);
561 AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
564 for (mod_count = 0; modifiers[mod_count]; mod_count++);
567 __dump_use_case(verb, NULL, 0, modifiers, mod_count, &dump_str[0]);
568 AUDIO_LOG_INFO("> UCM requested %s", dump_str);
570 if (old_verb && streq(verb, old_verb)) {
571 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
573 if (old_mod_count > 0) {
574 dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
575 for (i = 0; i < old_mod_count; i++) {
576 dis_mod_list[i] = NULL;
580 ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
581 for (i = 0; i < mod_count; i++) {
582 ena_mod_list[i] = NULL;
586 /* update disable modifiers list which are not present in new modifier list */
587 for (i = 0; i < old_mod_count; i++) {
588 int need_disable_mod = 1;
590 for (j = 0; j < mod_count; j++) {
591 if (streq(old_mod_list[i], modifiers[j])) {
592 need_disable_mod = 0;
596 if (need_disable_mod) {
597 if (is_mod_changed == 0)
599 dis_mod_list[dis_mod_count++] = old_mod_list[i];
603 /* update enable modifiers list which are not present in old modifier list */
604 for (i = 0; i < mod_count; i++) {
605 int need_enable_mod = 1;
607 for (j = 0; j < old_mod_count; j++) {
608 if (streq(modifiers[i], old_mod_list[j])) {
613 if (need_enable_mod) {
614 if (is_mod_changed == 0)
616 ena_mod_list[ena_mod_count++] = modifiers[i];
620 /* disable modifiers */
621 for (i = 0; i < dis_mod_count; i++) {
622 AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
623 if (snd_use_case_set(am->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
624 AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
627 /* enable modifiers */
628 for (i = 0; i < ena_mod_count; i++) {
629 AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
630 if (snd_use_case_set(am->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
631 AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
636 AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
638 if (snd_use_case_set(am->ucm.uc_mgr, "_verb", verb) < 0) {
639 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
640 audio_ret = AUDIO_ERR_UNDEFINED;
643 /* enable modifiers */
644 for (i = 0; i < mod_count; i++) {
645 AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
646 if(snd_use_case_set(am->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
647 AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
653 free((void *)old_verb);
655 snd_use_case_free_list(old_mod_list, old_mod_count);
657 free((void *)dis_mod_list);
659 free((void *)ena_mod_list);
661 if (is_verb_changed == 1 || is_mod_changed == 1) {
662 const char *new_verb = NULL, **new_mod_list = NULL;
663 int new_mod_count = 0;
665 snd_use_case_get(am->ucm.uc_mgr, "_verb", &new_verb);
666 new_mod_count = snd_use_case_get_list(am->ucm.uc_mgr, "_enamods", &new_mod_list);
667 __dump_use_case(new_verb, NULL, 0, new_mod_list, new_mod_count, &dump_str[0]);
668 AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
671 free((void *)new_verb);
673 snd_use_case_free_list(new_mod_list, new_mod_count);
679 audio_return_t _audio_ucm_get_verb (audio_mgr_t *am, const char **value)
681 audio_return_t ret = AUDIO_RET_OK;
683 AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
684 AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
686 if ((ret = snd_use_case_get(am->ucm.uc_mgr, "_verb", value)) < 0) {
687 AUDIO_LOG_ERROR("Getting current verb failed: Reason %d", ret);
688 ret = AUDIO_ERR_UNDEFINED;
695 audio_return_t _audio_ucm_reset_use_case (audio_mgr_t *am)
697 audio_return_t ret = AUDIO_RET_OK;
699 AUDIO_RETURN_VAL_IF_FAIL(am, AUDIO_ERR_PARAMETER);
701 AUDIO_LOG_INFO(">>> UCM reset Verb [ %s ]", AUDIO_USE_CASE_VERB_INACTIVE);
703 if ((ret = snd_use_case_set(am->ucm.uc_mgr, "_verb", AUDIO_USE_CASE_VERB_INACTIVE)) < 0) {
704 AUDIO_LOG_ERROR("Reset use case failed: Reason %d", ret);
705 ret = AUDIO_ERR_UNDEFINED;