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