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