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