1 /*
2  * Copyright (C) 2024 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 "AudioControl::XSD_Converter"
18 
19 #define LOG_NDEBUG 0
20 #include <android-base/logging.h>
21 
22 #include "../include/CarAudioConfigurationXmlConverter.h"
23 
24 #include <aidl/android/hardware/automotive/audiocontrol/RoutingDeviceConfiguration.h>
25 #include <android-base/parsebool.h>
26 #include <android_hardware_automotive_audiocontrol.h>
27 #include <android_hardware_automotive_audiocontrol_fade.h>
28 
29 #include <android-base/parseint.h>
30 #include <android-base/strings.h>
31 #include <media/AidlConversionCppNdk.h>
32 #include <media/TypeConverter.h>
33 #include <media/convert.h>
34 #include <system/audio.h>
35 #include <unistd.h>
36 #include <unordered_map>
37 
38 namespace android {
39 namespace hardware {
40 namespace audiocontrol {
41 namespace internal {
42 namespace xsd = ::android::hardware::automotive::audiocontrol;
43 namespace fade = android::hardware::automotive::audiocontrol::fade;
44 namespace api = ::aidl::android::hardware::automotive::audiocontrol;
45 
46 using aidl::android::media::audio::common::AudioAttributes;
47 using aidl::android::media::audio::common::AudioContentType;
48 using aidl::android::media::audio::common::AudioDevice;
49 using aidl::android::media::audio::common::AudioDeviceAddress;
50 using aidl::android::media::audio::common::AudioDeviceDescription;
51 using aidl::android::media::audio::common::AudioDeviceType;
52 using aidl::android::media::audio::common::AudioHalProductStrategy;
53 using aidl::android::media::audio::common::AudioPort;
54 using aidl::android::media::audio::common::AudioPortDeviceExt;
55 using aidl::android::media::audio::common::AudioPortExt;
56 using aidl::android::media::audio::common::AudioUsage;
57 
58 using namespace ::android::base;
59 
60 namespace {
61 
62 static const std::string kUseCoreRouting{"useCoreAudioRouting"};
63 static const std::string kUseCoreVolume{"useCoreAudioVolume"};
64 static const std::string kUseHalDuckingSignals{"useHalDuckingSignals"};
65 static const std::string kUseCarVolumeGroupMuting{"useCarVolumeGroupMuting"};
66 
67 static constexpr char kOutBusType[] = "AUDIO_DEVICE_OUT_BUS";
68 static constexpr char kInBusType[] = "AUDIO_DEVICE_IN_BUS";
69 
70 using ActivationMap = std::unordered_map<std::string, api::VolumeActivationConfiguration>;
71 using FadeConfigurationMap = std::unordered_map<
72         std::string, ::aidl::android::hardware::automotive::audiocontrol::AudioFadeConfiguration>;
73 
isReadableConfigurationFile(const std::string & filePath)74 inline bool isReadableConfigurationFile(const std::string& filePath) {
75     return !filePath.empty() && filePath.ends_with(".xml") && (access(filePath.c_str(), R_OK) == 0);
76 }
77 
parseBoolOrDefaultIfFailed(const std::string & value,bool defaultValue)78 inline bool parseBoolOrDefaultIfFailed(const std::string& value, bool defaultValue) {
79     ParseBoolResult results = ParseBool(value);
80     return results == ParseBoolResult::kError ? defaultValue : results == ParseBoolResult::kTrue;
81 }
82 
parseCoreRoutingInfo(const std::string & value,api::AudioDeviceConfiguration & config)83 void parseCoreRoutingInfo(const std::string& value, api::AudioDeviceConfiguration& config) {
84     if (!parseBoolOrDefaultIfFailed(value, /* defaultValue= */ false)) {
85         return;
86     }
87     config.routingConfig = api::RoutingDeviceConfiguration::CONFIGURABLE_AUDIO_ENGINE_ROUTING;
88 }
89 
parseCoreVolumeInfo(const std::string & value,api::AudioDeviceConfiguration & config)90 void parseCoreVolumeInfo(const std::string& value, api::AudioDeviceConfiguration& config) {
91     config.useCoreAudioVolume = parseBoolOrDefaultIfFailed(value, config.useCoreAudioVolume);
92 }
93 
parseHalDuckingInfo(const std::string & value,api::AudioDeviceConfiguration & config)94 void parseHalDuckingInfo(const std::string& value, api::AudioDeviceConfiguration& config) {
95     config.useHalDuckingSignals = parseBoolOrDefaultIfFailed(value, config.useHalDuckingSignals);
96 }
97 
parseHalMutingInfo(const std::string & value,api::AudioDeviceConfiguration & config)98 void parseHalMutingInfo(const std::string& value, api::AudioDeviceConfiguration& config) {
99     config.useCarVolumeGroupMuting =
100             parseBoolOrDefaultIfFailed(value, config.useCarVolumeGroupMuting);
101 }
102 
parseAudioAttributeUsageString(const std::string & usageString,AudioUsage & usage)103 bool parseAudioAttributeUsageString(const std::string& usageString, AudioUsage& usage) {
104     audio_usage_t legacyUsage;
105     if (!::android::UsageTypeConverter::fromString(usageString, legacyUsage)) {
106         LOG(ERROR) << __func__ << " could not parse usage from string " << usageString;
107         return false;
108     }
109     ConversionResult<AudioUsage> result =
110             ::aidl::android::legacy2aidl_audio_usage_t_AudioUsage(legacyUsage);
111     if (!result.ok()) {
112         LOG(ERROR) << __func__ << " could not parse usage legacy type " << legacyUsage;
113         return false;
114     }
115     usage = result.value();
116     return true;
117 }
118 
parseAudioAttributeUsage(const xsd::UsageType & usageType,AudioAttributes & attributes)119 bool parseAudioAttributeUsage(const xsd::UsageType& usageType, AudioAttributes& attributes) {
120     if (!usageType.hasValue()) {
121         LOG(ERROR) << __func__ << " usage does not have value";
122         return false;
123     }
124     if (!parseAudioAttributeUsageString(xsd::toString(usageType.getValue()), attributes.usage)) {
125         return false;
126     }
127     return true;
128 }
129 
parseAudioAttributesUsages(const std::vector<xsd::UsageType> & usages,std::vector<AudioAttributes> & audioAttributes)130 bool parseAudioAttributesUsages(const std::vector<xsd::UsageType>& usages,
131                                 std::vector<AudioAttributes>& audioAttributes) {
132     for (const auto& xsdUsage : usages) {
133         AudioAttributes attributes;
134         if (!parseAudioAttributeUsage(xsdUsage, attributes)) {
135             return false;
136         }
137         audioAttributes.push_back(attributes);
138     }
139     return true;
140 }
141 
parseContentTypeString(const std::string & typeString,AudioContentType & type)142 bool parseContentTypeString(const std::string& typeString, AudioContentType& type) {
143     audio_content_type_t legacyContentType;
144     if (!::android::AudioContentTypeConverter::fromString(typeString, legacyContentType)) {
145         LOG(ERROR) << __func__ << " could not parse content type from string " << typeString;
146         return false;
147     }
148     ConversionResult<AudioContentType> result =
149             ::aidl::android::legacy2aidl_audio_content_type_t_AudioContentType(legacyContentType);
150     if (!result.ok()) {
151         LOG(ERROR) << __func__ << " could not convert legacy content type " << legacyContentType;
152         return false;
153     }
154     type = result.value();
155     return true;
156 }
157 
parseAudioAttribute(const xsd::AttributesType & attributesType,AudioAttributes & attributes)158 bool parseAudioAttribute(const xsd::AttributesType& attributesType, AudioAttributes& attributes) {
159     if (attributesType.hasUsage()) {
160         if (!parseAudioAttributeUsageString(xsd::toString(attributesType.getUsage()),
161                                             attributes.usage)) {
162             LOG(ERROR) << __func__ << " could not parse audio usage: "
163                        << xsd::toString(attributesType.getUsage());
164             return false;
165         }
166     }
167 
168     if (attributesType.hasContentType()) {
169         if (!parseContentTypeString(xsd::toString(attributesType.getContentType()),
170                                     attributes.contentType)) {
171             return false;
172         }
173     }
174 
175     if (attributesType.hasTags()) {
176         attributes.tags.push_back(attributesType.getTags());
177     }
178     return true;
179 }
180 
parseAudioAttributes(const std::vector<xsd::AttributesType> & xsdAttributes,std::vector<AudioAttributes> & audioAttributes)181 bool parseAudioAttributes(const std::vector<xsd::AttributesType>& xsdAttributes,
182                           std::vector<AudioAttributes>& audioAttributes) {
183     for (const auto& xsdAttribute : xsdAttributes) {
184         AudioAttributes attribute;
185         if (!parseAudioAttribute(xsdAttribute, attribute)) {
186             return false;
187         }
188         audioAttributes.push_back(attribute);
189     }
190     return true;
191 }
192 
parseAudioAttributes(const xsd::AudioAttributesUsagesType & xsdAttributeOrUsages,std::vector<AudioAttributes> & audioAttributes)193 bool parseAudioAttributes(const xsd::AudioAttributesUsagesType& xsdAttributeOrUsages,
194                           std::vector<AudioAttributes>& audioAttributes) {
195     if (xsdAttributeOrUsages.hasUsage_optional()) {
196         if (!parseAudioAttributesUsages(xsdAttributeOrUsages.getUsage_optional(),
197                                         audioAttributes)) {
198             LOG(ERROR) << __func__ << " could not parse audio usages";
199             return false;
200         }
201     }
202 
203     if (xsdAttributeOrUsages.hasAudioAttribute_optional()) {
204         if (!parseAudioAttributes(xsdAttributeOrUsages.getAudioAttribute_optional(),
205                                   audioAttributes)) {
206             LOG(ERROR) << __func__ << " could not parse audio attributes";
207             return false;
208         }
209     }
210     return true;
211 }
212 
parseAudioContext(const xsd::OemContextType & xsdContextInfo,api::AudioZoneContextInfo & contextInfo)213 bool parseAudioContext(const xsd::OemContextType& xsdContextInfo,
214                        api::AudioZoneContextInfo& contextInfo) {
215     if (!xsdContextInfo.hasName()) {
216         LOG(ERROR) << __func__ << " Audio context info missing name";
217         return false;
218     }
219 
220     contextInfo.name = xsdContextInfo.getName();
221 
222     if (xsdContextInfo.hasId()) {
223         ParseInt(xsdContextInfo.getId().c_str(), &contextInfo.id);
224     }
225 
226     if (xsdContextInfo.hasAudioAttributes()) {
227         if (!parseAudioAttributes(*xsdContextInfo.getFirstAudioAttributes(),
228                                   contextInfo.audioAttributes)) {
229             return false;
230         }
231     }
232 
233     return true;
234 }
235 
parseAudioContexts(const xsd::OemContextsType * xsdContexts,api::AudioZoneContext & context)236 bool parseAudioContexts(const xsd::OemContextsType* xsdContexts, api::AudioZoneContext& context) {
237     if (!xsdContexts->hasOemContext()) {
238         return false;
239     }
240     const auto xsdContextInfos = xsdContexts->getOemContext();
241     for (const auto& xsdContextInfo : xsdContextInfos) {
242         api::AudioZoneContextInfo info;
243         if (!parseAudioContext(xsdContextInfo, info)) {
244             continue;
245         }
246         context.audioContextInfos.push_back(info);
247     }
248     return true;
249 }
250 
createAudioDevice(const std::string & address,const std::string & type,AudioPort & port)251 bool createAudioDevice(const std::string& address, const std::string& type, AudioPort& port) {
252     audio_devices_t legacyDeviceType = AUDIO_DEVICE_NONE;
253     ::android::DeviceConverter::fromString(type, legacyDeviceType);
254     std::string tempString;
255     ::android::DeviceConverter::toString(legacyDeviceType, tempString);
256     ConversionResult<AudioDeviceDescription> result =
257             ::aidl::android::legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyDeviceType);
258     if (legacyDeviceType == AUDIO_DEVICE_NONE || !result.ok()) {
259         LOG(ERROR) << __func__ << " could not parse legacy device type";
260         return false;
261     }
262     AudioDevice device;
263     if (!address.empty()) {
264         device.address = AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(address);
265     }
266     device.type = result.value();
267 
268     port.ext = AudioPortExt::make<AudioPortExt::Tag::device>(device);
269 
270     return true;
271 }
272 
outTypeToOutAudioDevice(const std::string & device)273 std::string outTypeToOutAudioDevice(const std::string& device) {
274     const static std::unordered_map<std::string, std::string> typeToOutDevice{
275             {"TYPE_BUILTIN_SPEAKER", "AUDIO_DEVICE_OUT_SPEAKER"},
276             {"TYPE_WIRED_HEADSET", "AUDIO_DEVICE_OUT_WIRED_HEADSET"},
277             {"TYPE_WIRED_HEADPHONES", "AUDIO_DEVICE_OUT_WIRED_HEADPHONE,"},
278             {"TYPE_BLUETOOTH_A2DP", "AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"},
279             {"TYPE_HDMI", "AUDIO_DEVICE_OUT_HDMI"},
280             {"TYPE_USB_ACCESSORY", "AUDIO_DEVICE_OUT_USB_ACCESSORY"},
281             {"TYPE_USB_DEVICE", "AUDIO_DEVICE_OUT_USB_DEVICE,"},
282             {"TYPE_USB_HEADSET", "AUDIO_DEVICE_OUT_USB_HEADSET"},
283             {"TYPE_AUX_LINE", "AUDIO_DEVICE_OUT_AUX_LINE"},
284             {"TYPE_BUS", "AUDIO_DEVICE_OUT_BUS"},
285             {"TYPE_BLE_HEADSET", "AUDIO_DEVICE_OUT_BLE_HEADSET"},
286             {"TYPE_BLE_SPEAKER", "AUDIO_DEVICE_OUT_BLE_SPEAKER"},
287             {"TYPE_BLE_BROADCAST", "AUDIO_DEVICE_OUT_BLE_BROADCAST"},
288     };
289 
290     if (!device.starts_with("TYPE_")) {
291         return device;
292     }
293 
294     const auto it = typeToOutDevice.find(device);
295     return it != typeToOutDevice.end() ? it->second : device;
296 }
297 
parseAudioDeviceToContexts(const xsd::DeviceRoutesType & deviceRoutesType,api::DeviceToContextEntry & route)298 bool parseAudioDeviceToContexts(const xsd::DeviceRoutesType& deviceRoutesType,
299                                 api::DeviceToContextEntry& route) {
300     std::string address = deviceRoutesType.hasAddress() ? deviceRoutesType.getAddress() : "";
301     // Default type is bus for schema
302     std::string type = outTypeToOutAudioDevice(deviceRoutesType.hasType()
303                                                        ? xsd::toString(deviceRoutesType.getType())
304                                                        : std::string(kOutBusType));
305     // Address must be present for audio device bus
306     if (address.empty() && type == std::string(kOutBusType)) {
307         LOG(ERROR) << __func__ << " empty device address for bus device type";
308         return false;
309     }
310     if (!createAudioDevice(address, type, route.device)) {
311         return false;
312     }
313 
314     if (!deviceRoutesType.hasContext()) {
315         LOG(ERROR) << __func__ << " empty device context mapping";
316         return false;
317     }
318 
319     for (const auto& xsdContext : deviceRoutesType.getContext()) {
320         if (!xsdContext.hasContext()) {
321             LOG(ERROR) << __func__ << " audio device route missing context info";
322             return false;
323         }
324         route.contextNames.push_back(xsdContext.getContext());
325     }
326 
327     return true;
328 }
329 
parseAudioDeviceRoutes(const std::vector<xsd::DeviceRoutesType> deviceRoutesTypes,std::vector<api::DeviceToContextEntry> & routes)330 bool parseAudioDeviceRoutes(const std::vector<xsd::DeviceRoutesType> deviceRoutesTypes,
331                             std::vector<api::DeviceToContextEntry>& routes) {
332     for (const auto& deviceRouteType : deviceRoutesTypes) {
333         api::DeviceToContextEntry entry;
334         if (!parseAudioDeviceToContexts(deviceRouteType, entry)) {
335             return false;
336         }
337         routes.push_back(entry);
338     }
339     return true;
340 }
341 
parseVolumeGroupActivation(const std::string & activationConfigName,const ActivationMap & activations,api::VolumeGroupConfig & volumeGroup)342 void parseVolumeGroupActivation(const std::string& activationConfigName,
343                                 const ActivationMap& activations,
344                                 api::VolumeGroupConfig& volumeGroup) {
345     if (activationConfigName.empty()) {
346         LOG(ERROR) << __func__ << " Volume group " << volumeGroup.name
347                    << " has empty volume group activation name";
348         return;
349     }
350     const auto& it = activations.find(activationConfigName);
351     if (it == activations.end()) {
352         LOG(ERROR) << __func__ << " Volume group " << volumeGroup.name
353                    << " has non-existing volume group activation name " << activationConfigName;
354         return;
355     }
356     volumeGroup.activationConfiguration = it->second;
357 }
358 
parseVolumeGroup(const xsd::VolumeGroupType & volumeGroupType,const ActivationMap & activations,api::VolumeGroupConfig & volumeGroup)359 bool parseVolumeGroup(const xsd::VolumeGroupType& volumeGroupType, const ActivationMap& activations,
360                       api::VolumeGroupConfig& volumeGroup) {
361     if (!volumeGroupType.hasDevice()) {
362         LOG(ERROR) << __func__ << " no device found";
363         return false;
364     }
365 
366     if (volumeGroupType.hasName()) {
367         volumeGroup.name = volumeGroupType.getName();
368     }
369 
370     if (!parseAudioDeviceRoutes(volumeGroupType.getDevice(), volumeGroup.carAudioRoutes)) {
371         return false;
372     }
373 
374     if (volumeGroupType.hasActivationConfig()) {
375         parseVolumeGroupActivation(volumeGroupType.getActivationConfig(), activations, volumeGroup);
376     }
377 
378     return true;
379 }
380 
parseVolumeGroups(const xsd::VolumeGroupsType * volumeGroupsType,const ActivationMap & activations,std::vector<api::VolumeGroupConfig> & volumeGroups)381 bool parseVolumeGroups(const xsd::VolumeGroupsType* volumeGroupsType,
382                        const ActivationMap& activations,
383                        std::vector<api::VolumeGroupConfig>& volumeGroups) {
384     if (!volumeGroupsType->hasGroup()) {
385         LOG(ERROR) << __func__ << " no volume groups found";
386         return false;
387     }
388     for (const auto& volumeGroupType : volumeGroupsType->getGroup()) {
389         api::VolumeGroupConfig volumeGroup;
390         if (!parseVolumeGroup(volumeGroupType, activations, volumeGroup)) {
391             return false;
392         }
393         volumeGroups.push_back(volumeGroup);
394     }
395     return true;
396 }
397 
parseFadeConfigurationUsages(const xsd::ApplyFadeConfigType & fadeConfigType,std::vector<AudioUsage> & usages)398 void parseFadeConfigurationUsages(const xsd::ApplyFadeConfigType& fadeConfigType,
399                                   std::vector<AudioUsage>& usages) {
400     if (!fadeConfigType.hasAudioAttributes()) {
401         return;
402     }
403     const xsd::AudioAttributeUsagesType* attributesOrUsagesType =
404             fadeConfigType.getFirstAudioAttributes();
405     if (!attributesOrUsagesType->hasUsage()) {
406         return;
407     }
408     for (const auto& usageType : attributesOrUsagesType->getUsage()) {
409         AudioUsage usage;
410         if (!usageType.hasValue() ||
411             !parseAudioAttributeUsageString(xsd::toString(usageType.getValue()), usage)) {
412             continue;
413         }
414         usages.push_back(usage);
415     }
416 }
417 
parseZoneFadeConfiguration(const xsd::ApplyFadeConfigType & fadeConfigType,const FadeConfigurationMap & fadeConfigurations,api::AudioZoneFadeConfiguration & zoneFadeConfiguration)418 void parseZoneFadeConfiguration(const xsd::ApplyFadeConfigType& fadeConfigType,
419                                 const FadeConfigurationMap& fadeConfigurations,
420                                 api::AudioZoneFadeConfiguration& zoneFadeConfiguration) {
421     if (!fadeConfigType.hasName()) {
422         LOG(ERROR) << __func__ << " Found a fade config without a name, skipping assignment";
423         return;
424     }
425 
426     const auto it = fadeConfigurations.find(fadeConfigType.getName());
427     if (it == fadeConfigurations.end()) {
428         LOG(ERROR) << __func__ << " Config name " << fadeConfigType.getName()
429                    << " not found, skipping assignment";
430         return;
431     }
432     // Return for default since default configurations do not have any audio attributes mapping
433     if (fadeConfigType.hasIsDefault()) {
434         zoneFadeConfiguration.defaultConfiguration = it->second;
435         return;
436     }
437 
438     api::TransientFadeConfigurationEntry entry;
439     entry.transientFadeConfiguration = it->second;
440     parseFadeConfigurationUsages(fadeConfigType, entry.transientUsages);
441     zoneFadeConfiguration.transientConfiguration.push_back(entry);
442 }
443 
parseZoneFadeConfigurations(const xsd::ZoneConfigType & zoneConfigType,const FadeConfigurationMap & fadeConfigurations,std::optional<api::AudioZoneFadeConfiguration> & zoneFadeConfig)444 void parseZoneFadeConfigurations(const xsd::ZoneConfigType& zoneConfigType,
445                                  const FadeConfigurationMap& fadeConfigurations,
446                                  std::optional<api::AudioZoneFadeConfiguration>& zoneFadeConfig) {
447     if (!zoneConfigType.hasApplyFadeConfigs()) {
448         return;
449     }
450     const xsd::ApplyFadeConfigsType* applyFadeConfigs = zoneConfigType.getFirstApplyFadeConfigs();
451     if (!applyFadeConfigs->hasFadeConfig()) {
452         return;
453     }
454     api::AudioZoneFadeConfiguration zoneFadeConfiguration;
455     for (const auto& fadeConfigType : applyFadeConfigs->getFadeConfig()) {
456         parseZoneFadeConfiguration(fadeConfigType, fadeConfigurations, zoneFadeConfiguration);
457     }
458     zoneFadeConfig = zoneFadeConfiguration;
459 }
460 
parseAudioZoneConfig(const xsd::ZoneConfigType & zoneConfigType,const ActivationMap & activations,const FadeConfigurationMap & fadeConfigurations,api::AudioZoneConfig & config)461 bool parseAudioZoneConfig(const xsd::ZoneConfigType& zoneConfigType,
462                           const ActivationMap& activations,
463                           const FadeConfigurationMap& fadeConfigurations,
464                           api::AudioZoneConfig& config) {
465     if (!zoneConfigType.hasVolumeGroups()) {
466         LOG(ERROR) << __func__ << " no volume groups found";
467         return false;
468     }
469 
470     if (zoneConfigType.hasName()) {
471         config.name = zoneConfigType.getName();
472     }
473     if (!parseVolumeGroups(zoneConfigType.getFirstVolumeGroups(), activations,
474                            config.volumeGroups)) {
475         return false;
476     }
477 
478     parseZoneFadeConfigurations(zoneConfigType, fadeConfigurations, config.fadeConfiguration);
479 
480     config.isDefault = zoneConfigType.hasIsDefault() && zoneConfigType.getIsDefault();
481 
482     return true;
483 }
484 
parseAudioZoneConfigs(const xsd::ZoneConfigsType * zoneConfigsType,const ActivationMap & activations,const FadeConfigurationMap & fadeConfigurations,std::vector<api::AudioZoneConfig> & configs)485 bool parseAudioZoneConfigs(const xsd::ZoneConfigsType* zoneConfigsType,
486                            const ActivationMap& activations,
487                            const FadeConfigurationMap& fadeConfigurations,
488                            std::vector<api::AudioZoneConfig>& configs) {
489     if (!zoneConfigsType->hasZoneConfig()) {
490         LOG(ERROR) << __func__ << " No zone configs found";
491         return false;
492     }
493 
494     if (zoneConfigsType->getZoneConfig().empty()) {
495         LOG(ERROR) << __func__ << " Empty list of audio configurations";
496         return false;
497     }
498 
499     for (const auto& zoneConfigType : zoneConfigsType->getZoneConfig()) {
500         api::AudioZoneConfig config;
501         if (!parseAudioZoneConfig(zoneConfigType, activations, fadeConfigurations, config)) {
502             return false;
503         }
504         configs.push_back(config);
505     }
506 
507     return true;
508 }
509 
parseInputDevice(const xsd::InputDeviceType & xsdInputDevice,AudioPort & inputDevice)510 bool parseInputDevice(const xsd::InputDeviceType& xsdInputDevice, AudioPort& inputDevice) {
511     // Input device must have a non-empty address
512     if (!xsdInputDevice.hasAddress() || xsdInputDevice.getAddress().empty()) {
513         LOG(ERROR) << __func__ << " missing device address";
514         return false;
515     }
516     // By default a device is bus type, unless specified
517     std::string inputDeviceType =
518             xsdInputDevice.hasType() ? xsd::toString(xsdInputDevice.getType()) : kInBusType;
519     if (!createAudioDevice(xsdInputDevice.getAddress(), inputDeviceType, inputDevice)) {
520         return false;
521     }
522     return true;
523 }
524 
parseInputDevices(const xsd::InputDevicesType * xsdInputDevices,std::vector<AudioPort> & inputDevices)525 void parseInputDevices(const xsd::InputDevicesType* xsdInputDevices,
526                        std::vector<AudioPort>& inputDevices) {
527     if (!xsdInputDevices->hasInputDevice()) {
528         return;
529     }
530     for (const auto& xsdInputDevice : xsdInputDevices->getInputDevice()) {
531         AudioPort inputDevice;
532         if (!parseInputDevice(xsdInputDevice, inputDevice)) {
533             continue;
534         }
535         inputDevices.push_back(inputDevice);
536     }
537 }
538 
parseAudioZone(const xsd::ZoneType & zone,const ActivationMap & activations,const FadeConfigurationMap & fadeConfigurations,api::AudioZone & audioZone)539 bool parseAudioZone(const xsd::ZoneType& zone, const ActivationMap& activations,
540                     const FadeConfigurationMap& fadeConfigurations, api::AudioZone& audioZone) {
541     static int kPrimaryZoneId = static_cast<int>(AudioHalProductStrategy::ZoneId::DEFAULT);
542     if (zone.hasName()) {
543         audioZone.name = zone.getName();
544     }
545 
546     if (zone.hasOccupantZoneId()) {
547         ParseInt(zone.getOccupantZoneId().c_str(), &audioZone.occupantZoneId);
548     }
549 
550     if (zone.hasInputDevices()) {
551         parseInputDevices(zone.getFirstInputDevices(), audioZone.inputAudioDevices);
552     }
553 
554     // Audio zone id is required
555     if (!zone.hasAudioZoneId()) {
556         LOG(ERROR) << __func__ << " Audio zone id required for each zone";
557         return false;
558     }
559 
560     bool isPrimary = zone.hasIsPrimary() && zone.getIsPrimary();
561 
562     if (isPrimary) {
563         audioZone.id = kPrimaryZoneId;
564     }
565 
566     // ID not required in XML for primary zone
567     if (!ParseInt(zone.getAudioZoneId().c_str(), &audioZone.id) && !isPrimary) {
568         LOG(ERROR) << __func__
569                    << " Could not parse audio zone id, must be a non-negative integer or isPrimary "
570                       "must be specify as true for primary zone";
571         return false;
572     }
573 
574     if (isPrimary && audioZone.id != kPrimaryZoneId) {
575         LOG(ERROR) << __func__ << " Audio zone is primary but has zone id "
576                    << std::to_string(audioZone.id) << " instead of primary zone id "
577                    << std::to_string(kPrimaryZoneId);
578         return false;
579     }
580 
581     if (!zone.hasZoneConfigs()) {
582         LOG(ERROR) << __func__ << " Missing audio zone configs for audio zone id " << audioZone.id;
583         return false;
584     }
585     if (!parseAudioZoneConfigs(zone.getFirstZoneConfigs(), activations, fadeConfigurations,
586                                audioZone.audioZoneConfigs)) {
587         LOG(ERROR) << __func__ << " Could not parse zone configs for audio zone id " << audioZone.id
588                    << ", name " << audioZone.name;
589         return false;
590     }
591 
592     return true;
593 }
594 
parseAudioZones(const xsd::ZonesType * zones,const api::AudioZoneContext & context,const ActivationMap & activations,const FadeConfigurationMap & fadeConfigurations,std::vector<api::AudioZone> & audioZones)595 std::string parseAudioZones(const xsd::ZonesType* zones, const api::AudioZoneContext& context,
596                             const ActivationMap& activations,
597                             const FadeConfigurationMap& fadeConfigurations,
598                             std::vector<api::AudioZone>& audioZones) {
599     if (!zones->hasZone()) {
600         return "audio zones are missing";
601     }
602     const auto& xsdZones = zones->getZone();
603     for (const auto& xsdZone : xsdZones) {
604         api::AudioZone audioZone;
605         audioZone.audioZoneContext = context;
606         if (!parseAudioZone(xsdZone, activations, fadeConfigurations, audioZone)) {
607             continue;
608         }
609         audioZones.push_back(audioZone);
610     }
611     return "";
612 }
613 
614 std::unordered_map<std::string,
615                    std::function<void(const std::string&, api::AudioDeviceConfiguration&)>>
getConfigsParsers()616 getConfigsParsers() {
617     static const std::unordered_map<
618             std::string, std::function<void(const std::string&, api::AudioDeviceConfiguration&)>>
619             parsers{
620                     {kUseCoreRouting, parseCoreRoutingInfo},
621                     {kUseCoreVolume, parseCoreVolumeInfo},
622                     {kUseHalDuckingSignals, parseHalDuckingInfo},
623                     {kUseCarVolumeGroupMuting, parseHalMutingInfo},
624             };
625 
626     return parsers;
627 }
628 
parseVolumeActivationType(const xsd::ActivationType & xsdType,api::VolumeInvocationType & activationType)629 bool parseVolumeActivationType(const xsd::ActivationType& xsdType,
630                                api::VolumeInvocationType& activationType) {
631     switch (xsdType) {
632         case xsd::ActivationType::onBoot:
633             activationType = api::VolumeInvocationType::ON_BOOT;
634             break;
635         case xsd::ActivationType::onSourceChanged:
636             activationType = api::VolumeInvocationType::ON_SOURCE_CHANGED;
637             break;
638         case xsd::ActivationType::onPlaybackChanged:
639             activationType = api::VolumeInvocationType::ON_PLAYBACK_CHANGED;
640             break;
641         default:
642             return false;
643     }
644     return true;
645 }
646 
parseVolumeGroupActivationEntry(const xsd::ActivationVolumeConfigEntryType & xsdEntry,api::VolumeActivationConfigurationEntry & entry)647 bool parseVolumeGroupActivationEntry(const xsd::ActivationVolumeConfigEntryType& xsdEntry,
648                                      api::VolumeActivationConfigurationEntry& entry) {
649     if (!xsdEntry.hasInvocationType()) {
650         // Legacy file had default invocation type as on playback changed
651         entry.type = api::VolumeInvocationType::ON_PLAYBACK_CHANGED;
652     } else if (!parseVolumeActivationType(xsdEntry.getInvocationType(), entry.type)) {
653         LOG(ERROR) << __func__ << " Could not parse configuration entry type";
654         return false;
655     }
656 
657     if (xsdEntry.hasMaxActivationVolumePercentage()) {
658         // Parse int ranges are not inclusive
659         ParseInt(xsdEntry.getMaxActivationVolumePercentage().c_str(),
660                  &entry.maxActivationVolumePercentage,
661                  api::VolumeActivationConfigurationEntry::DEFAULT_MIN_ACTIVATION_VALUE - 1,
662                  api::VolumeActivationConfigurationEntry::DEFAULT_MAX_ACTIVATION_VALUE + 1);
663     }
664 
665     if (xsdEntry.hasMinActivationVolumePercentage()) {
666         // Parse int ranges are not inclusive
667         ParseInt(xsdEntry.getMinActivationVolumePercentage().c_str(),
668                  &entry.minActivationVolumePercentage,
669                  api::VolumeActivationConfigurationEntry::DEFAULT_MIN_ACTIVATION_VALUE - 1,
670                  api::VolumeActivationConfigurationEntry::DEFAULT_MAX_ACTIVATION_VALUE + 1);
671     }
672 
673     return true;
674 }
675 
parseVolumeGroupActivationEntries(const std::vector<xsd::ActivationVolumeConfigEntryType> & xsdEntries,std::vector<api::VolumeActivationConfigurationEntry> & entries)676 bool parseVolumeGroupActivationEntries(
677         const std::vector<xsd::ActivationVolumeConfigEntryType>& xsdEntries,
678         std::vector<api::VolumeActivationConfigurationEntry>& entries) {
679     for (const auto& xsdEntry : xsdEntries) {
680         api::VolumeActivationConfigurationEntry entry;
681         if (!parseVolumeGroupActivationEntry(xsdEntry, entry)) {
682             LOG(ERROR) << __func__ << " Could not parse volume group activation entries";
683             return false;
684         }
685         entries.push_back(entry);
686     }
687     return true;
688 }
689 
parseVolumeGroupActivation(const xsd::ActivationVolumeConfigType & xsdActivationConfig,api::VolumeActivationConfiguration & activation)690 bool parseVolumeGroupActivation(const xsd::ActivationVolumeConfigType& xsdActivationConfig,
691                                 api::VolumeActivationConfiguration& activation) {
692     if (!xsdActivationConfig.hasName()) {
693         LOG(ERROR) << __func__ << " Activation config missing volume activation name";
694         return false;
695     }
696     if (!xsdActivationConfig.hasActivationVolumeConfigEntry()) {
697         LOG(ERROR) << __func__ << " Activation config missing volume activation entries";
698         return false;
699     }
700     if (!parseVolumeGroupActivationEntries(xsdActivationConfig.getActivationVolumeConfigEntry(),
701                                            activation.volumeActivationEntries)) {
702         LOG(ERROR) << __func__ << " Could not parse volume activation name";
703         return false;
704     }
705     activation.name = xsdActivationConfig.getName();
706     return true;
707 }
708 
parseVolumeGroupActivations(const xsd::ActivationVolumeConfigsType * xsdActivationConfigs,ActivationMap & activations)709 void parseVolumeGroupActivations(const xsd::ActivationVolumeConfigsType* xsdActivationConfigs,
710                                  ActivationMap& activations) {
711     if (!xsdActivationConfigs->hasActivationVolumeConfig()) {
712         LOG(ERROR) << __func__ << " No volume group activations found";
713         return;
714     }
715     for (const auto& xsdActivationConfig : xsdActivationConfigs->getActivationVolumeConfig()) {
716         api::VolumeActivationConfiguration activationConfiguration;
717         if (!parseVolumeGroupActivation(xsdActivationConfig, activationConfiguration)) {
718             continue;
719         }
720         std::string name = xsdActivationConfig.getName();
721         activations.emplace(name, activationConfiguration);
722     }
723 }
724 
parseOutputMirroringDevices(const xsd::MirroringDevicesType * mirroringDevicesType,std::vector<AudioPort> & mirroringDevices)725 void parseOutputMirroringDevices(const xsd::MirroringDevicesType* mirroringDevicesType,
726                                  std::vector<AudioPort>& mirroringDevices) {
727     if (!mirroringDevicesType->hasMirroringDevice()) {
728         LOG(ERROR) << __func__ << " Missing audio mirroring devices";
729         return;
730     }
731     for (const auto& xsdMirrorDevice : mirroringDevicesType->getMirroringDevice()) {
732         AudioPort mirrorDevicePort;
733         if (!xsdMirrorDevice.hasAddress()) {
734             LOG(ERROR) << __func__ << " Missing audio mirroring device address";
735             continue;
736         }
737         if (!createAudioDevice(xsdMirrorDevice.getAddress(), kOutBusType, mirrorDevicePort)) {
738             LOG(ERROR) << __func__ << " Could not create mirror device with address "
739                        << xsdMirrorDevice.getAddress();
740             continue;
741         }
742         mirroringDevices.push_back(mirrorDevicePort);
743     }
744 }
745 
getFadeState(const fade::FadeStateType & xsdFadeState)746 api::FadeState getFadeState(const fade::FadeStateType& xsdFadeState) {
747     // Return default value if missing
748     if (!xsdFadeState.hasValue()) {
749         return api::FadeState::FADE_STATE_ENABLED_DEFAULT;
750     }
751     // For legacy files, "0" and "1 " need to be supported.
752     switch (xsdFadeState.getValue()) {
753         case fade::FadeStateEnumType::_0:
754             // Fallthrough
755         case fade::FadeStateEnumType::FADE_STATE_DISABLED:
756             return api::FadeState::FADE_STATE_DISABLED;
757         case fade::FadeStateEnumType::_1:
758             // Fallthrough
759         case fade::FadeStateEnumType::FADE_STATE_ENABLED_DEFAULT:
760             // Fallthrough
761         default:
762             return api::FadeState::FADE_STATE_ENABLED_DEFAULT;
763     }
764 }
765 
parseFadeableUsages(const fade::FadeableUsagesType & fadeUsages,std::vector<AudioUsage> & usages)766 void parseFadeableUsages(const fade::FadeableUsagesType& fadeUsages,
767                          std::vector<AudioUsage>& usages) {
768     if (!fadeUsages.hasUsage()) {
769         return;
770     }
771     for (const auto& fadeUsage : fadeUsages.getUsage()) {
772         AudioUsage audioUsage;
773         if (!fadeUsage.hasValue() ||
774             !parseAudioAttributeUsageString(fade::toString(fadeUsage.getValue()), audioUsage)) {
775             continue;
776         }
777         usages.push_back(audioUsage);
778     }
779 }
780 
parseFadeAudioAttribute(const fade::AttributesType & fadeAttributes,AudioAttributes & attributes)781 void parseFadeAudioAttribute(const fade::AttributesType& fadeAttributes,
782                              AudioAttributes& attributes) {
783     if (fadeAttributes.hasUsage()) {
784         parseAudioAttributeUsageString(fade::toString(fadeAttributes.getUsage()), attributes.usage);
785     }
786     if (fadeAttributes.hasContentType()) {
787         parseContentTypeString(fade::toString(fadeAttributes.getContentType()),
788                                attributes.contentType);
789     }
790     if (fadeAttributes.hasTags()) {
791         attributes.tags.push_back(fadeAttributes.getTags());
792     }
793 }
794 
parseFadeAudioAttribute(const fade::AudioAttributesUsagesType & fadeAttributes,std::vector<AudioAttributes> & audioAttributes)795 bool parseFadeAudioAttribute(const fade::AudioAttributesUsagesType& fadeAttributes,
796                              std::vector<AudioAttributes>& audioAttributes) {
797     if (fadeAttributes.hasUsage_optional()) {
798         for (const auto& usage : fadeAttributes.getUsage_optional()) {
799             AudioAttributes attributes;
800             if (!usage.hasValue() || !parseAudioAttributeUsageString(
801                                              fade::toString(usage.getValue()), attributes.usage)) {
802                 continue;
803             }
804             audioAttributes.push_back(attributes);
805         }
806     }
807     if (fadeAttributes.hasAudioAttribute_optional()) {
808         for (const auto& fadeAttribute : fadeAttributes.getAudioAttribute_optional()) {
809             AudioAttributes attribute;
810             parseFadeAudioAttribute(fadeAttribute, attribute);
811             audioAttributes.push_back(attribute);
812         }
813     }
814     return true;
815 }
816 
parseUnfadeableAudioAttributes(const fade::UnfadeableAudioAttributesType & fadeAttributes,std::vector<AudioAttributes> & audioAttributes)817 void parseUnfadeableAudioAttributes(const fade::UnfadeableAudioAttributesType& fadeAttributes,
818                                     std::vector<AudioAttributes>& audioAttributes) {
819     if (!fadeAttributes.hasAudioAttributes()) {
820         return;
821     }
822     parseFadeAudioAttribute(*fadeAttributes.getFirstAudioAttributes(), audioAttributes);
823 }
824 
parseUnfadeableContentType(const fade::UnfadeableContentTypesType & fadeTypes,std::optional<std::vector<AudioContentType>> & contentTypes)825 void parseUnfadeableContentType(const fade::UnfadeableContentTypesType& fadeTypes,
826                                 std::optional<std::vector<AudioContentType>>& contentTypes) {
827     if (!fadeTypes.hasContentType()) {
828         return;
829     }
830     std::vector<AudioContentType> contents;
831     for (const auto& fadeContentType : fadeTypes.getContentType()) {
832         AudioContentType contentType;
833         if (!fadeContentType.hasValue() ||
834             !parseContentTypeString(fade::toString(fadeContentType.getValue()), contentType)) {
835             continue;
836         }
837         contents.push_back(contentType);
838     }
839     contentTypes = contents;
840 }
841 
parseFadeConfigAudioAttributes(const fade::AudioAttributesUsagesType & fadeAudioAttributesType,const int64_t fadeDurationMillins,std::vector<api::FadeConfiguration> & fadeInConfigurations)842 void parseFadeConfigAudioAttributes(const fade::AudioAttributesUsagesType& fadeAudioAttributesType,
843                                     const int64_t fadeDurationMillins,
844                                     std::vector<api::FadeConfiguration>& fadeInConfigurations) {
845     if (fadeAudioAttributesType.hasAudioAttribute_optional()) {
846         for (const auto& fadeAudioAttribute :
847              fadeAudioAttributesType.getAudioAttribute_optional()) {
848             api::FadeConfiguration fadeConfiguration;
849             AudioAttributes attributes;
850             parseFadeAudioAttribute(fadeAudioAttribute, attributes);
851             fadeConfiguration.fadeDurationMillis = fadeDurationMillins;
852             fadeConfiguration.audioAttributesOrUsage
853                     .set<api::FadeConfiguration::AudioAttributesOrUsage::fadeAttribute>(attributes);
854             fadeInConfigurations.push_back(fadeConfiguration);
855         }
856     }
857 
858     if (fadeAudioAttributesType.hasUsage_optional()) {
859         for (const auto& fadeAudioUsage : fadeAudioAttributesType.getUsage_optional()) {
860             api::FadeConfiguration fadeConfiguration;
861             AudioUsage usage;
862             if (!fadeAudioUsage.hasValue() ||
863                 !parseAudioAttributeUsageString(fade::toString(fadeAudioUsage.getValue()), usage)) {
864                 continue;
865             }
866             fadeConfiguration.fadeDurationMillis = fadeDurationMillins;
867             fadeConfiguration.audioAttributesOrUsage
868                     .set<api::FadeConfiguration::AudioAttributesOrUsage::usage>(usage);
869             fadeInConfigurations.push_back(fadeConfiguration);
870         }
871     }
872 }
parseFadeConfiguration(const fade::FadeConfigurationType & fadeConfigurationType,std::vector<api::FadeConfiguration> & fadeConfigurations)873 void parseFadeConfiguration(const fade::FadeConfigurationType& fadeConfigurationType,
874                             std::vector<api::FadeConfiguration>& fadeConfigurations) {
875     if (!fadeConfigurationType.hasFadeDurationMillis() ||
876         !fadeConfigurationType.hasAudioAttributes() ||
877         fadeConfigurationType.getAudioAttributes().empty()) {
878         return;
879     }
880 
881     int64_t fadeDurationMillis = 0L;
882 
883     if (!ParseInt(fadeConfigurationType.getFadeDurationMillis().c_str(), &fadeDurationMillis,
884                   static_cast<int64_t>(0))) {
885         return;
886     }
887     parseFadeConfigAudioAttributes(*fadeConfigurationType.getFirstAudioAttributes(),
888                                    fadeDurationMillis, fadeConfigurations);
889 }
890 
parseFadeInConfigurations(const fade::FadeInConfigurationsType & fadeInConfigurationsType,std::vector<api::FadeConfiguration> & fadeInConfigurations)891 void parseFadeInConfigurations(const fade::FadeInConfigurationsType& fadeInConfigurationsType,
892                                std::vector<api::FadeConfiguration>& fadeInConfigurations) {
893     if (!fadeInConfigurationsType.hasFadeConfiguration()) {
894         return;
895     }
896     for (const auto& fadeConfigurationType : fadeInConfigurationsType.getFadeConfiguration()) {
897         parseFadeConfiguration(fadeConfigurationType, fadeInConfigurations);
898     }
899 }
900 
parseFadeOutConfigurations(const fade::FadeOutConfigurationsType & fadeOutConfigurationsType,std::vector<api::FadeConfiguration> & fadeOutConfigurations)901 void parseFadeOutConfigurations(const fade::FadeOutConfigurationsType& fadeOutConfigurationsType,
902                                 std::vector<api::FadeConfiguration>& fadeOutConfigurations) {
903     if (!fadeOutConfigurationsType.hasFadeConfiguration()) {
904         return;
905     }
906     for (const auto& fadeConfigurationType : fadeOutConfigurationsType.getFadeConfiguration()) {
907         parseFadeConfiguration(fadeConfigurationType, fadeOutConfigurations);
908     }
909 }
910 
parseFadeConfig(const fade::FadeConfigurationConfig & fadeConfig,api::AudioFadeConfiguration & configuration)911 bool parseFadeConfig(const fade::FadeConfigurationConfig& fadeConfig,
912                      api::AudioFadeConfiguration& configuration) {
913     // Fade configuration must have a name for zone association. Fade state is also needed to
914     // determine accurate usage.
915     if (!fadeConfig.hasName()) {
916         LOG(ERROR) << __func__ << " Fade configuration missing name";
917         return false;
918     }
919     if (!fadeConfig.hasFadeState()) {
920         LOG(ERROR) << __func__ << " Fade configuration missing fade state";
921         return false;
922     }
923     configuration.name = fadeConfig.getName();
924     configuration.fadeState = getFadeState(*fadeConfig.getFirstFadeState());
925     if (fadeConfig.hasDefaultFadeOutDurationInMillis()) {
926         ParseInt(fadeConfig.getDefaultFadeOutDurationInMillis().c_str(),
927                  &configuration.fadeOutDurationMs, static_cast<int64_t>(0));
928     }
929     if (fadeConfig.hasDefaultFadeInDurationInMillis()) {
930         ParseInt(fadeConfig.getDefaultFadeInDurationInMillis().c_str(),
931                  &configuration.fadeInDurationMs, static_cast<int64_t>(0));
932     }
933     if (fadeConfig.hasDefaultFadeInDelayForOffenders()) {
934         ParseInt(fadeConfig.getDefaultFadeInDelayForOffenders().c_str(),
935                  &configuration.fadeInDelayedForOffendersMs, static_cast<int64_t>(0));
936     }
937 
938     if (fadeConfig.hasFadeableUsages()) {
939         parseFadeableUsages(*fadeConfig.getFirstFadeableUsages(), configuration.fadeableUsages);
940     }
941 
942     if (fadeConfig.hasUnfadeableContentTypes()) {
943         parseUnfadeableContentType(*fadeConfig.getFirstUnfadeableContentTypes(),
944                                    configuration.unfadeableContentTypes);
945     }
946 
947     if (fadeConfig.hasUnfadeableAudioAttributes()) {
948         parseUnfadeableAudioAttributes(*fadeConfig.getFirstUnfadeableAudioAttributes(),
949                                        configuration.unfadableAudioAttributes);
950     }
951     if (fadeConfig.hasFadeInConfigurations()) {
952         parseFadeInConfigurations(*fadeConfig.getFirstFadeInConfigurations(),
953                                   configuration.fadeInConfigurations);
954     }
955     if (fadeConfig.hasFadeOutConfigurations()) {
956         parseFadeOutConfigurations(*fadeConfig.getFirstFadeOutConfigurations(),
957                                    configuration.fadeOutConfigurations);
958     }
959 
960     return true;
961 }
962 
parseFadeConfigs(const std::vector<fade::FadeConfigurationConfig> & fadeConfigTypes,std::vector<api::AudioFadeConfiguration> & fadeConfigs)963 void parseFadeConfigs(const std::vector<fade::FadeConfigurationConfig>& fadeConfigTypes,
964                       std::vector<api::AudioFadeConfiguration>& fadeConfigs) {
965     for (const auto& fadeConfig : fadeConfigTypes) {
966         api::AudioFadeConfiguration configuration;
967         if (!parseFadeConfig(fadeConfig, configuration)) {
968             continue;
969         }
970         fadeConfigs.push_back(configuration);
971     }
972 }
973 
parseFadeConfigs(const fade::FadeConfigurationConfigs & fadeConfigsType,std::vector<api::AudioFadeConfiguration> & fadeConfigs)974 void parseFadeConfigs(const fade::FadeConfigurationConfigs& fadeConfigsType,
975                       std::vector<api::AudioFadeConfiguration>& fadeConfigs) {
976     if (!fadeConfigsType.hasConfig()) {
977         LOG(ERROR) << __func__ << " Fade config file does not contains any fade configs";
978         return;
979     }
980     parseFadeConfigs(fadeConfigsType.getConfig(), fadeConfigs);
981 }
982 }  // namespace
983 
init()984 void CarAudioConfigurationXmlConverter::init() {
985     if (!isReadableConfigurationFile(mAudioConfigFile)) {
986         mParseErrors = "Configuration file " + mAudioConfigFile + " is not readable";
987         initNonDynamicRouting();
988         return;
989     }
990 
991     // Supports loading legacy fade configurations from a different file
992     if (isReadableConfigurationFile(mFadeConfigFile)) {
993         initFadeConfigurations();
994     }
995 
996     const auto& configOptional = xsd::read(mAudioConfigFile.c_str());
997 
998     if (!configOptional.has_value()) {
999         mParseErrors =
1000                 "Configuration file " + mAudioConfigFile + " , does not have any configurations";
1001         initNonDynamicRouting();
1002         return;
1003     }
1004 
1005     const auto& configurations = configOptional.value();
1006     initAudioDeviceConfiguration(configurations);
1007     initCarAudioConfigurations(configurations);
1008 }
1009 
initFadeConfigurations()1010 void CarAudioConfigurationXmlConverter::initFadeConfigurations() {
1011     const auto& fadeConfigOptional = fade::read(mFadeConfigFile.c_str());
1012     if (!fadeConfigOptional.has_value() || !fadeConfigOptional.value().hasConfigs()) {
1013         LOG(ERROR) << __func__ << " Fade config file " << mFadeConfigFile.c_str()
1014                    << " does not contains fade configuration";
1015         return;
1016     }
1017 
1018     const auto& fadeConfigs = fadeConfigOptional.value().getConfigs();
1019 
1020     if (fadeConfigs.empty()) {
1021         LOG(ERROR) << __func__ << " Fade config file " << mFadeConfigFile.c_str()
1022                    << " does not contains fade configs";
1023     }
1024     std::vector<api::AudioFadeConfiguration> fadeConfigurations;
1025     parseFadeConfigs(fadeConfigs.front(), fadeConfigurations);
1026     for (const auto& fadeConfiguration : fadeConfigurations) {
1027         mFadeConfigurations.emplace(fadeConfiguration.name, fadeConfiguration);
1028     }
1029 }
1030 
initNonDynamicRouting()1031 void CarAudioConfigurationXmlConverter::initNonDynamicRouting() {
1032     mAudioDeviceConfiguration.routingConfig =
1033             api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING;
1034 }
1035 
initAudioDeviceConfiguration(const xsd::CarAudioConfigurationType & carAudioConfigurationType)1036 void CarAudioConfigurationXmlConverter::initAudioDeviceConfiguration(
1037         const xsd::CarAudioConfigurationType& carAudioConfigurationType) {
1038     parseAudioDeviceConfigurations(carAudioConfigurationType);
1039 }
1040 
parseAudioDeviceConfigurations(const xsd::CarAudioConfigurationType & carAudioConfigurationType)1041 void CarAudioConfigurationXmlConverter::parseAudioDeviceConfigurations(
1042         const xsd::CarAudioConfigurationType& carAudioConfigurationType) {
1043     if (!carAudioConfigurationType.hasDeviceConfigurations()) {
1044         return;
1045     }
1046 
1047     mAudioDeviceConfiguration.routingConfig =
1048             api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING;
1049 
1050     const auto deviceConfigs = carAudioConfigurationType.getFirstDeviceConfigurations();
1051     if (!deviceConfigs->hasDeviceConfiguration()) {
1052         return;
1053     }
1054 
1055     std::vector<::android::hardware::automotive::audiocontrol::DeviceConfigurationType> configs =
1056             deviceConfigs->getDeviceConfiguration();
1057     const auto& parsers = getConfigsParsers();
1058     for (const auto& deviceConfig : configs) {
1059         if (!deviceConfig.hasName() || !deviceConfig.hasValue()) {
1060             continue;
1061         }
1062         const auto& parser = parsers.find(deviceConfig.getName());
1063         if (parser == parsers.end()) {
1064             continue;
1065         }
1066         const auto& method = parser->second;
1067         method(deviceConfig.getValue(), mAudioDeviceConfiguration);
1068     }
1069 }
1070 
initCarAudioConfigurations(const automotive::audiocontrol::CarAudioConfigurationType & carAudioConfigurationType)1071 void CarAudioConfigurationXmlConverter::initCarAudioConfigurations(
1072         const automotive::audiocontrol::CarAudioConfigurationType& carAudioConfigurationType) {
1073     if (!carAudioConfigurationType.hasZones()) {
1074         mParseErrors = "Audio zones not found in file " + mAudioConfigFile;
1075         initNonDynamicRouting();
1076         return;
1077     }
1078 
1079     api::AudioZoneContext context;
1080     if (!carAudioConfigurationType.hasOemContexts() ||
1081         !parseAudioContexts(carAudioConfigurationType.getFirstOemContexts(), context)) {
1082         context = getDefaultCarAudioContext();
1083     }
1084 
1085     ActivationMap activations;
1086     if (carAudioConfigurationType.hasActivationVolumeConfigs()) {
1087         parseVolumeGroupActivations(carAudioConfigurationType.getFirstActivationVolumeConfigs(),
1088                                     activations);
1089     }
1090 
1091     if (carAudioConfigurationType.hasMirroringDevices()) {
1092         parseOutputMirroringDevices(carAudioConfigurationType.getFirstMirroringDevices(),
1093                                     mOutputMirroringDevices);
1094     }
1095 
1096     const auto audioZones = carAudioConfigurationType.getFirstZones();
1097 
1098     std::string message =
1099             parseAudioZones(audioZones, context, activations, mFadeConfigurations, mAudioZones);
1100 
1101     // Assign dynamic configuration if not assigned
1102     if (!mAudioZones.empty() && mAudioDeviceConfiguration.routingConfig ==
1103                                         api::RoutingDeviceConfiguration::DEFAULT_AUDIO_ROUTING) {
1104         mAudioDeviceConfiguration.routingConfig =
1105                 api::RoutingDeviceConfiguration::DYNAMIC_AUDIO_ROUTING;
1106     }
1107 
1108     if (message.empty()) {
1109         return;
1110     }
1111     mParseErrors =
1112             "Error parsing audio zone(s) in file " + mAudioConfigFile + ", message: " + message;
1113     LOG(ERROR) << __func__ << " Error parsing zones: " << message;
1114     initNonDynamicRouting();
1115 }
1116 
getAudioDeviceConfiguration() const1117 api::AudioDeviceConfiguration CarAudioConfigurationXmlConverter::getAudioDeviceConfiguration()
1118         const {
1119     return mAudioDeviceConfiguration;
1120 }
1121 
getAudioZones() const1122 std::vector<api::AudioZone> CarAudioConfigurationXmlConverter::getAudioZones() const {
1123     return mAudioZones;
1124 }
1125 
1126 std::vector<::aidl::android::media::audio::common::AudioPort>
getOutputMirroringDevices() const1127 CarAudioConfigurationXmlConverter::getOutputMirroringDevices() const {
1128     return mOutputMirroringDevices;
1129 }
1130 
1131 }  // namespace internal
1132 }  // namespace audiocontrol
1133 }  // namespace hardware
1134 }  // namespace android