Correct VOICE_PCM_DEVICE to "hw:sprdphone,1" and remove an unused device AUDIO_DEVICE...
[platform/adaptation/spreadtrum/audio-hal-sc7727.git] / tizen-audio-ucm.c
1 /*
2  * audio-hal
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef ALSA_UCM_DEBUG_TIME
28 #include <sys/time.h>
29 #include <time.h>
30 #endif
31
32 #include "tizen-audio-internal.h"
33
34 #ifdef ALSA_UCM_DEBUG_TIME
35 #define SND_USE_CASE_SET __set_use_case_with_time
36 #else
37 #define SND_USE_CASE_SET snd_use_case_set
38 #endif
39
40 audio_return_t _audio_ucm_init(audio_hal_t *ah)
41 {
42     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
43
44     snd_use_case_mgr_open(&ah->ucm.uc_mgr, ALSA_DEFAULT_CARD);
45
46     if (!ah->ucm.uc_mgr) {
47         AUDIO_LOG_ERROR("uc_mgr open failed");
48         return AUDIO_ERR_RESOURCE;
49     }
50     return AUDIO_RET_OK;
51 }
52
53 audio_return_t _audio_ucm_deinit(audio_hal_t *ah)
54 {
55     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
56     AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
57
58     snd_use_case_mgr_close(ah->ucm.uc_mgr);
59     ah->ucm.uc_mgr = NULL;
60
61     return AUDIO_RET_OK;
62 }
63
64 void _audio_ucm_get_device_name(audio_hal_t *ah, const char *use_case, audio_direction_t direction, const char **value)
65 {
66     char identifier[70] = {0};
67
68     AUDIO_RETURN_IF_FAIL(ah);
69     AUDIO_RETURN_IF_FAIL(ah->ucm.uc_mgr);
70
71     if (direction == AUDIO_DIRECTION_IN) {
72         sprintf(identifier, "CapturePCM//%s", use_case);
73     } else {
74         sprintf(identifier, "PlaybackPCM//%s", use_case);
75     }
76     snd_use_case_get(ah->ucm.uc_mgr, identifier, value);
77 }
78
79 static inline void __add_ucm_device_info(audio_hal_t *ah, const char *use_case, audio_direction_t direction, audio_device_info_t *device_info_list, int *device_info_count)
80 {
81     audio_device_info_t *device_info;
82     const char *device_name = NULL;
83     char *needle = NULL;
84
85     AUDIO_RETURN_IF_FAIL(ah);
86     AUDIO_RETURN_IF_FAIL(ah->ucm.uc_mgr);
87     AUDIO_RETURN_IF_FAIL(device_info_list);
88     AUDIO_RETURN_IF_FAIL(device_info_count);
89
90     _audio_ucm_get_device_name(ah, use_case, direction, &device_name);
91     if (device_name) {
92         device_info = &device_info_list[(*device_info_count)++];
93
94         memset(device_info, 0x00, sizeof(audio_device_info_t));
95         device_info->api = AUDIO_DEVICE_API_ALSA;
96         device_info->direction = direction;
97         needle = strstr(&device_name[3], ",");
98         if (needle) {
99             device_info->alsa.device_idx = *(needle+1) - '0';
100             device_info->alsa.card_name = strndup(&device_name[3], needle - (device_name+3));
101             device_info->alsa.card_idx = snd_card_get_index(device_info->alsa.card_name);
102             AUDIO_LOG_DEBUG("Card name: %s", device_info->alsa.card_name);
103         }
104
105         free((void *)device_name);
106     }
107 }
108
109 int _audio_ucm_fill_device_info_list(audio_hal_t *ah, audio_device_info_t *device_info_list, const char *verb)
110 {
111     int device_info_count = 0;
112     const char *curr_verb = NULL;
113
114     AUDIO_RETURN_VAL_IF_FAIL(ah, device_info_count);
115     AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, device_info_count);
116     AUDIO_RETURN_VAL_IF_FAIL(device_info_list, device_info_count);
117
118     if (!verb) {
119         snd_use_case_get(ah->ucm.uc_mgr, "_verb", &curr_verb);
120         verb = curr_verb;
121     }
122
123     /* prepare destination */
124     /*If the devices are VOICECALL LOOPBACK or FMRADIO then pulseaudio need not get the device notification*/
125     if (verb) {
126         if (strncmp(verb, AUDIO_USE_CASE_VERB_VOICECALL, strlen(AUDIO_USE_CASE_VERB_VOICECALL)) &&
127             strncmp(verb, AUDIO_USE_CASE_VERB_LOOPBACK, strlen(AUDIO_USE_CASE_VERB_LOOPBACK))) {
128             __add_ucm_device_info(ah, verb, AUDIO_DIRECTION_IN, device_info_list, &device_info_count);
129             if(strncmp(verb, AUDIO_USE_CASE_VERB_FMRADIO, strlen(AUDIO_USE_CASE_VERB_FMRADIO))) {
130                 __add_ucm_device_info(ah, verb, AUDIO_DIRECTION_OUT, device_info_list, &device_info_count);
131             }
132         }
133
134         if (curr_verb)
135             free((void *)curr_verb);
136
137     }
138
139     return device_info_count;
140 }
141
142 static void __dump_use_case(const char *verb, const char *devices[], int dev_count, const char *modifiers[], int mod_count, char *dump)
143 {
144     int i, len;
145
146     len = sprintf(dump, "Verb [ %s ] Devices [ ", verb ? verb : AUDIO_USE_CASE_VERB_INACTIVE);
147     if (len > 0)
148         dump += len;
149
150     for (i = 0; i < dev_count; i++) {
151         if (i != dev_count - 1) {
152             len = sprintf(dump, "%s, ", devices[i]);
153         } else {
154             len = sprintf(dump, "%s", devices[i]);
155         }
156         if (len > 0)
157             dump += len;
158     }
159
160     len = sprintf(dump, " ] Modifier [ ");
161     if (len > 0)
162         dump += len;
163
164     for (i = 0; i < mod_count; i++) {
165         if (i != mod_count - 1) {
166             len = sprintf(dump, "%s, ", modifiers[i]);
167         } else {
168             len = sprintf(dump, "%s", modifiers[i]);
169         }
170         if (len > 0)
171             dump += len;
172     }
173
174     len = sprintf(dump, " ]");
175     if (len > 0)
176         dump += len;
177
178     *dump = '\0';
179 }
180
181 #ifdef ALSA_UCM_DEBUG_TIME
182 static inline int __set_use_case_with_time(snd_use_case_mgr_t *uc_mgr, const char *identifier, const char *value)
183 {
184     int ret = 0;
185     struct timeval t_start, t_stop;
186     unsigned long long t_diff = 0;
187
188     gettimeofday(&t_start, NULL);
189     ret = snd_use_case_set(uc_mgr, identifier, value);
190     gettimeofday(&t_stop, NULL);
191     if (t_start.tv_sec < t_stop.tv_sec)
192         t_diff = (t_stop.tv_sec - t_start.tv_sec) * 1000000;
193     t_diff += (t_stop.tv_usec - t_start.tv_usec);
194     AUDIO_LOG_DEBUG("identifier %s value %s takes %lluusec", identifier, value, t_diff);
195
196     return ret;
197 }
198 #endif
199
200 /* UCM sequence
201     1) If verb is null or verb is not changed
202     1-1) If device is changed
203          (If there is request for same device, it will be ignored)
204          -> Set "Inactive" verb, disable modifiers & devices, set current verb again, enable devices & modifiers
205             (playback/capture device will be enabled again if there is no request for playback/capture device)
206     1-2) If device is not changed
207      1-2-1) If modifier is changed
208             (If there is request for same modifier, it will be ignored)
209             -> Disable modifiers, enable modifiers
210    2) If verb is changed
211       -> Reset, set new verb, enable devices & modifiers
212  */
213 audio_return_t _audio_ucm_set_use_case(audio_hal_t *ah, const char *verb, const char *devices[], const char *modifiers[])
214 {
215     audio_return_t audio_ret = AUDIO_RET_OK;
216     int is_verb_changed = 0, is_dev_changed = 0, is_mod_changed = 0;
217     const char *old_verb = NULL, **old_dev_list = NULL, **old_mod_list = NULL;
218     int old_dev_count = 0, dev_count = 0;
219     int old_mod_count = 0, mod_count = 0;
220     const char **dis_dev_list = NULL, **ena_dev_list = NULL;
221     const char **dis_mod_list = NULL, **ena_mod_list = NULL;
222     int dis_dev_count = 0, ena_dev_count = 0;
223     int dis_mod_count = 0, ena_mod_count = 0;
224     int i = 0, j = 0;
225     char dump_str[512];
226
227     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
228     AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
229     AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
230
231     snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
232     old_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &old_dev_list);
233     old_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &old_mod_list);
234     __dump_use_case(old_verb, old_dev_list, old_dev_count, old_mod_list, old_mod_count, &dump_str[0]);
235     AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
236
237     if (devices) {
238         for (dev_count = 0; devices[dev_count]; dev_count++);
239     }
240     if (modifiers) {
241         for (mod_count = 0; modifiers[mod_count]; mod_count++);
242     }
243
244     __dump_use_case(verb, devices, dev_count, modifiers, mod_count, &dump_str[0]);
245     AUDIO_LOG_INFO("> UCM requested %s", dump_str);
246
247     if (old_verb && streq(verb, old_verb)) {
248         AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
249
250         if (old_dev_count > 0) {
251             dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
252             for (i = 0; i < old_dev_count; i++) {
253                 dis_dev_list[i] = NULL;
254             }
255         }
256         if (dev_count > 0) {
257             ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
258             for (i = 0; i < dev_count; i++) {
259                 ena_dev_list[i] = NULL;
260             }
261         }
262         if (old_mod_count > 0) {
263             dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
264             for (i = 0; i < old_mod_count; i++) {
265                 dis_mod_list[i] = NULL;
266             }
267         }
268         if (mod_count > 0) {
269             ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
270             for (i = 0; i < mod_count; i++) {
271                 ena_mod_list[i] = NULL;
272             }
273         }
274
275         /* update disable modifiers list which are not present in new modifier list */
276         for (i = 0; i < old_mod_count; i++) {
277             int need_disable_mod = 1;
278
279             for (j = 0; j < mod_count; j++) {
280                 if (streq(old_mod_list[i], modifiers[j])) {
281                     need_disable_mod = 0;
282                     break;
283                 }
284             }
285             if (need_disable_mod) {
286                 if (is_mod_changed == 0)
287                     is_mod_changed = 1;
288                 dis_mod_list[dis_mod_count++] = old_mod_list[i];
289             }
290         }
291
292         /* update disable devices list which are not present in new device list */
293         for (i = 0; i < old_dev_count; i++) {
294             int need_disable_dev = 1;
295
296             for (j = 0; j < dev_count; j++) {
297                 if (streq(old_dev_list[i], devices[j])) {
298                     need_disable_dev = 0;
299                     break;
300                 }
301             }
302             if (need_disable_dev) {
303                 if (is_dev_changed == 0)
304                     is_dev_changed = 1;
305                 dis_dev_list[dis_dev_count++] = old_dev_list[i];
306             }
307         }
308
309         /* update enable devices list which are not present in old device list */
310         for (i = 0; i < dev_count; i++) {
311             int need_enable_dev = 1;
312
313             for (j = 0; j < old_dev_count; j++) {
314                 if (streq(devices[i], old_dev_list[j])) {
315                     need_enable_dev = 0;
316                     break;
317                 }
318             }
319             if (need_enable_dev) {
320                 if (is_dev_changed == 0)
321                     is_dev_changed = 1;
322                 ena_dev_list[ena_dev_count++] = devices[i];
323             }
324         }
325
326         /* update enable modifiers list which are not present in old modifier list */
327         for (i = 0; i < mod_count; i++) {
328             int need_enable_mod = 1;
329
330             for (j = 0; j < old_mod_count; j++) {
331                 if (streq(modifiers[i], old_mod_list[j])) {
332                     need_enable_mod = 0;
333                     break;
334                 }
335             }
336             if (need_enable_mod) {
337                 if (is_mod_changed == 0)
338                     is_mod_changed = 1;
339                 ena_mod_list[ena_mod_count++] = modifiers[i];
340             }
341         }
342
343         /* disable modifiers */
344         for (i = 0; i < dis_mod_count; i++) {
345             AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
346             if (snd_use_case_set(ah->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
347                 AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
348         }
349
350         /* disable devices */
351         for (i = 0; i < dis_dev_count; i++) {
352             AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
353             if (snd_use_case_set(ah->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
354                 AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
355         }
356
357         /* enable devices */
358         for (i = 0; i < ena_dev_count; i++) {
359             AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
360             if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
361                 AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
362         }
363
364         /* enable modifiers */
365         for (i = 0; i < ena_mod_count; i++) {
366             AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
367             if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
368                 AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
369         }
370     } else {
371         is_verb_changed = 1;
372
373         AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
374         /* set new verb */
375         if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
376             AUDIO_LOG_ERROR("Setting verb %s failed", verb);
377             audio_ret = AUDIO_ERR_UNDEFINED;
378             goto exit;
379         }
380         /* enable devices */
381         for (i = 0; i < dev_count; i++) {
382             AUDIO_LOG_DEBUG("Enable device : %s", devices[i]);
383             if(snd_use_case_set(ah->ucm.uc_mgr, "_enadev", devices[i]) < 0)
384                 AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
385         }
386         /* enable modifiers */
387         for (i = 0; i < mod_count; i++) {
388             AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
389             if(snd_use_case_set(ah->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
390                 AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
391         }
392     }
393
394 exit:
395     if (old_verb)
396         free((void *)old_verb);
397     if (old_dev_list)
398         snd_use_case_free_list(old_dev_list, old_dev_count);
399     if (old_mod_list)
400         snd_use_case_free_list(old_mod_list, old_mod_count);
401     if (dis_dev_list)
402         free((void *)dis_dev_list);
403     if (ena_dev_list)
404         free((void *)ena_dev_list);
405     if (dis_mod_list)
406         free((void *)dis_mod_list);
407     if (ena_mod_list)
408         free((void *)ena_mod_list);
409
410     if (is_verb_changed == 1 || is_dev_changed == 1 || is_mod_changed == 1) {
411         const char *new_verb = NULL, **new_dev_list = NULL, **new_mod_list = NULL;
412         int new_dev_count = 0, new_mod_count = 0;
413
414         snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
415         new_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &new_dev_list);
416         new_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &new_mod_list);
417         __dump_use_case(new_verb, new_dev_list, new_dev_count, new_mod_list, new_mod_count, &dump_str[0]);
418         AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
419
420         if (new_verb)
421             free((void *)new_verb);
422         if (new_dev_list)
423             snd_use_case_free_list(new_dev_list, new_dev_count);
424         if (new_mod_list)
425             snd_use_case_free_list(new_mod_list, new_mod_count);
426     }
427
428     return audio_ret;
429 }
430
431 audio_return_t _audio_ucm_set_devices(audio_hal_t *ah, const char *verb, const char *devices[])
432 {
433     audio_return_t audio_ret = AUDIO_RET_OK;
434     int is_verb_changed = 0, is_dev_changed = 0;
435     const char *old_verb = NULL, **old_dev_list = NULL;
436     int old_dev_count = 0, dev_count = 0;
437     const char **dis_dev_list = NULL, **ena_dev_list = NULL;
438     int dis_dev_count = 0, ena_dev_count = 0;
439     int i = 0, j = 0;
440     char dump_str[512];
441
442     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
443     AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
444     AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
445     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
446
447     snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
448     old_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &old_dev_list);
449     __dump_use_case(old_verb, old_dev_list, old_dev_count, NULL, 0, &dump_str[0]);
450     AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
451
452     if (devices) {
453         for (dev_count = 0; devices[dev_count]; dev_count++);
454     }
455
456     __dump_use_case(verb, devices, dev_count, NULL, 0, &dump_str[0]);
457     AUDIO_LOG_INFO("> UCM requested %s", dump_str);
458
459     if (old_verb && streq(verb, old_verb)) {
460         AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
461
462         if (old_dev_count > 0) {
463             dis_dev_list = (const char **)malloc(sizeof(const char *) * old_dev_count);
464             for (i = 0; i < old_dev_count; i++) {
465                 dis_dev_list[i] = NULL;
466             }
467         }
468         if (dev_count > 0) {
469             ena_dev_list = (const char **)malloc(sizeof(const char *) * dev_count);
470             for (i = 0; i < dev_count; i++) {
471                 ena_dev_list[i] = NULL;
472             }
473         }
474
475         /* update disable devices list which are not present in new device list */
476         for (i = 0; i < old_dev_count; i++) {
477             int need_disable_dev = 1;
478
479             for (j = 0; j < dev_count; j++) {
480                 if (streq(old_dev_list[i], devices[j])) {
481                     need_disable_dev = 0;
482                     break;
483                 }
484             }
485             if (need_disable_dev) {
486                 if (is_dev_changed == 0)
487                     is_dev_changed = 1;
488                 dis_dev_list[dis_dev_count++] = old_dev_list[i];
489             }
490         }
491
492         /* update enable devices list which are not present in old device list */
493         for (i = 0; i < dev_count; i++) {
494             int need_enable_dev = 1;
495
496             for (j = 0; j < old_dev_count; j++) {
497                 if (streq(devices[i], old_dev_list[j])) {
498                     need_enable_dev = 0;
499                     break;
500                 }
501             }
502             if (need_enable_dev) {
503                 if (is_dev_changed == 0)
504                     is_dev_changed = 1;
505                 ena_dev_list[ena_dev_count++] = devices[i];
506             }
507         }
508
509         /* disable devices */
510         for (i = 0; i < dis_dev_count; i++) {
511             AUDIO_LOG_INFO("Disable device : %s", dis_dev_list[i]);
512             if (snd_use_case_set(ah->ucm.uc_mgr, "_disdev", dis_dev_list[i]) < 0)
513                 AUDIO_LOG_ERROR("disable %s device failed", dis_dev_list[i]);
514         }
515
516         /* enable devices */
517         for (i = 0; i < ena_dev_count; i++) {
518             AUDIO_LOG_INFO("Enable device : %s", ena_dev_list[i]);
519             if (snd_use_case_set(ah->ucm.uc_mgr, "_enadev", ena_dev_list[i]) < 0)
520                 AUDIO_LOG_ERROR("enable %s device failed", ena_dev_list[i]);
521         }
522
523     } else {
524         is_verb_changed = 1;
525
526         AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
527         /* set new verb */
528         if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
529             AUDIO_LOG_ERROR("Setting verb %s failed", verb);
530             audio_ret = AUDIO_ERR_UNDEFINED;
531             goto exit;
532         }
533         /* enable devices */
534         for (i = 0; i < dev_count; i++) {
535             AUDIO_LOG_DEBUG("Enable device : %s", devices[i]);
536             if(snd_use_case_set(ah->ucm.uc_mgr, "_enadev", devices[i]) < 0)
537                 AUDIO_LOG_ERROR("Enable %s device failed", devices[i]);
538         }
539     }
540
541 exit:
542     if (old_verb)
543         free((void *)old_verb);
544     if (old_dev_list)
545         snd_use_case_free_list(old_dev_list, old_dev_count);
546     if (dis_dev_list)
547         free((void *)dis_dev_list);
548     if (ena_dev_list)
549         free((void *)ena_dev_list);
550
551     if (is_verb_changed == 1 || is_dev_changed == 1) {
552         const char *new_verb = NULL, **new_dev_list = NULL;
553         int new_dev_count = 0;
554
555         snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
556         new_dev_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enadevs", &new_dev_list);
557         __dump_use_case(new_verb, new_dev_list, new_dev_count, NULL, 0, &dump_str[0]);
558         AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
559
560         if (new_verb)
561             free((void *)new_verb);
562         if (new_dev_list)
563             snd_use_case_free_list(new_dev_list, new_dev_count);
564     }
565
566     return audio_ret;
567
568 }
569
570 audio_return_t _audio_ucm_set_modifiers(audio_hal_t *ah, const char *verb, const char *modifiers[])
571 {
572     audio_return_t audio_ret = AUDIO_RET_OK;
573     int is_verb_changed = 0, is_mod_changed = 0;
574     const char *old_verb = NULL, **old_mod_list = NULL;
575     int old_mod_count = 0, mod_count = 0;
576     const char **dis_mod_list = NULL, **ena_mod_list = NULL;
577     int dis_mod_count = 0, ena_mod_count = 0;
578     int i = 0, j = 0;
579     char dump_str[512];
580
581     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
582     AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
583     AUDIO_RETURN_VAL_IF_FAIL(verb, AUDIO_ERR_PARAMETER);
584     AUDIO_RETURN_VAL_IF_FAIL(modifiers, AUDIO_ERR_PARAMETER);
585
586     snd_use_case_get(ah->ucm.uc_mgr, "_verb", &old_verb);
587     old_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &old_mod_list);
588     __dump_use_case(old_verb, NULL, 0, old_mod_list, old_mod_count, &dump_str[0]);
589     AUDIO_LOG_INFO(">>> UCM current %s", dump_str);
590
591     if (modifiers) {
592         for (mod_count = 0; modifiers[mod_count]; mod_count++);
593     }
594
595     __dump_use_case(verb, NULL, 0, modifiers, mod_count, &dump_str[0]);
596     AUDIO_LOG_INFO("> UCM requested %s", dump_str);
597
598     if (old_verb && streq(verb, old_verb)) {
599         AUDIO_LOG_DEBUG("current verb and new verb is same. No need to change verb, disable devices explicitely");
600
601         if (old_mod_count > 0) {
602             dis_mod_list = (const char **)malloc(sizeof(const char *) * old_mod_count);
603             for (i = 0; i < old_mod_count; i++) {
604                 dis_mod_list[i] = NULL;
605             }
606         }
607         if (mod_count > 0) {
608             ena_mod_list = (const char **)malloc(sizeof(const char *) * mod_count);
609             for (i = 0; i < mod_count; i++) {
610                 ena_mod_list[i] = NULL;
611             }
612         }
613
614         /* update disable modifiers list which are not present in new modifier list */
615         for (i = 0; i < old_mod_count; i++) {
616             int need_disable_mod = 1;
617
618             for (j = 0; j < mod_count; j++) {
619                 if (streq(old_mod_list[i], modifiers[j])) {
620                     need_disable_mod = 0;
621                     break;
622                 }
623             }
624             if (need_disable_mod) {
625                 if (is_mod_changed == 0)
626                     is_mod_changed = 1;
627                 dis_mod_list[dis_mod_count++] = old_mod_list[i];
628             }
629         }
630
631         /* update enable modifiers list which are not present in old modifier list */
632         for (i = 0; i < mod_count; i++) {
633             int need_enable_mod = 1;
634
635             for (j = 0; j < old_mod_count; j++) {
636                 if (streq(modifiers[i], old_mod_list[j])) {
637                     need_enable_mod = 0;
638                     break;
639                 }
640             }
641             if (need_enable_mod) {
642                 if (is_mod_changed == 0)
643                     is_mod_changed = 1;
644                 ena_mod_list[ena_mod_count++] = modifiers[i];
645             }
646         }
647
648         /* disable modifiers */
649         for (i = 0; i < dis_mod_count; i++) {
650             AUDIO_LOG_INFO("Disable modifier : %s", dis_mod_list[i]);
651             if (snd_use_case_set(ah->ucm.uc_mgr, "_dismod", dis_mod_list[i]) < 0)
652                 AUDIO_LOG_ERROR("disable %s modifier failed", dis_mod_list[i]);
653         }
654
655         /* enable modifiers */
656         for (i = 0; i < ena_mod_count; i++) {
657             AUDIO_LOG_INFO("Enable modifier : %s", ena_mod_list[i]);
658             if (snd_use_case_set(ah->ucm.uc_mgr, "_enamod", ena_mod_list[i]) < 0)
659                 AUDIO_LOG_ERROR("enable %s modifier failed", ena_mod_list[i]);
660         }
661     } else {
662         is_verb_changed = 1;
663
664         AUDIO_LOG_DEBUG("Setting new verb: %s", verb);
665         /* set new verb */
666         if (snd_use_case_set(ah->ucm.uc_mgr, "_verb", verb) < 0) {
667             AUDIO_LOG_ERROR("Setting verb %s failed", verb);
668             audio_ret = AUDIO_ERR_UNDEFINED;
669             goto exit;
670         }
671         /* enable modifiers */
672         for (i = 0; i < mod_count; i++) {
673             AUDIO_LOG_DEBUG("Enable modifier : %s", modifiers[i]);
674             if(snd_use_case_set(ah->ucm.uc_mgr, "_enamod", modifiers[i]) < 0)
675                 AUDIO_LOG_ERROR("Enable %s modifier failed", modifiers[i]);
676         }
677     }
678
679 exit:
680     if (old_verb)
681         free((void *)old_verb);
682     if (old_mod_list)
683         snd_use_case_free_list(old_mod_list, old_mod_count);
684     if (dis_mod_list)
685         free((void *)dis_mod_list);
686     if (ena_mod_list)
687         free((void *)ena_mod_list);
688
689     if (is_verb_changed == 1 || is_mod_changed == 1) {
690         const char *new_verb = NULL, **new_mod_list = NULL;
691         int new_mod_count = 0;
692
693         snd_use_case_get(ah->ucm.uc_mgr, "_verb", &new_verb);
694         new_mod_count = snd_use_case_get_list(ah->ucm.uc_mgr, "_enamods", &new_mod_list);
695         __dump_use_case(new_verb, NULL, 0, new_mod_list, new_mod_count, &dump_str[0]);
696         AUDIO_LOG_INFO("<<< UCM changed %s", dump_str);
697
698         if (new_verb)
699             free((void *)new_verb);
700         if (new_mod_list)
701             snd_use_case_free_list(new_mod_list, new_mod_count);
702     }
703
704     return audio_ret;
705 }
706
707 audio_return_t _audio_ucm_get_verb(audio_hal_t *ah, const char **value)
708 {
709     audio_return_t ret = AUDIO_RET_OK;
710
711     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
712     AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
713     AUDIO_RETURN_VAL_IF_FAIL(value, AUDIO_ERR_PARAMETER);
714
715     if ((ret = snd_use_case_get(ah->ucm.uc_mgr, "_verb", value)) < 0) {
716         AUDIO_LOG_ERROR("Getting current verb failed: Reason %d", ret);
717         ret = AUDIO_ERR_UNDEFINED;
718     }
719
720     return ret;
721 }
722
723
724 audio_return_t _audio_ucm_reset_use_case(audio_hal_t *ah)
725 {
726     audio_return_t ret = AUDIO_RET_OK;
727
728     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
729     AUDIO_RETURN_VAL_IF_FAIL(ah->ucm.uc_mgr, AUDIO_ERR_PARAMETER);
730
731     AUDIO_LOG_INFO(">>> UCM reset Verb [ %s ]", AUDIO_USE_CASE_VERB_INACTIVE);
732
733     if ((ret = snd_use_case_set(ah->ucm.uc_mgr, "_verb", AUDIO_USE_CASE_VERB_INACTIVE)) < 0) {
734         AUDIO_LOG_ERROR("Reset use case failed: Reason %d", ret);
735         ret = AUDIO_ERR_UNDEFINED;
736     }
737
738     return ret;
739 }
740