blob: ba6110d39c0746438d65486310131601d8fc91ff [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>
François Gaffie57ccab72024-04-17 11:47:51 +020013#include <media/convert.h>
14#include <utils/FastStrcmp.h>
15
16#include <Utils.h>
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000017
18#include "core-impl/XmlConverter.h"
19#include "core-impl/XsdcConversion.h"
20
François Gaffie57ccab72024-04-17 11:47:51 +020021using aidl::android::hardware::audio::common::iequals;
22using aidl::android::hardware::audio::common::isValidAudioMode;
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +000023using aidl::android::hardware::audio::common::isValidAudioPolicyForcedConfig;
François Gaffie57ccab72024-04-17 11:47:51 +020024using aidl::android::hardware::audio::common::kValidAudioModes;
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +000025using aidl::android::hardware::audio::common::kValidAudioPolicyForcedConfig;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000026using aidl::android::media::audio::common::AudioChannelLayout;
François Gaffie57ccab72024-04-17 11:47:51 +020027using aidl::android::media::audio::common::AudioContentType;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000028using aidl::android::media::audio::common::AudioDevice;
29using aidl::android::media::audio::common::AudioDeviceAddress;
30using aidl::android::media::audio::common::AudioDeviceDescription;
31using aidl::android::media::audio::common::AudioDeviceType;
32using aidl::android::media::audio::common::AudioFormatDescription;
33using aidl::android::media::audio::common::AudioFormatType;
34using aidl::android::media::audio::common::AudioGain;
35using aidl::android::media::audio::common::AudioHalCapCriterion;
36using aidl::android::media::audio::common::AudioHalCapCriterionType;
François Gaffie57ccab72024-04-17 11:47:51 +020037using aidl::android::media::audio::common::AudioHalCapCriterionV2;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000038using aidl::android::media::audio::common::AudioHalVolumeCurve;
39using aidl::android::media::audio::common::AudioIoFlags;
François Gaffie57ccab72024-04-17 11:47:51 +020040using aidl::android::media::audio::common::AudioMode;
41using aidl::android::media::audio::common::AudioPolicyForcedConfig;
42using aidl::android::media::audio::common::AudioPolicyForceUse;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000043using aidl::android::media::audio::common::AudioPort;
44using aidl::android::media::audio::common::AudioPortConfig;
45using aidl::android::media::audio::common::AudioPortDeviceExt;
46using aidl::android::media::audio::common::AudioPortExt;
47using aidl::android::media::audio::common::AudioPortMixExt;
48using aidl::android::media::audio::common::AudioProfile;
François Gaffie57ccab72024-04-17 11:47:51 +020049using aidl::android::media::audio::common::AudioSource;
50using aidl::android::media::audio::common::AudioStreamType;
51using aidl::android::media::audio::common::AudioUsage;
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +000052using ::android::BAD_VALUE;
53using ::android::base::unexpected;
54using ::android::utilities::convertTo;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000055
56namespace ap_xsd = android::audio::policy::configuration;
57namespace eng_xsd = android::audio::policy::engine::configuration;
58
59namespace aidl::android::hardware::audio::core::internal {
60
François Gaffie57ccab72024-04-17 11:47:51 +020061static constexpr const char kXsdcForceConfigForCommunication[] = "ForceUseForCommunication";
62static constexpr const char kXsdcForceConfigForMedia[] = "ForceUseForMedia";
63static constexpr const char kXsdcForceConfigForRecord[] = "ForceUseForRecord";
64static constexpr const char kXsdcForceConfigForDock[] = "ForceUseForDock";
65static constexpr const char kXsdcForceConfigForSystem[] = "ForceUseForSystem";
66static constexpr const char kXsdcForceConfigForHdmiSystemAudio[] = "ForceUseForHdmiSystemAudio";
67static constexpr const char kXsdcForceConfigForEncodedSurround[] = "ForceUseForEncodedSurround";
68static constexpr const char kXsdcForceConfigForVibrateRinging[] = "ForceUseForVibrateRinging";
69
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +000070inline ConversionResult<std::string> assertNonEmpty(const std::string& s) {
71 if (s.empty()) {
72 LOG(ERROR) << __func__ << " Review Audio Policy config: "
73 << " empty string is not valid.";
74 return unexpected(BAD_VALUE);
75 }
76 return s;
77}
78
79#define NON_EMPTY_STRING_OR_FATAL(s) VALUE_OR_FATAL(assertNonEmpty(s))
80
François Gaffie57ccab72024-04-17 11:47:51 +020081ConversionResult<int32_t> convertAudioFlagsToAidl(
82 const std::vector<eng_xsd::FlagType>& xsdcFlagTypeVec) {
83 int legacyFlagMask = 0;
84 for (const eng_xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
85 if (xsdcFlagType != eng_xsd::FlagType::AUDIO_FLAG_NONE) {
86 audio_flags_mask_t legacyFlag = AUDIO_FLAG_NONE;
87 if (!::android::AudioFlagConverter::fromString(eng_xsd::toString(xsdcFlagType),
88 legacyFlag)) {
89 LOG(ERROR) << __func__ << " Review Audio Policy config, "
90 << eng_xsd::toString(xsdcFlagType) << " is not a valid flag.";
91 return unexpected(BAD_VALUE);
92 }
93 legacyFlagMask |= static_cast<int>(legacyFlag);
94 }
95 }
96 ConversionResult<int32_t> result = legacy2aidl_audio_flags_mask_t_int32_t_mask(
97 static_cast<audio_flags_mask_t>(legacyFlagMask));
98 if (!result.ok()) {
99 LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyFlagMask
100 << " has invalid flag(s).";
101 return unexpected(BAD_VALUE);
102 }
103 return result;
104}
105
106ConversionResult<AudioStreamType> convertAudioStreamTypeToAidl(const eng_xsd::Stream& xsdcStream) {
107 audio_stream_type_t legacyStreamType;
108 if (!::android::StreamTypeConverter::fromString(eng_xsd::toString(xsdcStream),
109 legacyStreamType)) {
110 LOG(ERROR) << __func__ << " Review Audio Policy config, " << eng_xsd::toString(xsdcStream)
111 << " is not a valid audio stream type.";
112 return unexpected(BAD_VALUE);
113 }
114 ConversionResult<AudioStreamType> result =
115 legacy2aidl_audio_stream_type_t_AudioStreamType(legacyStreamType);
116 if (!result.ok()) {
117 LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyStreamType
118 << " is not a valid audio stream type.";
119 return unexpected(BAD_VALUE);
120 }
121 return result;
122}
123
124ConversionResult<AudioSource> convertAudioSourceToAidl(
125 const eng_xsd::SourceEnumType& xsdcSourceType) {
126 audio_source_t legacySourceType;
127 if (!::android::SourceTypeConverter::fromString(eng_xsd::toString(xsdcSourceType),
128 legacySourceType)) {
129 LOG(ERROR) << __func__ << " Review Audio Policy config, "
130 << eng_xsd::toString(xsdcSourceType) << " is not a valid audio source.";
131 return unexpected(BAD_VALUE);
132 }
133 ConversionResult<AudioSource> result = legacy2aidl_audio_source_t_AudioSource(legacySourceType);
134 if (!result.ok()) {
135 LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacySourceType
136 << " is not a valid audio source.";
137 return unexpected(BAD_VALUE);
138 }
139 return result;
140}
141
142ConversionResult<AudioContentType> convertAudioContentTypeToAidl(
143 const eng_xsd::ContentType& xsdcContentType) {
144 audio_content_type_t legacyContentType;
145 if (!::android::AudioContentTypeConverter::fromString(eng_xsd::toString(xsdcContentType),
146 legacyContentType)) {
147 LOG(ERROR) << __func__ << " Review Audio Policy config, "
148 << eng_xsd::toString(xsdcContentType) << " is not a valid audio content type.";
149 return unexpected(BAD_VALUE);
150 }
151 ConversionResult<AudioContentType> result =
152 legacy2aidl_audio_content_type_t_AudioContentType(legacyContentType);
153 if (!result.ok()) {
154 LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyContentType
155 << " is not a valid audio content type.";
156 return unexpected(BAD_VALUE);
157 }
158 return result;
159}
160
161ConversionResult<AudioUsage> convertAudioUsageToAidl(const eng_xsd::UsageEnumType& xsdcUsage) {
162 audio_usage_t legacyUsage;
163 if (!::android::UsageTypeConverter::fromString(eng_xsd::toString(xsdcUsage), legacyUsage)) {
164 LOG(ERROR) << __func__ << " Review Audio Policy config, not a valid audio usage.";
165 return unexpected(BAD_VALUE);
166 }
167 ConversionResult<AudioUsage> result = legacy2aidl_audio_usage_t_AudioUsage(legacyUsage);
168 if (!result.ok()) {
169 LOG(ERROR) << __func__ << " Review Audio Policy config, not a valid audio usage.";
170 return unexpected(BAD_VALUE);
171 }
172 return result;
173}
174
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000175ConversionResult<AudioFormatDescription> convertAudioFormatToAidl(const std::string& xsdcFormat) {
176 audio_format_t legacyFormat = ::android::formatFromString(xsdcFormat, AUDIO_FORMAT_DEFAULT);
177 ConversionResult<AudioFormatDescription> result =
178 legacy2aidl_audio_format_t_AudioFormatDescription(legacyFormat);
179 if ((legacyFormat == AUDIO_FORMAT_DEFAULT && xsdcFormat.compare("AUDIO_FORMAT_DEFAULT") != 0) ||
180 !result.ok()) {
181 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xsdcFormat
182 << " is not a valid audio format.";
183 return unexpected(BAD_VALUE);
184 }
185 return result;
186}
187
188std::unordered_set<std::string> getAttachedDevices(const ap_xsd::Modules::Module& moduleConfig) {
189 std::unordered_set<std::string> attachedDeviceSet;
190 if (moduleConfig.hasAttachedDevices()) {
191 for (const ap_xsd::AttachedDevices& attachedDevices : moduleConfig.getAttachedDevices()) {
192 if (attachedDevices.hasItem()) {
193 attachedDeviceSet.insert(attachedDevices.getItem().begin(),
194 attachedDevices.getItem().end());
195 }
196 }
197 }
198 return attachedDeviceSet;
199}
200
201ConversionResult<AudioDeviceDescription> convertDeviceTypeToAidl(const std::string& xType) {
202 audio_devices_t legacyDeviceType = AUDIO_DEVICE_NONE;
203 ::android::DeviceConverter::fromString(xType, legacyDeviceType);
204 ConversionResult<AudioDeviceDescription> result =
205 legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyDeviceType);
206 if ((legacyDeviceType == AUDIO_DEVICE_NONE) || !result.ok()) {
207 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xType
208 << " is not a valid device type.";
209 return unexpected(BAD_VALUE);
210 }
211 return result;
212}
213
214ConversionResult<AudioDevice> createAudioDevice(
215 const ap_xsd::DevicePorts::DevicePort& xDevicePort) {
216 AudioDevice device = {
217 .type = VALUE_OR_FATAL(convertDeviceTypeToAidl(xDevicePort.getType())),
218 .address = xDevicePort.hasAddress()
219 ? AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(
220 xDevicePort.getAddress())
221 : AudioDeviceAddress{}};
222 if (device.type.type == AudioDeviceType::IN_MICROPHONE && device.type.connection.empty()) {
223 device.address = "bottom";
224 } else if (device.type.type == AudioDeviceType::IN_MICROPHONE_BACK &&
225 device.type.connection.empty()) {
226 device.address = "back";
227 }
228 return device;
229}
230
231ConversionResult<AudioPortExt> createAudioPortExt(
232 const ap_xsd::DevicePorts::DevicePort& xDevicePort,
233 const std::string& xDefaultOutputDevice) {
234 AudioPortDeviceExt deviceExt = {
235 .device = VALUE_OR_FATAL(createAudioDevice(xDevicePort)),
236 .flags = (xDevicePort.getTagName() == xDefaultOutputDevice)
237 ? 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE
238 : 0,
239 .encodedFormats =
240 xDevicePort.hasEncodedFormats()
241 ? VALUE_OR_FATAL(
242 (convertCollectionToAidl<std::string, AudioFormatDescription>(
243 xDevicePort.getEncodedFormats(),
244 &convertAudioFormatToAidl)))
245 : std::vector<AudioFormatDescription>{},
246 };
247 return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
248}
249
250ConversionResult<AudioPortExt> createAudioPortExt(const ap_xsd::MixPorts::MixPort& xMixPort) {
251 AudioPortMixExt mixExt = {
252 .maxOpenStreamCount =
253 xMixPort.hasMaxOpenCount() ? static_cast<int>(xMixPort.getMaxOpenCount()) : 0,
254 .maxActiveStreamCount = xMixPort.hasMaxActiveCount()
255 ? static_cast<int>(xMixPort.getMaxActiveCount())
256 : 1,
257 .recommendedMuteDurationMs =
258 xMixPort.hasRecommendedMuteDurationMs()
259 ? static_cast<int>(xMixPort.getRecommendedMuteDurationMs())
260 : 0};
261 return AudioPortExt::make<AudioPortExt::Tag::mix>(mixExt);
262}
263
264ConversionResult<int> convertGainModeToAidl(const std::vector<ap_xsd::AudioGainMode>& gainModeVec) {
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000265 int gainModeMask = 0;
266 for (const ap_xsd::AudioGainMode& gainMode : gainModeVec) {
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700267 audio_gain_mode_t legacyGainMode;
268 if (::android::GainModeConverter::fromString(ap_xsd::toString(gainMode), legacyGainMode)) {
269 gainModeMask |= static_cast<int>(legacyGainMode);
270 }
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000271 }
272 return gainModeMask;
273}
274
275ConversionResult<AudioChannelLayout> convertChannelMaskToAidl(
276 const ap_xsd::AudioChannelMask& xChannelMask) {
277 std::string xChannelMaskLiteral = ap_xsd::toString(xChannelMask);
278 audio_channel_mask_t legacyChannelMask = ::android::channelMaskFromString(xChannelMaskLiteral);
279 ConversionResult<AudioChannelLayout> result =
280 legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
281 legacyChannelMask,
282 /* isInput= */ xChannelMaskLiteral.find("AUDIO_CHANNEL_IN_") == 0);
283 if ((legacyChannelMask == AUDIO_CHANNEL_INVALID) || !result.ok()) {
284 LOG(ERROR) << __func__ << " Review Audio Policy config: " << xChannelMaskLiteral
285 << " is not a valid audio channel mask.";
286 return unexpected(BAD_VALUE);
287 }
288 return result;
289}
290
291ConversionResult<AudioGain> convertGainToAidl(const ap_xsd::Gains::Gain& xGain) {
292 return AudioGain{
293 .mode = VALUE_OR_FATAL(convertGainModeToAidl(xGain.getMode())),
294 .channelMask =
295 xGain.hasChannel_mask()
296 ? VALUE_OR_FATAL(convertChannelMaskToAidl(xGain.getChannel_mask()))
297 : AudioChannelLayout{},
298 .minValue = xGain.hasMinValueMB() ? xGain.getMinValueMB() : 0,
299 .maxValue = xGain.hasMaxValueMB() ? xGain.getMaxValueMB() : 0,
300 .defaultValue = xGain.hasDefaultValueMB() ? xGain.getDefaultValueMB() : 0,
301 .stepValue = xGain.hasStepValueMB() ? xGain.getStepValueMB() : 0,
302 .minRampMs = xGain.hasMinRampMs() ? xGain.getMinRampMs() : 0,
303 .maxRampMs = xGain.hasMaxRampMs() ? xGain.getMaxRampMs() : 0,
304 .useForVolume = xGain.hasUseForVolume() ? xGain.getUseForVolume() : false,
305 };
306}
307
308ConversionResult<AudioProfile> convertAudioProfileToAidl(const ap_xsd::Profile& xProfile) {
309 return AudioProfile{
310 .format = xProfile.hasFormat()
311 ? VALUE_OR_FATAL(convertAudioFormatToAidl(xProfile.getFormat()))
312 : AudioFormatDescription{},
313 .channelMasks =
314 xProfile.hasChannelMasks()
315 ? VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::AudioChannelMask,
316 AudioChannelLayout>(
317 xProfile.getChannelMasks(), &convertChannelMaskToAidl)))
318 : std::vector<AudioChannelLayout>{},
319 .sampleRates = xProfile.hasSamplingRates()
320 ? VALUE_OR_FATAL((convertCollectionToAidl<int64_t, int>(
321 xProfile.getSamplingRates(),
322 [](const int64_t x) -> int { return x; })))
323 : std::vector<int>{}};
324}
325
326ConversionResult<AudioIoFlags> convertIoFlagsToAidl(
327 const std::vector<ap_xsd::AudioInOutFlag>& flags, const ap_xsd::Role role,
328 bool flagsForMixPort) {
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800329 int legacyFlagMask = 0;
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000330 if ((role == ap_xsd::Role::sink && flagsForMixPort) ||
331 (role == ap_xsd::Role::source && !flagsForMixPort)) {
332 for (const ap_xsd::AudioInOutFlag& flag : flags) {
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700333 audio_input_flags_t legacyFlag;
334 if (::android::InputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800335 legacyFlagMask |= static_cast<int>(legacyFlag);
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700336 }
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000337 }
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800338 return AudioIoFlags::make<AudioIoFlags::Tag::input>(
339 VALUE_OR_FATAL(legacy2aidl_audio_input_flags_t_int32_t_mask(
340 static_cast<audio_input_flags_t>(legacyFlagMask))));
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000341 } else {
342 for (const ap_xsd::AudioInOutFlag& flag : flags) {
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700343 audio_output_flags_t legacyFlag;
344 if (::android::OutputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) {
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800345 legacyFlagMask |= static_cast<int>(legacyFlag);
Mikhail Naganovcc21b6f2023-10-17 19:39:27 -0700346 }
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000347 }
Mikhail Naganov37fe9e82023-11-28 17:07:23 -0800348 return AudioIoFlags::make<AudioIoFlags::Tag::output>(
349 VALUE_OR_FATAL(legacy2aidl_audio_output_flags_t_int32_t_mask(
350 static_cast<audio_output_flags_t>(legacyFlagMask))));
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000351 }
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000352}
353
354ConversionResult<AudioPort> convertDevicePortToAidl(
355 const ap_xsd::DevicePorts::DevicePort& xDevicePort, const std::string& xDefaultOutputDevice,
356 int32_t& nextPortId) {
357 return AudioPort{
358 .id = nextPortId++,
359 .name = NON_EMPTY_STRING_OR_FATAL(xDevicePort.getTagName()),
360 .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>(
361 xDevicePort.getProfile(), convertAudioProfileToAidl))),
362 .flags = VALUE_OR_FATAL(convertIoFlagsToAidl({}, xDevicePort.getRole(), false)),
363 .gains = VALUE_OR_FATAL(
364 (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>(
365 xDevicePort.getGains(), &ap_xsd::Gains::getGain, convertGainToAidl))),
366
367 .ext = VALUE_OR_FATAL(createAudioPortExt(xDevicePort, xDefaultOutputDevice))};
368}
369
370ConversionResult<std::vector<AudioPort>> convertDevicePortsInModuleToAidl(
371 const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) {
372 std::vector<AudioPort> audioPortVec;
373 std::vector<ap_xsd::DevicePorts> xDevicePortsVec = xModuleConfig.getDevicePorts();
374 if (xDevicePortsVec.size() > 1) {
375 LOG(ERROR) << __func__ << "Having multiple '<devicePorts>' elements is not allowed, found: "
376 << xDevicePortsVec.size();
377 return unexpected(BAD_VALUE);
378 }
379 if (!xDevicePortsVec.empty()) {
380 const std::string xDefaultOutputDevice = xModuleConfig.hasDefaultOutputDevice()
381 ? xModuleConfig.getDefaultOutputDevice()
382 : "";
383 audioPortVec.reserve(xDevicePortsVec[0].getDevicePort().size());
384 for (const ap_xsd::DevicePorts& xDevicePortsType : xDevicePortsVec) {
385 for (const ap_xsd::DevicePorts::DevicePort& xDevicePort :
386 xDevicePortsType.getDevicePort()) {
387 audioPortVec.push_back(VALUE_OR_FATAL(
388 convertDevicePortToAidl(xDevicePort, xDefaultOutputDevice, nextPortId)));
389 }
390 }
391 }
392 const std::unordered_set<std::string> xAttachedDeviceSet = getAttachedDevices(xModuleConfig);
393 for (const auto& port : audioPortVec) {
394 const auto& devicePort = port.ext.get<AudioPortExt::device>();
395 if (xAttachedDeviceSet.count(port.name) != devicePort.device.type.connection.empty()) {
396 LOG(ERROR) << __func__ << ": Review Audio Policy config: <attachedDevices> "
397 << "list is incorrect or devicePort \"" << port.name
398 << "\" type= " << devicePort.device.type.toString() << " is incorrect.";
399 return unexpected(BAD_VALUE);
400 }
401 }
402 return audioPortVec;
403}
404
405ConversionResult<AudioPort> convertMixPortToAidl(const ap_xsd::MixPorts::MixPort& xMixPort,
406 int32_t& nextPortId) {
407 return AudioPort{
408 .id = nextPortId++,
409 .name = NON_EMPTY_STRING_OR_FATAL(xMixPort.getName()),
410 .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>(
411 xMixPort.getProfile(), convertAudioProfileToAidl))),
412 .flags = xMixPort.hasFlags()
413 ? VALUE_OR_FATAL(convertIoFlagsToAidl(xMixPort.getFlags(),
414 xMixPort.getRole(), true))
415 : VALUE_OR_FATAL(convertIoFlagsToAidl({}, xMixPort.getRole(), true)),
416 .gains = VALUE_OR_FATAL(
417 (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>(
418 xMixPort.getGains(), &ap_xsd::Gains::getGain, &convertGainToAidl))),
419 .ext = VALUE_OR_FATAL(createAudioPortExt(xMixPort)),
420 };
421}
422
423ConversionResult<std::vector<AudioPort>> convertMixPortsInModuleToAidl(
424 const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) {
425 std::vector<AudioPort> audioPortVec;
426 std::vector<ap_xsd::MixPorts> xMixPortsVec = xModuleConfig.getMixPorts();
427 if (xMixPortsVec.size() > 1) {
428 LOG(ERROR) << __func__ << "Having multiple '<mixPorts>' elements is not allowed, found: "
429 << xMixPortsVec.size();
430 return unexpected(BAD_VALUE);
431 }
432 if (!xMixPortsVec.empty()) {
433 audioPortVec.reserve(xMixPortsVec[0].getMixPort().size());
434 for (const ap_xsd::MixPorts& xMixPortsType : xMixPortsVec) {
435 for (const ap_xsd::MixPorts::MixPort& xMixPort : xMixPortsType.getMixPort()) {
436 audioPortVec.push_back(VALUE_OR_FATAL(convertMixPortToAidl(xMixPort, nextPortId)));
437 }
438 }
439 }
440 return audioPortVec;
441}
442
443ConversionResult<int32_t> getSinkPortId(const ap_xsd::Routes::Route& xRoute,
444 const std::unordered_map<std::string, int32_t>& portMap) {
445 auto portMapIter = portMap.find(xRoute.getSink());
446 if (portMapIter == portMap.end()) {
447 LOG(ERROR) << __func__ << " Review Audio Policy config: audio route"
448 << "has sink: " << xRoute.getSink()
449 << " which is neither a device port nor mix port.";
450 return unexpected(BAD_VALUE);
451 }
452 return portMapIter->second;
453}
454
455ConversionResult<std::vector<int32_t>> getSourcePortIds(
456 const ap_xsd::Routes::Route& xRoute,
457 const std::unordered_map<std::string, int32_t>& portMap) {
458 std::vector<int32_t> sourcePortIds;
459 for (const std::string& rawSource : ::android::base::Split(xRoute.getSources(), ",")) {
460 const std::string source = ::android::base::Trim(rawSource);
461 auto portMapIter = portMap.find(source);
462 if (portMapIter == portMap.end()) {
463 LOG(ERROR) << __func__ << " Review Audio Policy config: audio route"
464 << "has source \"" << source
465 << "\" which is neither a device port nor mix port.";
466 return unexpected(BAD_VALUE);
467 }
468 sourcePortIds.push_back(portMapIter->second);
469 }
470 return sourcePortIds;
471}
472
473ConversionResult<AudioRoute> convertRouteToAidl(const ap_xsd::Routes::Route& xRoute,
474 const std::vector<AudioPort>& aidlAudioPorts) {
475 std::unordered_map<std::string, int32_t> portMap;
476 for (const AudioPort& port : aidlAudioPorts) {
477 portMap.insert({port.name, port.id});
478 }
479 return AudioRoute{.sourcePortIds = VALUE_OR_FATAL(getSourcePortIds(xRoute, portMap)),
480 .sinkPortId = VALUE_OR_FATAL(getSinkPortId(xRoute, portMap)),
481 .isExclusive = (xRoute.getType() == ap_xsd::MixType::mux)};
482}
483
484ConversionResult<std::vector<AudioRoute>> convertRoutesInModuleToAidl(
485 const ap_xsd::Modules::Module& xModuleConfig,
486 const std::vector<AudioPort>& aidlAudioPorts) {
487 std::vector<AudioRoute> audioRouteVec;
488 std::vector<ap_xsd::Routes> xRoutesVec = xModuleConfig.getRoutes();
489 if (!xRoutesVec.empty()) {
490 /*
491 * xRoutesVec likely only contains one element; that is, it's
492 * likely that all ap_xsd::Routes::MixPort types that we need to convert
493 * are inside of xRoutesVec[0].
494 */
495 audioRouteVec.reserve(xRoutesVec[0].getRoute().size());
496 for (const ap_xsd::Routes& xRoutesType : xRoutesVec) {
497 for (const ap_xsd::Routes::Route& xRoute : xRoutesType.getRoute()) {
498 audioRouteVec.push_back(VALUE_OR_FATAL(convertRouteToAidl(xRoute, aidlAudioPorts)));
499 }
500 }
501 }
502 return audioRouteVec;
503}
504
505ConversionResult<std::unique_ptr<Module::Configuration>> convertModuleConfigToAidl(
506 const ap_xsd::Modules::Module& xModuleConfig) {
507 auto result = std::make_unique<Module::Configuration>();
508 auto& aidlModuleConfig = *result;
509 std::vector<AudioPort> devicePorts = VALUE_OR_FATAL(
510 convertDevicePortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId));
511
512 // The XML config does not specify the default input device.
513 // Assign the first attached input device as the default.
514 for (auto& port : devicePorts) {
515 if (port.flags.getTag() != AudioIoFlags::input) continue;
516 auto& deviceExt = port.ext.get<AudioPortExt::device>();
517 if (!deviceExt.device.type.connection.empty()) continue;
518 deviceExt.flags |= 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
519 break;
520 }
521
522 std::vector<AudioPort> mixPorts = VALUE_OR_FATAL(
523 convertMixPortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId));
524 aidlModuleConfig.ports.reserve(devicePorts.size() + mixPorts.size());
525 aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), devicePorts.begin(),
526 devicePorts.end());
527 aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), mixPorts.begin(), mixPorts.end());
528
529 aidlModuleConfig.routes =
530 VALUE_OR_FATAL(convertRoutesInModuleToAidl(xModuleConfig, aidlModuleConfig.ports));
531 return result;
532}
533
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000534ConversionResult<AudioPolicyForcedConfig> convertForcedConfigToAidl(
535 const std::string& xsdcForcedConfigCriterionType) {
536 const auto it = std::find_if(
537 kValidAudioPolicyForcedConfig.begin(), kValidAudioPolicyForcedConfig.end(),
538 [&](const auto& config) { return toString(config) == xsdcForcedConfigCriterionType; });
539 if (it == kValidAudioPolicyForcedConfig.end()) {
540 LOG(ERROR) << __func__ << " invalid forced config " << xsdcForcedConfigCriterionType;
541 return unexpected(BAD_VALUE);
542 }
543 return *it;
544}
545
François Gaffie57ccab72024-04-17 11:47:51 +0200546ConversionResult<AudioMode> convertTelephonyModeToAidl(const std::string& xsdcModeCriterionType) {
547 const auto it = std::find_if(kValidAudioModes.begin(), kValidAudioModes.end(),
548 [&xsdcModeCriterionType](const auto& mode) {
549 return toString(mode) == xsdcModeCriterionType;
550 });
551 if (it == kValidAudioModes.end()) {
552 LOG(ERROR) << __func__ << " invalid mode " << xsdcModeCriterionType;
553 return unexpected(BAD_VALUE);
554 }
555 return *it;
556}
557
558ConversionResult<AudioDeviceAddress> convertDeviceAddressToAidl(const std::string& xsdcAddress) {
559 return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(xsdcAddress);
560}
561
562ConversionResult<eng_xsd::CriterionTypeType> getCriterionTypeByName(
563 const std::string& name,
564 const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
565 for (const auto& xsdCriterionTypes : xsdcCriterionTypesVec) {
566 for (const auto& xsdcCriterionType : xsdCriterionTypes.getCriterion_type()) {
567 if (xsdcCriterionType.getName() == name) {
568 return xsdcCriterionType;
569 }
570 }
571 }
572 LOG(ERROR) << __func__ << " failed to find criterion type " << name;
573 return unexpected(BAD_VALUE);
574}
575
576ConversionResult<std::vector<std::optional<AudioHalCapCriterionV2>>>
577convertCapCriteriaCollectionToAidl(
578 const std::vector<eng_xsd::CriteriaType>& xsdcCriteriaVec,
579 const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
580 std::vector<std::optional<AudioHalCapCriterionV2>> resultAidlCriterionVec;
581 if (xsdcCriteriaVec.empty() || xsdcCriterionTypesVec.empty()) {
582 LOG(ERROR) << __func__ << " empty criteria/criterionTypes";
583 return unexpected(BAD_VALUE);
584 }
585 for (const auto& xsdCriteria : xsdcCriteriaVec) {
586 for (const auto& xsdcCriterion : xsdCriteria.getCriterion()) {
587 resultAidlCriterionVec.push_back(
588 std::optional<AudioHalCapCriterionV2>(VALUE_OR_FATAL(
589 convertCapCriterionV2ToAidl(xsdcCriterion, xsdcCriterionTypesVec))));
590 }
591 }
592 return resultAidlCriterionVec;
593}
594
595ConversionResult<std::vector<AudioDeviceDescription>> convertDevicesToAidl(
596 const eng_xsd::CriterionTypeType& xsdcDeviceCriterionType) {
597 if (xsdcDeviceCriterionType.getValues().empty()) {
598 LOG(ERROR) << __func__ << " no values provided";
599 return unexpected(BAD_VALUE);
600 }
601 std::vector<AudioDeviceDescription> aidlDevices;
602 for (eng_xsd::ValuesType xsdcValues : xsdcDeviceCriterionType.getValues()) {
603 aidlDevices.reserve(xsdcValues.getValue().size());
604 for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
605 if (!xsdcValue.hasAndroid_type()) {
606 LOG(ERROR) << __func__ << " empty android type";
607 return unexpected(BAD_VALUE);
608 }
609 uint32_t integerValue;
610 if (!convertTo(xsdcValue.getAndroid_type(), integerValue)) {
611 LOG(ERROR) << __func__ << " failed to convert android type "
612 << xsdcValue.getAndroid_type();
613 return unexpected(BAD_VALUE);
614 }
615 aidlDevices.push_back(
616 VALUE_OR_RETURN(legacy2aidl_audio_devices_t_AudioDeviceDescription(
617 static_cast<audio_devices_t>(integerValue))));
618 }
619 }
620 return aidlDevices;
621}
622
623ConversionResult<std::vector<AudioDeviceAddress>> convertDeviceAddressesToAidl(
624 const eng_xsd::CriterionTypeType& xsdcDeviceAddressesCriterionType) {
625 if (xsdcDeviceAddressesCriterionType.getValues().empty()) {
626 LOG(ERROR) << __func__ << " no values provided";
627 return unexpected(BAD_VALUE);
628 }
629 std::vector<AudioDeviceAddress> aidlDeviceAddresses;
630 for (eng_xsd::ValuesType xsdcValues : xsdcDeviceAddressesCriterionType.getValues()) {
631 aidlDeviceAddresses.reserve(xsdcValues.getValue().size());
632 for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
633 aidlDeviceAddresses.push_back(
634 AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(xsdcValue.getLiteral()));
635 }
636 }
637 return aidlDeviceAddresses;
638}
639
640ConversionResult<std::vector<AudioMode>> convertTelephonyModesToAidl(
641 const eng_xsd::CriterionTypeType& xsdcTelephonyModeCriterionType) {
642 if (xsdcTelephonyModeCriterionType.getValues().empty()) {
643 LOG(ERROR) << __func__ << " no values provided";
644 return unexpected(BAD_VALUE);
645 }
646 std::vector<AudioMode> aidlAudioModes;
647 for (eng_xsd::ValuesType xsdcValues : xsdcTelephonyModeCriterionType.getValues()) {
648 aidlAudioModes.reserve(xsdcValues.getValue().size());
649 for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000650 int integerValue = xsdcValue.getNumerical();
651 if (!isValidAudioMode(AudioMode(integerValue))) {
652 LOG(ERROR) << __func__ << " invalid audio mode " << integerValue;
653 return unexpected(BAD_VALUE);
654 }
655 aidlAudioModes.push_back(AudioMode(integerValue));
François Gaffie57ccab72024-04-17 11:47:51 +0200656 }
657 }
658 return aidlAudioModes;
659}
660
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000661ConversionResult<std::vector<AudioPolicyForcedConfig>> convertForcedConfigsToAidl(
François Gaffie57ccab72024-04-17 11:47:51 +0200662 const eng_xsd::CriterionTypeType& xsdcForcedConfigCriterionType) {
663 if (xsdcForcedConfigCriterionType.getValues().empty()) {
664 LOG(ERROR) << __func__ << " no values provided";
665 return unexpected(BAD_VALUE);
666 }
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000667 std::vector<AudioPolicyForcedConfig> aidlForcedConfigs;
François Gaffie57ccab72024-04-17 11:47:51 +0200668 for (eng_xsd::ValuesType xsdcValues : xsdcForcedConfigCriterionType.getValues()) {
669 aidlForcedConfigs.reserve(xsdcValues.getValue().size());
670 for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000671 int integerValue = xsdcValue.getNumerical();
672 if (!isValidAudioPolicyForcedConfig(AudioPolicyForcedConfig(integerValue))) {
673 LOG(ERROR) << __func__ << " invalid forced config mode " << integerValue;
674 return unexpected(BAD_VALUE);
675 }
676 aidlForcedConfigs.push_back(AudioPolicyForcedConfig(integerValue));
François Gaffie57ccab72024-04-17 11:47:51 +0200677 }
678 }
679 return aidlForcedConfigs;
680}
681
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000682ConversionResult<AudioPolicyForceUse> convertForceUseCriterionToAidl(
683 const std::string& xsdcCriterionName) {
François Gaffie57ccab72024-04-17 11:47:51 +0200684 if (!fastcmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForCommunication,
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000685 strlen(kXsdcForceConfigForCommunication))) {
686 return AudioPolicyForceUse::COMMUNICATION;
François Gaffie57ccab72024-04-17 11:47:51 +0200687 }
688 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForMedia,
689 strlen(kXsdcForceConfigForMedia))) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000690 return AudioPolicyForceUse::MEDIA;
François Gaffie57ccab72024-04-17 11:47:51 +0200691 }
692 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForRecord,
693 strlen(kXsdcForceConfigForRecord))) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000694 return AudioPolicyForceUse::RECORD;
François Gaffie57ccab72024-04-17 11:47:51 +0200695 }
696 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForDock,
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000697 strlen(kXsdcForceConfigForDock))) {
698 return AudioPolicyForceUse::DOCK;
François Gaffie57ccab72024-04-17 11:47:51 +0200699 }
700 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForSystem,
701 strlen(kXsdcForceConfigForSystem))) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000702 return AudioPolicyForceUse::SYSTEM;
François Gaffie57ccab72024-04-17 11:47:51 +0200703 }
704 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForHdmiSystemAudio,
705 strlen(kXsdcForceConfigForHdmiSystemAudio))) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000706 return AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
François Gaffie57ccab72024-04-17 11:47:51 +0200707 }
708 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForEncodedSurround,
709 strlen(kXsdcForceConfigForEncodedSurround))) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000710 return AudioPolicyForceUse::ENCODED_SURROUND;
François Gaffie57ccab72024-04-17 11:47:51 +0200711 }
712 if (!fasticmp<strncmp>(xsdcCriterionName.c_str(), kXsdcForceConfigForVibrateRinging,
713 strlen(kXsdcForceConfigForVibrateRinging))) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000714 return AudioPolicyForceUse::VIBRATE_RINGING;
François Gaffie57ccab72024-04-17 11:47:51 +0200715 }
716 LOG(ERROR) << __func__ << " unrecognized force use " << xsdcCriterionName;
717 return unexpected(BAD_VALUE);
718}
719
720ConversionResult<AudioHalCapCriterionV2> convertCapCriterionV2ToAidl(
721 const eng_xsd::CriterionType& xsdcCriterion,
722 const std::vector<eng_xsd::CriterionTypesType>& xsdcCriterionTypesVec) {
723 eng_xsd::CriterionTypeType xsdcCriterionType =
724 VALUE_OR_RETURN(getCriterionTypeByName(xsdcCriterion.getType(), xsdcCriterionTypesVec));
725 std::string defaultLiteralValue =
726 xsdcCriterion.has_default() ? xsdcCriterion.get_default() : "";
727 using Tag = AudioHalCapCriterionV2::Tag;
728 if (iequals(xsdcCriterion.getName(), toString(Tag::availableInputDevices))) {
729 return AudioHalCapCriterionV2::make<Tag::availableInputDevices>(
730 VALUE_OR_RETURN(convertDevicesToAidl(xsdcCriterionType)));
731 }
732 if (iequals(xsdcCriterion.getName(), toString(Tag::availableOutputDevices))) {
733 return AudioHalCapCriterionV2::make<Tag::availableOutputDevices>(
734 VALUE_OR_RETURN(convertDevicesToAidl(xsdcCriterionType)));
735 }
736 if (iequals(xsdcCriterion.getName(), toString(Tag::availableInputDevicesAddresses))) {
737 return AudioHalCapCriterionV2::make<Tag::availableInputDevicesAddresses>(
738 VALUE_OR_RETURN(convertDeviceAddressesToAidl(xsdcCriterionType)));
739 }
740 if (iequals(xsdcCriterion.getName(), toString(Tag::availableOutputDevicesAddresses))) {
741 return AudioHalCapCriterionV2::make<Tag::availableOutputDevicesAddresses>(
742 VALUE_OR_RETURN(convertDeviceAddressesToAidl(xsdcCriterionType)));
743 }
744 if (iequals(xsdcCriterion.getName(), toString(Tag::telephonyMode))) {
745 return AudioHalCapCriterionV2::make<Tag::telephonyMode>(
746 VALUE_OR_RETURN(convertTelephonyModesToAidl(xsdcCriterionType)));
747 }
748 if (!fastcmp<strncmp>(xsdcCriterion.getName().c_str(), kXsdcForceConfigForUse,
749 strlen(kXsdcForceConfigForUse))) {
Priyanka Advani (xWF)50f4e8a2024-11-20 18:24:09 +0000750 return AudioHalCapCriterionV2::make<Tag::forceConfigForUse>(
751 VALUE_OR_RETURN(convertForceUseCriterionToAidl(xsdcCriterion.getName())),
752 VALUE_OR_RETURN(convertForcedConfigsToAidl(xsdcCriterionType)));
François Gaffie57ccab72024-04-17 11:47:51 +0200753 }
754 LOG(ERROR) << __func__ << " unrecognized criterion " << xsdcCriterion.getName();
755 return unexpected(BAD_VALUE);
756}
757
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000758ConversionResult<AudioHalCapCriterion> convertCapCriterionToAidl(
759 const eng_xsd::CriterionType& xsdcCriterion) {
760 AudioHalCapCriterion aidlCapCriterion;
761 aidlCapCriterion.name = xsdcCriterion.getName();
762 aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
François Gaffie57ccab72024-04-17 11:47:51 +0200763 aidlCapCriterion.defaultLiteralValue =
764 xsdcCriterion.has_default() ? xsdcCriterion.get_default() : "";
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000765 return aidlCapCriterion;
766}
767
Lorena Torres-Huerta394e2522022-12-20 02:21:41 +0000768ConversionResult<AudioHalVolumeCurve::CurvePoint> convertCurvePointToAidl(
769 const std::string& xsdcCurvePoint) {
770 AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
771 if ((sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
772 &aidlCurvePoint.attenuationMb) != 2) ||
773 (aidlCurvePoint.index < AudioHalVolumeCurve::CurvePoint::MIN_INDEX) ||
774 (aidlCurvePoint.index > AudioHalVolumeCurve::CurvePoint::MAX_INDEX)) {
775 LOG(ERROR) << __func__ << " Review Audio Policy config: volume curve point:"
776 << "\"" << xsdcCurvePoint << "\" is invalid";
777 return unexpected(BAD_VALUE);
778 }
779 return aidlCurvePoint;
780}
781} // namespace aidl::android::hardware::audio::core::internal