ConfigParsingUtils.cpp revision 1d4481fb9cb1ea149f79f2a5d22110af84fbc90b
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, String8(root->name)); 131 132 node = root->first_child; 133 while (node) { 134 if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) { 135 deviceDesc->mAddress = String8((char *)node->value); 136 } else if (strcmp(node->name, CHANNELS_TAG) == 0) { 137 if (audio_is_input_device(type)) { 138 deviceDesc->setSupportedChannelMasks(inputChannelMasksFromString(node->value)); 139 } else { 140 deviceDesc->setSupportedChannelMasks(outputChannelMasksFromString(node->value)); 141 } 142 } else if (strcmp(node->name, GAINS_TAG) == 0) { 143 loadDeviceDescriptorGains(node, deviceDesc); 144 } 145 node = node->next; 146 } 147 148 ALOGV("loadDevice() adding device tag (literal type) %s type %08x address %s", 149 deviceDesc->getTagName().string(), type, deviceDesc->mAddress.string()); 150 151 devices.add(deviceDesc); 152 return NO_ERROR; 153} 154 155//static 156status_t ConfigParsingUtils::loadHwModuleInput(cnode *root, sp<HwModule> &module) 157{ 158 cnode *node = root->first_child; 159 160 sp<InputProfile> profile = new InputProfile(String8(root->name)); 161 162 while (node) { 163 if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) { 164 profile->setSupportedSamplingRates(samplingRatesFromString(node->value)); 165 } else if (strcmp(node->name, FORMATS_TAG) == 0) { 166 profile->setSupportedFormats(formatsFromString(node->value)); 167 } else if (strcmp(node->name, CHANNELS_TAG) == 0) { 168 profile->setSupportedChannelMasks(inputChannelMasksFromString(node->value)); 169 } else if (strcmp(node->name, DEVICES_TAG) == 0) { 170 DeviceVector devices; 171 loadDevicesFromTag(node->value, devices, module->getDeclaredDevices()); 172 profile->setSupportedDevices(devices); 173 } else if (strcmp(node->name, FLAGS_TAG) == 0) { 174 profile->setFlags(InputFlagConverter::maskFromString(node->value)); 175 } else if (strcmp(node->name, GAINS_TAG) == 0) { 176 loadAudioPortGains(node, *profile); 177 } 178 node = node->next; 179 } 180 ALOGW_IF(profile->getSupportedDevices().isEmpty(), 181 "loadInput() invalid supported devices"); 182 ALOGW_IF(profile->mChannelMasks.size() == 0, 183 "loadInput() invalid supported channel masks"); 184 ALOGW_IF(profile->mSamplingRates.size() == 0, 185 "loadInput() invalid supported sampling rates"); 186 ALOGW_IF(profile->mFormats.size() == 0, 187 "loadInput() invalid supported formats"); 188 if (!profile->getSupportedDevices().isEmpty() && 189 (profile->mChannelMasks.size() != 0) && 190 (profile->mSamplingRates.size() != 0) && 191 (profile->mFormats.size() != 0)) { 192 193 ALOGV("loadInput() adding input Supported Devices %04x", 194 profile->getSupportedDevices().types()); 195 return module->addInputProfile(profile); 196 } else { 197 return BAD_VALUE; 198 } 199} 200 201//static 202status_t ConfigParsingUtils::loadHwModuleOutput(cnode *root, sp<HwModule> &module) 203{ 204 cnode *node = root->first_child; 205 206 sp<OutputProfile> profile = new OutputProfile(String8(root->name)); 207 208 while (node) { 209 if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) { 210 profile->setSupportedSamplingRates(samplingRatesFromString(node->value)); 211 } else if (strcmp(node->name, FORMATS_TAG) == 0) { 212 profile->setSupportedFormats(formatsFromString(node->value)); 213 } else if (strcmp(node->name, CHANNELS_TAG) == 0) { 214 profile->setSupportedChannelMasks(outputChannelMasksFromString(node->value)); 215 } else if (strcmp(node->name, DEVICES_TAG) == 0) { 216 DeviceVector devices; 217 loadDevicesFromTag(node->value, devices, module->getDeclaredDevices()); 218 profile->setSupportedDevices(devices); 219 } else if (strcmp(node->name, FLAGS_TAG) == 0) { 220 profile->setFlags(ConfigParsingUtils::parseOutputFlagNames(node->value)); 221 } else if (strcmp(node->name, GAINS_TAG) == 0) { 222 loadAudioPortGains(node, *profile); 223 } 224 node = node->next; 225 } 226 ALOGW_IF(profile->getSupportedDevices().isEmpty(), 227 "loadOutput() invalid supported devices"); 228 ALOGW_IF(profile->mChannelMasks.size() == 0, 229 "loadOutput() invalid supported channel masks"); 230 ALOGW_IF(profile->mSamplingRates.size() == 0, 231 "loadOutput() invalid supported sampling rates"); 232 ALOGW_IF(profile->mFormats.size() == 0, 233 "loadOutput() invalid supported formats"); 234 if (!profile->getSupportedDevices().isEmpty() && 235 (profile->mChannelMasks.size() != 0) && 236 (profile->mSamplingRates.size() != 0) && 237 (profile->mFormats.size() != 0)) { 238 239 ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x", 240 profile->getSupportedDevices().types(), profile->getFlags()); 241 return module->addOutputProfile(profile); 242 } else { 243 return BAD_VALUE; 244 } 245} 246 247//static 248status_t ConfigParsingUtils::loadHwModule(cnode *root, sp<HwModule> &module, 249 AudioPolicyConfig &config) 250{ 251 status_t status = NAME_NOT_FOUND; 252 cnode *node = config_find(root, DEVICES_TAG); 253 if (node != NULL) { 254 node = node->first_child; 255 DeviceVector devices; 256 while (node) { 257 ALOGV("loadHwModule() loading device %s", node->name); 258 status_t tmpStatus = loadHwModuleDevice(node, devices); 259 if (status == NAME_NOT_FOUND || status == NO_ERROR) { 260 status = tmpStatus; 261 } 262 node = node->next; 263 } 264 module->setDeclaredDevices(devices); 265 } 266 node = config_find(root, OUTPUTS_TAG); 267 if (node != NULL) { 268 node = node->first_child; 269 while (node) { 270 ALOGV("loadHwModule() loading output %s", node->name); 271 status_t tmpStatus = loadHwModuleOutput(node, module); 272 if (status == NAME_NOT_FOUND || status == NO_ERROR) { 273 status = tmpStatus; 274 } 275 node = node->next; 276 } 277 } 278 node = config_find(root, INPUTS_TAG); 279 if (node != NULL) { 280 node = node->first_child; 281 while (node) { 282 ALOGV("loadHwModule() loading input %s", node->name); 283 status_t tmpStatus = loadHwModuleInput(node, module); 284 if (status == NAME_NOT_FOUND || status == NO_ERROR) { 285 status = tmpStatus; 286 } 287 node = node->next; 288 } 289 } 290 loadModuleGlobalConfig(root, module, config); 291 return status; 292} 293 294//static 295void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules, 296 AudioPolicyConfig &config) 297{ 298 cnode *node = config_find(root, AUDIO_HW_MODULE_TAG); 299 if (node == NULL) { 300 return; 301 } 302 303 node = node->first_child; 304 while (node) { 305 ALOGV("loadHwModules() loading module %s", node->name); 306 sp<HwModule> module = new HwModule(node->name); 307 if (loadHwModule(node, module, config) == NO_ERROR) { 308 hwModules.add(module); 309 } 310 node = node->next; 311 } 312} 313 314//static 315void ConfigParsingUtils::loadDevicesFromTag(const char *tag, DeviceVector &devices, 316 const DeviceVector &declaredDevices) 317{ 318 char *tagLiteral = strndup(tag, strlen(tag)); 319 char *devTag = strtok(tagLiteral, "|"); 320 while (devTag != NULL) { 321 if (strlen(devTag) != 0) { 322 audio_devices_t type; 323 if (DeviceConverter::fromString(devTag, type)) { 324 sp<DeviceDescriptor> dev = new DeviceDescriptor(type); 325 devices.add(dev); 326 } else { 327 sp<DeviceDescriptor> deviceDesc = 328 declaredDevices.getDeviceFromTagName(String8(devTag)); 329 if (deviceDesc != 0) { 330 devices.add(deviceDesc); 331 } 332 } 333 } 334 devTag = strtok(NULL, "|"); 335 } 336 free(tagLiteral); 337} 338 339//static 340void ConfigParsingUtils::loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module, 341 AudioPolicyConfig &config) 342{ 343 cnode *node = config_find(root, GLOBAL_CONFIG_TAG); 344 345 if (node == NULL) { 346 return; 347 } 348 DeviceVector declaredDevices; 349 if (module != NULL) { 350 declaredDevices = module->getDeclaredDevices(); 351 } 352 353 node = node->first_child; 354 while (node) { 355 if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) { 356 DeviceVector availableOutputDevices; 357 loadDevicesFromTag(node->value, availableOutputDevices, declaredDevices); 358 ALOGV("loadGlobalConfig() Attached Output Devices %08x", 359 availableOutputDevices.types()); 360 config.addAvailableOutputDevices(availableOutputDevices); 361 } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) { 362 audio_devices_t device = AUDIO_DEVICE_NONE; 363 DeviceConverter::fromString(node->value, device); 364 if (device != AUDIO_DEVICE_NONE) { 365 sp<DeviceDescriptor> defaultOutputDevice = new DeviceDescriptor(device); 366 config.setDefaultOutputDevice(defaultOutputDevice); 367 ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type()); 368 } else { 369 ALOGW("loadGlobalConfig() default device not specified"); 370 } 371 } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) { 372 DeviceVector availableInputDevices; 373 loadDevicesFromTag(node->value, availableInputDevices, declaredDevices); 374 ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types()); 375 config.addAvailableInputDevices(availableInputDevices); 376 } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) { 377 uint32_t major, minor; 378 sscanf((char *)node->value, "%u.%u", &major, &minor); 379 module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor)); 380 ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u", 381 module->getHalVersion(), major, minor); 382 } 383 node = node->next; 384 } 385} 386 387//static 388void ConfigParsingUtils::loadGlobalConfig(cnode *root, AudioPolicyConfig &config, 389 const sp<HwModule>& primaryModule) 390{ 391 cnode *node = config_find(root, GLOBAL_CONFIG_TAG); 392 393 if (node == NULL) { 394 return; 395 } 396 node = node->first_child; 397 while (node) { 398 if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) { 399 bool speakerDrcEnabled; 400 if (utilities::convertTo<std::string, bool>(node->value, speakerDrcEnabled)) { 401 ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled); 402 config.setSpeakerDrcEnabled(speakerDrcEnabled); 403 } 404 } 405 node = node->next; 406 } 407 loadModuleGlobalConfig(root, primaryModule, config); 408} 409 410//static 411status_t ConfigParsingUtils::loadConfig(const char *path, AudioPolicyConfig &config) 412{ 413 cnode *root; 414 char *data; 415 416 data = (char *)load_file(path, NULL); 417 if (data == NULL) { 418 return -ENODEV; 419 } 420 root = config_node("", ""); 421 config_load(root, data); 422 423 HwModuleCollection hwModules; 424 loadHwModules(root, hwModules, config); 425 426 // legacy audio_policy.conf files have one global_configuration section, attached to primary. 427 loadGlobalConfig(root, config, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)); 428 429 config.setHwModules(hwModules); 430 431 config_free(root); 432 free(root); 433 free(data); 434 435 ALOGI("loadAudioPolicyConfig() loaded %s\n", path); 436 437 return NO_ERROR; 438} 439 440}; // namespace android 441