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