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