xref: /aosp_15_r20/hardware/interfaces/audio/aidl/default/CapEngineConfigXmlConverter.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #define LOG_TAG "AHAL_Config"
18*4d7e907cSAndroid Build Coastguard Worker 
19*4d7e907cSAndroid Build Coastguard Worker #include <aidl/android/media/audio/common/AudioProductStrategyType.h>
20*4d7e907cSAndroid Build Coastguard Worker #include <android-base/logging.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <media/AidlConversionCppNdk.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <media/TypeConverter.h>
23*4d7e907cSAndroid Build Coastguard Worker #include <media/convert.h>
24*4d7e907cSAndroid Build Coastguard Worker #include <utils/FastStrcmp.h>
25*4d7e907cSAndroid Build Coastguard Worker 
26*4d7e907cSAndroid Build Coastguard Worker #include "core-impl/CapEngineConfigXmlConverter.h"
27*4d7e907cSAndroid Build Coastguard Worker #include "core-impl/XsdcConversion.h"
28*4d7e907cSAndroid Build Coastguard Worker 
29*4d7e907cSAndroid Build Coastguard Worker using aidl::android::hardware::audio::common::iequals;
30*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioDeviceAddress;
31*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioDeviceDescription;
32*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioHalCapConfiguration;
33*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioHalCapCriterionV2;
34*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioHalCapDomain;
35*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioHalCapParameter;
36*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioHalCapRule;
37*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioPolicyForceUse;
38*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioSource;
39*4d7e907cSAndroid Build Coastguard Worker using aidl::android::media::audio::common::AudioStreamType;
40*4d7e907cSAndroid Build Coastguard Worker 
41*4d7e907cSAndroid Build Coastguard Worker using ::android::BAD_VALUE;
42*4d7e907cSAndroid Build Coastguard Worker using ::android::base::unexpected;
43*4d7e907cSAndroid Build Coastguard Worker using ::android::utilities::convertTo;
44*4d7e907cSAndroid Build Coastguard Worker 
45*4d7e907cSAndroid Build Coastguard Worker namespace eng_xsd = android::audio::policy::capengine::configuration;
46*4d7e907cSAndroid Build Coastguard Worker 
47*4d7e907cSAndroid Build Coastguard Worker namespace aidl::android::hardware::audio::core::internal {
48*4d7e907cSAndroid Build Coastguard Worker 
49*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gStrategiesParameter = "product_strategies";
50*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gInputSourcesParameter = "input_sources";
51*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gStreamsParameter = "streams";
52*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gOutputDevicesParameter = "selected_output_devices";
53*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gOutputDeviceAddressParameter = "device_address";
54*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gStrategyPrefix = "vx_";
55*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gLegacyOutputDevicePrefix = "AUDIO_DEVICE_OUT_";
56*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gLegacyInputDevicePrefix = "AUDIO_DEVICE_IN_";
57*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gLegacyStreamPrefix = "AUDIO_STREAM_";
58*4d7e907cSAndroid Build Coastguard Worker static constexpr const char* gLegacySourcePrefix = "AUDIO_SOURCE_";
59*4d7e907cSAndroid Build Coastguard Worker 
60*4d7e907cSAndroid Build Coastguard Worker std::optional<std::vector<std::optional<AudioHalCapDomain>>>&
getAidlCapEngineConfig()61*4d7e907cSAndroid Build Coastguard Worker CapEngineConfigXmlConverter::getAidlCapEngineConfig() {
62*4d7e907cSAndroid Build Coastguard Worker     return mAidlCapDomains;
63*4d7e907cSAndroid Build Coastguard Worker }
64*4d7e907cSAndroid Build Coastguard Worker 
convertCriterionRuleToAidl(const eng_xsd::SelectionCriterionRuleType & xsdcRule)65*4d7e907cSAndroid Build Coastguard Worker ConversionResult<AudioHalCapRule::CriterionRule> convertCriterionRuleToAidl(
66*4d7e907cSAndroid Build Coastguard Worker         const eng_xsd::SelectionCriterionRuleType& xsdcRule) {
67*4d7e907cSAndroid Build Coastguard Worker     using Tag = AudioHalCapCriterionV2::Tag;
68*4d7e907cSAndroid Build Coastguard Worker     AudioHalCapRule::CriterionRule rule{};
69*4d7e907cSAndroid Build Coastguard Worker     std::string criterionName = xsdcRule.getSelectionCriterion();
70*4d7e907cSAndroid Build Coastguard Worker     std::string criterionValue = xsdcRule.getValue();
71*4d7e907cSAndroid Build Coastguard Worker     if (iequals(criterionName, toString(Tag::availableInputDevices))) {
72*4d7e907cSAndroid Build Coastguard Worker         AudioHalCapCriterionV2::AvailableDevices value;
73*4d7e907cSAndroid Build Coastguard Worker         value.values.emplace_back(VALUE_OR_RETURN(
74*4d7e907cSAndroid Build Coastguard Worker                 convertDeviceTypeToAidl(gLegacyInputDevicePrefix + criterionValue)));
75*4d7e907cSAndroid Build Coastguard Worker         rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableInputDevices>(value);
76*4d7e907cSAndroid Build Coastguard Worker 
77*4d7e907cSAndroid Build Coastguard Worker     } else if (iequals(criterionName, toString(Tag::availableOutputDevices))) {
78*4d7e907cSAndroid Build Coastguard Worker         AudioHalCapCriterionV2::AvailableDevices value;
79*4d7e907cSAndroid Build Coastguard Worker         value.values.emplace_back(VALUE_OR_RETURN(
80*4d7e907cSAndroid Build Coastguard Worker                 convertDeviceTypeToAidl(gLegacyOutputDevicePrefix + criterionValue)));
81*4d7e907cSAndroid Build Coastguard Worker         rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::availableOutputDevices>(value);
82*4d7e907cSAndroid Build Coastguard Worker     } else if (iequals(criterionName, toString(Tag::availableInputDevicesAddresses))) {
83*4d7e907cSAndroid Build Coastguard Worker         AudioHalCapCriterionV2::AvailableDevicesAddresses value;
84*4d7e907cSAndroid Build Coastguard Worker         value.values.emplace_back(criterionValue);
85*4d7e907cSAndroid Build Coastguard Worker         rule.criterionAndValue =
86*4d7e907cSAndroid Build Coastguard Worker                 AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>(value);
87*4d7e907cSAndroid Build Coastguard Worker     } else if (iequals(criterionName, toString(Tag::availableOutputDevicesAddresses))) {
88*4d7e907cSAndroid Build Coastguard Worker         AudioHalCapCriterionV2::AvailableDevicesAddresses value;
89*4d7e907cSAndroid Build Coastguard Worker         value.values.emplace_back(criterionValue);
90*4d7e907cSAndroid Build Coastguard Worker         rule.criterionAndValue =
91*4d7e907cSAndroid Build Coastguard Worker                 AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>(value);
92*4d7e907cSAndroid Build Coastguard Worker     } else if (iequals(criterionName, toString(Tag::telephonyMode))) {
93*4d7e907cSAndroid Build Coastguard Worker         AudioHalCapCriterionV2::TelephonyMode value;
94*4d7e907cSAndroid Build Coastguard Worker         value.values.emplace_back(VALUE_OR_RETURN(convertTelephonyModeToAidl(criterionValue)));
95*4d7e907cSAndroid Build Coastguard Worker         rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::telephonyMode>(value);
96*4d7e907cSAndroid Build Coastguard Worker     } else if (!fastcmp<strncmp>(criterionName.c_str(), kXsdcForceConfigForUse,
97*4d7e907cSAndroid Build Coastguard Worker             strlen(kXsdcForceConfigForUse))) {
98*4d7e907cSAndroid Build Coastguard Worker         AudioHalCapCriterionV2::ForceConfigForUse value;
99*4d7e907cSAndroid Build Coastguard Worker         value.values.emplace_back(
100*4d7e907cSAndroid Build Coastguard Worker                 VALUE_OR_RETURN(convertForceUseToAidl(criterionName, criterionValue)));
101*4d7e907cSAndroid Build Coastguard Worker         rule.criterionAndValue = AudioHalCapCriterionV2::make<Tag::forceConfigForUse>(value);
102*4d7e907cSAndroid Build Coastguard Worker     } else {
103*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << " unrecognized criterion " << criterionName;
104*4d7e907cSAndroid Build Coastguard Worker         return unexpected(BAD_VALUE);
105*4d7e907cSAndroid Build Coastguard Worker     }
106*4d7e907cSAndroid Build Coastguard Worker     if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Excludes) {
107*4d7e907cSAndroid Build Coastguard Worker         rule.matchingRule = AudioHalCapRule::MatchingRule::EXCLUDES;
108*4d7e907cSAndroid Build Coastguard Worker     } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Includes) {
109*4d7e907cSAndroid Build Coastguard Worker         rule.matchingRule = AudioHalCapRule::MatchingRule::INCLUDES;
110*4d7e907cSAndroid Build Coastguard Worker     } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::Is) {
111*4d7e907cSAndroid Build Coastguard Worker         rule.matchingRule = AudioHalCapRule::MatchingRule::IS;
112*4d7e907cSAndroid Build Coastguard Worker     } else if (xsdcRule.getMatchesWhen() == eng_xsd::MatchesWhenEnum::IsNot) {
113*4d7e907cSAndroid Build Coastguard Worker         rule.matchingRule = AudioHalCapRule::MatchingRule::IS_NOT;
114*4d7e907cSAndroid Build Coastguard Worker     } else {
115*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Unsupported match when rule.";
116*4d7e907cSAndroid Build Coastguard Worker         return unexpected(BAD_VALUE);
117*4d7e907cSAndroid Build Coastguard Worker     }
118*4d7e907cSAndroid Build Coastguard Worker     return rule;
119*4d7e907cSAndroid Build Coastguard Worker }
120*4d7e907cSAndroid Build Coastguard Worker 
convertRule(const eng_xsd::CompoundRuleType & xsdcCompoundRule)121*4d7e907cSAndroid Build Coastguard Worker ConversionResult<AudioHalCapRule> convertRule(const eng_xsd::CompoundRuleType& xsdcCompoundRule) {
122*4d7e907cSAndroid Build Coastguard Worker     AudioHalCapRule rule{};
123*4d7e907cSAndroid Build Coastguard Worker     bool isPreviousCompoundRule = true;
124*4d7e907cSAndroid Build Coastguard Worker     if (xsdcCompoundRule.getType() == eng_xsd::TypeEnum::Any) {
125*4d7e907cSAndroid Build Coastguard Worker         rule.compoundRule = AudioHalCapRule::CompoundRule::ANY;
126*4d7e907cSAndroid Build Coastguard Worker     } else if (xsdcCompoundRule.getType() == eng_xsd::TypeEnum::All) {
127*4d7e907cSAndroid Build Coastguard Worker         rule.compoundRule = AudioHalCapRule::CompoundRule::ALL;
128*4d7e907cSAndroid Build Coastguard Worker     } else {
129*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "Unsupported compound rule type.";
130*4d7e907cSAndroid Build Coastguard Worker         return unexpected(BAD_VALUE);
131*4d7e907cSAndroid Build Coastguard Worker     }
132*4d7e907cSAndroid Build Coastguard Worker     for (const auto& childXsdcCoumpoundRule : xsdcCompoundRule.getCompoundRule_optional()) {
133*4d7e907cSAndroid Build Coastguard Worker         if (childXsdcCoumpoundRule.hasCompoundRule_optional()) {
134*4d7e907cSAndroid Build Coastguard Worker             rule.nestedRules.push_back(VALUE_OR_FATAL(convertRule(childXsdcCoumpoundRule)));
135*4d7e907cSAndroid Build Coastguard Worker         } else if (childXsdcCoumpoundRule.hasSelectionCriterionRule_optional()) {
136*4d7e907cSAndroid Build Coastguard Worker             rule.nestedRules.push_back(VALUE_OR_FATAL(convertRule(childXsdcCoumpoundRule)));
137*4d7e907cSAndroid Build Coastguard Worker         }
138*4d7e907cSAndroid Build Coastguard Worker     }
139*4d7e907cSAndroid Build Coastguard Worker     if (xsdcCompoundRule.hasSelectionCriterionRule_optional()) {
140*4d7e907cSAndroid Build Coastguard Worker         for (const auto& xsdcRule : xsdcCompoundRule.getSelectionCriterionRule_optional()) {
141*4d7e907cSAndroid Build Coastguard Worker             rule.criterionRules.push_back(VALUE_OR_FATAL(convertCriterionRuleToAidl(xsdcRule)));
142*4d7e907cSAndroid Build Coastguard Worker         }
143*4d7e907cSAndroid Build Coastguard Worker     }
144*4d7e907cSAndroid Build Coastguard Worker     return rule;
145*4d7e907cSAndroid Build Coastguard Worker }
146*4d7e907cSAndroid Build Coastguard Worker 
getAudioProductStrategyId(const std::string & path)147*4d7e907cSAndroid Build Coastguard Worker ConversionResult<int> getAudioProductStrategyId(const std::string& path) {
148*4d7e907cSAndroid Build Coastguard Worker     std::vector<std::string> strings;
149*4d7e907cSAndroid Build Coastguard Worker     std::istringstream pathStream(path);
150*4d7e907cSAndroid Build Coastguard Worker     std::string stringToken;
151*4d7e907cSAndroid Build Coastguard Worker     while (getline(pathStream, stringToken, '/')) {
152*4d7e907cSAndroid Build Coastguard Worker         std::size_t pos = stringToken.find(gStrategyPrefix);
153*4d7e907cSAndroid Build Coastguard Worker         if (pos != std::string::npos) {
154*4d7e907cSAndroid Build Coastguard Worker             std::string strategyIdLiteral = stringToken.substr(pos + std::strlen(gStrategyPrefix));
155*4d7e907cSAndroid Build Coastguard Worker             int strategyId;
156*4d7e907cSAndroid Build Coastguard Worker             if (!convertTo(strategyIdLiteral, strategyId)) {
157*4d7e907cSAndroid Build Coastguard Worker                 LOG(ERROR) << "Invalid strategy " << stringToken << " from path " << path;
158*4d7e907cSAndroid Build Coastguard Worker                 return unexpected(BAD_VALUE);
159*4d7e907cSAndroid Build Coastguard Worker             }
160*4d7e907cSAndroid Build Coastguard Worker             return strategyId;
161*4d7e907cSAndroid Build Coastguard Worker         }
162*4d7e907cSAndroid Build Coastguard Worker     }
163*4d7e907cSAndroid Build Coastguard Worker     return unexpected(BAD_VALUE);
164*4d7e907cSAndroid Build Coastguard Worker }
165*4d7e907cSAndroid Build Coastguard Worker 
getAudioSource(const std::string & path)166*4d7e907cSAndroid Build Coastguard Worker ConversionResult<AudioSource> getAudioSource(const std::string& path) {
167*4d7e907cSAndroid Build Coastguard Worker     std::vector<std::string> strings;
168*4d7e907cSAndroid Build Coastguard Worker     std::istringstream pathStream(path);
169*4d7e907cSAndroid Build Coastguard Worker     std::string stringToken;
170*4d7e907cSAndroid Build Coastguard Worker     while (getline(pathStream, stringToken, '/')) {
171*4d7e907cSAndroid Build Coastguard Worker         if (stringToken.find(gInputSourcesParameter) != std::string::npos) {
172*4d7e907cSAndroid Build Coastguard Worker             getline(pathStream, stringToken, '/');
173*4d7e907cSAndroid Build Coastguard Worker             std::transform(stringToken.begin(), stringToken.end(), stringToken.begin(),
174*4d7e907cSAndroid Build Coastguard Worker                            [](char c) { return std::toupper(c); });
175*4d7e907cSAndroid Build Coastguard Worker             std::string legacySourceLiteral = "AUDIO_SOURCE_" + stringToken;
176*4d7e907cSAndroid Build Coastguard Worker             audio_source_t legacySource;
177*4d7e907cSAndroid Build Coastguard Worker             if (!::android::SourceTypeConverter::fromString(legacySourceLiteral, legacySource)) {
178*4d7e907cSAndroid Build Coastguard Worker                 LOG(ERROR) << "Invalid source " << stringToken << " from path " << path;
179*4d7e907cSAndroid Build Coastguard Worker                 return unexpected(BAD_VALUE);
180*4d7e907cSAndroid Build Coastguard Worker             }
181*4d7e907cSAndroid Build Coastguard Worker             return legacy2aidl_audio_source_t_AudioSource(legacySource);
182*4d7e907cSAndroid Build Coastguard Worker         }
183*4d7e907cSAndroid Build Coastguard Worker     }
184*4d7e907cSAndroid Build Coastguard Worker     return unexpected(BAD_VALUE);
185*4d7e907cSAndroid Build Coastguard Worker }
186*4d7e907cSAndroid Build Coastguard Worker 
getAudioStreamType(const std::string & path)187*4d7e907cSAndroid Build Coastguard Worker ConversionResult<AudioStreamType> getAudioStreamType(const std::string& path) {
188*4d7e907cSAndroid Build Coastguard Worker     std::vector<std::string> strings;
189*4d7e907cSAndroid Build Coastguard Worker     std::istringstream pathStream(path);
190*4d7e907cSAndroid Build Coastguard Worker     std::string stringToken;
191*4d7e907cSAndroid Build Coastguard Worker 
192*4d7e907cSAndroid Build Coastguard Worker     while (getline(pathStream, stringToken, '/')) {
193*4d7e907cSAndroid Build Coastguard Worker         if (stringToken.find(gStreamsParameter) != std::string::npos) {
194*4d7e907cSAndroid Build Coastguard Worker             getline(pathStream, stringToken, '/');
195*4d7e907cSAndroid Build Coastguard Worker             std::transform(stringToken.begin(), stringToken.end(), stringToken.begin(),
196*4d7e907cSAndroid Build Coastguard Worker                            [](char c) { return std::toupper(c); });
197*4d7e907cSAndroid Build Coastguard Worker             std::string legacyStreamLiteral = std::string(gLegacyStreamPrefix) + stringToken;
198*4d7e907cSAndroid Build Coastguard Worker             audio_stream_type_t legacyStream;
199*4d7e907cSAndroid Build Coastguard Worker             if (!::android::StreamTypeConverter::fromString(legacyStreamLiteral, legacyStream)) {
200*4d7e907cSAndroid Build Coastguard Worker                 LOG(ERROR) << "Invalid stream " << stringToken << " from path " << path;
201*4d7e907cSAndroid Build Coastguard Worker                 return unexpected(BAD_VALUE);
202*4d7e907cSAndroid Build Coastguard Worker             }
203*4d7e907cSAndroid Build Coastguard Worker             return legacy2aidl_audio_stream_type_t_AudioStreamType(legacyStream);
204*4d7e907cSAndroid Build Coastguard Worker         }
205*4d7e907cSAndroid Build Coastguard Worker     }
206*4d7e907cSAndroid Build Coastguard Worker     return unexpected(BAD_VALUE);
207*4d7e907cSAndroid Build Coastguard Worker }
208*4d7e907cSAndroid Build Coastguard Worker 
toUpperAndAppendPrefix(const std::string & capName,const std::string & legacyPrefix)209*4d7e907cSAndroid Build Coastguard Worker ConversionResult<std::string> toUpperAndAppendPrefix(const std::string& capName,
210*4d7e907cSAndroid Build Coastguard Worker                                                      const std::string& legacyPrefix) {
211*4d7e907cSAndroid Build Coastguard Worker     std::string legacyName = capName;
212*4d7e907cSAndroid Build Coastguard Worker     std::transform(legacyName.begin(), legacyName.end(), legacyName.begin(),
213*4d7e907cSAndroid Build Coastguard Worker                    [](char c) { return std::toupper(c); });
214*4d7e907cSAndroid Build Coastguard Worker     return legacyPrefix + legacyName;
215*4d7e907cSAndroid Build Coastguard Worker }
216*4d7e907cSAndroid Build Coastguard Worker 
convertParamToAidl(const eng_xsd::ConfigurableElementSettingsType & element)217*4d7e907cSAndroid Build Coastguard Worker ConversionResult<AudioHalCapParameter> CapEngineConfigXmlConverter::convertParamToAidl(
218*4d7e907cSAndroid Build Coastguard Worker         const eng_xsd::ConfigurableElementSettingsType& element) {
219*4d7e907cSAndroid Build Coastguard Worker     const auto& path = element.getPath();
220*4d7e907cSAndroid Build Coastguard Worker 
221*4d7e907cSAndroid Build Coastguard Worker     AudioHalCapParameter parameterSetting;
222*4d7e907cSAndroid Build Coastguard Worker     if (path.find(gStrategiesParameter) != std::string::npos) {
223*4d7e907cSAndroid Build Coastguard Worker         int strategyId = VALUE_OR_FATAL(getAudioProductStrategyId(path));
224*4d7e907cSAndroid Build Coastguard Worker         if (path.find(gOutputDevicesParameter) != std::string::npos) {
225*4d7e907cSAndroid Build Coastguard Worker             // Value is 1 or 0
226*4d7e907cSAndroid Build Coastguard Worker             if (!element.hasBitParameter_optional()) {
227*4d7e907cSAndroid Build Coastguard Worker                 LOG(ERROR) << "Invalid strategy value type";
228*4d7e907cSAndroid Build Coastguard Worker                 return unexpected(BAD_VALUE);
229*4d7e907cSAndroid Build Coastguard Worker             }
230*4d7e907cSAndroid Build Coastguard Worker             // Convert name to output device type
231*4d7e907cSAndroid Build Coastguard Worker             const auto* xsdcParam = element.getFirstBitParameter_optional();
232*4d7e907cSAndroid Build Coastguard Worker             std::string outputDevice = VALUE_OR_FATAL(toUpperAndAppendPrefix(
233*4d7e907cSAndroid Build Coastguard Worker                     eng_xsd::toString(xsdcParam->getName()), gLegacyOutputDevicePrefix));
234*4d7e907cSAndroid Build Coastguard Worker             audio_devices_t legacyType;
235*4d7e907cSAndroid Build Coastguard Worker             if (!::android::OutputDeviceConverter::fromString(outputDevice, legacyType)) {
236*4d7e907cSAndroid Build Coastguard Worker                 LOG(ERROR) << "Invalid strategy device type " << outputDevice;
237*4d7e907cSAndroid Build Coastguard Worker                 return unexpected(BAD_VALUE);
238*4d7e907cSAndroid Build Coastguard Worker             }
239*4d7e907cSAndroid Build Coastguard Worker             AudioDeviceDescription aidlDevice =
240*4d7e907cSAndroid Build Coastguard Worker                     VALUE_OR_FATAL(legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
241*4d7e907cSAndroid Build Coastguard Worker             bool isSelected;
242*4d7e907cSAndroid Build Coastguard Worker             if (!convertTo(xsdcParam->getValue(), isSelected)) {
243*4d7e907cSAndroid Build Coastguard Worker                 LOG(ERROR) << "Invalid strategy device selection value " << xsdcParam->getValue();
244*4d7e907cSAndroid Build Coastguard Worker                 return unexpected(BAD_VALUE);
245*4d7e907cSAndroid Build Coastguard Worker             }
246*4d7e907cSAndroid Build Coastguard Worker             parameterSetting =
247*4d7e907cSAndroid Build Coastguard Worker                     AudioHalCapParameter::StrategyDevice(aidlDevice, strategyId, isSelected);
248*4d7e907cSAndroid Build Coastguard Worker         } else if (path.find(gOutputDeviceAddressParameter) != std::string::npos) {
249*4d7e907cSAndroid Build Coastguard Worker             // Value is the address
250*4d7e907cSAndroid Build Coastguard Worker             if (!element.hasStringParameter_optional()) {
251*4d7e907cSAndroid Build Coastguard Worker                 return unexpected(BAD_VALUE);
252*4d7e907cSAndroid Build Coastguard Worker             }
253*4d7e907cSAndroid Build Coastguard Worker             std::string address = element.getFirstStringParameter_optional()->getValue();
254*4d7e907cSAndroid Build Coastguard Worker             parameterSetting = AudioHalCapParameter::StrategyDeviceAddress(
255*4d7e907cSAndroid Build Coastguard Worker                     AudioDeviceAddress(address), strategyId);
256*4d7e907cSAndroid Build Coastguard Worker         }
257*4d7e907cSAndroid Build Coastguard Worker     } else if (path.find(gInputSourcesParameter) != std::string::npos) {
258*4d7e907cSAndroid Build Coastguard Worker         // Value is 1 or 0
259*4d7e907cSAndroid Build Coastguard Worker         if (!element.hasBitParameter_optional()) {
260*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Invalid source value type";
261*4d7e907cSAndroid Build Coastguard Worker             return unexpected(BAD_VALUE);
262*4d7e907cSAndroid Build Coastguard Worker         }
263*4d7e907cSAndroid Build Coastguard Worker         AudioSource audioSourceAidl = VALUE_OR_FATAL(getAudioSource(path));
264*4d7e907cSAndroid Build Coastguard Worker         const auto* xsdcParam = element.getFirstBitParameter_optional();
265*4d7e907cSAndroid Build Coastguard Worker         std::string inputDeviceLiteral = VALUE_OR_FATAL(toUpperAndAppendPrefix(
266*4d7e907cSAndroid Build Coastguard Worker                 eng_xsd::toString(xsdcParam->getName()), gLegacyInputDevicePrefix));
267*4d7e907cSAndroid Build Coastguard Worker         audio_devices_t inputDeviceType;
268*4d7e907cSAndroid Build Coastguard Worker         if (!::android::InputDeviceConverter::fromString(inputDeviceLiteral, inputDeviceType)) {
269*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Invalid source device type " << inputDeviceLiteral;
270*4d7e907cSAndroid Build Coastguard Worker             return unexpected(BAD_VALUE);
271*4d7e907cSAndroid Build Coastguard Worker         }
272*4d7e907cSAndroid Build Coastguard Worker         AudioDeviceDescription aidlDevice =
273*4d7e907cSAndroid Build Coastguard Worker                 VALUE_OR_FATAL(legacy2aidl_audio_devices_t_AudioDeviceDescription(inputDeviceType));
274*4d7e907cSAndroid Build Coastguard Worker 
275*4d7e907cSAndroid Build Coastguard Worker         bool isSelected;
276*4d7e907cSAndroid Build Coastguard Worker         if (!convertTo(xsdcParam->getValue(), isSelected)) {
277*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Invalid source value type " << xsdcParam->getValue();
278*4d7e907cSAndroid Build Coastguard Worker             return unexpected(BAD_VALUE);
279*4d7e907cSAndroid Build Coastguard Worker         }
280*4d7e907cSAndroid Build Coastguard Worker         parameterSetting =
281*4d7e907cSAndroid Build Coastguard Worker                 AudioHalCapParameter::InputSourceDevice(aidlDevice, audioSourceAidl, isSelected);
282*4d7e907cSAndroid Build Coastguard Worker     } else if (path.find(gStreamsParameter) != std::string::npos) {
283*4d7e907cSAndroid Build Coastguard Worker         AudioStreamType audioStreamAidl = VALUE_OR_FATAL(getAudioStreamType(path));
284*4d7e907cSAndroid Build Coastguard Worker         if (!element.hasEnumParameter_optional()) {
285*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Invalid stream value type";
286*4d7e907cSAndroid Build Coastguard Worker             return unexpected(BAD_VALUE);
287*4d7e907cSAndroid Build Coastguard Worker         }
288*4d7e907cSAndroid Build Coastguard Worker         const auto* xsdcParam = element.getFirstEnumParameter_optional();
289*4d7e907cSAndroid Build Coastguard Worker         std::string profileLiteral =
290*4d7e907cSAndroid Build Coastguard Worker                 VALUE_OR_FATAL(toUpperAndAppendPrefix(xsdcParam->getValue(), gLegacyStreamPrefix));
291*4d7e907cSAndroid Build Coastguard Worker         audio_stream_type_t profileLegacyStream;
292*4d7e907cSAndroid Build Coastguard Worker         if (!::android::StreamTypeConverter::fromString(profileLiteral, profileLegacyStream)) {
293*4d7e907cSAndroid Build Coastguard Worker             LOG(ERROR) << "Invalid stream value " << profileLiteral;
294*4d7e907cSAndroid Build Coastguard Worker             return unexpected(BAD_VALUE);
295*4d7e907cSAndroid Build Coastguard Worker         }
296*4d7e907cSAndroid Build Coastguard Worker         AudioStreamType profileStreamAidl = VALUE_OR_FATAL(
297*4d7e907cSAndroid Build Coastguard Worker                 legacy2aidl_audio_stream_type_t_AudioStreamType(profileLegacyStream));
298*4d7e907cSAndroid Build Coastguard Worker         parameterSetting =
299*4d7e907cSAndroid Build Coastguard Worker                 AudioHalCapParameter::StreamVolumeProfile(audioStreamAidl, profileStreamAidl);
300*4d7e907cSAndroid Build Coastguard Worker     }
301*4d7e907cSAndroid Build Coastguard Worker     return parameterSetting;
302*4d7e907cSAndroid Build Coastguard Worker }
303*4d7e907cSAndroid Build Coastguard Worker 
304*4d7e907cSAndroid Build Coastguard Worker ConversionResult<std::vector<AudioHalCapParameter>>
convertSettingToAidl(const eng_xsd::SettingsType::Configuration & xsdcSetting)305*4d7e907cSAndroid Build Coastguard Worker CapEngineConfigXmlConverter::convertSettingToAidl(
306*4d7e907cSAndroid Build Coastguard Worker         const eng_xsd::SettingsType::Configuration& xsdcSetting) {
307*4d7e907cSAndroid Build Coastguard Worker     std::vector<AudioHalCapParameter> aidlCapParameterSettings;
308*4d7e907cSAndroid Build Coastguard Worker     for (const auto& element : xsdcSetting.getConfigurableElement()) {
309*4d7e907cSAndroid Build Coastguard Worker         aidlCapParameterSettings.push_back(VALUE_OR_FATAL(convertParamToAidl(element)));
310*4d7e907cSAndroid Build Coastguard Worker     }
311*4d7e907cSAndroid Build Coastguard Worker     return aidlCapParameterSettings;
312*4d7e907cSAndroid Build Coastguard Worker }
313*4d7e907cSAndroid Build Coastguard Worker 
convertConfigurationToAidl(const eng_xsd::ConfigurationsType::Configuration & xsdcConfiguration,const eng_xsd::SettingsType::Configuration & xsdcSettingConfiguration)314*4d7e907cSAndroid Build Coastguard Worker ConversionResult<AudioHalCapConfiguration> CapEngineConfigXmlConverter::convertConfigurationToAidl(
315*4d7e907cSAndroid Build Coastguard Worker         const eng_xsd::ConfigurationsType::Configuration& xsdcConfiguration,
316*4d7e907cSAndroid Build Coastguard Worker         const eng_xsd::SettingsType::Configuration& xsdcSettingConfiguration) {
317*4d7e907cSAndroid Build Coastguard Worker     AudioHalCapConfiguration aidlCapConfiguration;
318*4d7e907cSAndroid Build Coastguard Worker     aidlCapConfiguration.name = xsdcConfiguration.getName();
319*4d7e907cSAndroid Build Coastguard Worker     if (xsdcConfiguration.hasCompoundRule()) {
320*4d7e907cSAndroid Build Coastguard Worker         if (xsdcConfiguration.getCompoundRule().size() != 1) {
321*4d7e907cSAndroid Build Coastguard Worker             return unexpected(BAD_VALUE);
322*4d7e907cSAndroid Build Coastguard Worker         }
323*4d7e907cSAndroid Build Coastguard Worker         aidlCapConfiguration.rule =
324*4d7e907cSAndroid Build Coastguard Worker                 VALUE_OR_FATAL(convertRule(xsdcConfiguration.getCompoundRule()[0]));
325*4d7e907cSAndroid Build Coastguard Worker         aidlCapConfiguration.parameterSettings =
326*4d7e907cSAndroid Build Coastguard Worker                 VALUE_OR_FATAL(convertSettingToAidl(xsdcSettingConfiguration));
327*4d7e907cSAndroid Build Coastguard Worker     }
328*4d7e907cSAndroid Build Coastguard Worker     return aidlCapConfiguration;
329*4d7e907cSAndroid Build Coastguard Worker }
330*4d7e907cSAndroid Build Coastguard Worker 
getConfigurationByName(const std::string & name,const std::vector<eng_xsd::SettingsType> & xsdcSettingsVec)331*4d7e907cSAndroid Build Coastguard Worker ConversionResult<eng_xsd::SettingsType::Configuration> getConfigurationByName(
332*4d7e907cSAndroid Build Coastguard Worker         const std::string& name, const std::vector<eng_xsd::SettingsType>& xsdcSettingsVec) {
333*4d7e907cSAndroid Build Coastguard Worker     for (const auto& xsdcSettings : xsdcSettingsVec) {
334*4d7e907cSAndroid Build Coastguard Worker         for (const auto& xsdcConfiguration : xsdcSettings.getConfiguration()) {
335*4d7e907cSAndroid Build Coastguard Worker             if (xsdcConfiguration.getName() == name) {
336*4d7e907cSAndroid Build Coastguard Worker                 return xsdcConfiguration;
337*4d7e907cSAndroid Build Coastguard Worker             }
338*4d7e907cSAndroid Build Coastguard Worker         }
339*4d7e907cSAndroid Build Coastguard Worker     }
340*4d7e907cSAndroid Build Coastguard Worker     LOG(ERROR) << __func__ << " failed to find configuration " << name;
341*4d7e907cSAndroid Build Coastguard Worker     return unexpected(BAD_VALUE);
342*4d7e907cSAndroid Build Coastguard Worker }
343*4d7e907cSAndroid Build Coastguard Worker 
344*4d7e907cSAndroid Build Coastguard Worker ConversionResult<std::vector<AudioHalCapConfiguration>>
convertConfigurationsToAidl(const std::vector<eng_xsd::ConfigurationsType> & xsdcConfigurationsVec,const std::vector<eng_xsd::SettingsType> & xsdcSettingsVec)345*4d7e907cSAndroid Build Coastguard Worker CapEngineConfigXmlConverter::convertConfigurationsToAidl(
346*4d7e907cSAndroid Build Coastguard Worker         const std::vector<eng_xsd::ConfigurationsType>& xsdcConfigurationsVec,
347*4d7e907cSAndroid Build Coastguard Worker         const std::vector<eng_xsd::SettingsType>& xsdcSettingsVec) {
348*4d7e907cSAndroid Build Coastguard Worker     if (xsdcConfigurationsVec.empty() || xsdcSettingsVec.empty()) {
349*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << " empty configurations/settings";
350*4d7e907cSAndroid Build Coastguard Worker         return unexpected(BAD_VALUE);
351*4d7e907cSAndroid Build Coastguard Worker     }
352*4d7e907cSAndroid Build Coastguard Worker     std::vector<AudioHalCapConfiguration> aidlConfigurations;
353*4d7e907cSAndroid Build Coastguard Worker     for (const auto& xsdcConfigurations : xsdcConfigurationsVec) {
354*4d7e907cSAndroid Build Coastguard Worker         for (const auto& xsdcConfiguration : xsdcConfigurations.getConfiguration()) {
355*4d7e907cSAndroid Build Coastguard Worker             auto xsdcSettingConfiguration = VALUE_OR_FATAL(
356*4d7e907cSAndroid Build Coastguard Worker                     getConfigurationByName(xsdcConfiguration.getName(), xsdcSettingsVec));
357*4d7e907cSAndroid Build Coastguard Worker             aidlConfigurations.push_back(VALUE_OR_FATAL(
358*4d7e907cSAndroid Build Coastguard Worker                     convertConfigurationToAidl(xsdcConfiguration, xsdcSettingConfiguration)));
359*4d7e907cSAndroid Build Coastguard Worker         }
360*4d7e907cSAndroid Build Coastguard Worker     }
361*4d7e907cSAndroid Build Coastguard Worker     return aidlConfigurations;
362*4d7e907cSAndroid Build Coastguard Worker }
363*4d7e907cSAndroid Build Coastguard Worker 
convertConfigurableDomainToAidl(const eng_xsd::ConfigurableDomainType & xsdcConfigurableDomain)364*4d7e907cSAndroid Build Coastguard Worker ConversionResult<AudioHalCapDomain> CapEngineConfigXmlConverter::convertConfigurableDomainToAidl(
365*4d7e907cSAndroid Build Coastguard Worker         const eng_xsd::ConfigurableDomainType& xsdcConfigurableDomain) {
366*4d7e907cSAndroid Build Coastguard Worker     AudioHalCapDomain aidlConfigurableDomain;
367*4d7e907cSAndroid Build Coastguard Worker 
368*4d7e907cSAndroid Build Coastguard Worker     aidlConfigurableDomain.name = xsdcConfigurableDomain.getName();
369*4d7e907cSAndroid Build Coastguard Worker     if (xsdcConfigurableDomain.hasSequenceAware() && xsdcConfigurableDomain.getSequenceAware()) {
370*4d7e907cSAndroid Build Coastguard Worker         LOG(ERROR) << "sequence aware not supported.";
371*4d7e907cSAndroid Build Coastguard Worker         return unexpected(BAD_VALUE);
372*4d7e907cSAndroid Build Coastguard Worker     }
373*4d7e907cSAndroid Build Coastguard Worker     if (xsdcConfigurableDomain.hasConfigurations() && xsdcConfigurableDomain.hasSettings()) {
374*4d7e907cSAndroid Build Coastguard Worker         aidlConfigurableDomain.configurations = VALUE_OR_FATAL(convertConfigurationsToAidl(
375*4d7e907cSAndroid Build Coastguard Worker                 xsdcConfigurableDomain.getConfigurations(), xsdcConfigurableDomain.getSettings()));
376*4d7e907cSAndroid Build Coastguard Worker     }
377*4d7e907cSAndroid Build Coastguard Worker     return aidlConfigurableDomain;
378*4d7e907cSAndroid Build Coastguard Worker }
379*4d7e907cSAndroid Build Coastguard Worker 
init()380*4d7e907cSAndroid Build Coastguard Worker void CapEngineConfigXmlConverter::init() {
381*4d7e907cSAndroid Build Coastguard Worker     if (getXsdcConfig()->hasConfigurableDomain()) {
382*4d7e907cSAndroid Build Coastguard Worker         mAidlCapDomains = std::make_optional<>(VALUE_OR_FATAL(
383*4d7e907cSAndroid Build Coastguard Worker                 (convertCollectionToAidlOptionalValues<eng_xsd::ConfigurableDomainType,
384*4d7e907cSAndroid Build Coastguard Worker                                                        AudioHalCapDomain>(
385*4d7e907cSAndroid Build Coastguard Worker                         getXsdcConfig()->getConfigurableDomain(),
386*4d7e907cSAndroid Build Coastguard Worker                         std::bind(&CapEngineConfigXmlConverter::convertConfigurableDomainToAidl,
387*4d7e907cSAndroid Build Coastguard Worker                                   this, std::placeholders::_1)))));
388*4d7e907cSAndroid Build Coastguard Worker     } else {
389*4d7e907cSAndroid Build Coastguard Worker         mAidlCapDomains = std::nullopt;
390*4d7e907cSAndroid Build Coastguard Worker     }
391*4d7e907cSAndroid Build Coastguard Worker }
392*4d7e907cSAndroid Build Coastguard Worker 
393*4d7e907cSAndroid Build Coastguard Worker }  // namespace aidl::android::hardware::audio::core::internal
394