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 
29 namespace android {
30 
31 // --- audio_policy.conf file parsing
32 
33 //static
loadAudioPortGain(cnode * root,AudioPort & audioPort,int index)34 void ConfigParsingUtils::loadAudioPortGain(cnode *root, AudioPort &audioPort, int index)
35 {
36     cnode *node = root->first_child;
37 
38     sp<AudioGain> gain = new AudioGain(index, audioPort.useInputChannelMask());
39 
40     while (node) {
41         if (strcmp(node->name, GAIN_MODE) == 0) {
42             gain->setMode(GainModeConverter::maskFromString(node->value));
43         } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
44             audio_channel_mask_t mask;
45             if (audioPort.useInputChannelMask()) {
46                 if (InputChannelConverter::fromString(node->value, mask)) {
47                     gain->setChannelMask(mask);
48                 }
49             } else {
50                 if (OutputChannelConverter::fromString(node->value, mask)) {
51                     gain->setChannelMask(mask);
52                 }
53             }
54         } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
55             gain->setMinValueInMb(atoi(node->value));
56         } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
57             gain->setMaxValueInMb(atoi(node->value));
58         } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
59             gain->setDefaultValueInMb(atoi(node->value));
60         } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
61             gain->setStepValueInMb(atoi(node->value));
62         } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
63             gain->setMinRampInMs(atoi(node->value));
64         } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
65             gain->setMaxRampInMs(atoi(node->value));
66         }
67         node = node->next;
68     }
69 
70     ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
71           gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
72           gain->getMaxValueInMb());
73 
74     if (gain->getMode() == 0) {
75         return;
76     }
77     audioPort.mGains.add(gain);
78 }
79 
loadAudioPortGains(cnode * root,AudioPort & audioPort)80 void ConfigParsingUtils::loadAudioPortGains(cnode *root, AudioPort &audioPort)
81 {
82     cnode *node = root->first_child;
83     int index = 0;
84     while (node) {
85         ALOGV("loadGains() loading gain %s", node->name);
86         loadAudioPortGain(node, audioPort, index++);
87         node = node->next;
88     }
89 }
90 
91 //static
loadDeviceDescriptorGains(cnode * root,sp<DeviceDescriptor> & deviceDesc)92 void ConfigParsingUtils::loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc)
93 {
94     loadAudioPortGains(root, *deviceDesc);
95     if (deviceDesc->mGains.size() > 0) {
96         deviceDesc->mGains[0]->getDefaultConfig(&deviceDesc->mGain);
97     }
98 }
99 
100 //static
loadHwModuleDevice(cnode * root,DeviceVector & devices)101 status_t ConfigParsingUtils::loadHwModuleDevice(cnode *root, DeviceVector &devices)
102 {
103     cnode *node = root->first_child;
104 
105     audio_devices_t type = AUDIO_DEVICE_NONE;
106     while (node) {
107         if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
108             DeviceConverter::fromString(node->value, type);
109             break;
110         }
111         node = node->next;
112     }
113     if (type == AUDIO_DEVICE_NONE ||
114             (!audio_is_input_device(type) && !audio_is_output_device(type))) {
115         ALOGW("loadDevice() bad type %08x", type);
116         return BAD_VALUE;
117     }
118     sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type, String8(root->name));
119 
120     node = root->first_child;
121     while (node) {
122         if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
123             deviceDesc->mAddress = String8((char *)node->value);
124         } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
125             if (audio_is_input_device(type)) {
126                 deviceDesc->addAudioProfile(
127                         new AudioProfile(gDynamicFormat,
128                                          inputChannelMasksFromString(node->value),
129                                          SampleRateVector()));
130             } else {
131                 deviceDesc->addAudioProfile(
132                         new AudioProfile(gDynamicFormat,
133                                          outputChannelMasksFromString(node->value),
134                                          SampleRateVector()));
135             }
136         } else if (strcmp(node->name, GAINS_TAG) == 0) {
137             loadDeviceDescriptorGains(node, deviceDesc);
138         }
139         node = node->next;
140     }
141 
142     ALOGV("loadDevice() adding device tag (literal type) %s type %08x address %s",
143           deviceDesc->getTagName().string(), type, deviceDesc->mAddress.string());
144 
145     devices.add(deviceDesc);
146     return NO_ERROR;
147 }
148 
149 //static
loadHwModuleProfile(cnode * root,sp<HwModule> & module,audio_port_role_t role)150 status_t ConfigParsingUtils::loadHwModuleProfile(cnode *root, sp<HwModule> &module,
151                                                  audio_port_role_t role)
152 {
153     cnode *node = root->first_child;
154 
155     sp<IOProfile> profile = new IOProfile(String8(root->name), role);
156 
157     AudioProfileVector audioProfiles;
158     SampleRateVector sampleRates;
159     ChannelsVector channels;
160     FormatVector formats;
161 
162     while (node) {
163         if (strcmp(node->name, FORMATS_TAG) == 0 &&
164                 strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
165             formats = formatsFromString(node->value);
166         } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0 &&
167                   strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
168             collectionFromString<SampleRateTraits>(node->value, sampleRates);
169         } else if (strcmp(node->name, CHANNELS_TAG) == 0 &&
170                    strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
171             if (role == AUDIO_PORT_ROLE_SINK) {
172                 channels = inputChannelMasksFromString(node->value);
173             } else {
174                 channels = outputChannelMasksFromString(node->value);
175             }
176         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
177             DeviceVector devices;
178             loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
179             profile->setSupportedDevices(devices);
180         } else if (strcmp(node->name, FLAGS_TAG) == 0) {
181             if (role == AUDIO_PORT_ROLE_SINK) {
182                 profile->setFlags(InputFlagConverter::maskFromString(node->value));
183             } else {
184                 profile->setFlags(OutputFlagConverter::maskFromString(node->value));
185             }
186         } else if (strcmp(node->name, GAINS_TAG) == 0) {
187             loadAudioPortGains(node, *profile);
188         }
189         node = node->next;
190     }
191     if (formats.isEmpty()) {
192         sp<AudioProfile> profileToAdd = new AudioProfile(gDynamicFormat, channels, sampleRates);
193         profileToAdd->setDynamicFormat(true);
194         profileToAdd->setDynamicChannels(channels.isEmpty());
195         profileToAdd->setDynamicRate(sampleRates.isEmpty());
196         audioProfiles.add(profileToAdd);
197     } else {
198         for (size_t i = 0; i < formats.size(); i++) {
199             // For compatibility reason, for each format, creates a profile with the same
200             // collection of rate and channels.
201             sp<AudioProfile> profileToAdd = new AudioProfile(formats[i], channels, sampleRates);
202             profileToAdd->setDynamicFormat(formats[i] == gDynamicFormat);
203             profileToAdd->setDynamicChannels(channels.isEmpty());
204             profileToAdd->setDynamicRate(sampleRates.isEmpty());
205             audioProfiles.add(profileToAdd);
206         }
207     }
208     profile->setAudioProfiles(audioProfiles);
209     ALOGW_IF(!profile->hasSupportedDevices(), "load%s() invalid supported devices",
210              role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output");
211     if (profile->hasSupportedDevices()) {
212         ALOGV("load%s() adding Supported Devices %04x, mFlags %04x",
213               role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output",
214               profile->getSupportedDevicesType(), profile->getFlags());
215         return module->addProfile(profile);
216     }
217     return BAD_VALUE;
218 }
219 
220 //static
loadHwModule(cnode * root,sp<HwModule> & module,AudioPolicyConfig & config)221 status_t ConfigParsingUtils::loadHwModule(cnode *root, sp<HwModule> &module,
222                                           AudioPolicyConfig &config)
223 {
224     status_t status = NAME_NOT_FOUND;
225     cnode *node = config_find(root, DEVICES_TAG);
226     if (node != NULL) {
227         node = node->first_child;
228         DeviceVector devices;
229         while (node) {
230             ALOGV("loadHwModule() loading device %s", node->name);
231             status_t tmpStatus = loadHwModuleDevice(node, devices);
232             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
233                 status = tmpStatus;
234             }
235             node = node->next;
236         }
237         module->setDeclaredDevices(devices);
238     }
239     node = config_find(root, OUTPUTS_TAG);
240     if (node != NULL) {
241         node = node->first_child;
242         while (node) {
243             ALOGV("loadHwModule() loading output %s", node->name);
244             status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SOURCE);
245             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
246                 status = tmpStatus;
247             }
248             node = node->next;
249         }
250     }
251     node = config_find(root, INPUTS_TAG);
252     if (node != NULL) {
253         node = node->first_child;
254         while (node) {
255             ALOGV("loadHwModule() loading input %s", node->name);
256             status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SINK);
257             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
258                 status = tmpStatus;
259             }
260             node = node->next;
261         }
262     }
263     loadModuleGlobalConfig(root, module, config);
264     return status;
265 }
266 
267 //static
loadHwModules(cnode * root,HwModuleCollection & hwModules,AudioPolicyConfig & config)268 void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
269                                        AudioPolicyConfig &config)
270 {
271     cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
272     if (node == NULL) {
273         return;
274     }
275 
276     node = node->first_child;
277     while (node) {
278         ALOGV("loadHwModules() loading module %s", node->name);
279         sp<HwModule> module = new HwModule(node->name);
280         if (loadHwModule(node, module, config) == NO_ERROR) {
281             hwModules.add(module);
282         }
283         node = node->next;
284     }
285 }
286 
287 //static
loadDevicesFromTag(const char * tag,DeviceVector & devices,const DeviceVector & declaredDevices)288 void ConfigParsingUtils::loadDevicesFromTag(const char *tag, DeviceVector &devices,
289                                             const DeviceVector &declaredDevices)
290 {
291     char *tagLiteral = strndup(tag, strlen(tag));
292     char *devTag = strtok(tagLiteral, "|");
293     while (devTag != NULL) {
294         if (strlen(devTag) != 0) {
295             audio_devices_t type;
296             if (DeviceConverter::fromString(devTag, type)) {
297                 uint32_t inBit = type & AUDIO_DEVICE_BIT_IN;
298                 type &= ~AUDIO_DEVICE_BIT_IN;
299                 while (type) {
300                   audio_devices_t singleType =
301                         inBit | (1 << (31 - __builtin_clz(type)));
302                     type &= ~singleType;
303                     sp<DeviceDescriptor> dev = new DeviceDescriptor(singleType);
304                     devices.add(dev);
305                 }
306             } else {
307                 sp<DeviceDescriptor> deviceDesc =
308                         declaredDevices.getDeviceFromTagName(String8(devTag));
309                 if (deviceDesc != 0) {
310                     devices.add(deviceDesc);
311                 }
312             }
313         }
314         devTag = strtok(NULL, "|");
315     }
316     free(tagLiteral);
317 }
318 
319 //static
loadModuleGlobalConfig(cnode * root,const sp<HwModule> & module,AudioPolicyConfig & config)320 void ConfigParsingUtils::loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
321                                                 AudioPolicyConfig &config)
322 {
323     cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
324 
325     if (node == NULL) {
326         return;
327     }
328     DeviceVector declaredDevices;
329     if (module != NULL) {
330         declaredDevices = module->getDeclaredDevices();
331     }
332 
333     node = node->first_child;
334     while (node) {
335         if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
336             DeviceVector availableOutputDevices;
337             loadDevicesFromTag(node->value, availableOutputDevices, declaredDevices);
338             ALOGV("loadGlobalConfig() Attached Output Devices %08x",
339                   availableOutputDevices.types());
340             config.addAvailableOutputDevices(availableOutputDevices);
341         } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
342             audio_devices_t device = AUDIO_DEVICE_NONE;
343             DeviceConverter::fromString(node->value, device);
344             if (device != AUDIO_DEVICE_NONE) {
345                 sp<DeviceDescriptor> defaultOutputDevice = new DeviceDescriptor(device);
346                 config.setDefaultOutputDevice(defaultOutputDevice);
347                 ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
348             } else {
349                 ALOGW("loadGlobalConfig() default device not specified");
350             }
351         } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
352             DeviceVector availableInputDevices;
353             loadDevicesFromTag(node->value, availableInputDevices, declaredDevices);
354             ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
355             config.addAvailableInputDevices(availableInputDevices);
356         } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
357             uint32_t major, minor;
358             sscanf((char *)node->value, "%u.%u", &major, &minor);
359             module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor));
360             ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
361                   module->getHalVersion(), major, minor);
362         }
363         node = node->next;
364     }
365 }
366 
367 //static
loadGlobalConfig(cnode * root,AudioPolicyConfig & config,const sp<HwModule> & primaryModule)368 void ConfigParsingUtils::loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
369                                           const sp<HwModule>& primaryModule)
370 {
371     cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
372 
373     if (node == NULL) {
374         return;
375     }
376     node = node->first_child;
377     while (node) {
378         if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
379             bool speakerDrcEnabled;
380             if (utilities::convertTo<std::string, bool>(node->value, speakerDrcEnabled)) {
381                 ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
382                 config.setSpeakerDrcEnabled(speakerDrcEnabled);
383             }
384         }
385         node = node->next;
386     }
387     loadModuleGlobalConfig(root, primaryModule, config);
388 }
389 
390 //static
loadConfig(const char * path,AudioPolicyConfig & config)391 status_t ConfigParsingUtils::loadConfig(const char *path, AudioPolicyConfig &config)
392 {
393     cnode *root;
394     char *data;
395 
396     data = (char *)load_file(path, NULL);
397     if (data == NULL) {
398         return -ENODEV;
399     }
400     root = config_node("", "");
401     config_load(root, data);
402 
403     HwModuleCollection hwModules;
404     loadHwModules(root, hwModules, config);
405 
406     // legacy audio_policy.conf files have one global_configuration section, attached to primary.
407     loadGlobalConfig(root, config, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
408 
409     config.setHwModules(hwModules);
410 
411     config_free(root);
412     free(root);
413     free(data);
414 
415     ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
416 
417     return NO_ERROR;
418 }
419 
420 }; // namespace android
421