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