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