blob: 71b4b0eb607c26c705d3f4f254d4ab19dbee8f1e [file] [log] [blame]
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +00001/*
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#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
24
25#include "core-impl/EngineConfigXmlConverter.h"
26
27using aidl::android::media::audio::common::AudioAttributes;
28using aidl::android::media::audio::common::AudioContentType;
29using aidl::android::media::audio::common::AudioFlag;
30using aidl::android::media::audio::common::AudioHalAttributesGroup;
31using aidl::android::media::audio::common::AudioHalCapCriterion;
32using aidl::android::media::audio::common::AudioHalCapCriterionType;
33using aidl::android::media::audio::common::AudioHalEngineConfig;
34using aidl::android::media::audio::common::AudioHalProductStrategy;
35using aidl::android::media::audio::common::AudioHalVolumeCurve;
36using aidl::android::media::audio::common::AudioHalVolumeGroup;
37using aidl::android::media::audio::common::AudioProductStrategyType;
38using aidl::android::media::audio::common::AudioSource;
39using aidl::android::media::audio::common::AudioStreamType;
40using aidl::android::media::audio::common::AudioUsage;
41
42namespace xsd = android::audio::policy::engine::configuration;
43
44namespace aidl::android::hardware::audio::core::internal {
45
46/**
47 * Valid curve points take the form "<index>,<attenuationMb>", where the index
48 * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
49 * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
50 * '.' instead of a ',' in their XML)-- using such a curve point will result in
51 * failed VTS tests.
52 */
53static const int8_t kInvalidCurvePointIndex = -1;
54
55void EngineConfigXmlConverter::initProductStrategyMap() {
56#define STRATEGY_ENTRY(name) {"STRATEGY_" #name, static_cast<int>(AudioProductStrategyType::name)}
57
58 mProductStrategyMap = {STRATEGY_ENTRY(MEDIA),
59 STRATEGY_ENTRY(PHONE),
60 STRATEGY_ENTRY(SONIFICATION),
61 STRATEGY_ENTRY(SONIFICATION_RESPECTFUL),
62 STRATEGY_ENTRY(DTMF),
63 STRATEGY_ENTRY(ENFORCED_AUDIBLE),
64 STRATEGY_ENTRY(TRANSMITTED_THROUGH_SPEAKER),
65 STRATEGY_ENTRY(ACCESSIBILITY)};
66#undef STRATEGY_ENTRY
67}
68
69int EngineConfigXmlConverter::convertProductStrategyNameToAidl(
70 const std::string& xsdcProductStrategyName) {
71 const auto [it, success] = mProductStrategyMap.insert(
72 std::make_pair(xsdcProductStrategyName, mNextVendorStrategy));
73 if (success) {
74 mNextVendorStrategy++;
75 }
76 return it->second;
77}
78
79bool 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
86AudioAttributes EngineConfigXmlConverter::convertAudioAttributesToAidl(
87 const xsd::AttributesType& xsdcAudioAttributes) {
88 if (xsdcAudioAttributes.hasAttributesRef()) {
89 if (mAttributesReferenceMap.empty()) {
90 mAttributesReferenceMap =
91 generateReferenceMap<xsd::AttributesRef, 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 = static_cast<AudioContentType>(
101 xsdcAudioAttributes.getFirstContentType()->getValue());
102 }
103 if (xsdcAudioAttributes.hasUsage()) {
104 aidlAudioAttributes.usage =
105 static_cast<AudioUsage>(xsdcAudioAttributes.getFirstUsage()->getValue());
106 }
107 if (xsdcAudioAttributes.hasSource()) {
108 aidlAudioAttributes.source =
109 static_cast<AudioSource>(xsdcAudioAttributes.getFirstSource()->getValue());
110 }
111 if (xsdcAudioAttributes.hasFlags()) {
112 std::vector<xsd::FlagType> xsdcFlagTypeVec =
113 xsdcAudioAttributes.getFirstFlags()->getValue();
114 for (const xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
115 if (xsdcFlagType != xsd::FlagType::AUDIO_FLAG_NONE) {
116 aidlAudioAttributes.flags |= 1 << (static_cast<int>(xsdcFlagType) - 1);
117 }
118 }
119 }
120 if (xsdcAudioAttributes.hasBundle()) {
121 const xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
122 aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue();
123 }
124 if (isDefaultAudioAttributes(aidlAudioAttributes)) {
125 mDefaultProductStrategyId = std::optional<int>{-1};
126 }
127 return aidlAudioAttributes;
128}
129
130AudioHalAttributesGroup EngineConfigXmlConverter::convertAttributesGroupToAidl(
131 const xsd::AttributesGroup& xsdcAttributesGroup) {
132 AudioHalAttributesGroup aidlAttributesGroup;
133 static const int kStreamTypeEnumOffset =
134 static_cast<int>(xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
135 static_cast<int>(AudioStreamType::VOICE_CALL);
136 aidlAttributesGroup.streamType = static_cast<AudioStreamType>(
137 static_cast<int>(xsdcAttributesGroup.getStreamType()) - kStreamTypeEnumOffset);
138 aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup();
139 if (xsdcAttributesGroup.hasAttributes_optional()) {
140 aidlAttributesGroup.attributes =
141 convertCollectionToAidl<xsd::AttributesType, AudioAttributes>(
142 xsdcAttributesGroup.getAttributes_optional(),
143 std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this,
144 std::placeholders::_1));
145 } else if (xsdcAttributesGroup.hasContentType_optional() ||
146 xsdcAttributesGroup.hasUsage_optional() ||
147 xsdcAttributesGroup.hasSource_optional() ||
148 xsdcAttributesGroup.hasFlags_optional() ||
149 xsdcAttributesGroup.hasBundle_optional()) {
150 aidlAttributesGroup.attributes.push_back(convertAudioAttributesToAidl(xsd::AttributesType(
151 xsdcAttributesGroup.getContentType_optional(),
152 xsdcAttributesGroup.getUsage_optional(), xsdcAttributesGroup.getSource_optional(),
153 xsdcAttributesGroup.getFlags_optional(), xsdcAttributesGroup.getBundle_optional(),
154 std::nullopt)));
155
156 } else {
157 // do nothing;
158 // TODO: check if this is valid or if we should treat as an error.
159 // Currently, attributes are not mandatory in schema, but an AttributesGroup
160 // without attributes does not make much sense.
161 }
162 return aidlAttributesGroup;
163}
164
165AudioHalProductStrategy EngineConfigXmlConverter::convertProductStrategyToAidl(
166 const xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
167 AudioHalProductStrategy aidlProductStrategy;
168
169 aidlProductStrategy.id = convertProductStrategyNameToAidl(xsdcProductStrategy.getName());
170
171 if (xsdcProductStrategy.hasAttributesGroup()) {
172 aidlProductStrategy.attributesGroups =
173 convertCollectionToAidl<xsd::AttributesGroup, AudioHalAttributesGroup>(
174 xsdcProductStrategy.getAttributesGroup(),
175 std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this,
176 std::placeholders::_1));
177 }
178 if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) {
179 mDefaultProductStrategyId = aidlProductStrategy.id;
180 }
181 return aidlProductStrategy;
182}
183
184AudioHalVolumeCurve::CurvePoint EngineConfigXmlConverter::convertCurvePointToAidl(
185 const std::string& xsdcCurvePoint) {
186 AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
187 if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
188 &aidlCurvePoint.attenuationMb) != 2) {
189 aidlCurvePoint.index = kInvalidCurvePointIndex;
190 }
191 return aidlCurvePoint;
192}
193
194AudioHalVolumeCurve EngineConfigXmlConverter::convertVolumeCurveToAidl(
195 const xsd::Volume& xsdcVolumeCurve) {
196 AudioHalVolumeCurve aidlVolumeCurve;
197 aidlVolumeCurve.deviceCategory =
198 static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
199 if (xsdcVolumeCurve.hasRef()) {
200 if (mVolumesReferenceMap.empty()) {
201 mVolumesReferenceMap = generateReferenceMap<xsd::VolumesType, xsd::VolumeRef>(
202 getXsdcConfig()->getVolumes());
203 }
204 aidlVolumeCurve.curvePoints =
205 convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
206 mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
207 std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
208 std::placeholders::_1));
209 } else {
210 aidlVolumeCurve.curvePoints =
211 convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
212 xsdcVolumeCurve.getPoint(),
213 std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
214 std::placeholders::_1));
215 }
216 return aidlVolumeCurve;
217}
218
219AudioHalVolumeGroup EngineConfigXmlConverter::convertVolumeGroupToAidl(
220 const xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
221 AudioHalVolumeGroup aidlVolumeGroup;
222 aidlVolumeGroup.name = xsdcVolumeGroup.getName();
223 aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin();
224 aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax();
225 aidlVolumeGroup.volumeCurves = convertCollectionToAidl<xsd::Volume, AudioHalVolumeCurve>(
226 xsdcVolumeGroup.getVolume(),
227 std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this,
228 std::placeholders::_1));
229 return aidlVolumeGroup;
230}
231
232AudioHalCapCriterion EngineConfigXmlConverter::convertCapCriterionToAidl(
233 const xsd::CriterionType& xsdcCriterion) {
234 AudioHalCapCriterion aidlCapCriterion;
235 aidlCapCriterion.name = xsdcCriterion.getName();
236 aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
237 aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
238 return aidlCapCriterion;
239}
240
241std::string EngineConfigXmlConverter::convertCriterionTypeValueToAidl(
242 const xsd::ValueType& xsdcCriterionTypeValue) {
243 return xsdcCriterionTypeValue.getLiteral();
244}
245
246AudioHalCapCriterionType EngineConfigXmlConverter::convertCapCriterionTypeToAidl(
247 const xsd::CriterionTypeType& xsdcCriterionType) {
248 AudioHalCapCriterionType aidlCapCriterionType;
249 aidlCapCriterionType.name = xsdcCriterionType.getName();
250 aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
251 aidlCapCriterionType.values =
252 convertWrappedCollectionToAidl<xsd::ValuesType, xsd::ValueType, std::string>(
253 xsdcCriterionType.getValues(), &xsd::ValuesType::getValue,
254 std::bind(&EngineConfigXmlConverter::convertCriterionTypeValueToAidl, this,
255 std::placeholders::_1));
256 return aidlCapCriterionType;
257}
258
259AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() {
260 return mAidlEngineConfig;
261}
262
263void EngineConfigXmlConverter::init() {
264 initProductStrategyMap();
265 if (getXsdcConfig()->hasProductStrategies()) {
266 mAidlEngineConfig.productStrategies =
267 convertWrappedCollectionToAidl<xsd::ProductStrategies,
268 xsd::ProductStrategies::ProductStrategy,
269 AudioHalProductStrategy>(
270 getXsdcConfig()->getProductStrategies(),
271 &xsd::ProductStrategies::getProductStrategy,
272 std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this,
273 std::placeholders::_1));
274 if (mDefaultProductStrategyId) {
275 mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value();
276 }
277 }
278 if (getXsdcConfig()->hasVolumeGroups()) {
279 mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidl<
280 xsd::VolumeGroupsType, xsd::VolumeGroupsType::VolumeGroup, AudioHalVolumeGroup>(
281 getXsdcConfig()->getVolumeGroups(), &xsd::VolumeGroupsType::getVolumeGroup,
282 std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
283 std::placeholders::_1));
284 }
285 if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
286 AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
287 capSpecificConfig.criteria =
288 convertWrappedCollectionToAidl<xsd::CriteriaType, xsd::CriterionType,
289 AudioHalCapCriterion>(
290 getXsdcConfig()->getCriteria(), &xsd::CriteriaType::getCriterion,
291 std::bind(&EngineConfigXmlConverter::convertCapCriterionToAidl, this,
292 std::placeholders::_1));
293 capSpecificConfig.criterionTypes =
294 convertWrappedCollectionToAidl<xsd::CriterionTypesType, xsd::CriterionTypeType,
295 AudioHalCapCriterionType>(
296 getXsdcConfig()->getCriterion_types(),
297 &xsd::CriterionTypesType::getCriterion_type,
298 std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this,
299 std::placeholders::_1));
300 mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
301 }
302}
303} // namespace aidl::android::hardware::audio::core::internal