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