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
26 namespace android {
27
28 //static
stringToEnum(const struct StringToEnum * table,size_t size,const char * name)29 uint32_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
enumToString(const struct StringToEnum * table,size_t size,uint32_t value)43 const 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
stringToBool(const char * value)56 bool 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
parseOutputFlagNames(char * name)64 uint32_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
parseInputFlagNames(char * name)90 uint32_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
parseDeviceNames(char * name)109 audio_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(sDeviceTypeToEnumTable,
117 ARRAY_SIZE(sDeviceTypeToEnumTable),
118 devName);
119 }
120 devName = strtok(NULL, "|");
121 }
122 return device;
123 }
124
125 //static
loadHwModule(cnode * root,HwModuleCollection & hwModules,DeviceVector & availableInputDevices,DeviceVector & availableOutputDevices,sp<DeviceDescriptor> & defaultOutputDevices,bool & isSpeakerDrcEnable)126 void 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
loadHwModules(cnode * root,HwModuleCollection & hwModules,DeviceVector & availableInputDevices,DeviceVector & availableOutputDevices,sp<DeviceDescriptor> & defaultOutputDevices,bool & isSpeakerDrcEnabled)181 void 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
loadGlobalConfig(cnode * root,const sp<HwModule> & module,DeviceVector & availableInputDevices,DeviceVector & availableOutputDevices,sp<DeviceDescriptor> & defaultOutputDevice,bool & speakerDrcEnabled)202 void 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.loadDevicesFromTag((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 sDeviceTypeToEnumTable,
228 ARRAY_SIZE(sDeviceTypeToEnumTable),
229 (char *)node->value);
230 if (device != AUDIO_DEVICE_NONE) {
231 defaultOutputDevice = new DeviceDescriptor(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.loadDevicesFromTag((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
loadAudioPolicyConfig(const char * path,HwModuleCollection & hwModules,DeviceVector & availableInputDevices,DeviceVector & availableOutputDevices,sp<DeviceDescriptor> & defaultOutputDevices,bool & isSpeakerDrcEnabled)255 status_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