1 /*
2 * Copyright (C) 2013 The Android Open Source Project
3 * Inspired by TinyHW, written by Mark Brown at Wolfson Micro
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #define LOG_TAG "audio_route"
19 /*#define LOG_NDEBUG 0*/
20
21 #include <errno.h>
22 #include <expat.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <log/log.h>
28
29 #include <tinyalsa/asoundlib.h>
30
31 #define BUF_SIZE 1024
32 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
33 #define INITIAL_MIXER_PATH_SIZE 8
34
35 union ctl_values {
36 int *enumerated;
37 long *integer;
38 void *ptr;
39 unsigned char *bytes;
40 };
41
42 struct mixer_state {
43 struct mixer_ctl *ctl;
44 unsigned int num_values;
45 union ctl_values old_value;
46 union ctl_values new_value;
47 union ctl_values reset_value;
48 unsigned int active_count;
49 };
50
51 struct mixer_setting {
52 unsigned int ctl_index;
53 unsigned int num_values;
54 unsigned int type;
55 union ctl_values value;
56 };
57
58 struct mixer_value {
59 unsigned int ctl_index;
60 int index;
61 long value;
62 };
63
64 struct mixer_path {
65 char *name;
66 unsigned int size;
67 unsigned int length;
68 struct mixer_setting *setting;
69 };
70
71 struct audio_route {
72 struct mixer *mixer;
73 unsigned int num_mixer_ctls;
74 struct mixer_state *mixer_state;
75
76 unsigned int mixer_path_size;
77 unsigned int num_mixer_paths;
78 struct mixer_path *mixer_path;
79 };
80
81 struct config_parse_state {
82 struct audio_route *ar;
83 struct mixer_path *path;
84 int level;
85 };
86
87 /* path functions */
88
is_supported_ctl_type(enum mixer_ctl_type type)89 static bool is_supported_ctl_type(enum mixer_ctl_type type)
90 {
91 switch (type) {
92 case MIXER_CTL_TYPE_BOOL:
93 case MIXER_CTL_TYPE_INT:
94 case MIXER_CTL_TYPE_ENUM:
95 case MIXER_CTL_TYPE_BYTE:
96 return true;
97 default:
98 return false;
99 }
100 }
101
102 /* as they match in alsa */
sizeof_ctl_type(enum mixer_ctl_type type)103 static size_t sizeof_ctl_type(enum mixer_ctl_type type) {
104 switch (type) {
105 case MIXER_CTL_TYPE_BOOL:
106 case MIXER_CTL_TYPE_INT:
107 return sizeof(long);
108 case MIXER_CTL_TYPE_ENUM:
109 return sizeof(int);
110 case MIXER_CTL_TYPE_BYTE:
111 return sizeof(unsigned char);
112 case MIXER_CTL_TYPE_INT64:
113 case MIXER_CTL_TYPE_IEC958:
114 case MIXER_CTL_TYPE_UNKNOWN:
115 default:
116 LOG_ALWAYS_FATAL("Unsupported mixer ctl type: %d, check type before calling", (int)type);
117 return 0;
118 }
119 }
120
index_to_ctl(struct audio_route * ar,unsigned int ctl_index)121 static inline struct mixer_ctl *index_to_ctl(struct audio_route *ar,
122 unsigned int ctl_index)
123 {
124 return ar->mixer_state[ctl_index].ctl;
125 }
126
127 #if 0
128 static void path_print(struct audio_route *ar, struct mixer_path *path)
129 {
130 unsigned int i;
131 unsigned int j;
132
133 ALOGE("Path: %s, length: %d", path->name, path->length);
134 for (i = 0; i < path->length; i++) {
135 struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index);
136
137 ALOGE(" id=%d: ctl=%s", i, mixer_ctl_get_name(ctl));
138 if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE) {
139 for (j = 0; j < path->setting[i].num_values; j++)
140 ALOGE(" id=%d value=0x%02x", j, path->setting[i].value.bytes[j]);
141 } else if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_ENUM) {
142 for (j = 0; j < path->setting[i].num_values; j++)
143 ALOGE(" id=%d value=%d", j, path->setting[i].value.enumerated[j]);
144 } else {
145 for (j = 0; j < path->setting[i].num_values; j++)
146 ALOGE(" id=%d value=%ld", j, path->setting[i].value.integer[j]);
147 }
148 }
149 }
150 #endif
151
path_free(struct audio_route * ar)152 static void path_free(struct audio_route *ar)
153 {
154 unsigned int i;
155
156 for (i = 0; i < ar->num_mixer_paths; i++) {
157 free(ar->mixer_path[i].name);
158 if (ar->mixer_path[i].setting) {
159 size_t j;
160 for (j = 0; j < ar->mixer_path[i].length; j++) {
161 free(ar->mixer_path[i].setting[j].value.ptr);
162 }
163 free(ar->mixer_path[i].setting);
164 ar->mixer_path[i].size = 0;
165 ar->mixer_path[i].length = 0;
166 ar->mixer_path[i].setting = NULL;
167 }
168 }
169 free(ar->mixer_path);
170 ar->mixer_path = NULL;
171 ar->mixer_path_size = 0;
172 ar->num_mixer_paths = 0;
173 }
174
path_get_by_name(struct audio_route * ar,const char * name)175 static struct mixer_path *path_get_by_name(struct audio_route *ar,
176 const char *name)
177 {
178 unsigned int i;
179
180 for (i = 0; i < ar->num_mixer_paths; i++)
181 if (strcmp(ar->mixer_path[i].name, name) == 0)
182 return &ar->mixer_path[i];
183
184 return NULL;
185 }
186
path_create(struct audio_route * ar,const char * name)187 static struct mixer_path *path_create(struct audio_route *ar, const char *name)
188 {
189 struct mixer_path *new_mixer_path = NULL;
190
191 if (path_get_by_name(ar, name)) {
192 ALOGE("Path name '%s' already exists", name);
193 return NULL;
194 }
195
196 /* check if we need to allocate more space for mixer paths */
197 if (ar->mixer_path_size <= ar->num_mixer_paths) {
198 if (ar->mixer_path_size == 0)
199 ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
200 else
201 ar->mixer_path_size *= 2;
202
203 new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
204 sizeof(struct mixer_path));
205 if (new_mixer_path == NULL) {
206 ALOGE("Unable to allocate more paths");
207 return NULL;
208 } else {
209 ar->mixer_path = new_mixer_path;
210 }
211 }
212
213 /* initialise the new mixer path */
214 ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
215 ar->mixer_path[ar->num_mixer_paths].size = 0;
216 ar->mixer_path[ar->num_mixer_paths].length = 0;
217 ar->mixer_path[ar->num_mixer_paths].setting = NULL;
218
219 /* return the mixer path just added, then increment number of them */
220 return &ar->mixer_path[ar->num_mixer_paths++];
221 }
222
find_ctl_index_in_path(struct mixer_path * path,unsigned int ctl_index)223 static int find_ctl_index_in_path(struct mixer_path *path,
224 unsigned int ctl_index)
225 {
226 unsigned int i;
227
228 for (i = 0; i < path->length; i++)
229 if (path->setting[i].ctl_index == ctl_index)
230 return i;
231
232 return -1;
233 }
234
alloc_path_setting(struct mixer_path * path)235 static int alloc_path_setting(struct mixer_path *path)
236 {
237 struct mixer_setting *new_path_setting;
238 int path_index;
239
240 /* check if we need to allocate more space for path settings */
241 if (path->size <= path->length) {
242 if (path->size == 0)
243 path->size = INITIAL_MIXER_PATH_SIZE;
244 else
245 path->size *= 2;
246
247 new_path_setting = realloc(path->setting,
248 path->size * sizeof(struct mixer_setting));
249 if (new_path_setting == NULL) {
250 ALOGE("Unable to allocate more path settings");
251 return -1;
252 } else {
253 path->setting = new_path_setting;
254 }
255 }
256
257 path_index = path->length;
258 path->length++;
259
260 return path_index;
261 }
262
path_add_setting(struct audio_route * ar,struct mixer_path * path,struct mixer_setting * setting)263 static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
264 struct mixer_setting *setting)
265 {
266 int path_index;
267
268 if (find_ctl_index_in_path(path, setting->ctl_index) != -1) {
269 struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index);
270
271 ALOGE("Control '%s' already exists in path '%s'",
272 mixer_ctl_get_name(ctl), path->name);
273 return -1;
274 }
275
276 if (!is_supported_ctl_type(setting->type)) {
277 ALOGE("unsupported type %d", (int)setting->type);
278 return -1;
279 }
280
281 path_index = alloc_path_setting(path);
282 if (path_index < 0)
283 return -1;
284
285 path->setting[path_index].ctl_index = setting->ctl_index;
286 path->setting[path_index].type = setting->type;
287 path->setting[path_index].num_values = setting->num_values;
288
289 size_t value_sz = sizeof_ctl_type(setting->type);
290
291 path->setting[path_index].value.ptr = calloc(setting->num_values, value_sz);
292 /* copy all values */
293 memcpy(path->setting[path_index].value.ptr, setting->value.ptr,
294 setting->num_values * value_sz);
295
296 return 0;
297 }
298
path_add_value(struct audio_route * ar,struct mixer_path * path,struct mixer_value * mixer_value)299 static int path_add_value(struct audio_route *ar, struct mixer_path *path,
300 struct mixer_value *mixer_value)
301 {
302 unsigned int i;
303 int path_index;
304 unsigned int num_values;
305 struct mixer_ctl *ctl;
306
307 /* Check that mixer value index is within range */
308 ctl = index_to_ctl(ar, mixer_value->ctl_index);
309 num_values = mixer_ctl_get_num_values(ctl);
310 if (mixer_value->index >= (int)num_values) {
311 ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
312 mixer_ctl_get_name(ctl));
313 return -1;
314 }
315
316 path_index = find_ctl_index_in_path(path, mixer_value->ctl_index);
317 if (path_index < 0) {
318 /* New path */
319
320 enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
321 if (!is_supported_ctl_type(type)) {
322 ALOGE("unsupported type %d", (int)type);
323 return -1;
324 }
325 path_index = alloc_path_setting(path);
326 if (path_index < 0)
327 return -1;
328
329 /* initialise the new path setting */
330 path->setting[path_index].ctl_index = mixer_value->ctl_index;
331 path->setting[path_index].num_values = num_values;
332 path->setting[path_index].type = type;
333
334 size_t value_sz = sizeof_ctl_type(type);
335 path->setting[path_index].value.ptr = calloc(num_values, value_sz);
336 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
337 path->setting[path_index].value.bytes[0] = mixer_value->value;
338 else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
339 path->setting[path_index].value.enumerated[0] = mixer_value->value;
340 else
341 path->setting[path_index].value.integer[0] = mixer_value->value;
342 }
343
344 if (mixer_value->index == -1) {
345 /* set all values the same */
346 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) {
347 for (i = 0; i < num_values; i++)
348 path->setting[path_index].value.bytes[i] = mixer_value->value;
349 } else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM) {
350 for (i = 0; i < num_values; i++)
351 path->setting[path_index].value.enumerated[i] = mixer_value->value;
352 } else {
353 for (i = 0; i < num_values; i++)
354 path->setting[path_index].value.integer[i] = mixer_value->value;
355 }
356 } else {
357 /* set only one value */
358 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
359 path->setting[path_index].value.bytes[mixer_value->index] = mixer_value->value;
360 else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
361 path->setting[path_index].value.enumerated[mixer_value->index] = mixer_value->value;
362 else
363 path->setting[path_index].value.integer[mixer_value->index] = mixer_value->value;
364 }
365
366 return 0;
367 }
368
path_add_path(struct audio_route * ar,struct mixer_path * path,struct mixer_path * sub_path)369 static int path_add_path(struct audio_route *ar, struct mixer_path *path,
370 struct mixer_path *sub_path)
371 {
372 unsigned int i;
373
374 for (i = 0; i < sub_path->length; i++)
375 if (path_add_setting(ar, path, &sub_path->setting[i]) < 0)
376 return -1;
377
378 return 0;
379 }
380
path_apply(struct audio_route * ar,struct mixer_path * path)381 static int path_apply(struct audio_route *ar, struct mixer_path *path)
382 {
383 unsigned int i;
384 unsigned int ctl_index;
385 struct mixer_ctl *ctl;
386 enum mixer_ctl_type type;
387
388 ALOGD("Apply path: %s", path->name != NULL ? path->name : "none");
389 for (i = 0; i < path->length; i++) {
390 ctl_index = path->setting[i].ctl_index;
391 ctl = index_to_ctl(ar, ctl_index);
392 type = mixer_ctl_get_type(ctl);
393 if (!is_supported_ctl_type(type))
394 continue;
395 size_t value_sz = sizeof_ctl_type(type);
396 memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr,
397 path->setting[i].num_values * value_sz);
398 }
399
400 return 0;
401 }
402
path_reset(struct audio_route * ar,struct mixer_path * path)403 static int path_reset(struct audio_route *ar, struct mixer_path *path)
404 {
405 unsigned int i;
406 unsigned int ctl_index;
407 struct mixer_ctl *ctl;
408 enum mixer_ctl_type type;
409
410 ALOGV("Reset path: %s", path->name != NULL ? path->name : "none");
411 for (i = 0; i < path->length; i++) {
412 ctl_index = path->setting[i].ctl_index;
413 ctl = index_to_ctl(ar, ctl_index);
414 type = mixer_ctl_get_type(ctl);
415 if (!is_supported_ctl_type(type))
416 continue;
417 size_t value_sz = sizeof_ctl_type(type);
418 /* reset the value(s) */
419 memcpy(ar->mixer_state[ctl_index].new_value.ptr,
420 ar->mixer_state[ctl_index].reset_value.ptr,
421 ar->mixer_state[ctl_index].num_values * value_sz);
422 }
423
424 return 0;
425 }
426
427 /* mixer helper function */
mixer_enum_string_to_value(struct mixer_ctl * ctl,const char * string)428 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
429 {
430 unsigned int i;
431 unsigned int num_values = mixer_ctl_get_num_enums(ctl);
432
433 if (string == NULL) {
434 ALOGE("NULL enum value string passed to mixer_enum_string_to_value() for ctl %s",
435 mixer_ctl_get_name(ctl));
436 return 0;
437 }
438
439 /* Search the enum strings for a particular one */
440 for (i = 0; i < num_values; i++) {
441 if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
442 break;
443 }
444 if (i == num_values) {
445 ALOGE("unknown enum value string %s for ctl %s",
446 string, mixer_ctl_get_name(ctl));
447 return 0;
448 }
449 return i;
450 }
451
start_tag(void * data,const XML_Char * tag_name,const XML_Char ** attr)452 static void start_tag(void *data, const XML_Char *tag_name,
453 const XML_Char **attr)
454 {
455 const XML_Char *attr_name = NULL;
456 const XML_Char *attr_id = NULL;
457 const XML_Char *attr_value = NULL;
458 struct config_parse_state *state = data;
459 struct audio_route *ar = state->ar;
460 unsigned int i;
461 unsigned int ctl_index;
462 struct mixer_ctl *ctl;
463 long value;
464 unsigned int id;
465 struct mixer_value mixer_value;
466 enum mixer_ctl_type type;
467
468 /* Get name, id and value attributes (these may be empty) */
469 for (i = 0; attr[i]; i += 2) {
470 if (strcmp(attr[i], "name") == 0)
471 attr_name = attr[i + 1];
472 if (strcmp(attr[i], "id") == 0)
473 attr_id = attr[i + 1];
474 else if (strcmp(attr[i], "value") == 0)
475 attr_value = attr[i + 1];
476 }
477
478 /* Look at tags */
479 if (strcmp(tag_name, "path") == 0) {
480 if (attr_name == NULL) {
481 ALOGE("Unnamed path!");
482 } else {
483 if (state->level == 1) {
484 /* top level path: create and stash the path */
485 state->path = path_create(ar, (char *)attr_name);
486 if (state->path == NULL)
487 ALOGE("path created failed, please check the path if existed");
488 } else {
489 /* nested path */
490 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
491 if (!sub_path) {
492 ALOGE("unable to find sub path '%s'", attr_name);
493 } else if (state->path != NULL) {
494 path_add_path(ar, state->path, sub_path);
495 }
496 }
497 }
498 }
499
500 else if (strcmp(tag_name, "ctl") == 0) {
501 /* Obtain the mixer ctl and value */
502 ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
503 if (ctl == NULL) {
504 ALOGE("Control '%s' doesn't exist - skipping", attr_name);
505 goto done;
506 }
507
508 switch (mixer_ctl_get_type(ctl)) {
509 case MIXER_CTL_TYPE_BOOL:
510 case MIXER_CTL_TYPE_INT:
511 value = strtol((char *)attr_value, NULL, 0);
512 break;
513 case MIXER_CTL_TYPE_BYTE:
514 value = (unsigned char) strtol((char *)attr_value, NULL, 16);
515 break;
516 case MIXER_CTL_TYPE_ENUM:
517 value = mixer_enum_string_to_value(ctl, (char *)attr_value);
518 break;
519 default:
520 value = 0;
521 break;
522 }
523
524 /* locate the mixer ctl in the list */
525 for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
526 if (ar->mixer_state[ctl_index].ctl == ctl)
527 break;
528 }
529
530 if (state->level == 1) {
531 /* top level ctl (initial setting) */
532
533 type = mixer_ctl_get_type(ctl);
534 if (is_supported_ctl_type(type)) {
535 /* apply the new value */
536 if (attr_id) {
537 /* set only one value */
538 id = atoi((char *)attr_id);
539 if (id < ar->mixer_state[ctl_index].num_values)
540 if (type == MIXER_CTL_TYPE_BYTE)
541 ar->mixer_state[ctl_index].new_value.bytes[id] = value;
542 else if (type == MIXER_CTL_TYPE_ENUM)
543 ar->mixer_state[ctl_index].new_value.enumerated[id] = value;
544 else
545 ar->mixer_state[ctl_index].new_value.integer[id] = value;
546 else
547 ALOGE("value id out of range for mixer ctl '%s'",
548 mixer_ctl_get_name(ctl));
549 } else {
550 /* set all values the same */
551 for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
552 if (type == MIXER_CTL_TYPE_BYTE)
553 ar->mixer_state[ctl_index].new_value.bytes[i] = value;
554 else if (type == MIXER_CTL_TYPE_ENUM)
555 ar->mixer_state[ctl_index].new_value.enumerated[i] = value;
556 else
557 ar->mixer_state[ctl_index].new_value.integer[i] = value;
558 }
559 }
560 } else {
561 /* nested ctl (within a path) */
562 mixer_value.ctl_index = ctl_index;
563 mixer_value.value = value;
564 if (attr_id)
565 mixer_value.index = atoi((char *)attr_id);
566 else
567 mixer_value.index = -1;
568 if (state->path != NULL)
569 path_add_value(ar, state->path, &mixer_value);
570 }
571 }
572
573 done:
574 state->level++;
575 }
576
end_tag(void * data,const XML_Char * tag_name)577 static void end_tag(void *data, const XML_Char *tag_name)
578 {
579 struct config_parse_state *state = data;
580 (void)tag_name;
581
582 state->level--;
583 }
584
alloc_mixer_state(struct audio_route * ar)585 static int alloc_mixer_state(struct audio_route *ar)
586 {
587 unsigned int i;
588 unsigned int num_values;
589 struct mixer_ctl *ctl;
590 enum mixer_ctl_type type;
591
592 ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
593 ar->mixer_state = calloc(ar->num_mixer_ctls, sizeof(struct mixer_state));
594 if (!ar->mixer_state)
595 return -1;
596
597 for (i = 0; i < ar->num_mixer_ctls; i++) {
598 ctl = mixer_get_ctl(ar->mixer, i);
599 num_values = mixer_ctl_get_num_values(ctl);
600
601 ar->mixer_state[i].ctl = ctl;
602 ar->mixer_state[i].num_values = num_values;
603 ar->mixer_state[i].active_count = 0;
604
605 /* Skip unsupported types that are not supported yet in XML */
606 type = mixer_ctl_get_type(ctl);
607
608 if (!is_supported_ctl_type(type))
609 continue;
610
611 size_t value_sz = sizeof_ctl_type(type);
612 ar->mixer_state[i].old_value.ptr = calloc(num_values, value_sz);
613 ar->mixer_state[i].new_value.ptr = calloc(num_values, value_sz);
614 ar->mixer_state[i].reset_value.ptr = calloc(num_values, value_sz);
615
616 if (type == MIXER_CTL_TYPE_ENUM)
617 ar->mixer_state[i].old_value.enumerated[0] = mixer_ctl_get_value(ctl, 0);
618 else
619 mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values);
620
621 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].old_value.ptr,
622 num_values * value_sz);
623 }
624
625 return 0;
626 }
627
free_mixer_state(struct audio_route * ar)628 static void free_mixer_state(struct audio_route *ar)
629 {
630 unsigned int i;
631 enum mixer_ctl_type type;
632
633 for (i = 0; i < ar->num_mixer_ctls; i++) {
634 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
635 if (!is_supported_ctl_type(type))
636 continue;
637
638 free(ar->mixer_state[i].old_value.ptr);
639 free(ar->mixer_state[i].new_value.ptr);
640 free(ar->mixer_state[i].reset_value.ptr);
641 }
642
643 free(ar->mixer_state);
644 ar->mixer_state = NULL;
645 }
646
647 /* Update the mixer with any changed values */
audio_route_update_mixer(struct audio_route * ar)648 int audio_route_update_mixer(struct audio_route *ar)
649 {
650 unsigned int i;
651 unsigned int j;
652 struct mixer_ctl *ctl;
653
654 for (i = 0; i < ar->num_mixer_ctls; i++) {
655 unsigned int num_values = ar->mixer_state[i].num_values;
656 enum mixer_ctl_type type;
657
658 ctl = ar->mixer_state[i].ctl;
659
660 /* Skip unsupported types */
661 type = mixer_ctl_get_type(ctl);
662 if (!is_supported_ctl_type(type))
663 continue;
664
665 /* if the value has changed, update the mixer */
666 bool changed = false;
667 if (type == MIXER_CTL_TYPE_BYTE) {
668 for (j = 0; j < num_values; j++) {
669 if (ar->mixer_state[i].old_value.bytes[j] != ar->mixer_state[i].new_value.bytes[j]) {
670 changed = true;
671 break;
672 }
673 }
674 } else if (type == MIXER_CTL_TYPE_ENUM) {
675 for (j = 0; j < num_values; j++) {
676 if (ar->mixer_state[i].old_value.enumerated[j]
677 != ar->mixer_state[i].new_value.enumerated[j]) {
678 changed = true;
679 break;
680 }
681 }
682 } else {
683 for (j = 0; j < num_values; j++) {
684 if (ar->mixer_state[i].old_value.integer[j] != ar->mixer_state[i].new_value.integer[j]) {
685 changed = true;
686 break;
687 }
688 }
689 }
690 if (changed) {
691 if (type == MIXER_CTL_TYPE_ENUM)
692 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.enumerated[0]);
693 else
694 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value.ptr, num_values);
695
696 size_t value_sz = sizeof_ctl_type(type);
697 memcpy(ar->mixer_state[i].old_value.ptr, ar->mixer_state[i].new_value.ptr,
698 num_values * value_sz);
699 }
700 }
701
702 return 0;
703 }
704
705 /* saves the current state of the mixer, for resetting all controls */
save_mixer_state(struct audio_route * ar)706 static void save_mixer_state(struct audio_route *ar)
707 {
708 unsigned int i;
709 enum mixer_ctl_type type;
710
711 for (i = 0; i < ar->num_mixer_ctls; i++) {
712 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
713 if (!is_supported_ctl_type(type))
714 continue;
715
716 size_t value_sz = sizeof_ctl_type(type);
717 memcpy(ar->mixer_state[i].reset_value.ptr, ar->mixer_state[i].new_value.ptr,
718 ar->mixer_state[i].num_values * value_sz);
719 }
720 }
721
722 /* Reset the audio routes back to the initial state */
audio_route_reset(struct audio_route * ar)723 void audio_route_reset(struct audio_route *ar)
724 {
725 unsigned int i;
726 enum mixer_ctl_type type;
727
728 /* load all of the saved values */
729 for (i = 0; i < ar->num_mixer_ctls; i++) {
730 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
731 if (!is_supported_ctl_type(type))
732 continue;
733
734 size_t value_sz = sizeof_ctl_type(type);
735 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].reset_value.ptr,
736 ar->mixer_state[i].num_values * value_sz);
737 }
738 }
739
740 /* Apply an audio route path by name */
audio_route_apply_path(struct audio_route * ar,const char * name)741 int audio_route_apply_path(struct audio_route *ar, const char *name)
742 {
743 struct mixer_path *path;
744
745 if (!ar) {
746 ALOGE("invalid audio_route");
747 return -1;
748 }
749
750 path = path_get_by_name(ar, name);
751 if (!path) {
752 ALOGE("unable to find path '%s'", name);
753 return -1;
754 }
755
756 path_apply(ar, path);
757
758 return 0;
759 }
760
761 /* Reset an audio route path by name */
audio_route_reset_path(struct audio_route * ar,const char * name)762 int audio_route_reset_path(struct audio_route *ar, const char *name)
763 {
764 struct mixer_path *path;
765
766 if (!ar) {
767 ALOGE("invalid audio_route");
768 return -1;
769 }
770
771 path = path_get_by_name(ar, name);
772 if (!path) {
773 ALOGE("unable to find path '%s'", name);
774 return -1;
775 }
776
777 path_reset(ar, path);
778
779 return 0;
780 }
781
782 /*
783 * Operates on the specified path .. controls will be updated in the
784 * order listed in the XML file
785 */
audio_route_update_path(struct audio_route * ar,const char * name,bool reverse)786 static int audio_route_update_path(struct audio_route *ar, const char *name, bool reverse)
787 {
788 struct mixer_path *path;
789 unsigned int j;
790
791 if (!ar) {
792 ALOGE("invalid audio_route");
793 return -1;
794 }
795
796 path = path_get_by_name(ar, name);
797 if (!path) {
798 ALOGE("unable to find path '%s'", name);
799 return -1;
800 }
801
802 for (size_t i = 0; i < path->length; ++i) {
803 unsigned int ctl_index;
804 enum mixer_ctl_type type;
805
806 ctl_index = path->setting[reverse ? path->length - 1 - i : i].ctl_index;
807
808 struct mixer_state * ms = &ar->mixer_state[ctl_index];
809
810 type = mixer_ctl_get_type(ms->ctl);
811 if (!is_supported_ctl_type(type)) {
812 continue;
813 }
814
815 if (reverse && ms->active_count > 0) {
816 ms->active_count--;
817 } else if (!reverse) {
818 ms->active_count++;
819 }
820
821 size_t value_sz = sizeof_ctl_type(type);
822 /* if any value has changed, update the mixer */
823 for (j = 0; j < ms->num_values; j++) {
824 if (type == MIXER_CTL_TYPE_BYTE) {
825 if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) {
826 if (reverse && ms->active_count > 0) {
827 ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
828 "because it is still needed by other paths", __func__,
829 mixer_ctl_get_name(ms->ctl), name);
830 memcpy(ms->new_value.bytes, ms->old_value.bytes,
831 ms->num_values * value_sz);
832 break;
833 }
834 mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values);
835 memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values * value_sz);
836 break;
837 }
838 } else if (type == MIXER_CTL_TYPE_ENUM) {
839 if (ms->old_value.enumerated[j] != ms->new_value.enumerated[j]) {
840 if (reverse && ms->active_count > 0) {
841 ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
842 "because it is still needed by other paths", __func__,
843 mixer_ctl_get_name(ms->ctl), name);
844 memcpy(ms->new_value.enumerated, ms->old_value.enumerated,
845 ms->num_values * value_sz);
846 break;
847 }
848 mixer_ctl_set_value(ms->ctl, 0, ms->new_value.enumerated[0]);
849 memcpy(ms->old_value.enumerated, ms->new_value.enumerated,
850 ms->num_values * value_sz);
851 break;
852 }
853 } else if (ms->old_value.integer[j] != ms->new_value.integer[j]) {
854 if (reverse && ms->active_count > 0) {
855 ALOGD("%s: skip to reset mixer control '%s' in path '%s' "
856 "because it is still needed by other paths", __func__,
857 mixer_ctl_get_name(ms->ctl), name);
858 memcpy(ms->new_value.integer, ms->old_value.integer,
859 ms->num_values * value_sz);
860 break;
861 }
862 mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values);
863 memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * value_sz);
864 break;
865 }
866 }
867 }
868 return 0;
869 }
870
audio_route_apply_and_update_path(struct audio_route * ar,const char * name)871 int audio_route_apply_and_update_path(struct audio_route *ar, const char *name)
872 {
873 if (audio_route_apply_path(ar, name) < 0) {
874 return -1;
875 }
876 return audio_route_update_path(ar, name, false /*reverse*/);
877 }
878
audio_route_reset_and_update_path(struct audio_route * ar,const char * name)879 int audio_route_reset_and_update_path(struct audio_route *ar, const char *name)
880 {
881 if (audio_route_reset_path(ar, name) < 0) {
882 return -1;
883 }
884 return audio_route_update_path(ar, name, true /*reverse*/);
885 }
886
audio_route_init(unsigned int card,const char * xml_path)887 struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
888 {
889 struct config_parse_state state;
890 XML_Parser parser;
891 FILE *file;
892 int bytes_read;
893 void *buf;
894 struct audio_route *ar;
895
896 ar = calloc(1, sizeof(struct audio_route));
897 if (!ar)
898 goto err_calloc;
899
900 ar->mixer = mixer_open(card);
901 if (!ar->mixer) {
902 ALOGE("Unable to open the mixer, aborting.");
903 goto err_mixer_open;
904 }
905
906 ar->mixer_path = NULL;
907 ar->mixer_path_size = 0;
908 ar->num_mixer_paths = 0;
909
910 /* allocate space for and read current mixer settings */
911 if (alloc_mixer_state(ar) < 0)
912 goto err_mixer_state;
913
914 /* use the default XML path if none is provided */
915 if (xml_path == NULL)
916 xml_path = MIXER_XML_PATH;
917
918 file = fopen(xml_path, "r");
919
920 if (!file) {
921 ALOGE("Failed to open %s: %s", xml_path, strerror(errno));
922 goto err_fopen;
923 }
924
925 parser = XML_ParserCreate(NULL);
926 if (!parser) {
927 ALOGE("Failed to create XML parser");
928 goto err_parser_create;
929 }
930
931 memset(&state, 0, sizeof(state));
932 state.ar = ar;
933 XML_SetUserData(parser, &state);
934 XML_SetElementHandler(parser, start_tag, end_tag);
935
936 for (;;) {
937 buf = XML_GetBuffer(parser, BUF_SIZE);
938 if (buf == NULL)
939 goto err_parse;
940
941 bytes_read = fread(buf, 1, BUF_SIZE, file);
942 if (bytes_read < 0)
943 goto err_parse;
944
945 if (XML_ParseBuffer(parser, bytes_read,
946 bytes_read == 0) == XML_STATUS_ERROR) {
947 ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
948 goto err_parse;
949 }
950
951 if (bytes_read == 0)
952 break;
953 }
954
955 /* apply the initial mixer values, and save them so we can reset the
956 mixer to the original values */
957 audio_route_update_mixer(ar);
958 save_mixer_state(ar);
959
960 XML_ParserFree(parser);
961 fclose(file);
962 return ar;
963
964 err_parse:
965 path_free(ar);
966 XML_ParserFree(parser);
967 err_parser_create:
968 fclose(file);
969 err_fopen:
970 free_mixer_state(ar);
971 err_mixer_state:
972 mixer_close(ar->mixer);
973 err_mixer_open:
974 free(ar);
975 ar = NULL;
976 err_calloc:
977 return NULL;
978 }
979
audio_route_free(struct audio_route * ar)980 void audio_route_free(struct audio_route *ar)
981 {
982 free_mixer_state(ar);
983 mixer_close(ar->mixer);
984 path_free(ar);
985 free(ar);
986 }
987