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