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