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.
30 #ifdef ALSA_UCM_DEBUG_TIME
35 #include "tizen-audio-internal.h"
37 #ifdef ALSA_UCM_DEBUG_TIME
38 #define SND_USE_CASE_SET __set_use_case_with_time
40 #define SND_USE_CASE_SET snd_use_case_set
43 #define UCM_PREFIX_CURRENT ">>> UCM current"
44 #define UCM_PREFIX_REQUESTED "> UCM requested"
45 #define UCM_PREFIX_CHANGED "<<< UCM changed"
50 typedef enum _ucm_identifier {
52 UCM_IDENTIFIER_ENABLE_DEVICE,
53 UCM_IDENTIFIER_DISABLE_DEVICE,
54 UCM_IDENTIFIER_ENABLE_MODIFIER,
55 UCM_IDENTIFIER_DISABLE_MODIFIER,
56 UCM_IDENTIFIER_ENABLED_DEVICES,
57 UCM_IDENTIFIER_ENABLED_MODIFIERS
60 typedef struct _ucm_case_set {
61 const char *identifier;
62 const char *description;
65 static const ucm_case_set_s ucm_set[] = {
66 [UCM_IDENTIFIER_VERB] = { "_verb", "Verb"},
67 [UCM_IDENTIFIER_ENABLE_DEVICE] = { "_enadev", "Enable device" },
68 [UCM_IDENTIFIER_DISABLE_DEVICE] = { "_disdev", "Disable device" },
69 [UCM_IDENTIFIER_ENABLE_MODIFIER] = { "_enamod", "Enable modifier" },
70 [UCM_IDENTIFIER_DISABLE_MODIFIER] = { "_dismod", "Disable modifier" },
71 [UCM_IDENTIFIER_ENABLED_DEVICES] = { "_enadevs", "Enabled devices" },
72 [UCM_IDENTIFIER_ENABLED_MODIFIERS] = { "_enamods", "Enabled modifiers" },
75 static void __dump_use_case(const char *prefix, const char *verb,
76 const char *devices[], int dev_count,
77 const char *modifiers[], int mod_count)
80 dump_data_t *dump = NULL;
82 if (!(dump = _audio_dump_new(DUMP_LEN))) {
83 AUDIO_LOG_ERROR("Failed to create dump string...");
88 _audio_dump_add_str(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
91 for (i = 0; devices && i < dev_count; i++)
92 _audio_dump_add_str(dump, (i != dev_count - 1) ? "%s, " : "%s", devices[i]);
94 _audio_dump_add_str(dump, " ] Modifier [ ");
97 for (i = 0; modifiers && i < mod_count; i++)
98 _audio_dump_add_str(dump, (i != mod_count - 1) ? "%s, " : "%s", modifiers[i]);
100 _audio_dump_add_str(dump, " ]");
102 AUDIO_LOG_INFO("TEST %s : %s", prefix, _audio_dump_get_str(dump));
104 _audio_dump_free(dump);
107 #ifdef ALSA_UCM_DEBUG_TIME
108 static inline int __set_use_case_with_time(snd_use_case_mgr_t *uc_mgr, const char *identifier, const char *value)
111 struct timeval t_start, t_stop;
112 unsigned long long t_diff = 0;
114 gettimeofday(&t_start, NULL);
115 ret = snd_use_case_set(uc_mgr, identifier, value);
116 gettimeofday(&t_stop, NULL);
117 if (t_start.tv_sec < t_stop.tv_sec)
118 t_diff = (t_stop.tv_sec - t_start.tv_sec) * 1000000;
119 t_diff += (t_stop.tv_usec - t_start.tv_usec);
120 AUDIO_LOG_DEBUG("identifier %s value %s takes %lluusec", identifier, value, t_diff);
126 audio_return_e _ucm_init(audio_hal_s *ah)
128 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
130 snd_use_case_mgr_open(&ah->ucm.uc_mgr, ALSA_DEFAULT_CARD);
132 if (!ah->ucm.uc_mgr) {
133 AUDIO_LOG_ERROR("uc_mgr open failed");
134 return AUDIO_ERR_RESOURCE;
139 audio_return_e _ucm_deinit(audio_hal_s *ah)
141 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
142 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
144 if (ah->ucm.uc_mgr) {
145 snd_use_case_mgr_close(ah->ucm.uc_mgr);
146 ah->ucm.uc_mgr = NULL;
153 static int __use_case_get_count(const char **list)
157 for (i = 0; list && list[i]; i++) {}
162 static void __use_case_list_set(snd_use_case_mgr_t *uc_mgr, ucm_identifier_e identifier,
163 const char **list, int count)
167 AUDIO_RETURN_IF_FAIL(count <= 0 || list);
169 for (i = 0; i < count; i++) {
170 AUDIO_LOG_INFO("%s : %s", ucm_set[identifier].description, list[i]);
171 if (snd_use_case_set(uc_mgr, ucm_set[identifier].identifier, list[i]) < 0)
172 AUDIO_LOG_ERROR("%s : %s, failed", ucm_set[identifier].description, list[i]);
176 static void __ucm_get_list_to_update(const char **list, int count,
177 const char **old_list, int old_count,
178 const char **new_list, int *new_count,
184 for (i = 0; i < count; i++) {
185 bool need_update = true;
187 for (j = 0; j < old_count; j++) {
188 if (streq(list[i], old_list[j])) {
197 new_list[_new_count++] = list[i];
201 *new_count = _new_count;
205 1) If verb is null or verb is not changed
206 1-1) If device is changed
207 (If there is request for same device, it will be ignored)
208 -> Set "Inactive" verb, disable modifiers & devices, set current verb again, enable devices & modifiers
209 (playback/capture device will be enabled again if there is no request for playback/capture device)
210 1-2) If device is not changed
211 1-2-1) If modifier is changed
212 (If there is request for same modifier, it will be ignored)
213 -> Disable modifiers, enable modifiers
214 2) If verb is changed
215 -> Reset, set new verb, enable devices & modifiers
217 audio_return_e _ucm_set_use_case(audio_hal_s *ah, const char *verb, const char *devices[], const char *modifiers[])
219 audio_return_e audio_ret = AUDIO_RET_OK;
220 bool is_verb_changed = false, is_dev_changed = false, is_mod_changed = false;
221 const char *old_verb = NULL, **old_dev_list = NULL, **old_mod_list = NULL;
222 int old_dev_count = 0, dev_count = 0;
223 int old_mod_count = 0, mod_count = 0;
224 const char **dis_dev_list = NULL, **ena_dev_list = NULL;
225 const char **dis_mod_list = NULL, **ena_mod_list = NULL;
226 int dis_dev_count = 0, ena_dev_count = 0;
227 int dis_mod_count = 0, ena_mod_count = 0;
229 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
230 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
231 AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
233 snd_use_case_get(ah->ucm.uc_mgr,
234 ucm_set[UCM_IDENTIFIER_VERB].identifier,
236 old_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr,
237 ucm_set[UCM_IDENTIFIER_ENABLED_DEVICES].identifier,
239 old_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr,
240 ucm_set[UCM_IDENTIFIER_ENABLED_MODIFIERS].identifier,
242 __dump_use_case(UCM_PREFIX_CURRENT, old_verb, old_dev_list, old_dev_count, old_mod_list, old_mod_count);
244 dev_count = __use_case_get_count(devices);
245 mod_count = __use_case_get_count(modifiers);
246 __dump_use_case(UCM_PREFIX_REQUESTED, verb, devices, dev_count, modifiers, mod_count);
248 is_verb_changed = !old_verb || !streq(verb, old_verb);
249 if (is_verb_changed) {
250 AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
252 if (snd_use_case_set(ah->ucm.uc_mgr, ucm_set[UCM_IDENTIFIER_VERB].identifier, verb) < 0) {
253 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
254 audio_ret = AUDIO_ERR_UNDEFINED;
258 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_ENABLE_DEVICE, devices, dev_count);
259 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_ENABLE_MODIFIER, modifiers, mod_count);
261 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitly");
263 if (old_dev_count > 0) {
264 dis_dev_list = (const char **)calloc(old_dev_count, sizeof(const char *));
265 assert(dis_dev_list);
268 ena_dev_list = (const char **)calloc(dev_count, sizeof(const char *));
269 assert(ena_dev_list);
271 if (old_mod_count > 0) {
272 dis_mod_list = (const char **)calloc(old_mod_count, sizeof(const char *));
273 assert(dis_mod_list);
276 ena_mod_list = (const char **)calloc(mod_count, sizeof(const char *));
277 assert(ena_mod_list);
280 __ucm_get_list_to_update(old_mod_list, old_mod_count, modifiers, mod_count,
281 dis_mod_list, &dis_mod_count, &is_mod_changed);
282 __ucm_get_list_to_update(old_dev_list, old_dev_count, devices, dev_count,
283 dis_dev_list, &dis_dev_count, &is_dev_changed);
284 __ucm_get_list_to_update(devices, dev_count, old_dev_list, old_dev_count,
285 ena_dev_list, &ena_dev_count, &is_dev_changed);
286 __ucm_get_list_to_update(modifiers, mod_count, old_mod_list, old_mod_count,
287 ena_mod_list, &ena_mod_count, &is_mod_changed);
289 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_DISABLE_MODIFIER, dis_mod_list, dis_mod_count);
290 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_DISABLE_DEVICE, dis_dev_list, dis_dev_count);
291 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_ENABLE_DEVICE, ena_dev_list, ena_dev_count);
292 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_ENABLE_MODIFIER, ena_mod_list, ena_mod_count);
297 free((void *)old_verb);
299 snd_use_case_free_list(old_dev_list, old_dev_count);
301 snd_use_case_free_list(old_mod_list, old_mod_count);
303 free((void *)dis_dev_list);
305 free((void *)ena_dev_list);
307 free((void *)dis_mod_list);
309 free((void *)ena_mod_list);
311 if (is_verb_changed || is_dev_changed || is_mod_changed ) {
313 const char *new_verb = NULL, **new_dev_list = NULL, **new_mod_list = NULL;
314 int new_dev_count = 0, new_mod_count = 0;
316 snd_use_case_get(ah->ucm.uc_mgr,
317 ucm_set[UCM_IDENTIFIER_VERB].identifier,
319 new_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr,
320 ucm_set[UCM_IDENTIFIER_ENABLED_DEVICES].identifier,
322 new_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr,
323 ucm_set[UCM_IDENTIFIER_ENABLED_MODIFIERS].identifier,
325 __dump_use_case(UCM_PREFIX_CHANGED, new_verb, new_dev_list, new_dev_count, new_mod_list, new_mod_count);
328 free((void *)new_verb);
330 snd_use_case_free_list(new_dev_list, new_dev_count);
332 snd_use_case_free_list(new_mod_list, new_mod_count);
338 audio_return_e _ucm_set_devices(audio_hal_s *ah, const char *verb, const char *devices[])
340 audio_return_e audio_ret = AUDIO_RET_OK;
341 bool is_verb_changed = false, is_dev_changed = false;
342 const char *old_verb = NULL, **old_dev_list = NULL;
343 int old_dev_count = 0, dev_count = 0;
344 const char **dis_dev_list = NULL, **ena_dev_list = NULL;
345 int dis_dev_count = 0, ena_dev_count = 0;
347 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
348 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
349 AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
350 AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
352 snd_use_case_get(ah->ucm.uc_mgr,
353 ucm_set[UCM_IDENTIFIER_VERB].identifier,
355 old_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr,
356 ucm_set[UCM_IDENTIFIER_ENABLED_DEVICES].identifier,
358 __dump_use_case(UCM_PREFIX_CURRENT, old_verb, old_dev_list, old_dev_count, NULL, 0);
360 dev_count = __use_case_get_count(devices);
361 __dump_use_case(UCM_PREFIX_REQUESTED, verb, devices, dev_count, NULL, 0);
363 is_verb_changed = !old_verb || !streq(verb, old_verb);
364 if (is_verb_changed) {
365 AUDIO_LOG_INFO("Setting new verb: %s", verb);
367 if (snd_use_case_set(ah->ucm.uc_mgr, ucm_set[UCM_IDENTIFIER_VERB].identifier, verb) < 0) {
368 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
369 audio_ret = AUDIO_ERR_UNDEFINED;
373 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_ENABLE_DEVICE, devices, dev_count);
375 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitly");
377 if (old_dev_count > 0) {
378 dis_dev_list = (const char **)calloc(old_dev_count, sizeof(const char *));
379 assert(dis_dev_list);
382 ena_dev_list = (const char **)calloc(dev_count, sizeof(const char *));
383 assert(ena_dev_list);
386 __ucm_get_list_to_update(old_dev_list, old_dev_count, devices, dev_count,
387 dis_dev_list, &dis_dev_count, &is_dev_changed);
388 __ucm_get_list_to_update(devices, dev_count, old_dev_list, old_dev_count,
389 ena_dev_list, &ena_dev_count, &is_dev_changed);
391 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_DISABLE_DEVICE, dis_dev_list, dis_dev_count);
392 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_ENABLE_DEVICE, ena_dev_list, ena_dev_count);
397 free((void *)old_verb);
399 snd_use_case_free_list(old_dev_list, old_dev_count);
401 free((void *)dis_dev_list);
403 free((void *)ena_dev_list);
405 if (is_verb_changed || is_dev_changed) {
406 const char *new_verb = NULL, **new_dev_list = NULL;
407 int new_dev_count = 0;
409 snd_use_case_get(ah->ucm.uc_mgr, ucm_set[UCM_IDENTIFIER_VERB].identifier, &new_verb);
410 new_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr,
411 ucm_set[UCM_IDENTIFIER_ENABLED_DEVICES].identifier,
413 __dump_use_case(UCM_PREFIX_CHANGED, new_verb, new_dev_list, new_dev_count, NULL, 0);
416 free((void *)new_verb);
418 snd_use_case_free_list(new_dev_list, new_dev_count);
424 audio_return_e _ucm_set_modifiers(audio_hal_s *ah, const char *verb, const char *modifiers[])
426 audio_return_e audio_ret = AUDIO_RET_OK;
427 bool is_verb_changed = false, is_mod_changed = false;
428 const char *old_verb = NULL, **old_mod_list = NULL;
429 int old_mod_count = 0, mod_count = 0;
430 const char **dis_mod_list = NULL, **ena_mod_list = NULL;
431 int dis_mod_count = 0, ena_mod_count = 0;
433 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
434 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
435 AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
436 AUDIO_RETURN_VAL_IF_FAIL(modifiers, AUDIO_ERR_PARAMETER);
438 snd_use_case_get(ah->ucm.uc_mgr,
439 ucm_set[UCM_IDENTIFIER_VERB].identifier,
441 old_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr,
442 ucm_set[UCM_IDENTIFIER_ENABLED_MODIFIERS].identifier,
444 __dump_use_case(UCM_PREFIX_CURRENT, old_verb, NULL, 0, old_mod_list, old_mod_count);
446 mod_count = __use_case_get_count(modifiers);
447 __dump_use_case(UCM_PREFIX_REQUESTED, verb, NULL, 0, modifiers, mod_count);
449 is_verb_changed = !old_verb || !streq(verb, old_verb);
450 if (is_verb_changed) {
451 AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
453 if (snd_use_case_set(ah->ucm.uc_mgr, ucm_set[UCM_IDENTIFIER_VERB].identifier, verb) < 0) {
454 AUDIO_LOG_ERROR("Setting verb %s failed", verb);
455 audio_ret = AUDIO_ERR_UNDEFINED;
458 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_ENABLE_MODIFIER, modifiers, mod_count);
460 AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitly");
462 if (old_mod_count > 0) {
463 dis_mod_list = (const char **)calloc(old_mod_count, sizeof(const char *));
464 assert(dis_mod_list);
467 ena_mod_list = (const char **)calloc(mod_count, sizeof(const char *));
468 assert(ena_mod_list);
471 __ucm_get_list_to_update(old_mod_list, old_mod_count, modifiers, mod_count,
472 dis_mod_list, &dis_mod_count, &is_mod_changed);
473 __ucm_get_list_to_update(modifiers, mod_count, old_mod_list, old_mod_count,
474 ena_mod_list, &ena_mod_count, &is_mod_changed);
476 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_DISABLE_MODIFIER, dis_mod_list, dis_mod_count);
477 __use_case_list_set(ah->ucm.uc_mgr, UCM_IDENTIFIER_ENABLE_MODIFIER, ena_mod_list, ena_mod_count);
482 free((void *)old_verb);
484 snd_use_case_free_list(old_mod_list, old_mod_count);
486 free((void *)dis_mod_list);
488 free((void *)ena_mod_list);
490 if (is_verb_changed || is_mod_changed) {
491 const char *new_verb = NULL, **new_mod_list = NULL;
492 int new_mod_count = 0;
494 snd_use_case_get(ah->ucm.uc_mgr,
495 ucm_set[UCM_IDENTIFIER_VERB].identifier,
497 new_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr,
498 ucm_set[UCM_IDENTIFIER_ENABLED_MODIFIERS].identifier,
500 __dump_use_case(UCM_PREFIX_CHANGED, new_verb, NULL, 0, new_mod_list, new_mod_count);
503 free((void *)new_verb);
505 snd_use_case_free_list(new_mod_list, new_mod_count);
511 audio_return_e _ucm_get_verb(audio_hal_s *ah, const char **value)
513 audio_return_e ret = AUDIO_RET_OK;
515 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
516 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
517 AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
519 if ((ret = snd_use_case_get(ah->ucm.uc_mgr,
520 ucm_set[UCM_IDENTIFIER_VERB].identifier,
522 AUDIO_LOG_ERROR("Getting current verb failed: Reason %d", ret);
523 ret = AUDIO_ERR_UNDEFINED;
529 audio_return_e _ucm_reset_use_case(audio_hal_s *ah)
531 audio_return_e ret = AUDIO_RET_OK;
533 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
534 AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
536 AUDIO_LOG_INFO(">>> UCM reset Verb [ %s ]", AUDIO_USE_CASE_VERB_INACTIVE);
538 if ((ret = snd_use_case_set(ah->ucm.uc_mgr,
539 ucm_set[UCM_IDENTIFIER_VERB].identifier,
540 AUDIO_USE_CASE_VERB_INACTIVE)) < 0) {
541 AUDIO_LOG_ERROR("Reset use case failed: Reason %d", ret);
542 ret = AUDIO_ERR_UNDEFINED;