Home | History | Annotate | Download | only in hal
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15 */
     16 
     17 #define LOG_TAG "platform_info"
     18 #define LOG_NDDEBUG 0
     19 
     20 #include <errno.h>
     21 #include <stdio.h>
     22 #include <expat.h>
     23 #include <log/log.h>
     24 #include <audio_hw.h>
     25 #include "platform_api.h"
     26 #include <platform.h>
     27 #include <math.h>
     28 
     29 typedef enum {
     30     ROOT,
     31     ACDB,
     32     PCM_ID,
     33     BACKEND_NAME,
     34     CONFIG_PARAMS,
     35     OPERATOR_SPECIFIC,
     36     GAIN_LEVEL_MAPPING,
     37     APP_TYPE,
     38     MICROPHONE_CHARACTERISTIC,
     39     SND_DEVICES,
     40     INPUT_SND_DEVICE,
     41     INPUT_SND_DEVICE_TO_MIC_MAPPING,
     42     SND_DEV,
     43     MIC_INFO,
     44     ACDB_METAINFO_KEY,
     45 } section_t;
     46 
     47 typedef void (* section_process_fn)(const XML_Char **attr);
     48 
     49 static void process_acdb_id(const XML_Char **attr);
     50 static void process_pcm_id(const XML_Char **attr);
     51 static void process_backend_name(const XML_Char **attr);
     52 static void process_config_params(const XML_Char **attr);
     53 static void process_root(const XML_Char **attr);
     54 static void process_operator_specific(const XML_Char **attr);
     55 static void process_gain_db_to_level_map(const XML_Char **attr);
     56 static void process_app_type(const XML_Char **attr);
     57 static void process_microphone_characteristic(const XML_Char **attr);
     58 static void process_snd_dev(const XML_Char **attr);
     59 static void process_mic_info(const XML_Char **attr);
     60 static void process_acdb_metainfo_key(const XML_Char **attr);
     61 
     62 static section_process_fn section_table[] = {
     63     [ROOT] = process_root,
     64     [ACDB] = process_acdb_id,
     65     [PCM_ID] = process_pcm_id,
     66     [BACKEND_NAME] = process_backend_name,
     67     [CONFIG_PARAMS] = process_config_params,
     68     [OPERATOR_SPECIFIC] = process_operator_specific,
     69     [GAIN_LEVEL_MAPPING] = process_gain_db_to_level_map,
     70     [APP_TYPE] = process_app_type,
     71     [MICROPHONE_CHARACTERISTIC] = process_microphone_characteristic,
     72     [SND_DEV] = process_snd_dev,
     73     [MIC_INFO] = process_mic_info,
     74     [ACDB_METAINFO_KEY] = process_acdb_metainfo_key,
     75 };
     76 
     77 static set_parameters_fn set_parameters = &platform_set_parameters;
     78 
     79 static section_t section;
     80 
     81 struct platform_info {
     82     bool              do_full_parse;
     83     void             *platform;
     84     struct str_parms *kvpairs;
     85 };
     86 
     87 static struct platform_info my_data = {true, NULL, NULL};
     88 
     89 struct audio_string_to_enum {
     90     const char* name;
     91     unsigned int value;
     92 };
     93 
     94 static snd_device_t in_snd_device;
     95 
     96 static const struct audio_string_to_enum mic_locations[AUDIO_MICROPHONE_LOCATION_CNT] = {
     97     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_UNKNOWN),
     98     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_MAINBODY),
     99     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_MAINBODY_MOVABLE),
    100     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_PERIPHERAL),
    101 };
    102 
    103 static const struct audio_string_to_enum mic_directionalities[AUDIO_MICROPHONE_DIRECTIONALITY_CNT] = {
    104     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_OMNI),
    105     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_BI_DIRECTIONAL),
    106     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN),
    107     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_CARDIOID),
    108     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_HYPER_CARDIOID),
    109     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID),
    110 };
    111 
    112 static const struct audio_string_to_enum mic_channel_mapping[AUDIO_MICROPHONE_CHANNEL_MAPPING_CNT] = {
    113     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED),
    114     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_CHANNEL_MAPPING_DIRECT),
    115     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_CHANNEL_MAPPING_PROCESSED),
    116 };
    117 
    118 static const struct audio_string_to_enum device_in_types[] = {
    119     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AMBIENT),
    120     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_COMMUNICATION),
    121     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
    122     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
    123     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
    124     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
    125     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI),
    126     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
    127     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
    128     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
    129     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
    130     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
    131     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
    132     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
    133     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
    134     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
    135     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
    136     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LINE),
    137     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_SPDIF),
    138     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
    139     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
    140     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_IP),
    141     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUS),
    142     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_PROXY),
    143     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_HEADSET),
    144     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_BLE),
    145     AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DEFAULT),
    146 };
    147 
    148 enum {
    149     AUDIO_MICROPHONE_CHARACTERISTIC_NONE = 0u, // 0x0
    150     AUDIO_MICROPHONE_CHARACTERISTIC_SENSITIVITY = 1u, // 0x1
    151     AUDIO_MICROPHONE_CHARACTERISTIC_MAX_SPL = 2u, // 0x2
    152     AUDIO_MICROPHONE_CHARACTERISTIC_MIN_SPL = 4u, // 0x4
    153     AUDIO_MICROPHONE_CHARACTERISTIC_ORIENTATION = 8u, // 0x8
    154     AUDIO_MICROPHONE_CHARACTERISTIC_GEOMETRIC_LOCATION = 16u, // 0x10
    155     AUDIO_MICROPHONE_CHARACTERISTIC_ALL = 31u, /* ((((SENSITIVITY | MAX_SPL) | MIN_SPL)
    156                                                   | ORIENTATION) | GEOMETRIC_LOCATION) */
    157 };
    158 
    159 static bool find_enum_by_string(const struct audio_string_to_enum * table, const char * name,
    160                                 int32_t len, unsigned int *value)
    161 {
    162     if (table == NULL) {
    163         ALOGE("%s: table is NULL", __func__);
    164         return false;
    165     }
    166 
    167     if (name == NULL) {
    168         ALOGE("null key");
    169         return false;
    170     }
    171 
    172     for (int i = 0; i < len; i++) {
    173         if (!strcmp(table[i].name, name)) {
    174             *value = table[i].value;
    175             return true;
    176         }
    177     }
    178     return false;
    179 }
    180 
    181 /*
    182  * <audio_platform_info>
    183  * <acdb_ids>
    184  * <device name="???" acdb_id="???"/>
    185  * ...
    186  * ...
    187  * </acdb_ids>
    188  * <backend_names>
    189  * <device name="???" backend="???"/>
    190  * ...
    191  * ...
    192  * </backend_names>
    193  * <pcm_ids>
    194  * <usecase name="???" type="in/out" id="???"/>
    195  * ...
    196  * ...
    197  * </pcm_ids>
    198  * <config_params>
    199  *      <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/>
    200  *      <param key="operator_info" value="tmus;aa;bb;cc"/>
    201  *      <param key="operator_info" value="sprint;xx;yy;zz"/>
    202  *      ...
    203  *      ...
    204  * </config_params>
    205  *
    206  * <operator_specific>
    207  *      <device name="???" operator="???" mixer_path="???" acdb_id="???"/>
    208  *      ...
    209  *      ...
    210  * </operator_specific>
    211  *
    212  * </audio_platform_info>
    213  */
    214 
    215 static void process_root(const XML_Char **attr __unused)
    216 {
    217 }
    218 
    219 /* mapping from usecase to pcm dev id */
    220 static void process_pcm_id(const XML_Char **attr)
    221 {
    222     int index;
    223 
    224     if (strcmp(attr[0], "name") != 0) {
    225         ALOGE("%s: 'name' not found, no pcm_id set!", __func__);
    226         goto done;
    227     }
    228 
    229     index = platform_get_usecase_index((char *)attr[1]);
    230     if (index < 0) {
    231         ALOGE("%s: usecase %s in %s not found!",
    232               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    233         goto done;
    234     }
    235 
    236     if (strcmp(attr[2], "type") != 0) {
    237         ALOGE("%s: usecase type not mentioned", __func__);
    238         goto done;
    239     }
    240 
    241     int type = -1;
    242 
    243     if (!strcasecmp((char *)attr[3], "in")) {
    244         type = 1;
    245     } else if (!strcasecmp((char *)attr[3], "out")) {
    246         type = 0;
    247     } else {
    248         ALOGE("%s: type must be IN or OUT", __func__);
    249         goto done;
    250     }
    251 
    252     if (strcmp(attr[4], "id") != 0) {
    253         ALOGE("%s: usecase id not mentioned", __func__);
    254         goto done;
    255     }
    256 
    257     int id = atoi((char *)attr[5]);
    258 
    259     if (platform_set_usecase_pcm_id(index, type, id) < 0) {
    260         ALOGE("%s: usecase %s in %s, type %d id %d was not set!",
    261               __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id);
    262         goto done;
    263     }
    264 
    265 done:
    266     return;
    267 }
    268 
    269 /* backend to be used for a device */
    270 static void process_backend_name(const XML_Char **attr)
    271 {
    272     int index;
    273     char *hw_interface = NULL;
    274 
    275     if (strcmp(attr[0], "name") != 0) {
    276         ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
    277         goto done;
    278     }
    279 
    280     index = platform_get_snd_device_index((char *)attr[1]);
    281     if (index < 0) {
    282         ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
    283               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    284         goto done;
    285     }
    286 
    287     if (strcmp(attr[2], "backend") != 0) {
    288         ALOGE("%s: Device %s in %s has no backed set!",
    289               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    290         goto done;
    291     }
    292 
    293     if (attr[4] != NULL) {
    294         if (strcmp(attr[4], "interface") != 0) {
    295             hw_interface = NULL;
    296         } else {
    297             hw_interface = (char *)attr[5];
    298         }
    299     }
    300 
    301     if (platform_set_snd_device_backend(index, attr[3], hw_interface) < 0) {
    302         ALOGE("%s: Device %s in %s, backend %s was not set!",
    303               __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]);
    304         goto done;
    305     }
    306 
    307 done:
    308     return;
    309 }
    310 
    311 static void process_gain_db_to_level_map(const XML_Char **attr)
    312 {
    313     struct amp_db_and_gain_table tbl_entry;
    314 
    315     if ((strcmp(attr[0], "db") != 0) ||
    316         (strcmp(attr[2], "level") != 0)) {
    317         ALOGE("%s: invalid attribute passed  %s %sexpected amp db level",
    318                __func__, attr[0], attr[2]);
    319         goto done;
    320     }
    321 
    322     tbl_entry.db = atof(attr[1]);
    323     tbl_entry.amp = exp(tbl_entry.db * 0.115129f);
    324     tbl_entry.level = atoi(attr[3]);
    325 
    326     //custome level should be > 0. Level 0 is fixed for default
    327     CHECK(tbl_entry.level > 0);
    328 
    329     ALOGV("%s: amp [%f]  db [%f] level [%d]", __func__,
    330            tbl_entry.amp, tbl_entry.db, tbl_entry.level);
    331     platform_add_gain_level_mapping(&tbl_entry);
    332 
    333 done:
    334     return;
    335 }
    336 
    337 static void process_acdb_id(const XML_Char **attr)
    338 {
    339     int index;
    340 
    341     if (strcmp(attr[0], "name") != 0) {
    342         ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
    343         goto done;
    344     }
    345 
    346     index = platform_get_snd_device_index((char *)attr[1]);
    347     if (index < 0) {
    348         ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
    349               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    350         goto done;
    351     }
    352 
    353     if (strcmp(attr[2], "acdb_id") != 0) {
    354         ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!",
    355               __func__, attr[1], PLATFORM_INFO_XML_PATH);
    356         goto done;
    357     }
    358 
    359     if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
    360         ALOGE("%s: Device %s in %s, ACDB ID %d was not set!",
    361               __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3]));
    362         goto done;
    363     }
    364 
    365 done:
    366     return;
    367 }
    368 
    369 
    370 static void process_operator_specific(const XML_Char **attr)
    371 {
    372     snd_device_t snd_device = SND_DEVICE_NONE;
    373 
    374     if (strcmp(attr[0], "name") != 0) {
    375         ALOGE("%s: 'name' not found", __func__);
    376         goto done;
    377     }
    378 
    379     snd_device = platform_get_snd_device_index((char *)attr[1]);
    380     if (snd_device < 0) {
    381         ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
    382               __func__, (char *)attr[3], PLATFORM_INFO_XML_PATH);
    383         goto done;
    384     }
    385 
    386     if (strcmp(attr[2], "operator") != 0) {
    387         ALOGE("%s: 'operator' not found", __func__);
    388         goto done;
    389     }
    390 
    391     if (strcmp(attr[4], "mixer_path") != 0) {
    392         ALOGE("%s: 'mixer_path' not found", __func__);
    393         goto done;
    394     }
    395 
    396     if (strcmp(attr[6], "acdb_id") != 0) {
    397         ALOGE("%s: 'acdb_id' not found", __func__);
    398         goto done;
    399     }
    400 
    401     platform_add_operator_specific_device(snd_device, (char *)attr[3], (char *)attr[5], atoi((char *)attr[7]));
    402 
    403 done:
    404     return;
    405 }
    406 
    407 /* platform specific configuration key-value pairs */
    408 static void process_config_params(const XML_Char **attr)
    409 {
    410     if (strcmp(attr[0], "key") != 0) {
    411         ALOGE("%s: 'key' not found", __func__);
    412         goto done;
    413     }
    414 
    415     if (strcmp(attr[2], "value") != 0) {
    416         ALOGE("%s: 'value' not found", __func__);
    417         goto done;
    418     }
    419 
    420     str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
    421     set_parameters(my_data.platform, my_data.kvpairs);
    422 done:
    423     return;
    424 }
    425 
    426 static void process_app_type(const XML_Char **attr)
    427 {
    428     if (strcmp(attr[0], "uc_type")) {
    429         ALOGE("%s: uc_type not found", __func__);
    430         goto done;
    431     }
    432 
    433     if (strcmp(attr[2], "mode")) {
    434         ALOGE("%s: mode not found", __func__);
    435         goto done;
    436     }
    437 
    438     if (strcmp(attr[4], "bit_width")) {
    439         ALOGE("%s: bit_width not found", __func__);
    440         goto done;
    441     }
    442 
    443     if (strcmp(attr[6], "id")) {
    444         ALOGE("%s: id not found", __func__);
    445         goto done;
    446     }
    447 
    448     if (strcmp(attr[8], "max_rate")) {
    449         ALOGE("%s: max rate not found", __func__);
    450         goto done;
    451     }
    452 
    453     platform_add_app_type(attr[1], attr[3], atoi(attr[5]), atoi(attr[7]),
    454                           atoi(attr[9]));
    455 done:
    456     return;
    457 }
    458 
    459 static void process_microphone_characteristic(const XML_Char **attr) {
    460     struct audio_microphone_characteristic_t microphone;
    461     uint32_t curIdx = 0;
    462 
    463     if (strcmp(attr[curIdx++], "valid_mask")) {
    464         ALOGE("%s: valid_mask not found", __func__);
    465         goto done;
    466     }
    467     uint32_t valid_mask = atoi(attr[curIdx++]);
    468 
    469     if (strcmp(attr[curIdx++], "device_id")) {
    470         ALOGE("%s: device_id not found", __func__);
    471         goto done;
    472     }
    473     if (strlen(attr[curIdx]) > AUDIO_MICROPHONE_ID_MAX_LEN) {
    474         ALOGE("%s: device_id %s is too long", __func__, attr[curIdx]);
    475         goto done;
    476     }
    477     strcpy(microphone.device_id, attr[curIdx++]);
    478 
    479     if (strcmp(attr[curIdx++], "type")) {
    480         ALOGE("%s: device not found", __func__);
    481         goto done;
    482     }
    483     if (!find_enum_by_string(device_in_types, (char*)attr[curIdx++],
    484             ARRAY_SIZE(device_in_types), &microphone.device)) {
    485         ALOGE("%s: type %s in %s not found!",
    486               __func__, attr[--curIdx], PLATFORM_INFO_XML_PATH);
    487         goto done;
    488     }
    489 
    490     if (strcmp(attr[curIdx++], "address")) {
    491         ALOGE("%s: address not found", __func__);
    492         goto done;
    493     }
    494     if (strlen(attr[curIdx]) > AUDIO_DEVICE_MAX_ADDRESS_LEN) {
    495         ALOGE("%s, address %s is too long", __func__, attr[curIdx]);
    496         goto done;
    497     }
    498     strcpy(microphone.address, attr[curIdx++]);
    499     if (strlen(microphone.address) == 0) {
    500         // If the address is empty, populate the address according to device type.
    501         if (microphone.device == AUDIO_DEVICE_IN_BUILTIN_MIC) {
    502             strcpy(microphone.address, AUDIO_BOTTOM_MICROPHONE_ADDRESS);
    503         } else if (microphone.device == AUDIO_DEVICE_IN_BACK_MIC) {
    504             strcpy(microphone.address, AUDIO_BACK_MICROPHONE_ADDRESS);
    505         }
    506     }
    507 
    508     if (strcmp(attr[curIdx++], "location")) {
    509         ALOGE("%s: location not found", __func__);
    510         goto done;
    511     }
    512     if (!find_enum_by_string(mic_locations, (char*)attr[curIdx++],
    513             AUDIO_MICROPHONE_LOCATION_CNT, &microphone.location)) {
    514         ALOGE("%s: location %s in %s not found!",
    515               __func__, attr[--curIdx], PLATFORM_INFO_XML_PATH);
    516         goto done;
    517     }
    518 
    519     if (strcmp(attr[curIdx++], "group")) {
    520         ALOGE("%s: group not found", __func__);
    521         goto done;
    522     }
    523     microphone.group = atoi(attr[curIdx++]);
    524 
    525     if (strcmp(attr[curIdx++], "index_in_the_group")) {
    526         ALOGE("%s: index_in_the_group not found", __func__);
    527         goto done;
    528     }
    529     microphone.index_in_the_group = atoi(attr[curIdx++]);
    530 
    531     if (strcmp(attr[curIdx++], "directionality")) {
    532         ALOGE("%s: directionality not found", __func__);
    533         goto done;
    534     }
    535     if (!find_enum_by_string(mic_directionalities, (char*)attr[curIdx++],
    536                 AUDIO_MICROPHONE_DIRECTIONALITY_CNT, &microphone.directionality)) {
    537         ALOGE("%s: directionality %s in %s not found!",
    538               __func__, attr[--curIdx], PLATFORM_INFO_XML_PATH);
    539         goto done;
    540     }
    541 
    542     if (strcmp(attr[curIdx++], "num_frequency_responses")) {
    543         ALOGE("%s: num_frequency_responses not found", __func__);
    544         goto done;
    545     }
    546     microphone.num_frequency_responses = atoi(attr[curIdx++]);
    547     if (microphone.num_frequency_responses > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) {
    548         ALOGE("%s: num_frequency_responses is too large", __func__);
    549         goto done;
    550     }
    551     if (microphone.num_frequency_responses > 0) {
    552         if (strcmp(attr[curIdx++], "frequencies")) {
    553             ALOGE("%s: frequencies not found", __func__);
    554             goto done;
    555         }
    556         char *token = strtok((char *)attr[curIdx++], " ");
    557         uint32_t num_frequencies = 0;
    558         while (token) {
    559             microphone.frequency_responses[0][num_frequencies++] = atof(token);
    560             if (num_frequencies > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) {
    561                 ALOGE("%s: num %u of frequency is too large", __func__, num_frequencies);
    562                 goto done;
    563             }
    564             token = strtok(NULL, " ");
    565         }
    566 
    567         if (strcmp(attr[curIdx++], "responses")) {
    568             ALOGE("%s: responses not found", __func__);
    569             goto done;
    570         }
    571         token = strtok((char *)attr[curIdx++], " ");
    572         uint32_t num_responses = 0;
    573         while (token) {
    574             microphone.frequency_responses[1][num_responses++] = atof(token);
    575             if (num_responses > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) {
    576                 ALOGE("%s: num %u of response is too large", __func__, num_responses);
    577                 goto done;
    578             }
    579             token = strtok(NULL, " ");
    580         }
    581 
    582         if (num_frequencies != num_responses
    583                 || num_frequencies != microphone.num_frequency_responses) {
    584             ALOGE("%s: num of frequency and response not match: %u, %u, %u",
    585                   __func__, num_frequencies, num_responses, microphone.num_frequency_responses);
    586             goto done;
    587         }
    588     }
    589 
    590     if (valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_SENSITIVITY) {
    591         if (strcmp(attr[curIdx++], "sensitivity")) {
    592             ALOGE("%s: sensitivity not found", __func__);
    593             goto done;
    594         }
    595         microphone.sensitivity = atof(attr[curIdx++]);
    596     } else {
    597         microphone.sensitivity = AUDIO_MICROPHONE_SENSITIVITY_UNKNOWN;
    598     }
    599 
    600     if (valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_MAX_SPL) {
    601         if (strcmp(attr[curIdx++], "max_spl")) {
    602             ALOGE("%s: max_spl not found", __func__);
    603             goto done;
    604         }
    605         microphone.max_spl = atof(attr[curIdx++]);
    606     } else {
    607         microphone.max_spl = AUDIO_MICROPHONE_SPL_UNKNOWN;
    608     }
    609 
    610     if (valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_MIN_SPL) {
    611         if (strcmp(attr[curIdx++], "min_spl")) {
    612             ALOGE("%s: min_spl not found", __func__);
    613             goto done;
    614         }
    615         microphone.min_spl = atof(attr[curIdx++]);
    616     } else {
    617         microphone.min_spl = AUDIO_MICROPHONE_SPL_UNKNOWN;
    618     }
    619 
    620     if (valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_ORIENTATION) {
    621         if (strcmp(attr[curIdx++], "orientation")) {
    622             ALOGE("%s: orientation not found", __func__);
    623             goto done;
    624         }
    625         char *token = strtok((char *)attr[curIdx++], " ");
    626         float orientation[3];
    627         uint32_t idx = 0;
    628         while (token) {
    629             orientation[idx++] = atof(token);
    630             if (idx > 3) {
    631                 ALOGE("%s: orientation invalid", __func__);
    632                 goto done;
    633             }
    634             token = strtok(NULL, " ");
    635         }
    636         if (idx != 3) {
    637             ALOGE("%s: orientation invalid", __func__);
    638             goto done;
    639         }
    640         microphone.orientation.x = orientation[0];
    641         microphone.orientation.y = orientation[1];
    642         microphone.orientation.z = orientation[2];
    643     } else {
    644         microphone.orientation.x = 0.0f;
    645         microphone.orientation.y = 0.0f;
    646         microphone.orientation.z = 0.0f;
    647     }
    648 
    649     if (valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_GEOMETRIC_LOCATION) {
    650         if (strcmp(attr[curIdx++], "geometric_location")) {
    651             ALOGE("%s: geometric_location not found", __func__);
    652             goto done;
    653         }
    654         char *token = strtok((char *)attr[curIdx++], " ");
    655         float geometric_location[3];
    656         uint32_t idx = 0;
    657         while (token) {
    658             geometric_location[idx++] = atof(token);
    659             if (idx > 3) {
    660                 ALOGE("%s: geometric_location invalid", __func__);
    661                 goto done;
    662             }
    663             token = strtok(NULL, " ");
    664         }
    665         if (idx != 3) {
    666             ALOGE("%s: geometric_location invalid", __func__);
    667             goto done;
    668         }
    669         microphone.geometric_location.x = geometric_location[0];
    670         microphone.geometric_location.y = geometric_location[1];
    671         microphone.geometric_location.z = geometric_location[2];
    672     } else {
    673         microphone.geometric_location.x = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
    674         microphone.geometric_location.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
    675         microphone.geometric_location.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
    676     }
    677 
    678     platform_set_microphone_characteristic(my_data.platform, microphone);
    679 done:
    680     return;
    681 }
    682 
    683 static void process_snd_dev(const XML_Char **attr)
    684 {
    685     uint32_t curIdx = 0;
    686     in_snd_device = SND_DEVICE_NONE;
    687 
    688     if (strcmp(attr[curIdx++], "in_snd_device")) {
    689         ALOGE("%s: snd_device not found", __func__);
    690         return;
    691     }
    692     in_snd_device = platform_get_snd_device_index((char *)attr[curIdx++]);
    693     if (in_snd_device < SND_DEVICE_IN_BEGIN ||
    694             in_snd_device >= SND_DEVICE_IN_END) {
    695         ALOGE("%s: Sound device not valid", __func__);
    696         in_snd_device = SND_DEVICE_NONE;
    697     }
    698 
    699     return;
    700 }
    701 
    702 static void process_mic_info(const XML_Char **attr)
    703 {
    704     uint32_t curIdx = 0;
    705     struct mic_info microphone;
    706 
    707     memset(&microphone.channel_mapping, AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED,
    708                sizeof(microphone.channel_mapping));
    709 
    710     if (strcmp(attr[curIdx++], "mic_device_id")) {
    711         ALOGE("%s: mic_device_id not found", __func__);
    712         goto on_error;
    713     }
    714     strlcpy(microphone.device_id,
    715                 (char *)attr[curIdx++], AUDIO_MICROPHONE_ID_MAX_LEN);
    716 
    717     if (strcmp(attr[curIdx++], "channel_mapping")) {
    718         ALOGE("%s: channel_mapping not found", __func__);
    719         goto on_error;
    720     }
    721     const char *token = strtok((char *)attr[curIdx++], " ");
    722     uint32_t idx = 0;
    723     while (token) {
    724         if (!find_enum_by_string(mic_channel_mapping, token,
    725                 AUDIO_MICROPHONE_CHANNEL_MAPPING_CNT,
    726                 &microphone.channel_mapping[idx++])) {
    727             ALOGE("%s: channel_mapping %s in %s not found!",
    728                       __func__, attr[--curIdx], PLATFORM_INFO_XML_PATH);
    729             goto on_error;
    730         }
    731         token = strtok(NULL, " ");
    732     }
    733     microphone.channel_count = idx;
    734 
    735     platform_set_microphone_map(my_data.platform, in_snd_device,
    736                                     &microphone);
    737     return;
    738 on_error:
    739     in_snd_device = SND_DEVICE_NONE;
    740     return;
    741 }
    742 
    743 /* process acdb meta info key value */
    744 static void process_acdb_metainfo_key(const XML_Char **attr)
    745 {
    746     if (strcmp(attr[0], "name") != 0) {
    747         ALOGE("%s: 'name' not found", __func__);
    748         goto done;
    749     }
    750     if (strcmp(attr[2], "value") != 0) {
    751         ALOGE("%s: 'value' not found", __func__);
    752         goto done;
    753     }
    754 
    755     int key = atoi((char *)attr[3]);
    756     if (platform_set_acdb_metainfo_key(my_data.platform,
    757                                        (char*)attr[1], key) < 0) {
    758         ALOGE("%s: key %d was not set!", __func__, key);
    759     }
    760 
    761 done:
    762     return;
    763 }
    764 
    765 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
    766                       const XML_Char **attr)
    767 {
    768     const XML_Char              *attr_name = NULL;
    769     const XML_Char              *attr_value = NULL;
    770     unsigned int                i;
    771 
    772 
    773     if (my_data.do_full_parse) {
    774         if (strcmp(tag_name, "acdb_ids") == 0) {
    775             section = ACDB;
    776         } else if (strcmp(tag_name, "pcm_ids") == 0) {
    777             section = PCM_ID;
    778         } else if (strcmp(tag_name, "backend_names") == 0) {
    779             section = BACKEND_NAME;
    780         } else if (strcmp(tag_name, "config_params") == 0) {
    781             section = CONFIG_PARAMS;
    782         } else if (strcmp(tag_name, "operator_specific") == 0) {
    783             section = OPERATOR_SPECIFIC;
    784         } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
    785             section = GAIN_LEVEL_MAPPING;
    786         } else if (strcmp(tag_name, "app_types") == 0) {
    787             section = APP_TYPE;
    788         } else if (strcmp(tag_name, "microphone_characteristics") == 0) {
    789             section = MICROPHONE_CHARACTERISTIC;
    790         } else if (strcmp(tag_name, "snd_devices") == 0) {
    791             section = SND_DEVICES;
    792         } else if(strcmp(tag_name, "acdb_metainfo_key") == 0) {
    793             section = ACDB_METAINFO_KEY;
    794         } else if (strcmp(tag_name, "device") == 0) {
    795             if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
    796                 ALOGE("device tag only supported for acdb/backend names");
    797                 return;
    798             }
    799 
    800             /* call into process function for the current section */
    801             section_process_fn fn = section_table[section];
    802             fn(attr);
    803         } else if (strcmp(tag_name, "usecase") == 0) {
    804             if (section != PCM_ID) {
    805                 ALOGE("usecase tag only supported with PCM_ID section");
    806                 return;
    807             }
    808 
    809             section_process_fn fn = section_table[PCM_ID];
    810             fn(attr);
    811         } else if (strcmp(tag_name, "param") == 0) {
    812             if ((section != CONFIG_PARAMS) && (section != ACDB_METAINFO_KEY)) {
    813                 ALOGE("param tag only supported with CONFIG_PARAMS section");
    814                 return;
    815             }
    816 
    817             section_process_fn fn = section_table[section];
    818             fn(attr);
    819         } else if (strcmp(tag_name, "gain_level_map") == 0) {
    820             if (section != GAIN_LEVEL_MAPPING) {
    821                 ALOGE("gain_level_map tag only supported with GAIN_LEVEL_MAPPING section");
    822                 return;
    823             }
    824 
    825             section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
    826             fn(attr);
    827         } else if (!strcmp(tag_name, "app")) {
    828             if (section != APP_TYPE) {
    829                 ALOGE("app tag only valid in section APP_TYPE");
    830                 return;
    831             }
    832 
    833             section_process_fn fn = section_table[APP_TYPE];
    834             fn(attr);
    835         } else if (strcmp(tag_name, "microphone") == 0) {
    836             if (section != MICROPHONE_CHARACTERISTIC) {
    837                 ALOGE("microphone tag only supported with MICROPHONE_CHARACTERISTIC section");
    838                 return;
    839             }
    840             section_process_fn fn = section_table[MICROPHONE_CHARACTERISTIC];
    841             fn(attr);
    842         } else if (strcmp(tag_name, "input_snd_device") == 0) {
    843             if (section != SND_DEVICES) {
    844                 ALOGE("input_snd_device tag only supported with SND_DEVICES section");
    845                 return;
    846             }
    847             section = INPUT_SND_DEVICE;
    848         } else if (strcmp(tag_name, "input_snd_device_mic_mapping") == 0) {
    849             if (section != INPUT_SND_DEVICE) {
    850                 ALOGE("input_snd_device_mic_mapping tag only supported with INPUT_SND_DEVICE section");
    851                 return;
    852             }
    853             section = INPUT_SND_DEVICE_TO_MIC_MAPPING;
    854         } else if (strcmp(tag_name, "snd_dev") == 0) {
    855             if (section != INPUT_SND_DEVICE_TO_MIC_MAPPING) {
    856                 ALOGE("snd_dev tag only supported with INPUT_SND_DEVICE_TO_MIC_MAPPING section");
    857                 return;
    858             }
    859             section_process_fn fn = section_table[SND_DEV];
    860             fn(attr);
    861         } else if (strcmp(tag_name, "mic_info") == 0) {
    862             if (section != INPUT_SND_DEVICE_TO_MIC_MAPPING) {
    863                 ALOGE("mic_info tag only supported with INPUT_SND_DEVICE_TO_MIC_MAPPING section");
    864                 return;
    865             }
    866             if (in_snd_device == SND_DEVICE_NONE) {
    867                 ALOGE("%s: Error in previous tags, do not process mic info", __func__);
    868                 return;
    869             }
    870             section_process_fn fn = section_table[MIC_INFO];
    871             fn(attr);
    872         }
    873     } else {
    874         if(strcmp(tag_name, "config_params") == 0) {
    875             section = CONFIG_PARAMS;
    876         } else if (strcmp(tag_name, "param") == 0) {
    877             if (section != CONFIG_PARAMS) {
    878                 ALOGE("param tag only supported with CONFIG_PARAMS section");
    879                 return;
    880             }
    881 
    882             section_process_fn fn = section_table[section];
    883             fn(attr);
    884         }
    885     }
    886 
    887     return;
    888 }
    889 
    890 static void end_tag(void *userdata __unused, const XML_Char *tag_name)
    891 {
    892     if (strcmp(tag_name, "acdb_ids") == 0) {
    893         section = ROOT;
    894     } else if (strcmp(tag_name, "pcm_ids") == 0) {
    895         section = ROOT;
    896     } else if (strcmp(tag_name, "backend_names") == 0) {
    897         section = ROOT;
    898     } else if (strcmp(tag_name, "config_params") == 0) {
    899         section = ROOT;
    900     } else if (strcmp(tag_name, "operator_specific") == 0) {
    901         section = ROOT;
    902     } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
    903         section = ROOT;
    904     } else if (strcmp(tag_name, "app_types") == 0) {
    905         section = ROOT;
    906     } else if (strcmp(tag_name, "microphone_characteristics") == 0) {
    907         section = ROOT;
    908     } else if (strcmp(tag_name, "snd_devices") == 0) {
    909         section = ROOT;
    910     } else if (strcmp(tag_name, "input_snd_device") == 0) {
    911         section = SND_DEVICES;
    912     } else if (strcmp(tag_name, "input_snd_device_mic_mapping") == 0) {
    913         section = INPUT_SND_DEVICE;
    914     } else if (strcmp(tag_name, "acdb_metainfo_key") == 0) {
    915         section = ROOT;
    916     }
    917 }
    918 
    919 int snd_card_info_init(const char *filename, void *platform, set_parameters_fn fn)
    920 {
    921     set_parameters = fn;
    922     my_data.do_full_parse = false;
    923     return platform_info_init(filename, platform);
    924 }
    925 
    926 int platform_info_init(const char *filename, void *platform)
    927 {
    928     XML_Parser      parser;
    929     FILE            *file;
    930     int             ret = 0;
    931     int             bytes_read;
    932     void            *buf;
    933     static const uint32_t kBufSize = 1024;
    934     char   platform_info_file_name[MIXER_PATH_MAX_LENGTH]= {0};
    935     section = ROOT;
    936 
    937     if (filename == NULL) {
    938         strlcpy(platform_info_file_name, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
    939     } else {
    940         strlcpy(platform_info_file_name, filename, MIXER_PATH_MAX_LENGTH);
    941     }
    942 
    943     ALOGV("%s: platform info file name is %s", __func__, platform_info_file_name);
    944 
    945     file = fopen(platform_info_file_name, "r");
    946 
    947     if (!file) {
    948         ALOGD("%s: Failed to open %s, using defaults.",
    949             __func__, platform_info_file_name);
    950         ret = -ENODEV;
    951         goto done;
    952     }
    953 
    954     parser = XML_ParserCreate(NULL);
    955     if (!parser) {
    956         ALOGE("%s: Failed to create XML parser!", __func__);
    957         ret = -ENODEV;
    958         goto err_close_file;
    959     }
    960 
    961     my_data.platform = platform;
    962     my_data.kvpairs = str_parms_create();
    963 
    964     XML_SetElementHandler(parser, start_tag, end_tag);
    965 
    966     while (1) {
    967         buf = XML_GetBuffer(parser, kBufSize);
    968         if (buf == NULL) {
    969             ALOGE("%s: XML_GetBuffer failed", __func__);
    970             ret = -ENOMEM;
    971             goto err_free_parser;
    972         }
    973 
    974         bytes_read = fread(buf, 1, kBufSize, file);
    975         if (bytes_read < 0) {
    976             ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
    977              ret = bytes_read;
    978             goto err_free_parser;
    979         }
    980 
    981         if (XML_ParseBuffer(parser, bytes_read,
    982                             bytes_read == 0) == XML_STATUS_ERROR) {
    983             ALOGE("%s: XML_ParseBuffer failed, for %s",
    984                 __func__, platform_info_file_name);
    985             ret = -EINVAL;
    986             goto err_free_parser;
    987         }
    988 
    989         if (bytes_read == 0)
    990             break;
    991     }
    992 
    993     set_parameters = &platform_set_parameters;
    994     my_data.do_full_parse = true;
    995 
    996 err_free_parser:
    997     XML_ParserFree(parser);
    998 err_close_file:
    999     fclose(file);
   1000 done:
   1001     return ret;
   1002 }
   1003