ConfigParsingUtils.cpp revision f4ad6e5637b6deccdac4b60615383f290b3806cf
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 33//static 34void 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 80void 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 92void 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 101status_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 DeviceConverter::fromString(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 150status_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 221status_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 268void 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 288void ConfigParsingUtils::loadDevicesFromTag(const char *tag, DeviceVector &devices, 289 const DeviceVector &declaredDevices) 290{ 291 char *tagLiteral = strndup(tag, strlen(tag)); 292 char *devTag = strtok(tagLiteral, "|"); 293 while (devTag != NULL) { 294 if (strlen(devTag) != 0) { 295 audio_devices_t type; 296 if (DeviceConverter::fromString(devTag, type)) { 297 sp<DeviceDescriptor> dev = new DeviceDescriptor(type); 298 devices.add(dev); 299 } else { 300 sp<DeviceDescriptor> deviceDesc = 301 declaredDevices.getDeviceFromTagName(String8(devTag)); 302 if (deviceDesc != 0) { 303 devices.add(deviceDesc); 304 } 305 } 306 } 307 devTag = strtok(NULL, "|"); 308 } 309 free(tagLiteral); 310} 311 312//static 313void ConfigParsingUtils::loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module, 314 AudioPolicyConfig &config) 315{ 316 cnode *node = config_find(root, GLOBAL_CONFIG_TAG); 317 318 if (node == NULL) { 319 return; 320 } 321 DeviceVector declaredDevices; 322 if (module != NULL) { 323 declaredDevices = module->getDeclaredDevices(); 324 } 325 326 node = node->first_child; 327 while (node) { 328 if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) { 329 DeviceVector availableOutputDevices; 330 loadDevicesFromTag(node->value, availableOutputDevices, declaredDevices); 331 ALOGV("loadGlobalConfig() Attached Output Devices %08x", 332 availableOutputDevices.types()); 333 config.addAvailableOutputDevices(availableOutputDevices); 334 } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) { 335 audio_devices_t device = AUDIO_DEVICE_NONE; 336 DeviceConverter::fromString(node->value, device); 337 if (device != AUDIO_DEVICE_NONE) { 338 sp<DeviceDescriptor> defaultOutputDevice = new DeviceDescriptor(device); 339 config.setDefaultOutputDevice(defaultOutputDevice); 340 ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type()); 341 } else { 342 ALOGW("loadGlobalConfig() default device not specified"); 343 } 344 } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) { 345 DeviceVector availableInputDevices; 346 loadDevicesFromTag(node->value, availableInputDevices, declaredDevices); 347 ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types()); 348 config.addAvailableInputDevices(availableInputDevices); 349 } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) { 350 uint32_t major, minor; 351 sscanf((char *)node->value, "%u.%u", &major, &minor); 352 module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor)); 353 ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u", 354 module->getHalVersion(), major, minor); 355 } 356 node = node->next; 357 } 358} 359 360//static 361void ConfigParsingUtils::loadGlobalConfig(cnode *root, AudioPolicyConfig &config, 362 const sp<HwModule>& primaryModule) 363{ 364 cnode *node = config_find(root, GLOBAL_CONFIG_TAG); 365 366 if (node == NULL) { 367 return; 368 } 369 node = node->first_child; 370 while (node) { 371 if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) { 372 bool speakerDrcEnabled; 373 if (utilities::convertTo<std::string, bool>(node->value, speakerDrcEnabled)) { 374 ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled); 375 config.setSpeakerDrcEnabled(speakerDrcEnabled); 376 } 377 } 378 node = node->next; 379 } 380 loadModuleGlobalConfig(root, primaryModule, config); 381} 382 383//static 384status_t ConfigParsingUtils::loadConfig(const char *path, AudioPolicyConfig &config) 385{ 386 cnode *root; 387 char *data; 388 389 data = (char *)load_file(path, NULL); 390 if (data == NULL) { 391 return -ENODEV; 392 } 393 root = config_node("", ""); 394 config_load(root, data); 395 396 HwModuleCollection hwModules; 397 loadHwModules(root, hwModules, config); 398 399 // legacy audio_policy.conf files have one global_configuration section, attached to primary. 400 loadGlobalConfig(root, config, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)); 401 402 config.setHwModules(hwModules); 403 404 config_free(root); 405 free(root); 406 free(data); 407 408 ALOGI("loadAudioPolicyConfig() loaded %s\n", path); 409 410 return NO_ERROR; 411} 412 413}; // namespace android 414