4 * Copyright (c) 2015 - 2016 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 #define UCM_PREFIX_CURRENT ">>> UCM current"
41 #define UCM_PREFIX_REQUESTED "> UCM requested"
42 #define UCM_PREFIX_CHANGED "<<< UCM changed"
46 static void __dump_use_case(const char* prefix, const char *verb, const char *devices[], int dev_count, const char *modifiers[], int mod_count)
49 dump_data_t* dump = NULL;
51 if (!(dump = _audio_dump_new(DUMP_LEN))) {
52 AUDIO_LOG_ERROR("Failed to create dump string...");
57 _audio_dump_add_str(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
61 for (i = 0; i < dev_count; i++) {
62 _audio_dump_add_str(dump, (i != dev_count - 1) ? "%s, " : "%s", devices[i]);
65 _audio_dump_add_str(dump, " ] Modifier [ ");
69 for (i = 0; i < mod_count; i++) {
70 _audio_dump_add_str(dump, (i != mod_count - 1) ? "%s, " : "%s", modifiers[i]);
73 _audio_dump_add_str(dump, " ]");
75 AUDIO_LOG_INFO("TEST %s : %s", prefix, _audio_dump_get_str(dump));
77 _audio_dump_free(dump);
80 #ifdef ALSA_UCM_DEBUG_TIME
81 static inline int __set_use_case_with_time(snd_use_case_mgr_t *uc_mgr, const char *identifier, const char *value)
84 struct timeval t_start, t_stop;
85 unsigned long long t_diff = 0;
87 gettimeofday(&t_start, NULL);
88 ret = snd_use_case_set(uc_mgr, identifier, value);
89 gettimeofday(&t_stop, NULL);
90 if (t_start.tv_sec < t_stop.tv_sec)
91 t_diff = (t_stop.tv_sec - t_start.tv_sec) * 1000000;
92 t_diff += (t_stop.tv_usec - t_start.tv_usec);
93 AUDIO_LOG_DEBUG("identifier %s value %s takes %lluusec", identifier, value, t_diff);
99 audio_return_t _ucm_init(audio_hal_t *ah)
101 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
103 snd_use_case_mgr_open(&ah->ucm.uc_mgr, ALSA_DEFAULT_CARD);
105 if (!ah->ucm.uc_mgr) {
106 AUDIO_LOG_ERROR("uc_mgr open failed");
107 return AUDIO_ERR_RESOURCE;
112 audio_return_t _ucm_deinit(audio_hal_t *ah)
114 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
115 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
117 if (ah->ucm.uc_mgr) {
118 snd_use_case_mgr_close(ah->ucm.uc_mgr);
119 ah->ucm.uc_mgr = NULL;
126 1) If verb is null or verb is not changed
127 1-1) If device is changed
128 (If there is request for same device, it will be ignored)
129 -> Set "Inactive" verb, disable modifiers & devices, set current verb again, enable devices & modifiers
130 (playback/capture device will be enabled again if there is no request for playback/capture device)
131 1-2) If device is not changed
132 1-2-1) If modifier is changed
133 (If there is request for same modifier, it will be ignored)
134 -> Disable modifiers, enable modifiers
135 2) If verb is changed
136 -> Reset, set new verb, enable devices & modifiers
138 audio_return_t _ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[])
140 audio_return_t audio_ret = AUDIO_RET_OK;
141 int is_verb_changed = 0, is_dev_changed = 0, is_mod_changed = 0;
142 const char *old_verb = NULL, **old_dev_list = NULL, **old_mod_list = NULL;
143 int old_dev_count = 0, dev_count = 0;
144 int old_mod_count = 0, mod_count = 0;
145 const char **dis_dev_list = NULL, **ena_dev_list = NULL;
146 const char **dis_mod_list = NULL, **ena_mod_list = NULL;
147 int dis_dev_count = 0, ena_dev_count = 0;
148 int dis_mod_count = 0, ena_mod_count = 0;
151 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
152 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
153 AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
155 snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
156 old_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &old_dev_list);
157 old_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &old_mod_list);
158 __dump_use_case(UCM_PREFIX_CURRENT, old_verb, old_dev_list, old_dev_count, old_mod_list, old_mod_count);
161 for (dev_count = 0; devices[dev_count]; dev_count++);
164 for (mod_count = 0; modifiers[mod_count]; mod_count++);
167 __dump_use_case(UCM_PREFIX_REQUESTED, verb, devices, dev_count, modifiers, mod_count);
169 if (old_verb && streq(verb, old_verb)) {
170 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
172 if (old_dev_count > 0) {
173 dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
174 for (i = 0; i < old_dev_count; i++) {
175 dis_dev_list[i] = NULL;
179 ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
180 for (i = 0; i < dev_count; i++) {
181 ena_dev_list[i] = NULL;
184 if (old_mod_count > 0) {
185 dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
186 for (i = 0; i < old_mod_count; i++) {
187 dis_mod_list[i] = NULL;
191 ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
192 for (i = 0; i < mod_count; i++) {
193 ena_mod_list[i] = NULL;
197 /* update disable modifiers list which are not present in new modifier list */
198 for (i = 0; i < old_mod_count; i++) {
199 int need_disable_mod = 1;
201 for (j = 0; j < mod_count; j++) {
202 if (streq(old_mod_list[i], modifiers[j])) {
203 need_disable_mod = 0;
207 if (need_disable_mod) {
208 if (is_mod_changed == 0)
210 dis_mod_list[dis_mod_count++] = old_mod_list[i];
214 /* update disable devices list which are not present in new device list */
215 for (i = 0; i < old_dev_count; i++) {
216 int need_disable_dev = 1;
218 for (j = 0; j < dev_count; j++) {
219 if (streq(old_dev_list[i], devices[j])) {
220 need_disable_dev = 0;
224 if (need_disable_dev) {
225 if (is_dev_changed == 0)
227 dis_dev_list[dis_dev_count++] = old_dev_list[i];
231 /* update enable devices list which are not present in old device list */
232 for (i = 0; i < dev_count; i++) {
233 int need_enable_dev = 1;
235 for (j = 0; j < old_dev_count; j++) {
236 if (streq(devices[i], old_dev_list[j])) {
241 if (need_enable_dev) {
242 if (is_dev_changed == 0)
244 ena_dev_list[ena_dev_count++] = devices[i];
248 /* update enable modifiers list which are not present in old modifier list */
249 for (i = 0; i < mod_count; i++) {
250 int need_enable_mod = 1;
252 for (j = 0; j < old_mod_count; j++) {
253 if (streq(modifiers[i], old_mod_list[j])) {
258 if (need_enable_mod) {
259 if (is_mod_changed == 0)
261 ena_mod_list[ena_mod_count++] = modifiers[i];
265 /* disable modifiers */
266 for (i = 0; i < dis_mod_count; i++) {
267 AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
268 if (snd_use_case_set(ah->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
269 AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
272 /* disable devices */
273 for (i = 0; i < dis_dev_count; i++) {
274 AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
275 if (snd_use_case_set(ah->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
276 AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
280 for (i = 0; i < ena_dev_count; i++) {
281 AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
282 if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
283 AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
286 /* enable modifiers */
287 for (i = 0; i < ena_mod_count; i++) {
288 AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
289 if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
290 AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
295 AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
297 if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
298 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
299 audio_ret = AUDIO_ERR_UNDEFINED;
303 for (i = 0; i < dev_count; i++) {
304 AUDIO_LOG_DEBUG("Enable device : %s", devices[i]);
305 if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", devices[i]) < 0)
306 AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
308 /* enable modifiers */
309 for (i = 0; i < mod_count; i++) {
310 AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
311 if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
312 AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
318 free((void *)old_verb);
320 snd_use_case_free_list(old_dev_list, old_dev_count);
322 snd_use_case_free_list(old_mod_list, old_mod_count);
324 free((void *)dis_dev_list);
326 free((void *)ena_dev_list);
328 free((void *)dis_mod_list);
330 free((void *)ena_mod_list);
332 if (is_verb_changed == 1 || is_dev_changed == 1 || is_mod_changed == 1) {
333 const char *new_verb = NULL, **new_dev_list = NULL, **new_mod_list = NULL;
334 int new_dev_count = 0, new_mod_count = 0;
336 snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
337 new_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &new_dev_list);
338 new_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &new_mod_list);
339 __dump_use_case(UCM_PREFIX_CHANGED, new_verb, new_dev_list, new_dev_count, new_mod_list, new_mod_count);
342 free((void *)new_verb);
344 snd_use_case_free_list(new_dev_list, new_dev_count);
346 snd_use_case_free_list(new_mod_list, new_mod_count);
352 audio_return_t _ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[])
354 audio_return_t audio_ret = AUDIO_RET_OK;
355 int is_verb_changed = 0, is_dev_changed = 0;
356 const char *old_verb = NULL, **old_dev_list = NULL;
357 int old_dev_count = 0, dev_count = 0;
358 const char **dis_dev_list = NULL, **ena_dev_list = NULL;
359 int dis_dev_count = 0, ena_dev_count = 0;
362 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
363 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
364 AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
365 AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
367 snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
368 old_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &old_dev_list);
369 __dump_use_case(UCM_PREFIX_CURRENT, old_verb, old_dev_list, old_dev_count, NULL, 0);
372 for (dev_count = 0; devices[dev_count]; dev_count++);
375 __dump_use_case(UCM_PREFIX_REQUESTED, verb, devices, dev_count, NULL, 0);
377 if (old_verb && streq(verb, old_verb)) {
378 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
380 if (old_dev_count > 0) {
381 dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
382 for (i = 0; i < old_dev_count; i++) {
383 dis_dev_list[i] = NULL;
387 ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
388 for (i = 0; i < dev_count; i++) {
389 ena_dev_list[i] = NULL;
393 /* update disable devices list which are not present in new device list */
394 for (i = 0; i < old_dev_count; i++) {
395 int need_disable_dev = 1;
397 for (j = 0; j < dev_count; j++) {
398 if (streq(old_dev_list[i], devices[j])) {
399 need_disable_dev = 0;
403 if (need_disable_dev) {
404 if (is_dev_changed == 0)
406 dis_dev_list[dis_dev_count++] = old_dev_list[i];
410 /* update enable devices list which are not present in old device list */
411 for (i = 0; i < dev_count; i++) {
412 int need_enable_dev = 1;
414 for (j = 0; j < old_dev_count; j++) {
415 if (streq(devices[i], old_dev_list[j])) {
420 if (need_enable_dev) {
421 if (is_dev_changed == 0)
423 ena_dev_list[ena_dev_count++] = devices[i];
427 /* disable devices */
428 for (i = 0; i < dis_dev_count; i++) {
429 AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
430 if (snd_use_case_set(ah->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
431 AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
435 for (i = 0; i < ena_dev_count; i++) {
436 AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
437 if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
438 AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
444 AUDIO_LOG_INFO("Setting new verb: %s", verb);
446 if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
447 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
448 audio_ret = AUDIO_ERR_UNDEFINED;
452 for (i = 0; i < dev_count; i++) {
453 AUDIO_LOG_INFO("Enable device : %s", devices[i]);
454 if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", devices[i]) < 0)
455 AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
461 free((void *)old_verb);
463 snd_use_case_free_list(old_dev_list, old_dev_count);
465 free((void *)dis_dev_list);
467 free((void *)ena_dev_list);
469 if (is_verb_changed == 1 || is_dev_changed == 1) {
470 const char *new_verb = NULL, **new_dev_list = NULL;
471 int new_dev_count = 0;
473 snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
474 new_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &new_dev_list);
475 __dump_use_case(UCM_PREFIX_CHANGED, new_verb, new_dev_list, new_dev_count, NULL, 0);
478 free((void *)new_verb);
480 snd_use_case_free_list(new_dev_list, new_dev_count);
487 audio_return_t _ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[])
489 audio_return_t audio_ret = AUDIO_RET_OK;
490 int is_verb_changed = 0, is_mod_changed = 0;
491 const char *old_verb = NULL, **old_mod_list = NULL;
492 int old_mod_count = 0, mod_count = 0;
493 const char **dis_mod_list = NULL, **ena_mod_list = NULL;
494 int dis_mod_count = 0, ena_mod_count = 0;
497 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
498 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
499 AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
500 AUDIO_RETURN_VAL_IF_FAIL(modifiers, AUDIO_ERR_PARAMETER);
502 snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
503 old_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &old_mod_list);
504 __dump_use_case(UCM_PREFIX_CURRENT, old_verb, NULL, 0, old_mod_list, old_mod_count);
507 for (mod_count = 0; modifiers[mod_count]; mod_count++);
510 __dump_use_case(UCM_PREFIX_REQUESTED, verb, NULL, 0, modifiers, mod_count);
512 if (old_verb && streq(verb, old_verb)) {
513 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
515 if (old_mod_count > 0) {
516 dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
517 for (i = 0; i < old_mod_count; i++) {
518 dis_mod_list[i] = NULL;
522 ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
523 for (i = 0; i < mod_count; i++) {
524 ena_mod_list[i] = NULL;
528 /* update disable modifiers list which are not present in new modifier list */
529 for (i = 0; i < old_mod_count; i++) {
530 int need_disable_mod = 1;
532 for (j = 0; j < mod_count; j++) {
533 if (streq(old_mod_list[i], modifiers[j])) {
534 need_disable_mod = 0;
538 if (need_disable_mod) {
539 if (is_mod_changed == 0)
541 dis_mod_list[dis_mod_count++] = old_mod_list[i];
545 /* update enable modifiers list which are not present in old modifier list */
546 for (i = 0; i < mod_count; i++) {
547 int need_enable_mod = 1;
549 for (j = 0; j < old_mod_count; j++) {
550 if (streq(modifiers[i], old_mod_list[j])) {
555 if (need_enable_mod) {
556 if (is_mod_changed == 0)
558 ena_mod_list[ena_mod_count++] = modifiers[i];
562 /* disable modifiers */
563 for (i = 0; i < dis_mod_count; i++) {
564 AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
565 if (snd_use_case_set(ah->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
566 AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
569 /* enable modifiers */
570 for (i = 0; i < ena_mod_count; i++) {
571 AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
572 if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
573 AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
578 AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
580 if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
581 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
582 audio_ret = AUDIO_ERR_UNDEFINED;
585 /* enable modifiers */
586 for (i = 0; i < mod_count; i++) {
587 AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
588 if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
589 AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
595 free((void *)old_verb);
597 snd_use_case_free_list(old_mod_list, old_mod_count);
599 free((void *)dis_mod_list);
601 free((void *)ena_mod_list);
603 if (is_verb_changed == 1 || is_mod_changed == 1) {
604 const char *new_verb = NULL, **new_mod_list = NULL;
605 int new_mod_count = 0;
607 snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
608 new_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &new_mod_list);
609 __dump_use_case(UCM_PREFIX_CHANGED, new_verb, NULL, 0, new_mod_list, new_mod_count);
612 free((void *)new_verb);
614 snd_use_case_free_list(new_mod_list, new_mod_count);
620 audio_return_t _ucm_get_verb(audio_hal_t *ah, const char **value)
622 audio_return_t ret = AUDIO_RET_OK;
624 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
625 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
626 AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
628 if ((ret = snd_use_case_get(ah->ucm.uc_mgr, "_verb", value)) < 0) {
629 AUDIO_LOG_ERROR("Getting current verb failed: Reason %d", ret);
630 ret = AUDIO_ERR_UNDEFINED;
636 audio_return_t _ucm_reset_use_case(audio_hal_t *ah)
638 audio_return_t ret = AUDIO_RET_OK;
640 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
641 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
643 AUDIO_LOG_INFO(">>> UCM reset Verb [ %s ]", AUDIO_USE_CASE_VERB_INACTIVE);
645 if ((ret = snd_use_case_set(ah->ucm.uc_mgr, "_verb", AUDIO_USE_CASE_VERB_INACTIVE)) < 0) {
646 AUDIO_LOG_ERROR("Reset use case failed: Reason %d", ret);
647 ret = AUDIO_ERR_UNDEFINED;