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*/
29 #include <tinyalsa/asoundlib.h>
32 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
33 #define INITIAL_MIXER_PATH_SIZE 8
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;
50 struct mixer_setting {
51 unsigned int ctl_index;
52 unsigned int num_values;
54 union ctl_values value;
58 unsigned int ctl_index;
67 struct mixer_setting *setting;
72 unsigned int num_mixer_ctls;
73 struct mixer_state *mixer_state;
75 unsigned int mixer_path_size;
76 unsigned int num_mixer_paths;
77 struct mixer_path *mixer_path;
80 struct config_parse_state {
81 struct audio_route *ar;
82 struct mixer_path *path;
88 static bool is_supported_ctl_type(enum mixer_ctl_type 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:
101 /* as they match in alsa */
102 static size_t sizeof_ctl_type(enum mixer_ctl_type type) {
104 case MIXER_CTL_TYPE_BOOL:
105 case MIXER_CTL_TYPE_INT:
107 case MIXER_CTL_TYPE_ENUM:
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:
115 LOG_ALWAYS_FATAL("Unsupported mixer ctl type: %d, check type before calling", (int)type);
120 static inline struct mixer_ctl *index_to_ctl(struct audio_route *ar,
121 unsigned int ctl_index)
123 return ar->mixer_state[ctl_index].ctl;
127 static void path_print(struct audio_route *ar, struct mixer_path *path)
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);
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]);
144 for (j = 0; j < path->setting[i].num_values; j++)
145 ALOGE(" id=%d value=%ld", j, path->setting[i].value.integer[j]);
151 static void path_free(struct audio_route *ar)
155 for (i = 0; i < ar->num_mixer_paths; i++) {
156 free(ar->mixer_path[i].name);
157 if (ar->mixer_path[i].setting) {
159 for (j = 0; j < ar->mixer_path[i].length; j++) {
160 free(ar->mixer_path[i].setting[j].value.ptr);
162 free(ar->mixer_path[i].setting);
163 ar->mixer_path[i].size = 0;
164 ar->mixer_path[i].length = 0;
165 ar->mixer_path[i].setting = NULL;
168 free(ar->mixer_path);
169 ar->mixer_path = NULL;
170 ar->mixer_path_size = 0;
171 ar->num_mixer_paths = 0;
174 static struct mixer_path *path_get_by_name(struct audio_route *ar,
179 for (i = 0; i < ar->num_mixer_paths; i++)
180 if (strcmp(ar->mixer_path[i].name, name) == 0)
181 return &ar->mixer_path[i];
186 static struct mixer_path *path_create(struct audio_route *ar, const char *name)
188 struct mixer_path *new_mixer_path = NULL;
190 if (path_get_by_name(ar, name)) {
191 ALOGE("Path name '%s' already exists", name);
195 /* check if we need to allocate more space for mixer paths */
196 if (ar->mixer_path_size <= ar->num_mixer_paths) {
197 if (ar->mixer_path_size == 0)
198 ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
200 ar->mixer_path_size *= 2;
202 new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
203 sizeof(struct mixer_path));
204 if (new_mixer_path == NULL) {
205 ALOGE("Unable to allocate more paths");
208 ar->mixer_path = new_mixer_path;
212 /* initialise the new mixer path */
213 ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
214 ar->mixer_path[ar->num_mixer_paths].size = 0;
215 ar->mixer_path[ar->num_mixer_paths].length = 0;
216 ar->mixer_path[ar->num_mixer_paths].setting = NULL;
218 /* return the mixer path just added, then increment number of them */
219 return &ar->mixer_path[ar->num_mixer_paths++];
222 static int find_ctl_index_in_path(struct mixer_path *path,
223 unsigned int ctl_index)
227 for (i = 0; i < path->length; i++)
228 if (path->setting[i].ctl_index == ctl_index)
234 static int alloc_path_setting(struct mixer_path *path)
236 struct mixer_setting *new_path_setting;
239 /* check if we need to allocate more space for path settings */
240 if (path->size <= path->length) {
242 path->size = INITIAL_MIXER_PATH_SIZE;
246 new_path_setting = realloc(path->setting,
247 path->size * sizeof(struct mixer_setting));
248 if (new_path_setting == NULL) {
249 ALOGE("Unable to allocate more path settings");
252 path->setting = new_path_setting;
256 path_index = path->length;
262 static int path_add_setting(struct audio_route *ar, struct mixer_path *path,
263 struct mixer_setting *setting)
267 if (find_ctl_index_in_path(path, setting->ctl_index) != -1) {
268 struct mixer_ctl *ctl = index_to_ctl(ar, setting->ctl_index);
270 ALOGE("Control '%s' already exists in path '%s'",
271 mixer_ctl_get_name(ctl), path->name);
275 if (!is_supported_ctl_type(setting->type)) {
276 ALOGE("unsupported type %d", (int)setting->type);
280 path_index = alloc_path_setting(path);
284 path->setting[path_index].ctl_index = setting->ctl_index;
285 path->setting[path_index].type = setting->type;
286 path->setting[path_index].num_values = setting->num_values;
288 size_t value_sz = sizeof_ctl_type(setting->type);
290 path->setting[path_index].value.ptr = calloc(setting->num_values, value_sz);
291 /* copy all values */
292 memcpy(path->setting[path_index].value.ptr, setting->value.ptr,
293 setting->num_values * value_sz);
298 static int path_add_value(struct audio_route *ar, struct mixer_path *path,
299 struct mixer_value *mixer_value)
303 unsigned int num_values;
304 struct mixer_ctl *ctl;
306 /* Check that mixer value index is within range */
307 ctl = index_to_ctl(ar, mixer_value->ctl_index);
308 num_values = mixer_ctl_get_num_values(ctl);
309 if (mixer_value->index >= (int)num_values) {
310 ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
311 mixer_ctl_get_name(ctl));
315 path_index = find_ctl_index_in_path(path, mixer_value->ctl_index);
316 if (path_index < 0) {
319 enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
320 if (!is_supported_ctl_type(type)) {
321 ALOGE("unsupported type %d", (int)type);
324 path_index = alloc_path_setting(path);
328 /* initialise the new path setting */
329 path->setting[path_index].ctl_index = mixer_value->ctl_index;
330 path->setting[path_index].num_values = num_values;
331 path->setting[path_index].type = type;
333 size_t value_sz = sizeof_ctl_type(type);
334 path->setting[path_index].value.ptr = calloc(num_values, value_sz);
335 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
336 path->setting[path_index].value.bytes[0] = mixer_value->value;
337 else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
338 path->setting[path_index].value.enumerated[0] = mixer_value->value;
340 path->setting[path_index].value.integer[0] = mixer_value->value;
343 if (mixer_value->index == -1) {
344 /* set all values the same */
345 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE) {
346 for (i = 0; i < num_values; i++)
347 path->setting[path_index].value.bytes[i] = mixer_value->value;
348 } else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM) {
349 for (i = 0; i < num_values; i++)
350 path->setting[path_index].value.enumerated[i] = mixer_value->value;
352 for (i = 0; i < num_values; i++)
353 path->setting[path_index].value.integer[i] = mixer_value->value;
356 /* set only one value */
357 if (path->setting[path_index].type == MIXER_CTL_TYPE_BYTE)
358 path->setting[path_index].value.bytes[mixer_value->index] = mixer_value->value;
359 else if (path->setting[path_index].type == MIXER_CTL_TYPE_ENUM)
360 path->setting[path_index].value.enumerated[mixer_value->index] = mixer_value->value;
362 path->setting[path_index].value.integer[mixer_value->index] = mixer_value->value;
368 static int path_add_path(struct audio_route *ar, struct mixer_path *path,
369 struct mixer_path *sub_path)
373 for (i = 0; i < sub_path->length; i++)
374 if (path_add_setting(ar, path, &sub_path->setting[i]) < 0)
380 static int path_apply(struct audio_route *ar, struct mixer_path *path)
383 unsigned int ctl_index;
384 struct mixer_ctl *ctl;
385 enum mixer_ctl_type type;
387 ALOGD("Apply path: %s", path->name != NULL ? path->name : "none");
388 for (i = 0; i < path->length; i++) {
389 ctl_index = path->setting[i].ctl_index;
390 ctl = index_to_ctl(ar, ctl_index);
391 type = mixer_ctl_get_type(ctl);
392 if (!is_supported_ctl_type(type))
394 size_t value_sz = sizeof_ctl_type(type);
395 memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr,
396 path->setting[i].num_values * value_sz);
402 static int path_reset(struct audio_route *ar, struct mixer_path *path)
405 unsigned int ctl_index;
406 struct mixer_ctl *ctl;
407 enum mixer_ctl_type type;
409 ALOGV("Reset path: %s", path->name != NULL ? path->name : "none");
410 for (i = 0; i < path->length; i++) {
411 ctl_index = path->setting[i].ctl_index;
412 ctl = index_to_ctl(ar, ctl_index);
413 type = mixer_ctl_get_type(ctl);
414 if (!is_supported_ctl_type(type))
416 size_t value_sz = sizeof_ctl_type(type);
417 /* reset the value(s) */
418 memcpy(ar->mixer_state[ctl_index].new_value.ptr,
419 ar->mixer_state[ctl_index].reset_value.ptr,
420 ar->mixer_state[ctl_index].num_values * value_sz);
426 /* mixer helper function */
427 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
430 unsigned int num_values = mixer_ctl_get_num_enums(ctl);
432 if (string == NULL) {
433 ALOGE("NULL enum value string passed to mixer_enum_string_to_value() for ctl %s",
434 mixer_ctl_get_name(ctl));
438 /* Search the enum strings for a particular one */
439 for (i = 0; i < num_values; i++) {
440 if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
443 if (i == num_values) {
444 ALOGE("unknown enum value string %s for ctl %s",
445 string, mixer_ctl_get_name(ctl));
451 static void start_tag(void *data, const XML_Char *tag_name,
452 const XML_Char **attr)
454 const XML_Char *attr_name = NULL;
455 const XML_Char *attr_id = NULL;
456 const XML_Char *attr_value = NULL;
457 struct config_parse_state *state = data;
458 struct audio_route *ar = state->ar;
460 unsigned int ctl_index;
461 struct mixer_ctl *ctl;
464 struct mixer_value mixer_value;
465 enum mixer_ctl_type type;
467 /* Get name, id and value attributes (these may be empty) */
468 for (i = 0; attr[i]; i += 2) {
469 if (strcmp(attr[i], "name") == 0)
470 attr_name = attr[i + 1];
471 if (strcmp(attr[i], "id") == 0)
472 attr_id = attr[i + 1];
473 else if (strcmp(attr[i], "value") == 0)
474 attr_value = attr[i + 1];
478 if (strcmp(tag_name, "path") == 0) {
479 if (attr_name == NULL) {
480 ALOGE("Unnamed path!");
482 if (state->level == 1) {
483 /* top level path: create and stash the path */
484 state->path = path_create(ar, (char *)attr_name);
485 if (state->path == NULL)
486 ALOGE("path created failed, please check the path if existed");
489 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
491 ALOGE("unable to find sub path '%s'", attr_name);
492 } else if (state->path != NULL) {
493 path_add_path(ar, state->path, sub_path);
499 else if (strcmp(tag_name, "ctl") == 0) {
500 /* Obtain the mixer ctl and value */
501 ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
503 ALOGE("Control '%s' doesn't exist - skipping", attr_name);
507 switch (mixer_ctl_get_type(ctl)) {
508 case MIXER_CTL_TYPE_BOOL:
509 case MIXER_CTL_TYPE_INT:
510 value = strtol((char *)attr_value, NULL, 0);
512 case MIXER_CTL_TYPE_BYTE:
513 value = (unsigned char) strtol((char *)attr_value, NULL, 16);
515 case MIXER_CTL_TYPE_ENUM:
516 value = mixer_enum_string_to_value(ctl, (char *)attr_value);
523 /* locate the mixer ctl in the list */
524 for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
525 if (ar->mixer_state[ctl_index].ctl == ctl)
529 if (state->level == 1) {
530 /* top level ctl (initial setting) */
532 type = mixer_ctl_get_type(ctl);
533 if (is_supported_ctl_type(type)) {
534 /* apply the new value */
536 /* set only one value */
537 id = atoi((char *)attr_id);
538 if (id < ar->mixer_state[ctl_index].num_values)
539 if (type == MIXER_CTL_TYPE_BYTE)
540 ar->mixer_state[ctl_index].new_value.bytes[id] = value;
541 else if (type == MIXER_CTL_TYPE_ENUM)
542 ar->mixer_state[ctl_index].new_value.enumerated[id] = value;
544 ar->mixer_state[ctl_index].new_value.integer[id] = value;
546 ALOGE("value id out of range for mixer ctl '%s'",
547 mixer_ctl_get_name(ctl));
549 /* set all values the same */
550 for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++)
551 if (type == MIXER_CTL_TYPE_BYTE)
552 ar->mixer_state[ctl_index].new_value.bytes[i] = value;
553 else if (type == MIXER_CTL_TYPE_ENUM)
554 ar->mixer_state[ctl_index].new_value.enumerated[i] = value;
556 ar->mixer_state[ctl_index].new_value.integer[i] = value;
560 /* nested ctl (within a path) */
561 mixer_value.ctl_index = ctl_index;
562 mixer_value.value = value;
564 mixer_value.index = atoi((char *)attr_id);
566 mixer_value.index = -1;
567 if (state->path != NULL)
568 path_add_value(ar, state->path, &mixer_value);
576 static void end_tag(void *data, const XML_Char *tag_name)
578 struct config_parse_state *state = data;
584 static int alloc_mixer_state(struct audio_route *ar)
587 unsigned int num_values;
588 struct mixer_ctl *ctl;
589 enum mixer_ctl_type type;
591 ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
592 ar->mixer_state = calloc(ar->num_mixer_ctls, sizeof(struct mixer_state));
593 if (!ar->mixer_state)
596 for (i = 0; i < ar->num_mixer_ctls; i++) {
597 ctl = mixer_get_ctl(ar->mixer, i);
598 num_values = mixer_ctl_get_num_values(ctl);
600 ar->mixer_state[i].ctl = ctl;
601 ar->mixer_state[i].num_values = num_values;
603 /* Skip unsupported types that are not supported yet in XML */
604 type = mixer_ctl_get_type(ctl);
606 if (!is_supported_ctl_type(type))
609 size_t value_sz = sizeof_ctl_type(type);
610 ar->mixer_state[i].old_value.ptr = calloc(num_values, value_sz);
611 ar->mixer_state[i].new_value.ptr = calloc(num_values, value_sz);
612 ar->mixer_state[i].reset_value.ptr = calloc(num_values, value_sz);
614 if (type == MIXER_CTL_TYPE_ENUM)
615 ar->mixer_state[i].old_value.enumerated[0] = mixer_ctl_get_value(ctl, 0);
617 mixer_ctl_get_array(ctl, ar->mixer_state[i].old_value.ptr, num_values);
619 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].old_value.ptr,
620 num_values * value_sz);
626 static void free_mixer_state(struct audio_route *ar)
629 enum mixer_ctl_type type;
631 for (i = 0; i < ar->num_mixer_ctls; i++) {
632 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
633 if (!is_supported_ctl_type(type))
636 free(ar->mixer_state[i].old_value.ptr);
637 free(ar->mixer_state[i].new_value.ptr);
638 free(ar->mixer_state[i].reset_value.ptr);
641 free(ar->mixer_state);
642 ar->mixer_state = NULL;
645 /* Update the mixer with any changed values */
646 int audio_route_update_mixer(struct audio_route *ar)
650 struct mixer_ctl *ctl;
652 for (i = 0; i < ar->num_mixer_ctls; i++) {
653 unsigned int num_values = ar->mixer_state[i].num_values;
654 enum mixer_ctl_type type;
656 ctl = ar->mixer_state[i].ctl;
658 /* Skip unsupported types */
659 type = mixer_ctl_get_type(ctl);
660 if (!is_supported_ctl_type(type))
663 /* if the value has changed, update the mixer */
664 bool changed = false;
665 if (type == MIXER_CTL_TYPE_BYTE) {
666 for (j = 0; j < num_values; j++) {
667 if (ar->mixer_state[i].old_value.bytes[j] != ar->mixer_state[i].new_value.bytes[j]) {
672 } else if (type == MIXER_CTL_TYPE_ENUM) {
673 for (j = 0; j < num_values; j++) {
674 if (ar->mixer_state[i].old_value.enumerated[j]
675 != ar->mixer_state[i].new_value.enumerated[j]) {
681 for (j = 0; j < num_values; j++) {
682 if (ar->mixer_state[i].old_value.integer[j] != ar->mixer_state[i].new_value.integer[j]) {
689 if (type == MIXER_CTL_TYPE_ENUM)
690 mixer_ctl_set_value(ctl, 0, ar->mixer_state[i].new_value.enumerated[0]);
692 mixer_ctl_set_array(ctl, ar->mixer_state[i].new_value.ptr, num_values);
694 size_t value_sz = sizeof_ctl_type(type);
695 memcpy(ar->mixer_state[i].old_value.ptr, ar->mixer_state[i].new_value.ptr,
696 num_values * value_sz);
703 /* saves the current state of the mixer, for resetting all controls */
704 static void save_mixer_state(struct audio_route *ar)
707 enum mixer_ctl_type type;
709 for (i = 0; i < ar->num_mixer_ctls; i++) {
710 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
711 if (!is_supported_ctl_type(type))
714 size_t value_sz = sizeof_ctl_type(type);
715 memcpy(ar->mixer_state[i].reset_value.ptr, ar->mixer_state[i].new_value.ptr,
716 ar->mixer_state[i].num_values * value_sz);
720 /* Reset the audio routes back to the initial state */
721 void audio_route_reset(struct audio_route *ar)
724 enum mixer_ctl_type type;
726 /* load all of the saved values */
727 for (i = 0; i < ar->num_mixer_ctls; i++) {
728 type = mixer_ctl_get_type(ar->mixer_state[i].ctl);
729 if (!is_supported_ctl_type(type))
732 size_t value_sz = sizeof_ctl_type(type);
733 memcpy(ar->mixer_state[i].new_value.ptr, ar->mixer_state[i].reset_value.ptr,
734 ar->mixer_state[i].num_values * value_sz);
738 /* Apply an audio route path by name */
739 int audio_route_apply_path(struct audio_route *ar, const char *name)
741 struct mixer_path *path;
744 ALOGE("invalid audio_route");
748 path = path_get_by_name(ar, name);
750 ALOGE("unable to find path '%s'", name);
754 path_apply(ar, path);
759 /* Reset an audio route path by name */
760 int audio_route_reset_path(struct audio_route *ar, const char *name)
762 struct mixer_path *path;
765 ALOGE("invalid audio_route");
769 path = path_get_by_name(ar, name);
771 ALOGE("unable to find path '%s'", name);
775 path_reset(ar, path);
781 * Operates on the specified path .. controls will be updated in the
782 * order listed in the XML file
784 static int audio_route_update_path(struct audio_route *ar, const char *name, bool reverse)
786 struct mixer_path *path;
791 ALOGE("invalid audio_route");
795 path = path_get_by_name(ar, name);
797 ALOGE("unable to find path '%s'", name);
801 i = reverse ? (path->length - 1) : 0;
802 end = reverse ? -1 : (int32_t)path->length;
805 unsigned int ctl_index;
806 enum mixer_ctl_type type;
808 ctl_index = path->setting[i].ctl_index;
810 struct mixer_state * ms = &ar->mixer_state[ctl_index];
812 type = mixer_ctl_get_type(ms->ctl);
813 if (!is_supported_ctl_type(type)) {
817 size_t value_sz = sizeof_ctl_type(type);
818 /* if any value has changed, update the mixer */
819 for (j = 0; j < ms->num_values; j++) {
820 if (type == MIXER_CTL_TYPE_BYTE) {
821 if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) {
822 mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values);
823 memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values * value_sz);
826 } else if (type == MIXER_CTL_TYPE_ENUM) {
827 if (ms->old_value.enumerated[j] != ms->new_value.enumerated[j]) {
828 mixer_ctl_set_value(ms->ctl, 0, ms->new_value.enumerated[0]);
829 memcpy(ms->old_value.enumerated, ms->new_value.enumerated,
830 ms->num_values * value_sz);
833 } else if (ms->old_value.integer[j] != ms->new_value.integer[j]) {
834 mixer_ctl_set_array(ms->ctl, ms->new_value.integer, ms->num_values);
835 memcpy(ms->old_value.integer, ms->new_value.integer, ms->num_values * value_sz);
840 i = reverse ? (i - 1) : (i + 1);
845 int audio_route_apply_and_update_path(struct audio_route *ar, const char *name)
847 if (audio_route_apply_path(ar, name) < 0) {
850 return audio_route_update_path(ar, name, false /*reverse*/);
853 int audio_route_reset_and_update_path(struct audio_route *ar, const char *name)
855 if (audio_route_reset_path(ar, name) < 0) {
858 return audio_route_update_path(ar, name, true /*reverse*/);
861 struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
863 struct config_parse_state state;
868 struct audio_route *ar;
870 ar = calloc(1, sizeof(struct audio_route));
874 ar->mixer = mixer_open(card);
876 ALOGE("Unable to open the mixer, aborting.");
880 ar->mixer_path = NULL;
881 ar->mixer_path_size = 0;
882 ar->num_mixer_paths = 0;
884 /* allocate space for and read current mixer settings */
885 if (alloc_mixer_state(ar) < 0)
886 goto err_mixer_state;
888 /* use the default XML path if none is provided */
889 if (xml_path == NULL)
890 xml_path = MIXER_XML_PATH;
892 file = fopen(xml_path, "r");
895 ALOGE("Failed to open %s: %s", xml_path, strerror(errno));
899 parser = XML_ParserCreate(NULL);
901 ALOGE("Failed to create XML parser");
902 goto err_parser_create;
905 memset(&state, 0, sizeof(state));
907 XML_SetUserData(parser, &state);
908 XML_SetElementHandler(parser, start_tag, end_tag);
911 buf = XML_GetBuffer(parser, BUF_SIZE);
915 bytes_read = fread(buf, 1, BUF_SIZE, file);
919 if (XML_ParseBuffer(parser, bytes_read,
920 bytes_read == 0) == XML_STATUS_ERROR) {
921 ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
929 /* apply the initial mixer values, and save them so we can reset the
930 mixer to the original values */
931 audio_route_update_mixer(ar);
932 save_mixer_state(ar);
934 XML_ParserFree(parser);
940 XML_ParserFree(parser);
944 free_mixer_state(ar);
946 mixer_close(ar->mixer);
954 void audio_route_free(struct audio_route *ar)
956 free_mixer_state(ar);
957 mixer_close(ar->mixer);