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