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