Home | History | Annotate | Download | only in audio_route
      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 struct mixer_state {
     36     struct mixer_ctl *ctl;
     37     unsigned int num_values;
     38     int *old_value;
     39     int *new_value;
     40     int *reset_value;
     41     /* If linked is true, only the first element in each array is valid */
     42     bool old_linked;
     43     bool new_linked;
     44     bool reset_linked;
     45 };
     46 
     47 struct mixer_setting {
     48     struct mixer_ctl *ctl;
     49     unsigned int num_values;
     50     int *value;
     51     /* If linked is true, only the first element in each array is valid */
     52     bool linked;
     53 };
     54 
     55 struct mixer_value {
     56     struct mixer_ctl *ctl;
     57     int index;
     58     int value;
     59 };
     60 
     61 struct mixer_path {
     62     char *name;
     63     unsigned int size;
     64     unsigned int length;
     65     struct mixer_setting *setting;
     66 };
     67 
     68 struct audio_route {
     69     struct mixer *mixer;
     70     unsigned int num_mixer_ctls;
     71     struct mixer_state *mixer_state;
     72 
     73     unsigned int mixer_path_size;
     74     unsigned int num_mixer_paths;
     75     struct mixer_path *mixer_path;
     76 };
     77 
     78 struct config_parse_state {
     79     struct audio_route *ar;
     80     struct mixer_path *path;
     81     int level;
     82 };
     83 
     84 /* path functions */
     85 
     86 static void path_print(struct mixer_path *path)
     87 {
     88     unsigned int i;
     89     unsigned int j;
     90 
     91     ALOGE("Path: %s, length: %d", path->name, path->length);
     92     for (i = 0; i < path->length; i++) {
     93         ALOGE("  id=%d: ctl=%s linked=%c", i,
     94               mixer_ctl_get_name(path->setting[i].ctl),
     95               path->setting[i].linked ? 'y' : 'n');
     96         for (j = 0; j < path->setting[i].num_values; j++)
     97             ALOGE("    id=%d value=%d", j, path->setting[i].value[j]);
     98     }
     99 }
    100 
    101 static void path_free(struct audio_route *ar)
    102 {
    103     unsigned int i;
    104 
    105     for (i = 0; i < ar->num_mixer_paths; i++) {
    106         if (ar->mixer_path[i].name)
    107             free(ar->mixer_path[i].name);
    108         if (ar->mixer_path[i].setting) {
    109             if (ar->mixer_path[i].setting->value)
    110                 free(ar->mixer_path[i].setting->value);
    111             free(ar->mixer_path[i].setting);
    112         }
    113     }
    114     free(ar->mixer_path);
    115 }
    116 
    117 static struct mixer_path *path_get_by_name(struct audio_route *ar,
    118                                            const char *name)
    119 {
    120     unsigned int i;
    121 
    122     for (i = 0; i < ar->num_mixer_paths; i++)
    123         if (strcmp(ar->mixer_path[i].name, name) == 0)
    124             return &ar->mixer_path[i];
    125 
    126     return NULL;
    127 }
    128 
    129 static struct mixer_path *path_create(struct audio_route *ar, const char *name)
    130 {
    131     struct mixer_path *new_mixer_path = NULL;
    132 
    133     if (path_get_by_name(ar, name)) {
    134         ALOGE("Path name '%s' already exists", name);
    135         return NULL;
    136     }
    137 
    138     /* check if we need to allocate more space for mixer paths */
    139     if (ar->mixer_path_size <= ar->num_mixer_paths) {
    140         if (ar->mixer_path_size == 0)
    141             ar->mixer_path_size = INITIAL_MIXER_PATH_SIZE;
    142         else
    143             ar->mixer_path_size *= 2;
    144 
    145         new_mixer_path = realloc(ar->mixer_path, ar->mixer_path_size *
    146                                  sizeof(struct mixer_path));
    147         if (new_mixer_path == NULL) {
    148             ALOGE("Unable to allocate more paths");
    149             return NULL;
    150         } else {
    151             ar->mixer_path = new_mixer_path;
    152         }
    153     }
    154 
    155     /* initialise the new mixer path */
    156     ar->mixer_path[ar->num_mixer_paths].name = strdup(name);
    157     ar->mixer_path[ar->num_mixer_paths].size = 0;
    158     ar->mixer_path[ar->num_mixer_paths].length = 0;
    159     ar->mixer_path[ar->num_mixer_paths].setting = NULL;
    160 
    161     /* return the mixer path just added, then increment number of them */
    162     return &ar->mixer_path[ar->num_mixer_paths++];
    163 }
    164 
    165 static int find_ctl_in_path(struct mixer_path *path, struct mixer_ctl *ctl)
    166 {
    167     unsigned int i;
    168 
    169     for (i = 0; i < path->length; i++)
    170         if (path->setting[i].ctl == ctl)
    171             return i;
    172 
    173     return -1;
    174 }
    175 
    176 static int alloc_path_setting(struct mixer_path *path)
    177 {
    178     struct mixer_setting *new_path_setting;
    179     int path_index;
    180 
    181     /* check if we need to allocate more space for path settings */
    182     if (path->size <= path->length) {
    183         if (path->size == 0)
    184             path->size = INITIAL_MIXER_PATH_SIZE;
    185         else
    186             path->size *= 2;
    187 
    188         new_path_setting = realloc(path->setting,
    189                                    path->size * sizeof(struct mixer_setting));
    190         if (new_path_setting == NULL) {
    191             ALOGE("Unable to allocate more path settings");
    192             return -1;
    193         } else {
    194             path->setting = new_path_setting;
    195         }
    196     }
    197 
    198     path_index = path->length;
    199     path->length++;
    200 
    201     return path_index;
    202 }
    203 
    204 static int path_add_setting(struct mixer_path *path,
    205                             struct mixer_setting *setting)
    206 {
    207     unsigned int i;
    208     int path_index;
    209 
    210     if (find_ctl_in_path(path, setting->ctl) != -1) {
    211         ALOGE("Control '%s' already exists in path '%s'",
    212               mixer_ctl_get_name(setting->ctl), path->name);
    213         return -1;
    214     }
    215 
    216     path_index = alloc_path_setting(path);
    217     if (path_index < 0)
    218         return -1;
    219 
    220     path->setting[path_index].ctl = setting->ctl;
    221     path->setting[path_index].num_values = setting->num_values;
    222     path->setting[path_index].value = malloc(setting->num_values * sizeof(int));
    223     path->setting[path_index].linked = setting->linked;
    224     if (setting->linked) {
    225         path->setting[path_index].value[0] = setting->value[0];
    226     } else {
    227         for (i = 0; i < setting->num_values; i++)
    228             path->setting[path_index].value[i] = setting->value[i];
    229     }
    230 
    231     return 0;
    232 }
    233 
    234 static int path_add_value(struct mixer_path *path,
    235                           struct mixer_value *mixer_value)
    236 {
    237     unsigned int i;
    238     int path_index;
    239     unsigned int num_values;
    240 
    241     /* Check that mixer value index is within range */
    242     num_values = mixer_ctl_get_num_values(mixer_value->ctl);
    243     if (mixer_value->index >= (int)num_values) {
    244         ALOGE("mixer index %d is out of range for '%s'", mixer_value->index,
    245               mixer_ctl_get_name(mixer_value->ctl));
    246         return -1;
    247     }
    248 
    249     path_index = find_ctl_in_path(path, mixer_value->ctl);
    250     if (path_index < 0) {
    251         /* New path */
    252 
    253         path_index = alloc_path_setting(path);
    254         if (path_index < 0)
    255             return -1;
    256 
    257         /* initialise the new path setting */
    258         path->setting[path_index].ctl = mixer_value->ctl;
    259         path->setting[path_index].num_values = num_values;
    260         path->setting[path_index].value = malloc(num_values * sizeof(int));
    261         path->setting[path_index].linked = true;
    262         path->setting[path_index].value[0] = mixer_value->value;
    263     }
    264 
    265     if (mixer_value->index == -1) {
    266         /* Linked, so only set the first value */
    267         path->setting[path_index].linked = true;
    268         path->setting[path_index].value[0] = mixer_value->value;
    269     } else {
    270         if (path->setting[path_index].linked && (num_values > 1)) {
    271             /* Unlinking the values, so duplicate them across */
    272             for (i = 1; i < num_values; i++) {
    273                 path->setting[path_index].value[i] =
    274                         path->setting[path_index].value[0];
    275             }
    276             path->setting[path_index].linked = false;
    277         }
    278         path->setting[path_index].value[mixer_value->index] = mixer_value->value;
    279     }
    280 
    281     return 0;
    282 }
    283 
    284 static int path_add_path(struct mixer_path *path, struct mixer_path *sub_path)
    285 {
    286     unsigned int i;
    287 
    288     for (i = 0; i < sub_path->length; i++)
    289         if (path_add_setting(path, &sub_path->setting[i]) < 0)
    290             return -1;
    291 
    292     return 0;
    293 }
    294 
    295 static int path_apply(struct audio_route *ar, struct mixer_path *path)
    296 {
    297     unsigned int i;
    298     unsigned int j;
    299     unsigned int ctl_index;
    300 
    301     for (i = 0; i < path->length; i++) {
    302         struct mixer_ctl *ctl = path->setting[i].ctl;
    303 
    304         /* locate the mixer ctl in the list */
    305         for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++)
    306             if (ar->mixer_state[ctl_index].ctl == ctl)
    307                 break;
    308 
    309         /* apply the new value(s) */
    310         for (j = 0; j < ar->mixer_state[ctl_index].num_values; j++) {
    311             ar->mixer_state[ctl_index].new_value[j] = path->setting[i].value[j];
    312             if (path->setting[i].linked)
    313                 break;
    314         }
    315         ar->mixer_state[ctl_index].new_linked = path->setting[i].linked;
    316     }
    317 
    318     return 0;
    319 }
    320 
    321 static int path_reset(struct audio_route *ar, struct mixer_path *path)
    322 {
    323     unsigned int i;
    324     unsigned int j;
    325     unsigned int ctl_index;
    326 
    327     for (i = 0; i < path->length; i++) {
    328         struct mixer_ctl *ctl = path->setting[i].ctl;
    329 
    330         /* locate the mixer ctl in the list */
    331         for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
    332             if (ar->mixer_state[ctl_index].ctl == ctl)
    333                 break;
    334         }
    335 
    336         /* reset the value(s) */
    337         for (j = 0; j < ar->mixer_state[ctl_index].num_values; j++) {
    338             ar->mixer_state[ctl_index].new_value[j] = ar->mixer_state[ctl_index].reset_value[j];
    339             if (ar->mixer_state[ctl_index].reset_linked)
    340                 break;
    341         }
    342         ar->mixer_state[ctl_index].new_linked = ar->mixer_state[ctl_index].reset_linked;
    343     }
    344 
    345     return 0;
    346 }
    347 
    348 /* mixer helper function */
    349 static int mixer_enum_string_to_value(struct mixer_ctl *ctl, const char *string)
    350 {
    351     unsigned int i;
    352 
    353     /* Search the enum strings for a particular one */
    354     for (i = 0; i < mixer_ctl_get_num_enums(ctl); i++) {
    355         if (strcmp(mixer_ctl_get_enum_string(ctl, i), string) == 0)
    356             break;
    357     }
    358 
    359     return i;
    360 }
    361 
    362 static void start_tag(void *data, const XML_Char *tag_name,
    363                       const XML_Char **attr)
    364 {
    365     const XML_Char *attr_name = NULL;
    366     const XML_Char *attr_id = NULL;
    367     const XML_Char *attr_value = NULL;
    368     struct config_parse_state *state = data;
    369     struct audio_route *ar = state->ar;
    370     unsigned int i;
    371     unsigned int ctl_index;
    372     struct mixer_ctl *ctl;
    373     int value;
    374     unsigned int id;
    375     struct mixer_value mixer_value;
    376 
    377     /* Get name, id and value attributes (these may be empty) */
    378     for (i = 0; attr[i]; i += 2) {
    379         if (strcmp(attr[i], "name") == 0)
    380             attr_name = attr[i + 1];
    381         if (strcmp(attr[i], "id") == 0)
    382             attr_id = attr[i + 1];
    383         else if (strcmp(attr[i], "value") == 0)
    384             attr_value = attr[i + 1];
    385     }
    386 
    387     /* Look at tags */
    388     if (strcmp(tag_name, "path") == 0) {
    389         if (attr_name == NULL) {
    390             ALOGE("Unnamed path!");
    391         } else {
    392             if (state->level == 1) {
    393                 /* top level path: create and stash the path */
    394                 state->path = path_create(ar, (char *)attr_name);
    395             } else {
    396                 /* nested path */
    397                 struct mixer_path *sub_path = path_get_by_name(ar, attr_name);
    398                 path_add_path(state->path, sub_path);
    399             }
    400         }
    401     }
    402 
    403     else if (strcmp(tag_name, "ctl") == 0) {
    404         /* Obtain the mixer ctl and value */
    405         ctl = mixer_get_ctl_by_name(ar->mixer, attr_name);
    406         switch (mixer_ctl_get_type(ctl)) {
    407         case MIXER_CTL_TYPE_BOOL:
    408         case MIXER_CTL_TYPE_INT:
    409             value = atoi((char *)attr_value);
    410             break;
    411         case MIXER_CTL_TYPE_ENUM:
    412             value = mixer_enum_string_to_value(ctl, (char *)attr_value);
    413             break;
    414         default:
    415             value = 0;
    416             break;
    417         }
    418 
    419         if (state->level == 1) {
    420             /* top level ctl (initial setting) */
    421 
    422             /* locate the mixer ctl in the list */
    423             for (ctl_index = 0; ctl_index < ar->num_mixer_ctls; ctl_index++) {
    424                 if (ar->mixer_state[ctl_index].ctl == ctl)
    425                     break;
    426             }
    427 
    428             /* apply the new value */
    429             if (attr_id) {
    430                 /* set only one value */
    431                 id = atoi((char *)attr_id);
    432                 if (id < ar->mixer_state[ctl_index].num_values) {
    433                     if (ar->mixer_state[ctl_index].new_linked) {
    434                         /*
    435                          * We're unlinking the values, so copy old_value[0] into
    436                          * all the new_value elements.
    437                          */
    438                         for (i = 0; i < ar->mixer_state[ctl_index].num_values; i++) {
    439                             ar->mixer_state[ctl_index].new_value[i] =
    440                                     ar->mixer_state[ctl_index].old_value[0];
    441                         }
    442                         ar->mixer_state[ctl_index].new_linked = false;
    443                     }
    444                     ar->mixer_state[ctl_index].new_value[id] = value;
    445                 } else {
    446                     ALOGE("value id out of range for mixer ctl '%s'",
    447                           mixer_ctl_get_name(ctl));
    448                 }
    449             } else {
    450                 ar->mixer_state[ctl_index].new_value[0] = value;
    451                 ar->mixer_state[ctl_index].new_linked = true;
    452             }
    453         } else {
    454             /* nested ctl (within a path) */
    455             mixer_value.ctl = ctl;
    456             mixer_value.value = value;
    457             if (attr_id)
    458                 mixer_value.index = atoi((char *)attr_id);
    459             else
    460                 mixer_value.index = -1;
    461             path_add_value(state->path, &mixer_value);
    462         }
    463     }
    464 
    465     state->level++;
    466 }
    467 
    468 static void end_tag(void *data, const XML_Char *tag_name)
    469 {
    470     struct config_parse_state *state = data;
    471 
    472     state->level--;
    473 }
    474 
    475 static int alloc_mixer_state(struct audio_route *ar)
    476 {
    477     unsigned int i;
    478     unsigned int j;
    479     unsigned int num_values;
    480     struct mixer_ctl *ctl;
    481     bool linked;
    482 
    483     ar->num_mixer_ctls = mixer_get_num_ctls(ar->mixer);
    484     ar->mixer_state = malloc(ar->num_mixer_ctls * sizeof(struct mixer_state));
    485     if (!ar->mixer_state)
    486         return -1;
    487 
    488     for (i = 0; i < ar->num_mixer_ctls; i++) {
    489         ctl = mixer_get_ctl(ar->mixer, i);
    490         num_values = mixer_ctl_get_num_values(ctl);
    491 
    492         ar->mixer_state[i].old_value = malloc(num_values * sizeof(int));
    493         ar->mixer_state[i].new_value = malloc(num_values * sizeof(int));
    494         ar->mixer_state[i].reset_value = malloc(num_values * sizeof(int));
    495 
    496         /*
    497          * Get all mixer values for controls with multiple values. If all
    498          * values are the same, set the linked flag.
    499          */
    500         linked = true;
    501         for (j = 0; j < num_values; j++) {
    502             ar->mixer_state[i].old_value[j] = mixer_ctl_get_value(ctl, j);
    503             ar->mixer_state[i].new_value[j] = ar->mixer_state[i].old_value[j];
    504 
    505             /*
    506              * If the next value is different from the last, set linked to
    507              * false.
    508              */
    509             if ((j > 0) && (ar->mixer_state[i].old_value[j - 1] !=
    510                             ar->mixer_state[i].old_value[j])) {
    511                 linked = false;
    512             }
    513         }
    514         ar->mixer_state[i].ctl = ctl;
    515         ar->mixer_state[i].old_linked = linked;
    516         ar->mixer_state[i].new_linked = linked;
    517         ar->mixer_state[i].num_values = num_values;
    518     }
    519 
    520     return 0;
    521 }
    522 
    523 static void free_mixer_state(struct audio_route *ar)
    524 {
    525     unsigned int i;
    526 
    527     for (i = 0; i < ar->num_mixer_ctls; i++) {
    528         free(ar->mixer_state[i].old_value);
    529         free(ar->mixer_state[i].new_value);
    530         free(ar->mixer_state[i].reset_value);
    531     }
    532 
    533     free(ar->mixer_state);
    534     ar->mixer_state = NULL;
    535 }
    536 
    537 /* Update the mixer with any changed values */
    538 int audio_route_update_mixer(struct audio_route *ar)
    539 {
    540     unsigned int i;
    541     unsigned int j;
    542 
    543     for (i = 0; i < ar->num_mixer_ctls; i++) {
    544         unsigned int num_values = ar->mixer_state[i].num_values;
    545 
    546         /* if the value has changed, update the mixer */
    547         if (ar->mixer_state[i].new_linked) {
    548             if (ar->mixer_state[i].old_value[0] != ar->mixer_state[i].new_value[0]) {
    549                 /* linked ctl, so set all ctl values the same */
    550                 for (j = 0; j < num_values; j++)
    551                     mixer_ctl_set_value(ar->mixer_state[i].ctl, j,
    552                                         ar->mixer_state[i].new_value[0]);
    553                 ar->mixer_state[i].old_value[0] = ar->mixer_state[i].new_value[0];
    554             }
    555         } else {
    556             for (j = 0; j < num_values; j++) {
    557                 /*
    558                  * unlinked ctl, so set each value if necessary.
    559                  * Note that if the new value is unlinked but the old is
    560                  * linked, only value 0 is valid, so we always have to
    561                  * update the mixer for the other values.
    562                  */
    563                 if (ar->mixer_state[i].old_linked ||
    564                     (ar->mixer_state[i].old_value[j] !=
    565                             ar->mixer_state[i].new_value[j])) {
    566                     mixer_ctl_set_value(ar->mixer_state[i].ctl, j,
    567                                         ar->mixer_state[i].new_value[j]);
    568                     ar->mixer_state[i].old_value[j] = ar->mixer_state[i].new_value[j];
    569                 }
    570             }
    571         }
    572         ar->mixer_state[i].old_linked = ar->mixer_state[i].new_linked;
    573     }
    574 
    575     return 0;
    576 }
    577 
    578 /* saves the current state of the mixer, for resetting all controls */
    579 static void save_mixer_state(struct audio_route *ar)
    580 {
    581     unsigned int i;
    582     unsigned int j;
    583 
    584     for (i = 0; i < ar->num_mixer_ctls; i++) {
    585         for (j = 0; j < ar->mixer_state[i].num_values; j++) {
    586             ar->mixer_state[i].reset_value[j] = ar->mixer_state[i].new_value[j];
    587 
    588             /* if the values are linked, only need to save value 0 */
    589             if (ar->mixer_state[i].new_linked)
    590                 break;
    591         }
    592         ar->mixer_state[i].reset_linked = ar->mixer_state[i].new_linked;
    593     }
    594 }
    595 
    596 /* Reset the audio routes back to the initial state */
    597 void audio_route_reset(struct audio_route *ar)
    598 {
    599     unsigned int i;
    600     unsigned int j;
    601 
    602     /* load all of the saved values */
    603     for (i = 0; i < ar->num_mixer_ctls; i++) {
    604         for (j = 0; j < ar->mixer_state[i].num_values; j++) {
    605             ar->mixer_state[i].new_value[j] = ar->mixer_state[i].reset_value[j];
    606 
    607             /* if the values are linked, only need to save value 0 */
    608             if (ar->mixer_state[i].reset_linked)
    609                 break;
    610         }
    611         ar->mixer_state[i].new_linked = ar->mixer_state[i].reset_linked;
    612     }
    613 }
    614 
    615 /* Apply an audio route path by name */
    616 int audio_route_apply_path(struct audio_route *ar, const char *name)
    617 {
    618     struct mixer_path *path;
    619 
    620     if (!ar) {
    621         ALOGE("invalid audio_route");
    622         return -1;
    623     }
    624 
    625     path = path_get_by_name(ar, name);
    626     if (!path) {
    627         ALOGE("unable to find path '%s'", name);
    628         return -1;
    629     }
    630 
    631     path_apply(ar, path);
    632 
    633     return 0;
    634 }
    635 
    636 /* Reset an audio route path by name */
    637 int audio_route_reset_path(struct audio_route *ar, const char *name)
    638 {
    639     struct mixer_path *path;
    640 
    641     if (!ar) {
    642         ALOGE("invalid audio_route");
    643         return -1;
    644     }
    645 
    646     path = path_get_by_name(ar, name);
    647     if (!path) {
    648         ALOGE("unable to find path '%s'", name);
    649         return -1;
    650     }
    651 
    652     path_reset(ar, path);
    653 
    654     return 0;
    655 }
    656 
    657 struct audio_route *audio_route_init(unsigned int card, const char *xml_path)
    658 {
    659     struct config_parse_state state;
    660     XML_Parser parser;
    661     FILE *file;
    662     int bytes_read;
    663     void *buf;
    664     int i;
    665     struct audio_route *ar;
    666 
    667     ar = calloc(1, sizeof(struct audio_route));
    668     if (!ar)
    669         goto err_calloc;
    670 
    671     ar->mixer = mixer_open(card);
    672     if (!ar->mixer) {
    673         ALOGE("Unable to open the mixer, aborting.");
    674         goto err_mixer_open;
    675     }
    676 
    677     ar->mixer_path = NULL;
    678     ar->mixer_path_size = 0;
    679     ar->num_mixer_paths = 0;
    680 
    681     /* allocate space for and read current mixer settings */
    682     if (alloc_mixer_state(ar) < 0)
    683         goto err_mixer_state;
    684 
    685     /* use the default XML path if none is provided */
    686     if (xml_path == NULL)
    687         xml_path = MIXER_XML_PATH;
    688 
    689     file = fopen(xml_path, "r");
    690 
    691     if (!file) {
    692         ALOGE("Failed to open %s", xml_path);
    693         goto err_fopen;
    694     }
    695 
    696     parser = XML_ParserCreate(NULL);
    697     if (!parser) {
    698         ALOGE("Failed to create XML parser");
    699         goto err_parser_create;
    700     }
    701 
    702     memset(&state, 0, sizeof(state));
    703     state.ar = ar;
    704     XML_SetUserData(parser, &state);
    705     XML_SetElementHandler(parser, start_tag, end_tag);
    706 
    707     for (;;) {
    708         buf = XML_GetBuffer(parser, BUF_SIZE);
    709         if (buf == NULL)
    710             goto err_parse;
    711 
    712         bytes_read = fread(buf, 1, BUF_SIZE, file);
    713         if (bytes_read < 0)
    714             goto err_parse;
    715 
    716         if (XML_ParseBuffer(parser, bytes_read,
    717                             bytes_read == 0) == XML_STATUS_ERROR) {
    718             ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH);
    719             goto err_parse;
    720         }
    721 
    722         if (bytes_read == 0)
    723             break;
    724     }
    725 
    726     /* apply the initial mixer values, and save them so we can reset the
    727        mixer to the original values */
    728     audio_route_update_mixer(ar);
    729     save_mixer_state(ar);
    730 
    731     XML_ParserFree(parser);
    732     fclose(file);
    733     return ar;
    734 
    735 err_parse:
    736     XML_ParserFree(parser);
    737 err_parser_create:
    738     fclose(file);
    739 err_fopen:
    740     free_mixer_state(ar);
    741 err_mixer_state:
    742     mixer_close(ar->mixer);
    743 err_mixer_open:
    744     free(ar);
    745     ar = NULL;
    746 err_calloc:
    747     return NULL;
    748 }
    749 
    750 void audio_route_free(struct audio_route *ar)
    751 {
    752     free_mixer_state(ar);
    753     mixer_close(ar->mixer);
    754     free(ar);
    755 }
    756