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