1 /*
2 * Copyright (C) 2022 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 #include <fcntl.h>
18 #include <inttypes.h>
19 #include <unistd.h>
20 #include <functional>
21 #include <unordered_map>
22
23 #define LOG_TAG "AHAL_Config"
24 #include <aidl/android/media/audio/common/AudioFlag.h>
25 #include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
26 #include <aidl/android/media/audio/common/AudioProductStrategyType.h>
27 #include <android-base/logging.h>
28
29 #include "core-impl/CapEngineConfigXmlConverter.h"
30 #include "core-impl/EngineConfigXmlConverter.h"
31 #include "core-impl/XsdcConversion.h"
32
33 using aidl::android::hardware::audio::core::internal::CapEngineConfigXmlConverter;
34 using aidl::android::hardware::audio::core::internal::convertAudioUsageToAidl;
35 using aidl::android::media::audio::common::AudioAttributes;
36 using aidl::android::media::audio::common::AudioContentType;
37 using aidl::android::media::audio::common::AudioFlag;
38 using aidl::android::media::audio::common::AudioHalAttributesGroup;
39 using aidl::android::media::audio::common::AudioHalCapCriterion;
40 using aidl::android::media::audio::common::AudioHalCapCriterionType;
41 using aidl::android::media::audio::common::AudioHalCapCriterionV2;
42 using aidl::android::media::audio::common::AudioHalEngineConfig;
43 using aidl::android::media::audio::common::AudioHalProductStrategy;
44 using aidl::android::media::audio::common::AudioHalVolumeCurve;
45 using aidl::android::media::audio::common::AudioHalVolumeGroup;
46 using aidl::android::media::audio::common::AudioProductStrategyType;
47 using aidl::android::media::audio::common::AudioSource;
48 using aidl::android::media::audio::common::AudioStreamType;
49 using aidl::android::media::audio::common::AudioUsage;
50
51 using ::android::BAD_VALUE;
52 using ::android::base::unexpected;
53
54 namespace eng_xsd = android::audio::policy::engine::configuration;
55
56 namespace aidl::android::hardware::audio::core::internal {
57
58 /** Default path of audio policy cap engine configuration file. */
59 static constexpr char kCapEngineConfigFileName[] =
60 "/parameter-framework/Settings/Policy/PolicyConfigurableDomains.xml";
61
convertProductStrategyNameToAidl(const std::string & xsdcProductStrategyName)62 ConversionResult<int> EngineConfigXmlConverter::convertProductStrategyNameToAidl(
63 const std::string& xsdcProductStrategyName) {
64 const auto [it, success] = mProductStrategyMap.insert(
65 std::make_pair(xsdcProductStrategyName, mNextVendorStrategy));
66 if (success) {
67 mNextVendorStrategy++;
68 }
69 return it->second;
70 }
71
convertProductStrategyIdToAidl(int xsdcId)72 ConversionResult<int> EngineConfigXmlConverter::convertProductStrategyIdToAidl(int xsdcId) {
73 if (xsdcId < AudioHalProductStrategy::VENDOR_STRATEGY_ID_START) {
74 return unexpected(BAD_VALUE);
75 }
76 return xsdcId;
77 }
78
isDefaultAudioAttributes(const AudioAttributes & attributes)79 bool isDefaultAudioAttributes(const AudioAttributes& attributes) {
80 return ((attributes.contentType == AudioContentType::UNKNOWN) &&
81 (attributes.usage == AudioUsage::UNKNOWN) &&
82 (attributes.source == AudioSource::DEFAULT) && (attributes.flags == 0) &&
83 (attributes.tags.empty()));
84 }
85
convertAudioAttributesToAidl(const eng_xsd::AttributesType & xsdcAudioAttributes)86 ConversionResult<AudioAttributes> EngineConfigXmlConverter::convertAudioAttributesToAidl(
87 const eng_xsd::AttributesType& xsdcAudioAttributes) {
88 if (xsdcAudioAttributes.hasAttributesRef()) {
89 if (mAttributesReferenceMap.empty()) {
90 mAttributesReferenceMap =
91 generateReferenceMap<eng_xsd::AttributesRef, eng_xsd::AttributesRefType>(
92 getXsdcConfig()->getAttributesRef());
93 }
94 return convertAudioAttributesToAidl(
95 *(mAttributesReferenceMap.at(xsdcAudioAttributes.getAttributesRef())
96 .getFirstAttributes()));
97 }
98 AudioAttributes aidlAudioAttributes;
99 if (xsdcAudioAttributes.hasContentType()) {
100 aidlAudioAttributes.contentType = VALUE_OR_FATAL(convertAudioContentTypeToAidl(
101 xsdcAudioAttributes.getFirstContentType()->getValue()));
102 }
103 if (xsdcAudioAttributes.hasUsage()) {
104 aidlAudioAttributes.usage = VALUE_OR_FATAL(
105 convertAudioUsageToAidl(xsdcAudioAttributes.getFirstUsage()->getValue()));
106 }
107 if (xsdcAudioAttributes.hasSource()) {
108 aidlAudioAttributes.source = VALUE_OR_FATAL(
109 convertAudioSourceToAidl(xsdcAudioAttributes.getFirstSource()->getValue()));
110 }
111 if (xsdcAudioAttributes.hasFlags()) {
112 std::vector<eng_xsd::FlagType> xsdcFlagTypeVec =
113 xsdcAudioAttributes.getFirstFlags()->getValue();
114 aidlAudioAttributes.flags = VALUE_OR_FATAL(convertAudioFlagsToAidl(xsdcFlagTypeVec));
115 }
116 if (xsdcAudioAttributes.hasBundle()) {
117 const eng_xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
118 aidlAudioAttributes.tags.reserve(1);
119 aidlAudioAttributes.tags.push_back(xsdcBundle->getKey() + "_" + xsdcBundle->getValue());
120 }
121 if (isDefaultAudioAttributes(aidlAudioAttributes)) {
122 mDefaultProductStrategyId = std::optional<int>{-1};
123 }
124 return aidlAudioAttributes;
125 }
126
convertAttributesGroupToAidl(const eng_xsd::AttributesGroup & xsdcAttributesGroup)127 ConversionResult<AudioHalAttributesGroup> EngineConfigXmlConverter::convertAttributesGroupToAidl(
128 const eng_xsd::AttributesGroup& xsdcAttributesGroup) {
129 AudioHalAttributesGroup aidlAttributesGroup;
130 static const int kStreamTypeEnumOffset =
131 static_cast<int>(eng_xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
132 static_cast<int>(AudioStreamType::VOICE_CALL);
133 aidlAttributesGroup.streamType = xsdcAttributesGroup.hasStreamType()
134 ? VALUE_OR_FATAL(convertAudioStreamTypeToAidl(
135 xsdcAttributesGroup.getStreamType()))
136 : AudioStreamType::INVALID;
137 aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup();
138 if (xsdcAttributesGroup.hasAttributes_optional()) {
139 aidlAttributesGroup.attributes =
140 VALUE_OR_FATAL((convertCollectionToAidl<eng_xsd::AttributesType, AudioAttributes>(
141 xsdcAttributesGroup.getAttributes_optional(),
142 std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this,
143 std::placeholders::_1))));
144 } else if (xsdcAttributesGroup.hasContentType_optional() ||
145 xsdcAttributesGroup.hasUsage_optional() ||
146 xsdcAttributesGroup.hasSource_optional() ||
147 xsdcAttributesGroup.hasFlags_optional() ||
148 xsdcAttributesGroup.hasBundle_optional()) {
149 aidlAttributesGroup.attributes.push_back(VALUE_OR_FATAL(convertAudioAttributesToAidl(
150 eng_xsd::AttributesType(xsdcAttributesGroup.getContentType_optional(),
151 xsdcAttributesGroup.getUsage_optional(),
152 xsdcAttributesGroup.getSource_optional(),
153 xsdcAttributesGroup.getFlags_optional(),
154 xsdcAttributesGroup.getBundle_optional(), std::nullopt))));
155
156 } else {
157 LOG(ERROR) << __func__ << " Review Audio Policy config: no audio attributes provided for "
158 << aidlAttributesGroup.toString();
159 return unexpected(BAD_VALUE);
160 }
161 return aidlAttributesGroup;
162 }
163
convertProductStrategyToAidl(const eng_xsd::ProductStrategies::ProductStrategy & xsdcProductStrategy)164 ConversionResult<AudioHalProductStrategy> EngineConfigXmlConverter::convertProductStrategyToAidl(
165 const eng_xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
166 AudioHalProductStrategy aidlProductStrategy;
167
168 if (xsdcProductStrategy.hasId()) {
169 aidlProductStrategy.id =
170 VALUE_OR_FATAL(convertProductStrategyIdToAidl(xsdcProductStrategy.getId()));
171 } else {
172 aidlProductStrategy.id =
173 VALUE_OR_FATAL(convertProductStrategyNameToAidl(xsdcProductStrategy.getName()));
174 }
175 aidlProductStrategy.name = xsdcProductStrategy.getName();
176
177 if (xsdcProductStrategy.hasAttributesGroup()) {
178 aidlProductStrategy.attributesGroups = VALUE_OR_FATAL(
179 (convertCollectionToAidl<eng_xsd::AttributesGroup, AudioHalAttributesGroup>(
180 xsdcProductStrategy.getAttributesGroup(),
181 std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this,
182 std::placeholders::_1))));
183 }
184 if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) {
185 mDefaultProductStrategyId = aidlProductStrategy.id;
186 }
187 return aidlProductStrategy;
188 }
189
convertVolumeCurveToAidl(const eng_xsd::Volume & xsdcVolumeCurve)190 ConversionResult<AudioHalVolumeCurve> EngineConfigXmlConverter::convertVolumeCurveToAidl(
191 const eng_xsd::Volume& xsdcVolumeCurve) {
192 AudioHalVolumeCurve aidlVolumeCurve;
193 aidlVolumeCurve.deviceCategory =
194 static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
195 if (xsdcVolumeCurve.hasRef()) {
196 if (mVolumesReferenceMap.empty()) {
197 mVolumesReferenceMap = generateReferenceMap<eng_xsd::VolumesType, eng_xsd::VolumeRef>(
198 getXsdcConfig()->getVolumes());
199 }
200 aidlVolumeCurve.curvePoints = VALUE_OR_FATAL(
201 (convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
202 mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
203 &convertCurvePointToAidl)));
204 } else {
205 aidlVolumeCurve.curvePoints = VALUE_OR_FATAL(
206 (convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
207 xsdcVolumeCurve.getPoint(), &convertCurvePointToAidl)));
208 }
209 return aidlVolumeCurve;
210 }
211
convertVolumeGroupToAidl(const eng_xsd::VolumeGroupsType::VolumeGroup & xsdcVolumeGroup)212 ConversionResult<AudioHalVolumeGroup> EngineConfigXmlConverter::convertVolumeGroupToAidl(
213 const eng_xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
214 AudioHalVolumeGroup aidlVolumeGroup;
215 aidlVolumeGroup.name = xsdcVolumeGroup.getName();
216 aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin();
217 aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax();
218 aidlVolumeGroup.volumeCurves =
219 VALUE_OR_FATAL((convertCollectionToAidl<eng_xsd::Volume, AudioHalVolumeCurve>(
220 xsdcVolumeGroup.getVolume(),
221 std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this,
222 std::placeholders::_1))));
223 return aidlVolumeGroup;
224 }
225
getAidlEngineConfig()226 AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() {
227 return mAidlEngineConfig;
228 }
229
init()230 void EngineConfigXmlConverter::init() {
231 mProductStrategyMap = getLegacyProductStrategyMap();
232 if (getXsdcConfig()->hasProductStrategies()) {
233 mAidlEngineConfig.productStrategies = VALUE_OR_FATAL(
234 (convertWrappedCollectionToAidl<eng_xsd::ProductStrategies,
235 eng_xsd::ProductStrategies::ProductStrategy,
236 AudioHalProductStrategy>(
237 getXsdcConfig()->getProductStrategies(),
238 &eng_xsd::ProductStrategies::getProductStrategy,
239 std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this,
240 std::placeholders::_1))));
241 if (mDefaultProductStrategyId) {
242 mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value();
243 }
244 }
245 if (getXsdcConfig()->hasVolumeGroups()) {
246 mAidlEngineConfig.volumeGroups = VALUE_OR_FATAL(
247 (convertWrappedCollectionToAidl<eng_xsd::VolumeGroupsType,
248 eng_xsd::VolumeGroupsType::VolumeGroup,
249 AudioHalVolumeGroup>(
250 getXsdcConfig()->getVolumeGroups(),
251 &eng_xsd::VolumeGroupsType::getVolumeGroup,
252 std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
253 std::placeholders::_1))));
254 }
255 if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
256 AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
257 capSpecificConfig.criteriaV2 =
258 std::make_optional<>(VALUE_OR_FATAL((convertCapCriteriaCollectionToAidl(
259 getXsdcConfig()->getCriteria(), getXsdcConfig()->getCriterion_types()))));
260 internal::CapEngineConfigXmlConverter capEngConfigConverter{
261 ::android::audio_find_readable_configuration_file(kCapEngineConfigFileName)};
262 if (capEngConfigConverter.getStatus() == ::android::OK) {
263 capSpecificConfig.domains = std::move(capEngConfigConverter.getAidlCapEngineConfig());
264 }
265 mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
266 }
267 }
268 } // namespace aidl::android::hardware::audio::core::internal
269