blob: 96b555c640b9907aa5b1abc68e88ee202a27cee3 [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
Mikhail Naganovaf75a672023-10-13 23:38:25 +000044namespace xsd = android::audio::policy::engine::configuration;
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +000045
46namespace aidl::android::hardware::audio::core::internal {
47
Mikhail Naganovaf75a672023-10-13 23:38:25 +000048/**
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
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +000057void 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
Mikhail Naganovaf75a672023-10-13 23:38:25 +000071int EngineConfigXmlConverter::convertProductStrategyNameToAidl(
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +000072 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
Mikhail Naganovaf75a672023-10-13 23:38:25 +000088AudioAttributes EngineConfigXmlConverter::convertAudioAttributesToAidl(
89 const xsd::AttributesType& xsdcAudioAttributes) {
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +000090 if (xsdcAudioAttributes.hasAttributesRef()) {
91 if (mAttributesReferenceMap.empty()) {
92 mAttributesReferenceMap =
Mikhail Naganovaf75a672023-10-13 23:38:25 +000093 generateReferenceMap<xsd::AttributesRef, xsd::AttributesRefType>(
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +000094 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()) {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000114 std::vector<xsd::FlagType> xsdcFlagTypeVec =
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000115 xsdcAudioAttributes.getFirstFlags()->getValue();
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000116 for (const xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
117 if (xsdcFlagType != xsd::FlagType::AUDIO_FLAG_NONE) {
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000118 aidlAudioAttributes.flags |= 1 << (static_cast<int>(xsdcFlagType) - 1);
119 }
120 }
121 }
122 if (xsdcAudioAttributes.hasBundle()) {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000123 const xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000124 aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue();
125 }
126 if (isDefaultAudioAttributes(aidlAudioAttributes)) {
127 mDefaultProductStrategyId = std::optional<int>{-1};
128 }
129 return aidlAudioAttributes;
130}
131
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000132AudioHalAttributesGroup EngineConfigXmlConverter::convertAttributesGroupToAidl(
133 const xsd::AttributesGroup& xsdcAttributesGroup) {
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000134 AudioHalAttributesGroup aidlAttributesGroup;
135 static const int kStreamTypeEnumOffset =
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000136 static_cast<int>(xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000137 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 =
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000143 convertCollectionToAidlUnchecked<xsd::AttributesType, AudioAttributes>(
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000144 xsdcAttributesGroup.getAttributes_optional(),
145 std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this,
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000146 std::placeholders::_1));
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000147 } else if (xsdcAttributesGroup.hasContentType_optional() ||
148 xsdcAttributesGroup.hasUsage_optional() ||
149 xsdcAttributesGroup.hasSource_optional() ||
150 xsdcAttributesGroup.hasFlags_optional() ||
151 xsdcAttributesGroup.hasBundle_optional()) {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000152 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)));
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000157
158 } else {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000159 // 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.
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000163 }
164 return aidlAttributesGroup;
165}
166
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000167AudioHalProductStrategy EngineConfigXmlConverter::convertProductStrategyToAidl(
168 const xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000169 AudioHalProductStrategy aidlProductStrategy;
170
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000171 aidlProductStrategy.id = convertProductStrategyNameToAidl(xsdcProductStrategy.getName());
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000172
173 if (xsdcProductStrategy.hasAttributesGroup()) {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000174 aidlProductStrategy.attributesGroups =
175 convertCollectionToAidlUnchecked<xsd::AttributesGroup, AudioHalAttributesGroup>(
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000176 xsdcProductStrategy.getAttributesGroup(),
177 std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this,
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000178 std::placeholders::_1));
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000179 }
180 if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) {
181 mDefaultProductStrategyId = aidlProductStrategy.id;
182 }
183 return aidlProductStrategy;
184}
185
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000186AudioHalVolumeCurve::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) {
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000198 AudioHalVolumeCurve aidlVolumeCurve;
199 aidlVolumeCurve.deviceCategory =
200 static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
201 if (xsdcVolumeCurve.hasRef()) {
202 if (mVolumesReferenceMap.empty()) {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000203 mVolumesReferenceMap = generateReferenceMap<xsd::VolumesType, xsd::VolumeRef>(
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000204 getXsdcConfig()->getVolumes());
205 }
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000206 aidlVolumeCurve.curvePoints =
207 convertCollectionToAidlUnchecked<std::string, AudioHalVolumeCurve::CurvePoint>(
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000208 mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000209 std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
210 std::placeholders::_1));
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000211 } else {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000212 aidlVolumeCurve.curvePoints =
213 convertCollectionToAidlUnchecked<std::string, AudioHalVolumeCurve::CurvePoint>(
214 xsdcVolumeCurve.getPoint(),
215 std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
216 std::placeholders::_1));
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000217 }
218 return aidlVolumeCurve;
219}
220
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000221AudioHalVolumeGroup EngineConfigXmlConverter::convertVolumeGroupToAidl(
222 const xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000223 AudioHalVolumeGroup aidlVolumeGroup;
224 aidlVolumeGroup.name = xsdcVolumeGroup.getName();
225 aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin();
226 aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax();
Lorena Torres-Huertaaa8f76a2022-12-12 18:17:10 +0000227 aidlVolumeGroup.volumeCurves =
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000228 convertCollectionToAidlUnchecked<xsd::Volume, AudioHalVolumeCurve>(
Lorena Torres-Huertaaa8f76a2022-12-12 18:17:10 +0000229 xsdcVolumeGroup.getVolume(),
230 std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this,
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000231 std::placeholders::_1));
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000232 return aidlVolumeGroup;
233}
234
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000235AudioHalCapCriterion EngineConfigXmlConverter::convertCapCriterionToAidl(
236 const xsd::CriterionType& xsdcCriterion) {
237 AudioHalCapCriterion aidlCapCriterion;
238 aidlCapCriterion.name = xsdcCriterion.getName();
239 aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
240 aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
241 return aidlCapCriterion;
242}
243
244std::string EngineConfigXmlConverter::convertCriterionTypeValueToAidl(
245 const xsd::ValueType& xsdcCriterionTypeValue) {
246 return xsdcCriterionTypeValue.getLiteral();
247}
248
249AudioHalCapCriterionType EngineConfigXmlConverter::convertCapCriterionTypeToAidl(
250 const xsd::CriterionTypeType& xsdcCriterionType) {
251 AudioHalCapCriterionType aidlCapCriterionType;
252 aidlCapCriterionType.name = xsdcCriterionType.getName();
253 aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
254 aidlCapCriterionType.values =
255 convertWrappedCollectionToAidlUnchecked<xsd::ValuesType, xsd::ValueType, std::string>(
256 xsdcCriterionType.getValues(), &xsd::ValuesType::getValue,
257 std::bind(&EngineConfigXmlConverter::convertCriterionTypeValueToAidl, this,
258 std::placeholders::_1));
259 return aidlCapCriterionType;
260}
261
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000262AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() {
263 return mAidlEngineConfig;
264}
265
266void EngineConfigXmlConverter::init() {
267 initProductStrategyMap();
268 if (getXsdcConfig()->hasProductStrategies()) {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000269 mAidlEngineConfig.productStrategies =
270 convertWrappedCollectionToAidlUnchecked<xsd::ProductStrategies,
271 xsd::ProductStrategies::ProductStrategy,
272 AudioHalProductStrategy>(
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000273 getXsdcConfig()->getProductStrategies(),
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000274 &xsd::ProductStrategies::getProductStrategy,
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000275 std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this,
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000276 std::placeholders::_1));
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000277 if (mDefaultProductStrategyId) {
278 mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value();
279 }
280 }
281 if (getXsdcConfig()->hasVolumeGroups()) {
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000282 mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidlUnchecked<
283 xsd::VolumeGroupsType, xsd::VolumeGroupsType::VolumeGroup, AudioHalVolumeGroup>(
284 getXsdcConfig()->getVolumeGroups(), &xsd::VolumeGroupsType::getVolumeGroup,
285 std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
286 std::placeholders::_1));
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000287 }
288 if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
289 AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
Mikhail Naganovaf75a672023-10-13 23:38:25 +0000290 capSpecificConfig.criteria =
291 convertWrappedCollectionToAidlUnchecked<xsd::CriteriaType, xsd::CriterionType,
292 AudioHalCapCriterion>(
293 getXsdcConfig()->getCriteria(), &xsd::CriteriaType::getCriterion,
294 std::bind(&EngineConfigXmlConverter::convertCapCriterionToAidl, this,
295 std::placeholders::_1));
296 capSpecificConfig.criterionTypes = convertWrappedCollectionToAidlUnchecked<
297 xsd::CriterionTypesType, xsd::CriterionTypeType, AudioHalCapCriterionType>(
298 getXsdcConfig()->getCriterion_types(), &xsd::CriterionTypesType::getCriterion_type,
299 std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this,
300 std::placeholders::_1));
301 mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
Lorena Torres-Huertabc585bd2022-10-23 20:41:35 +0000302 }
303}
Lorena Torres-Huertaaa8f76a2022-12-12 18:17:10 +0000304} // namespace aidl::android::hardware::audio::core::internal