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