ConfigParsingUtils.cpp revision 53615e29c99c5e9d2ca77aaefd7bf5c770513120
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 <hardware/audio.h>
23#include <utils/Log.h>
24#include <cutils/misc.h>
25
26namespace android {
27
28//static
29uint32_t ConfigParsingUtils::stringToEnum(const struct StringToEnum *table,
30                                              size_t size,
31                                              const char *name)
32{
33    for (size_t i = 0; i < size; i++) {
34        if (strcmp(table[i].name, name) == 0) {
35            ALOGV("stringToEnum() found %s", table[i].name);
36            return table[i].value;
37        }
38    }
39    return 0;
40}
41
42//static
43const char *ConfigParsingUtils::enumToString(const struct StringToEnum *table,
44                                              size_t size,
45                                              uint32_t value)
46{
47    for (size_t i = 0; i < size; i++) {
48        if (table[i].value == value) {
49            return table[i].name;
50        }
51    }
52    return "";
53}
54
55//static
56bool ConfigParsingUtils::stringToBool(const char *value)
57{
58    return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
59}
60
61
62// --- audio_policy.conf file parsing
63//static
64uint32_t ConfigParsingUtils::parseOutputFlagNames(char *name)
65{
66    uint32_t flag = 0;
67
68    // it is OK to cast name to non const here as we are not going to use it after
69    // strtok() modifies it
70    char *flagName = strtok(name, "|");
71    while (flagName != NULL) {
72        if (strlen(flagName) != 0) {
73            flag |= ConfigParsingUtils::stringToEnum(sOutputFlagNameToEnumTable,
74                               ARRAY_SIZE(sOutputFlagNameToEnumTable),
75                               flagName);
76        }
77        flagName = strtok(NULL, "|");
78    }
79    //force direct flag if offload flag is set: offloading implies a direct output stream
80    // and all common behaviors are driven by checking only the direct flag
81    // this should normally be set appropriately in the policy configuration file
82    if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
83        flag |= AUDIO_OUTPUT_FLAG_DIRECT;
84    }
85
86    return flag;
87}
88
89//static
90uint32_t ConfigParsingUtils::parseInputFlagNames(char *name)
91{
92    uint32_t flag = 0;
93
94    // it is OK to cast name to non const here as we are not going to use it after
95    // strtok() modifies it
96    char *flagName = strtok(name, "|");
97    while (flagName != NULL) {
98        if (strlen(flagName) != 0) {
99            flag |= stringToEnum(sInputFlagNameToEnumTable,
100                               ARRAY_SIZE(sInputFlagNameToEnumTable),
101                               flagName);
102        }
103        flagName = strtok(NULL, "|");
104    }
105    return flag;
106}
107
108//static
109audio_devices_t ConfigParsingUtils::parseDeviceNames(char *name)
110{
111    uint32_t device = 0;
112
113    char *devName = strtok(name, "|");
114    while (devName != NULL) {
115        if (strlen(devName) != 0) {
116            device |= stringToEnum(sDeviceNameToEnumTable,
117                                 ARRAY_SIZE(sDeviceNameToEnumTable),
118                                 devName);
119         }
120        devName = strtok(NULL, "|");
121     }
122    return device;
123}
124
125//static
126void ConfigParsingUtils::loadHwModule(cnode *root, HwModuleCollection &hwModules,
127                                      DeviceVector &availableInputDevices,
128                                      DeviceVector &availableOutputDevices,
129                                      sp<DeviceDescriptor> &defaultOutputDevices,
130                                      bool &isSpeakerDrcEnable)
131{
132    status_t status = NAME_NOT_FOUND;
133    cnode *node;
134    sp<HwModule> module = new HwModule(root->name);
135
136    node = config_find(root, DEVICES_TAG);
137    if (node != NULL) {
138        node = node->first_child;
139        while (node) {
140            ALOGV("loadHwModule() loading device %s", node->name);
141            status_t tmpStatus = module->loadDevice(node);
142            if (status == NAME_NOT_FOUND || status == NO_ERROR) {
143                status = tmpStatus;
144            }
145            node = node->next;
146        }
147    }
148    node = config_find(root, OUTPUTS_TAG);
149    if (node != NULL) {
150        node = node->first_child;
151        while (node) {
152            ALOGV("loadHwModule() loading output %s", node->name);
153            status_t tmpStatus = module->loadOutput(node);
154            if (status == NAME_NOT_FOUND || status == NO_ERROR) {
155                status = tmpStatus;
156            }
157            node = node->next;
158        }
159    }
160    node = config_find(root, INPUTS_TAG);
161    if (node != NULL) {
162        node = node->first_child;
163        while (node) {
164            ALOGV("loadHwModule() loading input %s", node->name);
165            status_t tmpStatus = module->loadInput(node);
166            if (status == NAME_NOT_FOUND || status == NO_ERROR) {
167                status = tmpStatus;
168            }
169            node = node->next;
170        }
171    }
172    loadGlobalConfig(root, module, availableInputDevices, availableOutputDevices,
173                     defaultOutputDevices, isSpeakerDrcEnable);
174
175    if (status == NO_ERROR) {
176        hwModules.add(module);
177    }
178}
179
180//static
181void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
182                                       DeviceVector &availableInputDevices,
183                                       DeviceVector &availableOutputDevices,
184                                       sp<DeviceDescriptor> &defaultOutputDevices,
185                                       bool &isSpeakerDrcEnabled)
186{
187    cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
188    if (node == NULL) {
189        return;
190    }
191
192    node = node->first_child;
193    while (node) {
194        ALOGV("loadHwModules() loading module %s", node->name);
195        loadHwModule(node, hwModules, availableInputDevices, availableOutputDevices,
196                     defaultOutputDevices, isSpeakerDrcEnabled);
197        node = node->next;
198    }
199}
200
201//static
202void ConfigParsingUtils::loadGlobalConfig(cnode *root, const sp<HwModule>& module,
203                                          DeviceVector &availableInputDevices,
204                                          DeviceVector &availableOutputDevices,
205                                          sp<DeviceDescriptor> &defaultOutputDevice,
206                                          bool &speakerDrcEnabled)
207{
208    cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
209
210    if (node == NULL) {
211        return;
212    }
213    DeviceVector declaredDevices;
214    if (module != NULL) {
215        declaredDevices = module->mDeclaredDevices;
216    }
217
218    node = node->first_child;
219    while (node) {
220        if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
221            availableOutputDevices.loadDevicesFromName((char *)node->value,
222                                                        declaredDevices);
223            ALOGV("loadGlobalConfig() Attached Output Devices %08x",
224                  availableOutputDevices.types());
225        } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
226            audio_devices_t device = (audio_devices_t)stringToEnum(
227                    sDeviceNameToEnumTable,
228                    ARRAY_SIZE(sDeviceNameToEnumTable),
229                    (char *)node->value);
230            if (device != AUDIO_DEVICE_NONE) {
231                defaultOutputDevice = new DeviceDescriptor(String8("default-output"), device);
232            } else {
233                ALOGW("loadGlobalConfig() default device not specified");
234            }
235            ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
236        } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
237            availableInputDevices.loadDevicesFromName((char *)node->value,
238                                                       declaredDevices);
239            ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
240        } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
241            speakerDrcEnabled = stringToBool((char *)node->value);
242            ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
243        } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
244            uint32_t major, minor;
245            sscanf((char *)node->value, "%u.%u", &major, &minor);
246            module->mHalVersion = HARDWARE_DEVICE_API_VERSION(major, minor);
247            ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
248                  module->mHalVersion, major, minor);
249        }
250        node = node->next;
251    }
252}
253
254//static
255status_t ConfigParsingUtils::loadAudioPolicyConfig(const char *path,
256                                                   HwModuleCollection &hwModules,
257                                                   DeviceVector &availableInputDevices,
258                                                   DeviceVector &availableOutputDevices,
259                                                   sp<DeviceDescriptor> &defaultOutputDevices,
260                                                   bool &isSpeakerDrcEnabled)
261{
262    cnode *root;
263    char *data;
264
265    data = (char *)load_file(path, NULL);
266    if (data == NULL) {
267        return -ENODEV;
268    }
269    root = config_node("", "");
270    config_load(root, data);
271
272    loadHwModules(root, hwModules,
273                  availableInputDevices, availableOutputDevices,
274                  defaultOutputDevices, isSpeakerDrcEnabled);
275    // legacy audio_policy.conf files have one global_configuration section
276    loadGlobalConfig(root, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY),
277                     availableInputDevices, availableOutputDevices,
278                     defaultOutputDevices, isSpeakerDrcEnabled);
279    config_free(root);
280    free(root);
281    free(data);
282
283    ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
284
285    return NO_ERROR;
286}
287
288}; // namespace android
289