Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 1 | #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 | |
| 17 | using aidl::android::media::audio::common::AudioChannelLayout; |
| 18 | using aidl::android::media::audio::common::AudioDevice; |
| 19 | using aidl::android::media::audio::common::AudioDeviceAddress; |
| 20 | using aidl::android::media::audio::common::AudioDeviceDescription; |
| 21 | using aidl::android::media::audio::common::AudioDeviceType; |
| 22 | using aidl::android::media::audio::common::AudioFormatDescription; |
| 23 | using aidl::android::media::audio::common::AudioFormatType; |
| 24 | using aidl::android::media::audio::common::AudioGain; |
| 25 | using aidl::android::media::audio::common::AudioHalCapCriterion; |
| 26 | using aidl::android::media::audio::common::AudioHalCapCriterionType; |
| 27 | using aidl::android::media::audio::common::AudioHalVolumeCurve; |
| 28 | using aidl::android::media::audio::common::AudioIoFlags; |
| 29 | using aidl::android::media::audio::common::AudioPort; |
| 30 | using aidl::android::media::audio::common::AudioPortConfig; |
| 31 | using aidl::android::media::audio::common::AudioPortDeviceExt; |
| 32 | using aidl::android::media::audio::common::AudioPortExt; |
| 33 | using aidl::android::media::audio::common::AudioPortMixExt; |
| 34 | using aidl::android::media::audio::common::AudioProfile; |
| 35 | using ::android::BAD_VALUE; |
| 36 | using ::android::base::unexpected; |
| 37 | |
| 38 | namespace ap_xsd = android::audio::policy::configuration; |
| 39 | namespace eng_xsd = android::audio::policy::engine::configuration; |
| 40 | |
| 41 | namespace aidl::android::hardware::audio::core::internal { |
| 42 | |
| 43 | inline 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 | |
| 54 | ConversionResult<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 | |
| 67 | std::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 | |
| 80 | ConversionResult<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 | |
| 93 | ConversionResult<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 | |
| 110 | ConversionResult<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 | |
| 129 | ConversionResult<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 | |
| 143 | ConversionResult<int> convertGainModeToAidl(const std::vector<ap_xsd::AudioGainMode>& gainModeVec) { |
Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 144 | int gainModeMask = 0; |
| 145 | for (const ap_xsd::AudioGainMode& gainMode : gainModeVec) { |
Mikhail Naganov | cc21b6f | 2023-10-17 19:39:27 -0700 | [diff] [blame] | 146 | audio_gain_mode_t legacyGainMode; |
| 147 | if (::android::GainModeConverter::fromString(ap_xsd::toString(gainMode), legacyGainMode)) { |
| 148 | gainModeMask |= static_cast<int>(legacyGainMode); |
| 149 | } |
Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 150 | } |
| 151 | return gainModeMask; |
| 152 | } |
| 153 | |
| 154 | ConversionResult<AudioChannelLayout> convertChannelMaskToAidl( |
| 155 | const ap_xsd::AudioChannelMask& xChannelMask) { |
| 156 | std::string xChannelMaskLiteral = ap_xsd::toString(xChannelMask); |
| 157 | audio_channel_mask_t legacyChannelMask = ::android::channelMaskFromString(xChannelMaskLiteral); |
| 158 | ConversionResult<AudioChannelLayout> result = |
| 159 | legacy2aidl_audio_channel_mask_t_AudioChannelLayout( |
| 160 | legacyChannelMask, |
| 161 | /* isInput= */ xChannelMaskLiteral.find("AUDIO_CHANNEL_IN_") == 0); |
| 162 | if ((legacyChannelMask == AUDIO_CHANNEL_INVALID) || !result.ok()) { |
| 163 | LOG(ERROR) << __func__ << " Review Audio Policy config: " << xChannelMaskLiteral |
| 164 | << " is not a valid audio channel mask."; |
| 165 | return unexpected(BAD_VALUE); |
| 166 | } |
| 167 | return result; |
| 168 | } |
| 169 | |
| 170 | ConversionResult<AudioGain> convertGainToAidl(const ap_xsd::Gains::Gain& xGain) { |
| 171 | return AudioGain{ |
| 172 | .mode = VALUE_OR_FATAL(convertGainModeToAidl(xGain.getMode())), |
| 173 | .channelMask = |
| 174 | xGain.hasChannel_mask() |
| 175 | ? VALUE_OR_FATAL(convertChannelMaskToAidl(xGain.getChannel_mask())) |
| 176 | : AudioChannelLayout{}, |
| 177 | .minValue = xGain.hasMinValueMB() ? xGain.getMinValueMB() : 0, |
| 178 | .maxValue = xGain.hasMaxValueMB() ? xGain.getMaxValueMB() : 0, |
| 179 | .defaultValue = xGain.hasDefaultValueMB() ? xGain.getDefaultValueMB() : 0, |
| 180 | .stepValue = xGain.hasStepValueMB() ? xGain.getStepValueMB() : 0, |
| 181 | .minRampMs = xGain.hasMinRampMs() ? xGain.getMinRampMs() : 0, |
| 182 | .maxRampMs = xGain.hasMaxRampMs() ? xGain.getMaxRampMs() : 0, |
| 183 | .useForVolume = xGain.hasUseForVolume() ? xGain.getUseForVolume() : false, |
| 184 | }; |
| 185 | } |
| 186 | |
| 187 | ConversionResult<AudioProfile> convertAudioProfileToAidl(const ap_xsd::Profile& xProfile) { |
| 188 | return AudioProfile{ |
| 189 | .format = xProfile.hasFormat() |
| 190 | ? VALUE_OR_FATAL(convertAudioFormatToAidl(xProfile.getFormat())) |
| 191 | : AudioFormatDescription{}, |
| 192 | .channelMasks = |
| 193 | xProfile.hasChannelMasks() |
| 194 | ? VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::AudioChannelMask, |
| 195 | AudioChannelLayout>( |
| 196 | xProfile.getChannelMasks(), &convertChannelMaskToAidl))) |
| 197 | : std::vector<AudioChannelLayout>{}, |
| 198 | .sampleRates = xProfile.hasSamplingRates() |
| 199 | ? VALUE_OR_FATAL((convertCollectionToAidl<int64_t, int>( |
| 200 | xProfile.getSamplingRates(), |
| 201 | [](const int64_t x) -> int { return x; }))) |
| 202 | : std::vector<int>{}}; |
| 203 | } |
| 204 | |
| 205 | ConversionResult<AudioIoFlags> convertIoFlagsToAidl( |
| 206 | const std::vector<ap_xsd::AudioInOutFlag>& flags, const ap_xsd::Role role, |
| 207 | bool flagsForMixPort) { |
Mikhail Naganov | 37fe9e8 | 2023-11-28 17:07:23 -0800 | [diff] [blame] | 208 | int legacyFlagMask = 0; |
Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 209 | if ((role == ap_xsd::Role::sink && flagsForMixPort) || |
| 210 | (role == ap_xsd::Role::source && !flagsForMixPort)) { |
| 211 | for (const ap_xsd::AudioInOutFlag& flag : flags) { |
Mikhail Naganov | cc21b6f | 2023-10-17 19:39:27 -0700 | [diff] [blame] | 212 | audio_input_flags_t legacyFlag; |
| 213 | if (::android::InputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) { |
Mikhail Naganov | 37fe9e8 | 2023-11-28 17:07:23 -0800 | [diff] [blame] | 214 | legacyFlagMask |= static_cast<int>(legacyFlag); |
Mikhail Naganov | cc21b6f | 2023-10-17 19:39:27 -0700 | [diff] [blame] | 215 | } |
Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 216 | } |
Mikhail Naganov | 37fe9e8 | 2023-11-28 17:07:23 -0800 | [diff] [blame] | 217 | return AudioIoFlags::make<AudioIoFlags::Tag::input>( |
| 218 | VALUE_OR_FATAL(legacy2aidl_audio_input_flags_t_int32_t_mask( |
| 219 | static_cast<audio_input_flags_t>(legacyFlagMask)))); |
Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 220 | } else { |
| 221 | for (const ap_xsd::AudioInOutFlag& flag : flags) { |
Mikhail Naganov | cc21b6f | 2023-10-17 19:39:27 -0700 | [diff] [blame] | 222 | audio_output_flags_t legacyFlag; |
| 223 | if (::android::OutputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) { |
Mikhail Naganov | 37fe9e8 | 2023-11-28 17:07:23 -0800 | [diff] [blame] | 224 | legacyFlagMask |= static_cast<int>(legacyFlag); |
Mikhail Naganov | cc21b6f | 2023-10-17 19:39:27 -0700 | [diff] [blame] | 225 | } |
Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 226 | } |
Mikhail Naganov | 37fe9e8 | 2023-11-28 17:07:23 -0800 | [diff] [blame] | 227 | return AudioIoFlags::make<AudioIoFlags::Tag::output>( |
| 228 | VALUE_OR_FATAL(legacy2aidl_audio_output_flags_t_int32_t_mask( |
| 229 | static_cast<audio_output_flags_t>(legacyFlagMask)))); |
Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 230 | } |
Lorena Torres-Huerta | 394e252 | 2022-12-20 02:21:41 +0000 | [diff] [blame] | 231 | } |
| 232 | |
| 233 | ConversionResult<AudioPort> convertDevicePortToAidl( |
| 234 | const ap_xsd::DevicePorts::DevicePort& xDevicePort, const std::string& xDefaultOutputDevice, |
| 235 | int32_t& nextPortId) { |
| 236 | return AudioPort{ |
| 237 | .id = nextPortId++, |
| 238 | .name = NON_EMPTY_STRING_OR_FATAL(xDevicePort.getTagName()), |
| 239 | .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>( |
| 240 | xDevicePort.getProfile(), convertAudioProfileToAidl))), |
| 241 | .flags = VALUE_OR_FATAL(convertIoFlagsToAidl({}, xDevicePort.getRole(), false)), |
| 242 | .gains = VALUE_OR_FATAL( |
| 243 | (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>( |
| 244 | xDevicePort.getGains(), &ap_xsd::Gains::getGain, convertGainToAidl))), |
| 245 | |
| 246 | .ext = VALUE_OR_FATAL(createAudioPortExt(xDevicePort, xDefaultOutputDevice))}; |
| 247 | } |
| 248 | |
| 249 | ConversionResult<std::vector<AudioPort>> convertDevicePortsInModuleToAidl( |
| 250 | const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) { |
| 251 | std::vector<AudioPort> audioPortVec; |
| 252 | std::vector<ap_xsd::DevicePorts> xDevicePortsVec = xModuleConfig.getDevicePorts(); |
| 253 | if (xDevicePortsVec.size() > 1) { |
| 254 | LOG(ERROR) << __func__ << "Having multiple '<devicePorts>' elements is not allowed, found: " |
| 255 | << xDevicePortsVec.size(); |
| 256 | return unexpected(BAD_VALUE); |
| 257 | } |
| 258 | if (!xDevicePortsVec.empty()) { |
| 259 | const std::string xDefaultOutputDevice = xModuleConfig.hasDefaultOutputDevice() |
| 260 | ? xModuleConfig.getDefaultOutputDevice() |
| 261 | : ""; |
| 262 | audioPortVec.reserve(xDevicePortsVec[0].getDevicePort().size()); |
| 263 | for (const ap_xsd::DevicePorts& xDevicePortsType : xDevicePortsVec) { |
| 264 | for (const ap_xsd::DevicePorts::DevicePort& xDevicePort : |
| 265 | xDevicePortsType.getDevicePort()) { |
| 266 | audioPortVec.push_back(VALUE_OR_FATAL( |
| 267 | convertDevicePortToAidl(xDevicePort, xDefaultOutputDevice, nextPortId))); |
| 268 | } |
| 269 | } |
| 270 | } |
| 271 | const std::unordered_set<std::string> xAttachedDeviceSet = getAttachedDevices(xModuleConfig); |
| 272 | for (const auto& port : audioPortVec) { |
| 273 | const auto& devicePort = port.ext.get<AudioPortExt::device>(); |
| 274 | if (xAttachedDeviceSet.count(port.name) != devicePort.device.type.connection.empty()) { |
| 275 | LOG(ERROR) << __func__ << ": Review Audio Policy config: <attachedDevices> " |
| 276 | << "list is incorrect or devicePort \"" << port.name |
| 277 | << "\" type= " << devicePort.device.type.toString() << " is incorrect."; |
| 278 | return unexpected(BAD_VALUE); |
| 279 | } |
| 280 | } |
| 281 | return audioPortVec; |
| 282 | } |
| 283 | |
| 284 | ConversionResult<AudioPort> convertMixPortToAidl(const ap_xsd::MixPorts::MixPort& xMixPort, |
| 285 | int32_t& nextPortId) { |
| 286 | return AudioPort{ |
| 287 | .id = nextPortId++, |
| 288 | .name = NON_EMPTY_STRING_OR_FATAL(xMixPort.getName()), |
| 289 | .profiles = VALUE_OR_FATAL((convertCollectionToAidl<ap_xsd::Profile, AudioProfile>( |
| 290 | xMixPort.getProfile(), convertAudioProfileToAidl))), |
| 291 | .flags = xMixPort.hasFlags() |
| 292 | ? VALUE_OR_FATAL(convertIoFlagsToAidl(xMixPort.getFlags(), |
| 293 | xMixPort.getRole(), true)) |
| 294 | : VALUE_OR_FATAL(convertIoFlagsToAidl({}, xMixPort.getRole(), true)), |
| 295 | .gains = VALUE_OR_FATAL( |
| 296 | (convertWrappedCollectionToAidl<ap_xsd::Gains, ap_xsd::Gains::Gain, AudioGain>( |
| 297 | xMixPort.getGains(), &ap_xsd::Gains::getGain, &convertGainToAidl))), |
| 298 | .ext = VALUE_OR_FATAL(createAudioPortExt(xMixPort)), |
| 299 | }; |
| 300 | } |
| 301 | |
| 302 | ConversionResult<std::vector<AudioPort>> convertMixPortsInModuleToAidl( |
| 303 | const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) { |
| 304 | std::vector<AudioPort> audioPortVec; |
| 305 | std::vector<ap_xsd::MixPorts> xMixPortsVec = xModuleConfig.getMixPorts(); |
| 306 | if (xMixPortsVec.size() > 1) { |
| 307 | LOG(ERROR) << __func__ << "Having multiple '<mixPorts>' elements is not allowed, found: " |
| 308 | << xMixPortsVec.size(); |
| 309 | return unexpected(BAD_VALUE); |
| 310 | } |
| 311 | if (!xMixPortsVec.empty()) { |
| 312 | audioPortVec.reserve(xMixPortsVec[0].getMixPort().size()); |
| 313 | for (const ap_xsd::MixPorts& xMixPortsType : xMixPortsVec) { |
| 314 | for (const ap_xsd::MixPorts::MixPort& xMixPort : xMixPortsType.getMixPort()) { |
| 315 | audioPortVec.push_back(VALUE_OR_FATAL(convertMixPortToAidl(xMixPort, nextPortId))); |
| 316 | } |
| 317 | } |
| 318 | } |
| 319 | return audioPortVec; |
| 320 | } |
| 321 | |
| 322 | ConversionResult<int32_t> getSinkPortId(const ap_xsd::Routes::Route& xRoute, |
| 323 | const std::unordered_map<std::string, int32_t>& portMap) { |
| 324 | auto portMapIter = portMap.find(xRoute.getSink()); |
| 325 | if (portMapIter == portMap.end()) { |
| 326 | LOG(ERROR) << __func__ << " Review Audio Policy config: audio route" |
| 327 | << "has sink: " << xRoute.getSink() |
| 328 | << " which is neither a device port nor mix port."; |
| 329 | return unexpected(BAD_VALUE); |
| 330 | } |
| 331 | return portMapIter->second; |
| 332 | } |
| 333 | |
| 334 | ConversionResult<std::vector<int32_t>> getSourcePortIds( |
| 335 | const ap_xsd::Routes::Route& xRoute, |
| 336 | const std::unordered_map<std::string, int32_t>& portMap) { |
| 337 | std::vector<int32_t> sourcePortIds; |
| 338 | for (const std::string& rawSource : ::android::base::Split(xRoute.getSources(), ",")) { |
| 339 | const std::string source = ::android::base::Trim(rawSource); |
| 340 | auto portMapIter = portMap.find(source); |
| 341 | if (portMapIter == portMap.end()) { |
| 342 | LOG(ERROR) << __func__ << " Review Audio Policy config: audio route" |
| 343 | << "has source \"" << source |
| 344 | << "\" which is neither a device port nor mix port."; |
| 345 | return unexpected(BAD_VALUE); |
| 346 | } |
| 347 | sourcePortIds.push_back(portMapIter->second); |
| 348 | } |
| 349 | return sourcePortIds; |
| 350 | } |
| 351 | |
| 352 | ConversionResult<AudioRoute> convertRouteToAidl(const ap_xsd::Routes::Route& xRoute, |
| 353 | const std::vector<AudioPort>& aidlAudioPorts) { |
| 354 | std::unordered_map<std::string, int32_t> portMap; |
| 355 | for (const AudioPort& port : aidlAudioPorts) { |
| 356 | portMap.insert({port.name, port.id}); |
| 357 | } |
| 358 | return AudioRoute{.sourcePortIds = VALUE_OR_FATAL(getSourcePortIds(xRoute, portMap)), |
| 359 | .sinkPortId = VALUE_OR_FATAL(getSinkPortId(xRoute, portMap)), |
| 360 | .isExclusive = (xRoute.getType() == ap_xsd::MixType::mux)}; |
| 361 | } |
| 362 | |
| 363 | ConversionResult<std::vector<AudioRoute>> convertRoutesInModuleToAidl( |
| 364 | const ap_xsd::Modules::Module& xModuleConfig, |
| 365 | const std::vector<AudioPort>& aidlAudioPorts) { |
| 366 | std::vector<AudioRoute> audioRouteVec; |
| 367 | std::vector<ap_xsd::Routes> xRoutesVec = xModuleConfig.getRoutes(); |
| 368 | if (!xRoutesVec.empty()) { |
| 369 | /* |
| 370 | * xRoutesVec likely only contains one element; that is, it's |
| 371 | * likely that all ap_xsd::Routes::MixPort types that we need to convert |
| 372 | * are inside of xRoutesVec[0]. |
| 373 | */ |
| 374 | audioRouteVec.reserve(xRoutesVec[0].getRoute().size()); |
| 375 | for (const ap_xsd::Routes& xRoutesType : xRoutesVec) { |
| 376 | for (const ap_xsd::Routes::Route& xRoute : xRoutesType.getRoute()) { |
| 377 | audioRouteVec.push_back(VALUE_OR_FATAL(convertRouteToAidl(xRoute, aidlAudioPorts))); |
| 378 | } |
| 379 | } |
| 380 | } |
| 381 | return audioRouteVec; |
| 382 | } |
| 383 | |
| 384 | ConversionResult<std::unique_ptr<Module::Configuration>> convertModuleConfigToAidl( |
| 385 | const ap_xsd::Modules::Module& xModuleConfig) { |
| 386 | auto result = std::make_unique<Module::Configuration>(); |
| 387 | auto& aidlModuleConfig = *result; |
| 388 | std::vector<AudioPort> devicePorts = VALUE_OR_FATAL( |
| 389 | convertDevicePortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId)); |
| 390 | |
| 391 | // The XML config does not specify the default input device. |
| 392 | // Assign the first attached input device as the default. |
| 393 | for (auto& port : devicePorts) { |
| 394 | if (port.flags.getTag() != AudioIoFlags::input) continue; |
| 395 | auto& deviceExt = port.ext.get<AudioPortExt::device>(); |
| 396 | if (!deviceExt.device.type.connection.empty()) continue; |
| 397 | deviceExt.flags |= 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE; |
| 398 | break; |
| 399 | } |
| 400 | |
| 401 | std::vector<AudioPort> mixPorts = VALUE_OR_FATAL( |
| 402 | convertMixPortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId)); |
| 403 | aidlModuleConfig.ports.reserve(devicePorts.size() + mixPorts.size()); |
| 404 | aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), devicePorts.begin(), |
| 405 | devicePorts.end()); |
| 406 | aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), mixPorts.begin(), mixPorts.end()); |
| 407 | |
| 408 | aidlModuleConfig.routes = |
| 409 | VALUE_OR_FATAL(convertRoutesInModuleToAidl(xModuleConfig, aidlModuleConfig.ports)); |
| 410 | return result; |
| 411 | } |
| 412 | |
| 413 | ConversionResult<AudioHalCapCriterion> convertCapCriterionToAidl( |
| 414 | const eng_xsd::CriterionType& xsdcCriterion) { |
| 415 | AudioHalCapCriterion aidlCapCriterion; |
| 416 | aidlCapCriterion.name = xsdcCriterion.getName(); |
| 417 | aidlCapCriterion.criterionTypeName = xsdcCriterion.getType(); |
| 418 | aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default(); |
| 419 | return aidlCapCriterion; |
| 420 | } |
| 421 | |
| 422 | ConversionResult<std::string> convertCriterionTypeValueToAidl( |
| 423 | const eng_xsd::ValueType& xsdcCriterionTypeValue) { |
| 424 | return xsdcCriterionTypeValue.getLiteral(); |
| 425 | } |
| 426 | |
| 427 | ConversionResult<AudioHalCapCriterionType> convertCapCriterionTypeToAidl( |
| 428 | const eng_xsd::CriterionTypeType& xsdcCriterionType) { |
| 429 | AudioHalCapCriterionType aidlCapCriterionType; |
| 430 | aidlCapCriterionType.name = xsdcCriterionType.getName(); |
| 431 | aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType())); |
| 432 | aidlCapCriterionType.values = VALUE_OR_RETURN( |
| 433 | (convertWrappedCollectionToAidl<eng_xsd::ValuesType, eng_xsd::ValueType, std::string>( |
| 434 | xsdcCriterionType.getValues(), &eng_xsd::ValuesType::getValue, |
| 435 | &convertCriterionTypeValueToAidl))); |
| 436 | return aidlCapCriterionType; |
| 437 | } |
| 438 | |
| 439 | ConversionResult<AudioHalVolumeCurve::CurvePoint> convertCurvePointToAidl( |
| 440 | const std::string& xsdcCurvePoint) { |
| 441 | AudioHalVolumeCurve::CurvePoint aidlCurvePoint{}; |
| 442 | if ((sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index, |
| 443 | &aidlCurvePoint.attenuationMb) != 2) || |
| 444 | (aidlCurvePoint.index < AudioHalVolumeCurve::CurvePoint::MIN_INDEX) || |
| 445 | (aidlCurvePoint.index > AudioHalVolumeCurve::CurvePoint::MAX_INDEX)) { |
| 446 | LOG(ERROR) << __func__ << " Review Audio Policy config: volume curve point:" |
| 447 | << "\"" << xsdcCurvePoint << "\" is invalid"; |
| 448 | return unexpected(BAD_VALUE); |
| 449 | } |
| 450 | return aidlCurvePoint; |
| 451 | } |
| 452 | } // namespace aidl::android::hardware::audio::core::internal |