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