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