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