2 * Copyright (C) 2013 The Android Open Source Project
3 * Inspired by TinyHW, written by Mark Brown at Wolfson Micro
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #define LOG_TAG "audio_route"
19 /*#define LOG_NDEBUG 0*/
27 #include <cutils/log.h>
29 #include <tinyalsa/asoundlib.h>
32 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
33 #define INITIAL_MIXER_PATH_SIZE 8
42 struct mixer_ctl *ctl;
43 unsigned int num_values;
44 union ctl_values old_value;
45 union ctl_values new_value;
46 union ctl_values reset_value;
49 struct mixer_setting {
50 unsigned int ctl_index;
51 unsigned int num_values;
53 union ctl_values value;
57 unsigned int ctl_index;
66 struct mixer_setting *setting;
71 unsigned int num_mixer_ctls;
72 struct mixer_state *mixer_state;
74 unsigned int mixer_path_size;
75 unsigned int num_mixer_paths;
76 struct mixer_path *mixer_path;
79 struct config_parse_state {
80 struct audio_route *ar;
81 struct mixer_path *path;
87 static bool is_supported_ctl_type(enum mixer_ctl_type type)
90 case MIXER_CTL_TYPE_BOOL:
91 case MIXER_CTL_TYPE_INT:
92 case MIXER_CTL_TYPE_ENUM:
93 case MIXER_CTL_TYPE_BYTE:
100 static inline struct mixer_ctl *index_to_ctl(struct audio_route *ar,
101 unsigned int ctl_index)
103 return ar->mixer_state[ctl_index].ctl;
106 static void path_print(struct audio_route *ar, struct mixer_path *path)
111 ALOGE("Path: %s, length: %d", path->name, path->length);
112 for (i = 0; i < path->length; i++) {
113 struct mixer_ctl *ctl = index_to_ctl(ar, path->setting[i].ctl_index);
115 ALOGE(" id=%d: ctl=%s", i, mixer_ctl_get_name(ctl));
116 if (mixer_ctl_get_type(ctl) == MIXER_CTL_TYPE_BYTE) {
117 for (j = 0; j < path->setting[i].num_values; j++)
118 ALOGE(" id=%d value=0x%02x", j, path->setting[i].value.bytes[j]);
120 for (j = 0; j < path->setting[i].num_values; j++)
121 ALOGE(" id=%d value=%d", j, path->setting[i].value.integer[j]);
126 static void path_free(struct audio_route *ar)
130 for (i = 0; i < ar->num_mixer_paths; i++) {
131 if (ar->mixer_path[i].name)
132 free(ar->mixer_path[i].name);
133 if (ar->mixer_path[i].setting) {
134 if (ar->mixer_path[i].setting->value.ptr)
135 free(ar->mixer_path[i].setting->value.ptr);
136 free(ar->mixer_path[i].setting);
139 free(ar->mixer_path);
142 static struct mixer_path *path_get_by_name(struct audio_route *ar,
147 for (i = 0; i < ar->num_mixer_paths; i++)
148 if (strcmp(ar->mixer_path[i].name, name) == 0)
149 return &ar->mixer_path[i];
154 static struct mixer_path *path_create(struct audio_route *ar, const char *name)
156 struct mixer_path *new_mixer_path = NULL;
158 if (path_get_by_name(ar, name)) {
159 ALOGE("Path name '%s' already exists", name);
163 /* check if we need to allocate more space for mixer paths */
164 if (ar->mixer_path_size <= ar->num_mixer_paths) {
165 if (ar->mixer_path_size == 0)
166 ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
168 ar->mixer_path_size *= 2;
170 new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
171 sizeof(struct mixer_path));
172 if (new_mixer_path == NULL) {
173 ALOGE("Unable to allocate more paths");
176 ar->mixer_path = new_mixer_path;
180 /* initialise the new mixer path */
181 ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
182 ar->mixer_path[ar->num_mixer_paths].size = 0;
183 ar->mixer_path[ar->num_mixer_paths].length = 0;
184 ar->mixer_path[ar->num_mixer_paths].setting = NULL;
186 /* return the mixer path just added, then increment number of them */
187 return &ar->mixer_path[ar->num_mixer_paths++];
190 static int find_ctl_index_in_path(struct mixer_path *path,
191 unsigned int ctl_index)
195 for (i = 0; i < path->length; i++)
196 if (path->setting[i].ctl_index == ctl_index)
202 static int alloc_path_setting(struct mixer_path *path)
204 struct mixer_setting *new_path_setting;
207 /* check if we need to allocate more space for path settings */
208 if (path->size <= path->length) {
210 path->size = INITIAL_MIXER_PATH_SIZE;
214 new_path_setting = realloc(path->setting,
215 path->size * sizeof(struct mixer_setting));
216 if (new_path_setting == NULL) {
217 ALOGE("Unable to allocate more path settings");
220 path->setting = new_path_setting;
224 path_index = path->length;
230 static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
231 struct mixer_setting *setting)
234 unsigned int value_sz = sizeof(int);
236 if (find_ctl_index_in_path(path, setting->ctl_index) != -1) {
237 struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index);
239 ALOGE("Control '%s' already exists in path '%s'",
240 mixer_ctl_get_name(ctl), path->name);
244 path_index = alloc_path_setting(path);
248 path->setting[path_index].ctl_index = setting->ctl_index;
249 path->setting[path_index].type = setting->type;
250 path->setting[path_index].num_values = setting->num_values;
252 if (setting->type == MIXER_CTL_TYPE_BYTE)
253 value_sz = sizeof(unsigned char);
255 path->setting[path_index].value.ptr = malloc(setting->num_values * value_sz);
256 /* copy all values */
257 memcpy(path->setting[path_index].value.ptr, setting->value.ptr,
258 setting->num_values * value_sz);
263 static int path_add_value(struct audio_route *ar, struct mixer_path *path,
264 struct mixer_value *mixer_value)
268 unsigned int num_values;
269 unsigned int value_sz = sizeof(int);
270 struct mixer_ctl *ctl;
272 /* Check that mixer value index is within range */
273 ctl = index_to_ctl(ar, mixer_value->ctl_index);
274 num_values = mixer_ctl_get_num_values(ctl);
275 if (mixer_value->index >= (int)num_values) {
276 ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
277 mixer_ctl_get_name(ctl));
281 path_index = find_ctl_index_in_path(path, mixer_value->ctl_index);
282 if (path_index < 0) {
285 path_index = alloc_path_setting(path);
289 /* initialise the new path setting */
290 path->setting[path_index].ctl_index = mixer_value->ctl_index;
291 path->setting[path_index].num_values = num_values;
292 path->setting[path_index].type = mixer_ctl_get_type(ctl);
294 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
295 value_sz = sizeof(unsigned char);
297 path->setting[path_index].value.ptr = malloc(num_values * value_sz);
298 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
299 path->setting[path_index].value.bytes[0] = mixer_value->value;
301 path->setting[path_index].value.integer[0] = mixer_value->value;
304 if (mixer_value->index == -1) {
305 /* set all values the same */
306 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) {
307 for (i = 0; i < num_values; i++)
308 path->setting[path_index].value.bytes[i] = mixer_value->value;
310 for (i = 0; i < num_values; i++)
311 path->setting[path_index].value.integer[i] = mixer_value->value;
314 /* set only one value */
315 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
316 path->setting[path_index].value.bytes[mixer_value->index] = mixer_value->value;
318 path->setting[path_index].value.integer[mixer_value->index] = mixer_value->value;
324 static int path_add_path(struct audio_route *ar, struct mixer_path *path,
325 struct mixer_path *sub_path)
329 for (i = 0; i < sub_path->length; i++)
330 if (path_add_setting(ar, path, &sub_path->setting[i]) < 0)
336 static int path_apply(struct audio_route *ar, struct mixer_path *path)
339 unsigned int value_sz;
340 unsigned int ctl_index;
341 struct mixer_ctl *ctl;
342 enum mixer_ctl_type type;
344 for (i = 0; i < path->length; i++) {
345 ctl_index = path->setting[i].ctl_index;
346 ctl = index_to_ctl(ar, ctl_index);
347 type = mixer_ctl_get_type(ctl);
348 if (!is_supported_ctl_type(type))
351 if (type == MIXER_CTL_TYPE_BYTE)
352 value_sz = sizeof(unsigned char);
354 value_sz = sizeof(int);
356 memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr,
357 path->setting[i].num_values * value_sz);
363 static int path_reset(struct audio_route *ar, struct mixer_path *path)
367 unsigned int value_sz;
368 unsigned int ctl_index;
369 struct mixer_ctl *ctl;
370 enum mixer_ctl_type type;
372 for (i = 0; i < path->length; i++) {
373 ctl_index = path->setting[i].ctl_index;
374 ctl = index_to_ctl(ar, ctl_index);
375 type = mixer_ctl_get_type(ctl);
376 if (!is_supported_ctl_type(type))
379 if (type == MIXER_CTL_TYPE_BYTE)
380 value_sz = sizeof(unsigned char);
382 value_sz = sizeof(int);
384 /* reset the value(s) */
385 memcpy(ar->mixer_state[ctl_index].new_value.ptr,
386 ar->mixer_state[ctl_index].reset_value.ptr,
387 ar->mixer_state[ctl_index].num_values * value_sz);
393 /* mixer helper function */
394 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
398 /* Search the enum strings for a particular one */
399 for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) {
400 if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
407 static void start_tag(void *data, const XML_Char *tag_name,
408 const XML_Char **attr)
410 const XML_Char *attr_name = NULL;
411 const XML_Char *attr_id = NULL;
412 const XML_Char *attr_value = NULL;
413 struct config_parse_state *state = data;
414 struct audio_route *ar = state->ar;
416 unsigned int ctl_index;
417 struct mixer_ctl *ctl;
420 struct mixer_value mixer_value;
421 enum mixer_ctl_type type;
423 /* Get name, id and value attributes (these may be empty) */
424 for (i = 0; attr[i]; i += 2) {
425 if (strcmp(attr[i], "name") == 0)
426 attr_name = attr[i + 1];
427 if (strcmp(attr[i], "id") == 0)
428 attr_id = attr[i + 1];
429 else if (strcmp(attr[i], "value") == 0)
430 attr_value = attr[i + 1];
434 if (strcmp(tag_name, "path") == 0) {
435 if (attr_name == NULL) {
436 ALOGE("Unnamed path!");
438 if (state->level == 1) {
439 /* top level path: create and stash the path */
440 state->path = path_create(ar, (char *)attr_name);
443 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
444 path_add_path(ar, state->path, sub_path);
449 else if (strcmp(tag_name, "ctl") == 0) {
450 /* Obtain the mixer ctl and value */
451 ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
453 ALOGE("Control '%s' doesn't exist - skipping", attr_name);
457 switch (mixer_ctl_get_type(ctl)) {
458 case MIXER_CTL_TYPE_BOOL:
459 case MIXER_CTL_TYPE_INT:
460 value = (int) strtol((char *)attr_value, NULL, 0);
462 case MIXER_CTL_TYPE_BYTE:
463 value = (unsigned char) strtol((char *)attr_value, NULL, 16);
465 case MIXER_CTL_TYPE_ENUM:
466 value = mixer_enum_string_to_value(ctl, (char *)attr_value);
473 /* locate the mixer ctl in the list */
474 for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
475 if (ar->mixer_state[ctl_index].ctl == ctl)
479 if (state->level == 1) {
480 /* top level ctl (initial setting) */
482 type = mixer_ctl_get_type(ctl);
483 if (is_supported_ctl_type(type)) {
484 /* apply the new value */
486 /* set only one value */
487 id = atoi((char *)attr_id);
488 if (id < ar->mixer_state[ctl_index].num_values)
489 if (type == MIXER_CTL_TYPE_BYTE)
490 ar->mixer_state[ctl_index].new_value.bytes[id] = value;
492 ar->mixer_state[ctl_index].new_value.integer[id] = value;
494 ALOGE("value id out of range for mixer ctl '%s'",
495 mixer_ctl_get_name(ctl));
497 /* set all values the same */
498 for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
499 if (type == MIXER_CTL_TYPE_BYTE)
500 ar->mixer_state[ctl_index].new_value.bytes[i] = value;
502 ar->mixer_state[ctl_index].new_value.integer[i] = value;
506 /* nested ctl (within a path) */
507 mixer_value.ctl_index = ctl_index;
508 mixer_value.value = value;
510 mixer_value.index = atoi((char *)attr_id);
512 mixer_value.index = -1;
513 path_add_value(ar, state->path, &mixer_value);
521 static void end_tag(void *data, const XML_Char *tag_name)
523 struct config_parse_state *state = data;
529 static int alloc_mixer_state(struct audio_route *ar)
533 unsigned int num_values;
534 unsigned int value_sz;
535 struct mixer_ctl *ctl;
536 enum mixer_ctl_type type;
538 ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
539 ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state));
540 if (!ar->mixer_state)
543 for (i = 0; i < ar->num_mixer_ctls; i++) {
544 ctl = mixer_get_ctl(ar->mixer, i);
545 num_values = mixer_ctl_get_num_values(ctl);
547 ar->mixer_state[i].ctl = ctl;
548 ar->mixer_state[i].num_values = num_values;
550 /* Skip unsupported types that are not supported yet in XML */
551 type = mixer_ctl_get_type(ctl);
553 if (!is_supported_ctl_type(type))
556 if (type == MIXER_CTL_TYPE_BYTE)
557 value_sz = sizeof(unsigned char);
559 value_sz = sizeof(int);
561 ar->mixer_state[i].old_value.ptr = malloc(num_values * value_sz);
562 ar->mixer_state[i].new_value.ptr = malloc(num_values * value_sz);
563 ar->mixer_state[i].reset_value.ptr = malloc(num_values * value_sz);
565 if (type == MIXER_CTL_TYPE_ENUM)
566 ar->mixer_state[i].old_value.integer[0] = mixer_ctl_get_value(ctl, 0);
568 mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values);
570 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].old_value.ptr,
571 num_values * value_sz);
577 static void free_mixer_state(struct audio_route *ar)
580 enum mixer_ctl_type type;
582 for (i = 0; i < ar->num_mixer_ctls; i++) {
583 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
584 if (!is_supported_ctl_type(type))
587 free(ar->mixer_state[i].old_value.ptr);
588 free(ar->mixer_state[i].new_value.ptr);
589 free(ar->mixer_state[i].reset_value.ptr);
592 free(ar->mixer_state);
593 ar->mixer_state = NULL;
596 /* Update the mixer with any changed values */
597 int audio_route_update_mixer(struct audio_route *ar)
601 struct mixer_ctl *ctl;
603 for (i = 0; i < ar->num_mixer_ctls; i++) {
604 unsigned int num_values = ar->mixer_state[i].num_values;
605 enum mixer_ctl_type type;
607 ctl = ar->mixer_state[i].ctl;
609 /* Skip unsupported types */
610 type = mixer_ctl_get_type(ctl);
611 if (!is_supported_ctl_type(type))
614 /* if the value has changed, update the mixer */
615 bool changed = false;
616 if (type == MIXER_CTL_TYPE_BYTE) {
617 for (j = 0; j < num_values; j++) {
618 if (ar->mixer_state[i].old_value.bytes[j] != ar->mixer_state[i].new_value.bytes[j]) {
624 for (j = 0; j < num_values; j++) {
625 if (ar->mixer_state[i].old_value.integer[j] != ar->mixer_state[i].new_value.integer[j]) {
632 unsigned int value_sz = sizeof(int);
634 if (type == MIXER_CTL_TYPE_BYTE)
635 value_sz = sizeof(unsigned char);
637 if (type == MIXER_CTL_TYPE_ENUM)
638 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.integer[0]);
640 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value.ptr, num_values);
642 memcpy(ar->mixer_state[i].old_value.ptr, ar->mixer_state[i].new_value.ptr,
643 num_values * value_sz);
650 /* saves the current state of the mixer, for resetting all controls */
651 static void save_mixer_state(struct audio_route *ar)
654 unsigned int value_sz;
655 enum mixer_ctl_type type;
657 for (i = 0; i < ar->num_mixer_ctls; i++) {
658 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
659 if (!is_supported_ctl_type(type))
662 if (type == MIXER_CTL_TYPE_BYTE)
663 value_sz = sizeof(unsigned char);
665 value_sz = sizeof(int);
667 memcpy(ar->mixer_state[i].reset_value.ptr, ar->mixer_state[i].new_value.ptr,
668 ar->mixer_state[i].num_values * value_sz);
672 /* Reset the audio routes back to the initial state */
673 void audio_route_reset(struct audio_route *ar)
676 unsigned int value_sz;
677 enum mixer_ctl_type type;
679 /* load all of the saved values */
680 for (i = 0; i < ar->num_mixer_ctls; i++) {
681 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
682 if (!is_supported_ctl_type(type))
685 if (type == MIXER_CTL_TYPE_BYTE)
686 value_sz = sizeof(unsigned char);
688 value_sz = sizeof(int);
690 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].reset_value.ptr,
691 ar->mixer_state[i].num_values * value_sz);
695 /* Apply an audio route path by name */
696 int audio_route_apply_path(struct audio_route *ar, const char *name)
698 struct mixer_path *path;
701 ALOGE("invalid audio_route");
705 path = path_get_by_name(ar, name);
707 ALOGE("unable to find path '%s'", name);
711 path_apply(ar, path);
716 /* Reset an audio route path by name */
717 int audio_route_reset_path(struct audio_route *ar, const char *name)
719 struct mixer_path *path;
722 ALOGE("invalid audio_route");
726 path = path_get_by_name(ar, name);
728 ALOGE("unable to find path '%s'", name);
732 path_reset(ar, path);
738 * Operates on the specified path .. controls will be updated in the
739 * order listed in the XML file
741 static int audio_route_update_path(struct audio_route *ar, const char *name, bool reverse)
743 struct mixer_path *path;
748 ALOGE("invalid audio_route");
752 path = path_get_by_name(ar, name);
754 ALOGE("unable to find path '%s'", name);
758 i = reverse ? (path->length - 1) : 0;
759 end = reverse ? -1 : (int32_t)path->length;
762 unsigned int ctl_index;
763 enum mixer_ctl_type type;
765 ctl_index = path->setting[i].ctl_index;
767 struct mixer_state * ms = &ar->mixer_state[ctl_index];
769 type = mixer_ctl_get_type(ms->ctl);
770 if (!is_supported_ctl_type(type)) {
774 /* if any value has changed, update the mixer */
775 for (j = 0; j < ms->num_values; j++) {
776 if (type == MIXER_CTL_TYPE_BYTE) {
777 if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) {
778 mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values);
779 memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values);
783 else if (ms->old_value.integer[j] != ms->new_value.integer[j]) {
784 if (type == MIXER_CTL_TYPE_ENUM)
785 mixer_ctl_set_value(ms->ctl, 0, ms->new_value.integer[0]);
787 mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values);
788 memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * sizeof(int));
793 i = reverse ? (i - 1) : (i + 1);
798 int audio_route_apply_and_update_path(struct audio_route *ar, const char *name)
800 if (audio_route_apply_path(ar, name) < 0) {
803 return audio_route_update_path(ar, name, false /*reverse*/);
806 int audio_route_reset_and_update_path(struct audio_route *ar, const char *name)
808 if (audio_route_reset_path(ar, name) < 0) {
811 return audio_route_update_path(ar, name, true /*reverse*/);
814 struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
816 struct config_parse_state state;
822 struct audio_route *ar;
824 ar = calloc(1, sizeof(struct audio_route));
828 ar->mixer = mixer_open(card);
830 ALOGE("Unable to open the mixer, aborting.");
834 ar->mixer_path = NULL;
835 ar->mixer_path_size = 0;
836 ar->num_mixer_paths = 0;
838 /* allocate space for and read current mixer settings */
839 if (alloc_mixer_state(ar) < 0)
840 goto err_mixer_state;
842 /* use the default XML path if none is provided */
843 if (xml_path == NULL)
844 xml_path = MIXER_XML_PATH;
846 file = fopen(xml_path, "r");
849 ALOGE("Failed to open %s", xml_path);
853 parser = XML_ParserCreate(NULL);
855 ALOGE("Failed to create XML parser");
856 goto err_parser_create;
859 memset(&state, 0, sizeof(state));
861 XML_SetUserData(parser, &state);
862 XML_SetElementHandler(parser, start_tag, end_tag);
865 buf = XML_GetBuffer(parser, BUF_SIZE);
869 bytes_read = fread(buf, 1, BUF_SIZE, file);
873 if (XML_ParseBuffer(parser, bytes_read,
874 bytes_read == 0) == XML_STATUS_ERROR) {
875 ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
883 /* apply the initial mixer values, and save them so we can reset the
884 mixer to the original values */
885 audio_route_update_mixer(ar);
886 save_mixer_state(ar);
888 XML_ParserFree(parser);
893 XML_ParserFree(parser);
897 free_mixer_state(ar);
899 mixer_close(ar->mixer);
907 void audio_route_free(struct audio_route *ar)
909 free_mixer_state(ar);
910 mixer_close(ar->mixer);