blob: 2feb0c3b8c852f5401bfc9b97d34b42f054c3809 [file] [log] [blame]
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +00001#include <inttypes.h>
2
3#include <unordered_set>
4
5#define LOG_TAG "AHAL_Config"
6#include <android-base/logging.h>
7#include <android-base/strings.h>
8
9#include <aidl/android/media/audio/common/AudioPort.h>
10#include <aidl/android/media/audio/common/AudioPortConfig.h>
11#include <media/AidlConversionCppNdk.h>
12#include <media/TypeConverter.h>
13
14#include "core-impl/XmlConverter.h"
15#include "core-impl/XsdcConversion.h"
16
17using aidl::android::media::audio::common::AudioChannelLayout;
18using aidl::android::media::audio::common::AudioDevice;
19using aidl::android::media::audio::common::AudioDeviceAddress;
20using aidl::android::media::audio::common::AudioDeviceDescription;
21using aidl::android::media::audio::common::AudioDeviceType;
22using aidl::android::media::audio::common::AudioFormatDescription;
23using aidl::android::media::audio::common::AudioFormatType;
24using aidl::android::media::audio::common::AudioGain;
25using aidl::android::media::audio::common::AudioHalCapCriterion;
26using aidl::android::media::audio::common::AudioHalCapCriterionType;
27using aidl::android::media::audio::common::AudioHalVolumeCurve;
28using aidl::android::media::audio::common::AudioIoFlags;
29using aidl::android::media::audio::common::AudioPort;
30using aidl::android::media::audio::common::AudioPortConfig;
31using aidl::android::media::audio::common::AudioPortDeviceExt;
32using aidl::android::media::audio::common::AudioPortExt;
33using aidl::android::media::audio::common::AudioPortMixExt;
34using aidl::android::media::audio::common::AudioProfile;
35using ::android::BAD_VALUE;
36using ::android::base::unexpected;
37
38namespace ap_xsd = android::audio::policy::configuration;
39namespace eng_xsd = android::audio::policy::engine::configuration;
40
41namespace aidl::android::hardware::audio::core::internal {
42
43inline ConversionResult<std::string> assertNonEmpty(const std::string& s) {
44 if (s.empty()) {
45 LOG(ERROR) << __func__ << " Review Audio Policy config: "
46 << " empty string is not valid.";
47 return unexpected(BAD_VALUE);
48 }
49 return s;
50}
51
52#define NON_EMPTY_STRING_OR_FATAL(s) VALUE_OR_FATAL(assertNonEmpty(s))
53
54ConversionResult<AudioFormatDescription> convertAudioFormatToAidl(const std::string& xsdcFormat) {
55 audio_format_t legacyFormat = ::android::formatFromString(xsdcFormat, AUDIO_FORMAT_DEFAULT);
56 ConversionResult<AudioFormatDescription> result =
57 legacy2aidl_audio_format_t_AudioFormatDescription(legacyFormat);
58 if ((legacyFormat == AUDIO_FORMAT_DEFAULT && xsdcFormat.compare("AUDIO_FORMAT_DEFAULT") != 0) ||
59 !result.ok()) {
60 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xsdcFormat
61 << " is not a valid audio format.";
62 return unexpected(BAD_VALUE);
63 }
64 return result;
65}
66
67std::unordered_set<std::string> getAttachedDevices(const ap_xsd::Modules::Module& moduleConfig) {
68 std::unordered_set<std::string> attachedDeviceSet;
69 if (moduleConfig.hasAttachedDevices()) {
70 for (const ap_xsd::AttachedDevices& attachedDevices : moduleConfig.getAttachedDevices()) {
71 if (attachedDevices.hasItem()) {
72 attachedDeviceSet.insert(attachedDevices.getItem().begin(),
73 attachedDevices.getItem().end());
74 }
75 }
76 }
77 return attachedDeviceSet;
78}
79
80ConversionResult<AudioDeviceDescription> convertDeviceTypeToAidl(const std::string& xType) {
81 audio_devices_t legacyDeviceType = AUDIO_DEVICE_NONE;
82 ::android::DeviceConverter::fromString(xType, legacyDeviceType);
83 ConversionResult<AudioDeviceDescription> result =
84 legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyDeviceType);
85 if ((legacyDeviceType == AUDIO_DEVICE_NONE) || !result.ok()) {
86 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xType
87 << " is not a valid device type.";
88 return unexpected(BAD_VALUE);
89 }
90 return result;
91}
92
93ConversionResult<AudioDevice> createAudioDevice(
94 const ap_xsd::DevicePorts::DevicePort& xDevicePort) {
95 AudioDevice device = {
96 .type = VALUE_OR_FATAL(convertDeviceTypeToAidl(xDevicePort.getType())),
97 .address = xDevicePort.hasAddress()
98 ? AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(
99 xDevicePort.getAddress())
100 : AudioDeviceAddress{}};
101 if (device.type.type == AudioDeviceType::IN_MICROPHONE && device.type.connection.empty()) {
102 device.address = "bottom";
103 } else if (device.type.type == AudioDeviceType::IN_MICROPHONE_BACK &&
104 device.type.connection.empty()) {
105 device.address = "back";
106 }
107 return device;
108}
109
110ConversionResult<AudioPortExt> createAudioPortExt(
111 const ap_xsd::DevicePorts::DevicePort& xDevicePort,
112 const std::string& xDefaultOutputDevice) {
113 AudioPortDeviceExt deviceExt = {
114 .device = VALUE_OR_FATAL(createAudioDevice(xDevicePort)),
115 .flags = (xDevicePort.getTagName() == xDefaultOutputDevice)
116 ? 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE
117 : 0,
118 .encodedFormats =
119 xDevicePort.hasEncodedFormats()
120 ? VALUE_OR_FATAL(
121 (convertCollectionToAidl<std::string, AudioFormatDescription>(
122 xDevicePort.getEncodedFormats(),
123 &convertAudioFormatToAidl)))
124 : std::vector<AudioFormatDescription>{},
125 };
126 return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
127}
128
129ConversionResult<AudioPortExt> createAudioPortExt(const ap_xsd::MixPorts::MixPort& xMixPort) {
130 AudioPortMixExt mixExt = {
131 .maxOpenStreamCount =
132 xMixPort.hasMaxOpenCount() ? static_cast<int>(xMixPort.getMaxOpenCount()) : 0,
133 .maxActiveStreamCount = xMixPort.hasMaxActiveCount()
134 ? static_cast<int>(xMixPort.getMaxActiveCount())
135 : 1,
136 .recommendedMuteDurationMs =
137 xMixPort.hasRecommendedMuteDurationMs()
138 ? static_cast<int>(xMixPort.getRecommendedMuteDurationMs())
139 : 0};
140 return AudioPortExt::make<AudioPortExt::Tag::mix>(mixExt);
141}
142
143ConversionResult<int> convertGainModeToAidl(const std::vector<ap_xsd::AudioGainMode>& gainModeVec) {
144 static const char gainModeSeparator = ' ';
145 int gainModeMask = 0;
146 for (const ap_xsd::AudioGainMode& gainMode : gainModeVec) {
147 gainModeMask |= static_cast<int>(::android::GainModeConverter::maskFromString(
148 ap_xsd::toString(gainMode), &gainModeSeparator));
149 }
150 return gainModeMask;
151}
152
153ConversionResult<AudioChannelLayout> convertChannelMaskToAidl(
154 const ap_xsd::AudioChannelMask& xChannelMask) {
155 std::string xChannelMaskLiteral = ap_xsd::toString(xChannelMask);
156 audio_channel_mask_t legacyChannelMask = ::android::channelMaskFromString(xChannelMaskLiteral);
157 ConversionResult<AudioChannelLayout> result =
158 legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
159 legacyChannelMask,
160 /* isInput= */ xChannelMaskLiteral.find("AUDIO_CHANNEL_IN_") == 0);
161 if ((legacyChannelMask == AUDIO_CHANNEL_INVALID) || !result.ok()) {
162 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xChannelMaskLiteral
163 << " is not a valid audio channel mask.";
164 return unexpected(BAD_VALUE);
165 }
166 return result;
167}
168
169ConversionResult<AudioGain> convertGainToAidl(const ap_xsd::Gains::Gain& xGain) {
170 return AudioGain{
171 .mode = VALUE_OR_FATAL(convertGainModeToAidl(xGain.getMode())),
172 .channelMask =
173 xGain.hasChannel_mask()
174 ? VALUE_OR_FATAL(convertChannelMaskToAidl(xGain.getChannel_mask()))
175 : AudioChannelLayout{},
176 .minValue = xGain.hasMinValueMB() ? xGain.getMinValueMB() : 0,
177 .maxValue = xGain.hasMaxValueMB() ? xGain.getMaxValueMB() : 0,
178 .defaultValue = xGain.hasDefaultValueMB() ? xGain.getDefaultValueMB() : 0,
179 .stepValue = xGain.hasStepValueMB() ? xGain.getStepValueMB() : 0,
180 .minRampMs = xGain.hasMinRampMs() ? xGain.getMinRampMs() : 0,
181 .maxRampMs = xGain.hasMaxRampMs() ? xGain.getMaxRampMs() : 0,
182 .useForVolume = xGain.hasUseForVolume() ? xGain.getUseForVolume() : false,
183 };
184}
185
186ConversionResult<AudioProfile> convertAudioProfileToAidl(const ap_xsd::Profile& xProfile) {
187 return AudioProfile{
188 .format = xProfile.hasFormat()
189 ? VALUE_OR_FATAL(convertAudioFormatToAidl(xProfile.getFormat()))
190 : AudioFormatDescription{},
191 .channelMasks =
192 xProfile.hasChannelMasks()
193 ? VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::AudioChannelMask,
194 AudioChannelLayout>(
195 xProfile.getChannelMasks(), &convertChannelMaskToAidl)))
196 : std::vector<AudioChannelLayout>{},
197 .sampleRates = xProfile.hasSamplingRates()
198 ? VALUE_OR_FATAL((convertCollectionToAidl<int64_t, int>(
199 xProfile.getSamplingRates(),
200 [](const int64_t x) -> int { return x; })))
201 : std::vector<int>{}};
202}
203
204ConversionResult<AudioIoFlags> convertIoFlagsToAidl(
205 const std::vector<ap_xsd::AudioInOutFlag>& flags, const ap_xsd::Role role,
206 bool flagsForMixPort) {
207 static const char flagSeparator = ' ';
208 int flagMask = 0;
209 if ((role == ap_xsd::Role::sink && flagsForMixPort) ||
210 (role == ap_xsd::Role::source && !flagsForMixPort)) {
211 for (const ap_xsd::AudioInOutFlag& flag : flags) {
212 flagMask |= static_cast<int>(::android::InputFlagConverter::maskFromString(
213 ap_xsd::toString(flag), &flagSeparator));
214 }
215 return AudioIoFlags::make<AudioIoFlags::Tag::input>(flagMask);
216 } else {
217 for (const ap_xsd::AudioInOutFlag& flag : flags) {
218 flagMask |= static_cast<int>(::android::OutputFlagConverter::maskFromString(
219 ap_xsd::toString(flag), &flagSeparator));
220 }
221 }
222 return AudioIoFlags::make<AudioIoFlags::Tag::output>(flagMask);
223}
224
225ConversionResult<AudioPort> convertDevicePortToAidl(
226 const ap_xsd::DevicePorts::DevicePort& xDevicePort, const std::string& xDefaultOutputDevice,
227 int32_t& nextPortId) {
228 return AudioPort{
229 .id = nextPortId++,
230 .name = NON_EMPTY_STRING_OR_FATAL(xDevicePort.getTagName()),
231 .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>(
232 xDevicePort.getProfile(), convertAudioProfileToAidl))),
233 .flags = VALUE_OR_FATAL(convertIoFlagsToAidl({}, xDevicePort.getRole(), false)),
234 .gains = VALUE_OR_FATAL(
235 (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>(
236 xDevicePort.getGains(), &ap_xsd::Gains::getGain, convertGainToAidl))),
237
238 .ext = VALUE_OR_FATAL(createAudioPortExt(xDevicePort, xDefaultOutputDevice))};
239}
240
241ConversionResult<std::vector<AudioPort>> convertDevicePortsInModuleToAidl(
242 const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) {
243 std::vector<AudioPort> audioPortVec;
244 std::vector<ap_xsd::DevicePorts> xDevicePortsVec = xModuleConfig.getDevicePorts();
245 if (xDevicePortsVec.size() > 1) {
246 LOG(ERROR) << __func__ << "Having multiple '<devicePorts>' elements is not allowed, found: "
247 << xDevicePortsVec.size();
248 return unexpected(BAD_VALUE);
249 }
250 if (!xDevicePortsVec.empty()) {
251 const std::string xDefaultOutputDevice = xModuleConfig.hasDefaultOutputDevice()
252 ? xModuleConfig.getDefaultOutputDevice()
253 : "";
254 audioPortVec.reserve(xDevicePortsVec[0].getDevicePort().size());
255 for (const ap_xsd::DevicePorts& xDevicePortsType : xDevicePortsVec) {
256 for (const ap_xsd::DevicePorts::DevicePort& xDevicePort :
257 xDevicePortsType.getDevicePort()) {
258 audioPortVec.push_back(VALUE_OR_FATAL(
259 convertDevicePortToAidl(xDevicePort, xDefaultOutputDevice, nextPortId)));
260 }
261 }
262 }
263 const std::unordered_set<std::string> xAttachedDeviceSet = getAttachedDevices(xModuleConfig);
264 for (const auto& port : audioPortVec) {
265 const auto& devicePort = port.ext.get<AudioPortExt::device>();
266 if (xAttachedDeviceSet.count(port.name) != devicePort.device.type.connection.empty()) {
267 LOG(ERROR) << __func__ << ": Review Audio Policy config: <attachedDevices> "
268 << "list is incorrect or devicePort \"" << port.name
269 << "\" type= " << devicePort.device.type.toString() << " is incorrect.";
270 return unexpected(BAD_VALUE);
271 }
272 }
273 return audioPortVec;
274}
275
276ConversionResult<AudioPort> convertMixPortToAidl(const ap_xsd::MixPorts::MixPort& xMixPort,
277 int32_t& nextPortId) {
278 return AudioPort{
279 .id = nextPortId++,
280 .name = NON_EMPTY_STRING_OR_FATAL(xMixPort.getName()),
281 .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>(
282 xMixPort.getProfile(), convertAudioProfileToAidl))),
283 .flags = xMixPort.hasFlags()
284 ? VALUE_OR_FATAL(convertIoFlagsToAidl(xMixPort.getFlags(),
285 xMixPort.getRole(), true))
286 : VALUE_OR_FATAL(convertIoFlagsToAidl({}, xMixPort.getRole(), true)),
287 .gains = VALUE_OR_FATAL(
288 (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>(
289 xMixPort.getGains(), &ap_xsd::Gains::getGain, &convertGainToAidl))),
290 .ext = VALUE_OR_FATAL(createAudioPortExt(xMixPort)),
291 };
292}
293
294ConversionResult<std::vector<AudioPort>> convertMixPortsInModuleToAidl(
295 const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) {
296 std::vector<AudioPort> audioPortVec;
297 std::vector<ap_xsd::MixPorts> xMixPortsVec = xModuleConfig.getMixPorts();
298 if (xMixPortsVec.size() > 1) {
299 LOG(ERROR) << __func__ << "Having multiple '<mixPorts>' elements is not allowed, found: "
300 << xMixPortsVec.size();
301 return unexpected(BAD_VALUE);
302 }
303 if (!xMixPortsVec.empty()) {
304 audioPortVec.reserve(xMixPortsVec[0].getMixPort().size());
305 for (const ap_xsd::MixPorts& xMixPortsType : xMixPortsVec) {
306 for (const ap_xsd::MixPorts::MixPort& xMixPort : xMixPortsType.getMixPort()) {
307 audioPortVec.push_back(VALUE_OR_FATAL(convertMixPortToAidl(xMixPort, nextPortId)));
308 }
309 }
310 }
311 return audioPortVec;
312}
313
314ConversionResult<int32_t> getSinkPortId(const ap_xsd::Routes::Route& xRoute,
315 const std::unordered_map<std::string, int32_t>& portMap) {
316 auto portMapIter = portMap.find(xRoute.getSink());
317 if (portMapIter == portMap.end()) {
318 LOG(ERROR) << __func__ << " Review Audio Policy config: audio route"
319 << "has sink: " << xRoute.getSink()
320 << " which is neither a device port nor mix port.";
321 return unexpected(BAD_VALUE);
322 }
323 return portMapIter->second;
324}
325
326ConversionResult<std::vector<int32_t>> getSourcePortIds(
327 const ap_xsd::Routes::Route& xRoute,
328 const std::unordered_map<std::string, int32_t>& portMap) {
329 std::vector<int32_t> sourcePortIds;
330 for (const std::string& rawSource : ::android::base::Split(xRoute.getSources(), ",")) {
331 const std::string source = ::android::base::Trim(rawSource);
332 auto portMapIter = portMap.find(source);
333 if (portMapIter == portMap.end()) {
334 LOG(ERROR) << __func__ << " Review Audio Policy config: audio route"
335 << "has source \"" << source
336 << "\" which is neither a device port nor mix port.";
337 return unexpected(BAD_VALUE);
338 }
339 sourcePortIds.push_back(portMapIter->second);
340 }
341 return sourcePortIds;
342}
343
344ConversionResult<AudioRoute> convertRouteToAidl(const ap_xsd::Routes::Route& xRoute,
345 const std::vector<AudioPort>& aidlAudioPorts) {
346 std::unordered_map<std::string, int32_t> portMap;
347 for (const AudioPort& port : aidlAudioPorts) {
348 portMap.insert({port.name, port.id});
349 }
350 return AudioRoute{.sourcePortIds = VALUE_OR_FATAL(getSourcePortIds(xRoute, portMap)),
351 .sinkPortId = VALUE_OR_FATAL(getSinkPortId(xRoute, portMap)),
352 .isExclusive = (xRoute.getType() == ap_xsd::MixType::mux)};
353}
354
355ConversionResult<std::vector<AudioRoute>> convertRoutesInModuleToAidl(
356 const ap_xsd::Modules::Module& xModuleConfig,
357 const std::vector<AudioPort>& aidlAudioPorts) {
358 std::vector<AudioRoute> audioRouteVec;
359 std::vector<ap_xsd::Routes> xRoutesVec = xModuleConfig.getRoutes();
360 if (!xRoutesVec.empty()) {
361 /*
362 * xRoutesVec likely only contains one element; that is, it's
363 * likely that all ap_xsd::Routes::MixPort types that we need to convert
364 * are inside of xRoutesVec[0].
365 */
366 audioRouteVec.reserve(xRoutesVec[0].getRoute().size());
367 for (const ap_xsd::Routes& xRoutesType : xRoutesVec) {
368 for (const ap_xsd::Routes::Route& xRoute : xRoutesType.getRoute()) {
369 audioRouteVec.push_back(VALUE_OR_FATAL(convertRouteToAidl(xRoute, aidlAudioPorts)));
370 }
371 }
372 }
373 return audioRouteVec;
374}
375
376ConversionResult<std::unique_ptr<Module::Configuration>> convertModuleConfigToAidl(
377 const ap_xsd::Modules::Module& xModuleConfig) {
378 auto result = std::make_unique<Module::Configuration>();
379 auto& aidlModuleConfig = *result;
380 std::vector<AudioPort> devicePorts = VALUE_OR_FATAL(
381 convertDevicePortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId));
382
383 // The XML config does not specify the default input device.
384 // Assign the first attached input device as the default.
385 for (auto& port : devicePorts) {
386 if (port.flags.getTag() != AudioIoFlags::input) continue;
387 auto& deviceExt = port.ext.get<AudioPortExt::device>();
388 if (!deviceExt.device.type.connection.empty()) continue;
389 deviceExt.flags |= 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
390 break;
391 }
392
393 std::vector<AudioPort> mixPorts = VALUE_OR_FATAL(
394 convertMixPortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId));
395 aidlModuleConfig.ports.reserve(devicePorts.size() + mixPorts.size());
396 aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), devicePorts.begin(),
397 devicePorts.end());
398 aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), mixPorts.begin(), mixPorts.end());
399
400 aidlModuleConfig.routes =
401 VALUE_OR_FATAL(convertRoutesInModuleToAidl(xModuleConfig, aidlModuleConfig.ports));
402 return result;
403}
404
405ConversionResult<AudioHalCapCriterion> convertCapCriterionToAidl(
406 const eng_xsd::CriterionType& xsdcCriterion) {
407 AudioHalCapCriterion aidlCapCriterion;
408 aidlCapCriterion.name = xsdcCriterion.getName();
409 aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
410 aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
411 return aidlCapCriterion;
412}
413
414ConversionResult<std::string> convertCriterionTypeValueToAidl(
415 const eng_xsd::ValueType& xsdcCriterionTypeValue) {
416 return xsdcCriterionTypeValue.getLiteral();
417}
418
419ConversionResult<AudioHalCapCriterionType> convertCapCriterionTypeToAidl(
420 const eng_xsd::CriterionTypeType& xsdcCriterionType) {
421 AudioHalCapCriterionType aidlCapCriterionType;
422 aidlCapCriterionType.name = xsdcCriterionType.getName();
423 aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
424 aidlCapCriterionType.values = VALUE_OR_RETURN(
425 (convertWrappedCollectionToAidl<eng_xsd::ValuesType, eng_xsd::ValueType, std::string>(
426 xsdcCriterionType.getValues(), &eng_xsd::ValuesType::getValue,
427 &convertCriterionTypeValueToAidl)));
428 return aidlCapCriterionType;
429}
430
431ConversionResult<AudioHalVolumeCurve::CurvePoint> convertCurvePointToAidl(
432 const std::string& xsdcCurvePoint) {
433 AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
434 if ((sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
435 &aidlCurvePoint.attenuationMb) != 2) ||
436 (aidlCurvePoint.index < AudioHalVolumeCurve::CurvePoint::MIN_INDEX) ||
437 (aidlCurvePoint.index > AudioHalVolumeCurve::CurvePoint::MAX_INDEX)) {
438 LOG(ERROR) << __func__ << " Review Audio Policy config: volume curve point:"
439 << "\"" << xsdcCurvePoint << "\" is invalid";
440 return unexpected(BAD_VALUE);
441 }
442 return aidlCurvePoint;
443}
444} // namespace aidl::android::hardware::audio::core::internal