Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2015 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 "APM::ConfigParsingUtils"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include "ConfigParsingUtils.h"
     21 #include "AudioGain.h"
     22 #include "IOProfile.h"
     23 #include <system/audio.h>
     24 #include <media/AudioParameter.h>
     25 #include <media/TypeConverter.h>
     26 #include <utils/Log.h>
     27 #include <cutils/misc.h>
     28 
     29 namespace android {
     30 
     31 // --- audio_policy.conf file parsing
     32 
     33 //static
     34 void ConfigParsingUtils::loadAudioPortGain(cnode *root, AudioPort &audioPort, int index)
     35 {
     36     cnode *node = root->first_child;
     37 
     38     sp<AudioGain> gain = new AudioGain(index, audioPort.useInputChannelMask());
     39 
     40     while (node) {
     41         if (strcmp(node->name, GAIN_MODE) == 0) {
     42             gain->setMode(GainModeConverter::maskFromString(node->value));
     43         } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
     44             audio_channel_mask_t mask;
     45             if (audioPort.useInputChannelMask()) {
     46                 if (InputChannelConverter::fromString(node->value, mask)) {
     47                     gain->setChannelMask(mask);
     48                 }
     49             } else {
     50                 if (OutputChannelConverter::fromString(node->value, mask)) {
     51                     gain->setChannelMask(mask);
     52                 }
     53             }
     54         } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
     55             gain->setMinValueInMb(atoi(node->value));
     56         } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
     57             gain->setMaxValueInMb(atoi(node->value));
     58         } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
     59             gain->setDefaultValueInMb(atoi(node->value));
     60         } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
     61             gain->setStepValueInMb(atoi(node->value));
     62         } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
     63             gain->setMinRampInMs(atoi(node->value));
     64         } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
     65             gain->setMaxRampInMs(atoi(node->value));
     66         }
     67         node = node->next;
     68     }
     69 
     70     ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
     71           gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
     72           gain->getMaxValueInMb());
     73 
     74     if (gain->getMode() == 0) {
     75         return;
     76     }
     77     audioPort.mGains.add(gain);
     78 }
     79 
     80 void ConfigParsingUtils::loadAudioPortGains(cnode *root, AudioPort &audioPort)
     81 {
     82     cnode *node = root->first_child;
     83     int index = 0;
     84     while (node) {
     85         ALOGV("loadGains() loading gain %s", node->name);
     86         loadAudioPortGain(node, audioPort, index++);
     87         node = node->next;
     88     }
     89 }
     90 
     91 //static
     92 void ConfigParsingUtils::loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc)
     93 {
     94     loadAudioPortGains(root, *deviceDesc);
     95     if (deviceDesc->mGains.size() > 0) {
     96         deviceDesc->mGains[0]->getDefaultConfig(&deviceDesc->mGain);
     97     }
     98 }
     99 
    100 //static
    101 status_t ConfigParsingUtils::loadHwModuleDevice(cnode *root, DeviceVector &devices)
    102 {
    103     cnode *node = root->first_child;
    104 
    105     audio_devices_t type = AUDIO_DEVICE_NONE;
    106     while (node) {
    107         if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
    108             deviceFromString(node->value, type);
    109             break;
    110         }
    111         node = node->next;
    112     }
    113     if (type == AUDIO_DEVICE_NONE ||
    114             (!audio_is_input_device(type) && !audio_is_output_device(type))) {
    115         ALOGW("loadDevice() bad type %08x", type);
    116         return BAD_VALUE;
    117     }
    118     sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type, String8(root->name));
    119 
    120     node = root->first_child;
    121     while (node) {
    122         if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
    123             deviceDesc->mAddress = String8((char *)node->value);
    124         } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
    125             if (audio_is_input_device(type)) {
    126                 deviceDesc->addAudioProfile(
    127                         new AudioProfile(gDynamicFormat,
    128                                          inputChannelMasksFromString(node->value),
    129                                          SampleRateVector()));
    130             } else {
    131                 deviceDesc->addAudioProfile(
    132                         new AudioProfile(gDynamicFormat,
    133                                          outputChannelMasksFromString(node->value),
    134                                          SampleRateVector()));
    135             }
    136         } else if (strcmp(node->name, GAINS_TAG) == 0) {
    137             loadDeviceDescriptorGains(node, deviceDesc);
    138         }
    139         node = node->next;
    140     }
    141 
    142     ALOGV("loadDevice() adding device tag (literal type) %s type %08x address %s",
    143           deviceDesc->getTagName().string(), type, deviceDesc->mAddress.string());
    144 
    145     devices.add(deviceDesc);
    146     return NO_ERROR;
    147 }
    148 
    149 //static
    150 status_t ConfigParsingUtils::loadHwModuleProfile(cnode *root, sp<HwModule> &module,
    151                                                  audio_port_role_t role)
    152 {
    153     cnode *node = root->first_child;
    154 
    155     sp<IOProfile> profile = new IOProfile(String8(root->name), role);
    156 
    157     AudioProfileVector audioProfiles;
    158     SampleRateVector sampleRates;
    159     ChannelsVector channels;
    160     FormatVector formats;
    161 
    162     while (node) {
    163         if (strcmp(node->name, FORMATS_TAG) == 0 &&
    164                 strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
    165             formats = formatsFromString(node->value);
    166         } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0 &&
    167                   strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
    168             collectionFromString<SampleRateTraits>(node->value, sampleRates);
    169         } else if (strcmp(node->name, CHANNELS_TAG) == 0 &&
    170                    strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
    171             if (role == AUDIO_PORT_ROLE_SINK) {
    172                 channels = inputChannelMasksFromString(node->value);
    173             } else {
    174                 channels = outputChannelMasksFromString(node->value);
    175             }
    176         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
    177             DeviceVector devices;
    178             loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
    179             profile->setSupportedDevices(devices);
    180         } else if (strcmp(node->name, FLAGS_TAG) == 0) {
    181             if (role == AUDIO_PORT_ROLE_SINK) {
    182                 profile->setFlags(InputFlagConverter::maskFromString(node->value));
    183             } else {
    184                 profile->setFlags(OutputFlagConverter::maskFromString(node->value));
    185             }
    186         } else if (strcmp(node->name, GAINS_TAG) == 0) {
    187             loadAudioPortGains(node, *profile);
    188         }
    189         node = node->next;
    190     }
    191     if (formats.isEmpty()) {
    192         sp<AudioProfile> profileToAdd = new AudioProfile(gDynamicFormat, channels, sampleRates);
    193         profileToAdd->setDynamicFormat(true);
    194         profileToAdd->setDynamicChannels(channels.isEmpty());
    195         profileToAdd->setDynamicRate(sampleRates.isEmpty());
    196         audioProfiles.add(profileToAdd);
    197     } else {
    198         for (size_t i = 0; i < formats.size(); i++) {
    199             // For compatibility reason, for each format, creates a profile with the same
    200             // collection of rate and channels.
    201             sp<AudioProfile> profileToAdd = new AudioProfile(formats[i], channels, sampleRates);
    202             profileToAdd->setDynamicFormat(formats[i] == gDynamicFormat);
    203             profileToAdd->setDynamicChannels(channels.isEmpty());
    204             profileToAdd->setDynamicRate(sampleRates.isEmpty());
    205             audioProfiles.add(profileToAdd);
    206         }
    207     }
    208     profile->setAudioProfiles(audioProfiles);
    209     ALOGW_IF(!profile->hasSupportedDevices(), "load%s() invalid supported devices",
    210              role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output");
    211     if (profile->hasSupportedDevices()) {
    212         ALOGV("load%s() adding Supported Devices %04x, mFlags %04x",
    213               role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output",
    214               profile->getSupportedDevicesType(), profile->getFlags());
    215         return module->addProfile(profile);
    216     }
    217     return BAD_VALUE;
    218 }
    219 
    220 //static
    221 status_t ConfigParsingUtils::loadHwModule(cnode *root, sp<HwModule> &module,
    222                                           AudioPolicyConfig &config)
    223 {
    224     status_t status = NAME_NOT_FOUND;
    225     cnode *node = config_find(root, DEVICES_TAG);
    226     if (node != NULL) {
    227         node = node->first_child;
    228         DeviceVector devices;
    229         while (node) {
    230             ALOGV("loadHwModule() loading device %s", node->name);
    231             status_t tmpStatus = loadHwModuleDevice(node, devices);
    232             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
    233                 status = tmpStatus;
    234             }
    235             node = node->next;
    236         }
    237         module->setDeclaredDevices(devices);
    238     }
    239     node = config_find(root, OUTPUTS_TAG);
    240     if (node != NULL) {
    241         node = node->first_child;
    242         while (node) {
    243             ALOGV("loadHwModule() loading output %s", node->name);
    244             status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SOURCE);
    245             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
    246                 status = tmpStatus;
    247             }
    248             node = node->next;
    249         }
    250     }
    251     node = config_find(root, INPUTS_TAG);
    252     if (node != NULL) {
    253         node = node->first_child;
    254         while (node) {
    255             ALOGV("loadHwModule() loading input %s", node->name);
    256             status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SINK);
    257             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
    258                 status = tmpStatus;
    259             }
    260             node = node->next;
    261         }
    262     }
    263     loadModuleGlobalConfig(root, module, config);
    264     return status;
    265 }
    266 
    267 //static
    268 void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
    269                                        AudioPolicyConfig &config)
    270 {
    271     cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
    272     if (node == NULL) {
    273         return;
    274     }
    275 
    276     node = node->first_child;
    277     while (node) {
    278         ALOGV("loadHwModules() loading module %s", node->name);
    279         sp<HwModule> module = new HwModule(node->name);
    280         if (loadHwModule(node, module, config) == NO_ERROR) {
    281             hwModules.add(module);
    282         }
    283         node = node->next;
    284     }
    285 }
    286 
    287 //static
    288 void ConfigParsingUtils::loadDevicesFromTag(const char *tag, DeviceVector &devices,
    289                                             const DeviceVector &declaredDevices)
    290 {
    291     char *tagLiteral = strndup(tag, strlen(tag));
    292     char *devTag = strtok(tagLiteral, AudioParameter::valueListSeparator);
    293     while (devTag != NULL) {
    294         if (strlen(devTag) != 0) {
    295             audio_devices_t type;
    296             if (deviceFromString(devTag, type)) {
    297                 uint32_t inBit = type & AUDIO_DEVICE_BIT_IN;
    298                 type &= ~AUDIO_DEVICE_BIT_IN;
    299                 while (type) {
    300                   audio_devices_t singleType =
    301                         inBit | (1 << (31 - __builtin_clz(type)));
    302                     type &= ~singleType;
    303                     sp<DeviceDescriptor> dev = new DeviceDescriptor(singleType);
    304                     devices.add(dev);
    305                 }
    306             } else {
    307                 sp<DeviceDescriptor> deviceDesc =
    308                         declaredDevices.getDeviceFromTagName(String8(devTag));
    309                 if (deviceDesc != 0) {
    310                     devices.add(deviceDesc);
    311                 }
    312             }
    313         }
    314         devTag = strtok(NULL, AudioParameter::valueListSeparator);
    315     }
    316     free(tagLiteral);
    317 }
    318 
    319 //static
    320 void ConfigParsingUtils::loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
    321                                                 AudioPolicyConfig &config)
    322 {
    323     cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
    324 
    325     if (node == NULL) {
    326         return;
    327     }
    328     DeviceVector declaredDevices;
    329     if (module != NULL) {
    330         declaredDevices = module->getDeclaredDevices();
    331     }
    332 
    333     node = node->first_child;
    334     while (node) {
    335         if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
    336             DeviceVector availableOutputDevices;
    337             loadDevicesFromTag(node->value, availableOutputDevices, declaredDevices);
    338             ALOGV("loadGlobalConfig() Attached Output Devices %08x",
    339                   availableOutputDevices.types());
    340             config.addAvailableOutputDevices(availableOutputDevices);
    341         } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
    342             audio_devices_t device = AUDIO_DEVICE_NONE;
    343             deviceFromString(node->value, device);
    344             if (device != AUDIO_DEVICE_NONE) {
    345                 sp<DeviceDescriptor> defaultOutputDevice = new DeviceDescriptor(device);
    346                 config.setDefaultOutputDevice(defaultOutputDevice);
    347                 ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
    348             } else {
    349                 ALOGW("loadGlobalConfig() default device not specified");
    350             }
    351         } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
    352             DeviceVector availableInputDevices;
    353             loadDevicesFromTag(node->value, availableInputDevices, declaredDevices);
    354             ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
    355             config.addAvailableInputDevices(availableInputDevices);
    356         } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
    357             uint32_t major, minor;
    358             sscanf((char *)node->value, "%u.%u", &major, &minor);
    359             module->setHalVersion(major, minor);
    360             ALOGV("loadGlobalConfig() mHalVersion = major %u minor %u", major, minor);
    361         }
    362         node = node->next;
    363     }
    364 }
    365 
    366 //static
    367 void ConfigParsingUtils::loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
    368                                           const sp<HwModule>& primaryModule)
    369 {
    370     cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
    371 
    372     if (node == NULL) {
    373         return;
    374     }
    375     node = node->first_child;
    376     while (node) {
    377         if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
    378             bool speakerDrcEnabled;
    379             if (utilities::convertTo<std::string, bool>(node->value, speakerDrcEnabled)) {
    380                 ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
    381                 config.setSpeakerDrcEnabled(speakerDrcEnabled);
    382             }
    383         }
    384         node = node->next;
    385     }
    386     loadModuleGlobalConfig(root, primaryModule, config);
    387 }
    388 
    389 //static
    390 status_t ConfigParsingUtils::loadConfig(const char *path, AudioPolicyConfig &config)
    391 {
    392     cnode *root;
    393     char *data;
    394 
    395     data = (char *)load_file(path, NULL);
    396     if (data == NULL) {
    397         return -ENODEV;
    398     }
    399     root = config_node("", "");
    400     config_load(root, data);
    401 
    402     HwModuleCollection hwModules;
    403     loadHwModules(root, hwModules, config);
    404 
    405     // legacy audio_policy.conf files have one global_configuration section, attached to primary.
    406     loadGlobalConfig(root, config, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
    407 
    408     config.setHwModules(hwModules);
    409 
    410     config_free(root);
    411     free(root);
    412     free(data);
    413 
    414     ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
    415 
    416     return NO_ERROR;
    417 }
    418 
    419 } // namespace android
    420