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