/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #define LOG_TAG "AHAL_Config" #include #include #include #include #include #include #include #include #include #include #include "core-impl/XmlConverter.h" #include "core-impl/XsdcConversion.h" using aidl::android::hardware::audio::common::iequals; using aidl::android::hardware::audio::common::isValidAudioMode; using aidl::android::hardware::audio::common::kValidAudioModes; using aidl::android::media::audio::common::AudioChannelLayout; using aidl::android::media::audio::common::AudioContentType; using aidl::android::media::audio::common::AudioDevice; using aidl::android::media::audio::common::AudioDeviceAddress; using aidl::android::media::audio::common::AudioDeviceDescription; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; using aidl::android::media::audio::common::AudioGain; using aidl::android::media::audio::common::AudioHalCapCriterion; using aidl::android::media::audio::common::AudioHalCapCriterionType; using aidl::android::media::audio::common::AudioHalCapCriterionV2; using aidl::android::media::audio::common::AudioHalVolumeCurve; using aidl::android::media::audio::common::AudioIoFlags; using aidl::android::media::audio::common::AudioMode; using aidl::android::media::audio::common::AudioPolicyForceUse; using aidl::android::media::audio::common::AudioPort; using aidl::android::media::audio::common::AudioPortConfig; using aidl::android::media::audio::common::AudioPortDeviceExt; using aidl::android::media::audio::common::AudioPortExt; using aidl::android::media::audio::common::AudioPortMixExt; using aidl::android::media::audio::common::AudioProfile; using aidl::android::media::audio::common::AudioSource; using aidl::android::media::audio::common::AudioStreamType; using aidl::android::media::audio::common::AudioUsage; using android::BAD_VALUE; using android::base::unexpected; using android::utilities::convertTo; using ndk::enum_range; namespace ap_xsd = android::audio::policy::configuration; namespace eng_xsd = android::audio::policy::engine::configuration; namespace aidl::android::hardware::audio::core::internal { static constexpr const char kXsdcForceConfigForCommunication[] = "ForceUseForCommunication"; static constexpr const char kXsdcForceConfigForMedia[] = "ForceUseForMedia"; static constexpr const char kXsdcForceConfigForRecord[] = "ForceUseForRecord"; static constexpr const char kXsdcForceConfigForDock[] = "ForceUseForDock"; static constexpr const char kXsdcForceConfigForSystem[] = "ForceUseForSystem"; static constexpr const char kXsdcForceConfigForHdmiSystemAudio[] = "ForceUseForHdmiSystemAudio"; static constexpr const char kXsdcForceConfigForEncodedSurround[] = "ForceUseForEncodedSurround"; static constexpr const char kXsdcForceConfigForVibrateRinging[] = "ForceUseForVibrateRinging"; inline ConversionResult assertNonEmpty(const std::string& s) { if (s.empty()) { LOG(ERROR) << __func__ << " Review Audio Policy config: " << " empty string is not valid."; return unexpected(BAD_VALUE); } return s; } #define NON_EMPTY_STRING_OR_FATAL(s) VALUE_OR_FATAL(assertNonEmpty(s)) ConversionResult convertAudioFlagsToAidl( const std::vector& xsdcFlagTypeVec) { int legacyFlagMask = 0; for (const eng_xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) { if (xsdcFlagType != eng_xsd::FlagType::AUDIO_FLAG_NONE) { audio_flags_mask_t legacyFlag = AUDIO_FLAG_NONE; if (!::android::AudioFlagConverter::fromString(eng_xsd::toString(xsdcFlagType), legacyFlag)) { LOG(ERROR) << __func__ << " Review Audio Policy config, " << eng_xsd::toString(xsdcFlagType) << " is not a valid flag."; return unexpected(BAD_VALUE); } legacyFlagMask |= static_cast(legacyFlag); } } ConversionResult result = legacy2aidl_audio_flags_mask_t_int32_t_mask( static_cast(legacyFlagMask)); if (!result.ok()) { LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyFlagMask << " has invalid flag(s)."; return unexpected(BAD_VALUE); } return result; } ConversionResult convertAudioStreamTypeToAidl(const eng_xsd::Stream& xsdcStream) { audio_stream_type_t legacyStreamType; if (!::android::StreamTypeConverter::fromString(eng_xsd::toString(xsdcStream), legacyStreamType)) { LOG(ERROR) << __func__ << " Review Audio Policy config, " << eng_xsd::toString(xsdcStream) << " is not a valid audio stream type."; return unexpected(BAD_VALUE); } ConversionResult result = legacy2aidl_audio_stream_type_t_AudioStreamType(legacyStreamType); if (!result.ok()) { LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyStreamType << " is not a valid audio stream type."; return unexpected(BAD_VALUE); } return result; } ConversionResult convertAudioSourceToAidl( const eng_xsd::SourceEnumType& xsdcSourceType) { audio_source_t legacySourceType; if (!::android::SourceTypeConverter::fromString(eng_xsd::toString(xsdcSourceType), legacySourceType)) { LOG(ERROR) << __func__ << " Review Audio Policy config, " << eng_xsd::toString(xsdcSourceType) << " is not a valid audio source."; return unexpected(BAD_VALUE); } ConversionResult result = legacy2aidl_audio_source_t_AudioSource(legacySourceType); if (!result.ok()) { LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacySourceType << " is not a valid audio source."; return unexpected(BAD_VALUE); } return result; } ConversionResult convertAudioContentTypeToAidl( const eng_xsd::ContentType& xsdcContentType) { audio_content_type_t legacyContentType; if (!::android::AudioContentTypeConverter::fromString(eng_xsd::toString(xsdcContentType), legacyContentType)) { LOG(ERROR) << __func__ << " Review Audio Policy config, " << eng_xsd::toString(xsdcContentType) << " is not a valid audio content type."; return unexpected(BAD_VALUE); } ConversionResult result = legacy2aidl_audio_content_type_t_AudioContentType(legacyContentType); if (!result.ok()) { LOG(ERROR) << __func__ << " Review Audio Policy config, " << legacyContentType << " is not a valid audio content type."; return unexpected(BAD_VALUE); } return result; } ConversionResult convertAudioUsageToAidl(const eng_xsd::UsageEnumType& xsdcUsage) { audio_usage_t legacyUsage; if (!::android::UsageTypeConverter::fromString(eng_xsd::toString(xsdcUsage), legacyUsage)) { LOG(ERROR) << __func__ << " Review Audio Policy config, not a valid audio usage."; return unexpected(BAD_VALUE); } ConversionResult result = legacy2aidl_audio_usage_t_AudioUsage(legacyUsage); if (!result.ok()) { LOG(ERROR) << __func__ << " Review Audio Policy config, not a valid audio usage."; return unexpected(BAD_VALUE); } return result; } ConversionResult convertAudioFormatToAidl(const std::string& xsdcFormat) { audio_format_t legacyFormat = ::android::formatFromString(xsdcFormat, AUDIO_FORMAT_DEFAULT); ConversionResult result = legacy2aidl_audio_format_t_AudioFormatDescription(legacyFormat); if ((legacyFormat == AUDIO_FORMAT_DEFAULT && xsdcFormat.compare("AUDIO_FORMAT_DEFAULT") != 0) || !result.ok()) { LOG(ERROR) << __func__ << " Review Audio Policy config: " << xsdcFormat << " is not a valid audio format."; return unexpected(BAD_VALUE); } return result; } std::unordered_set getAttachedDevices(const ap_xsd::Modules::Module& moduleConfig) { std::unordered_set attachedDeviceSet; if (moduleConfig.hasAttachedDevices()) { for (const ap_xsd::AttachedDevices& attachedDevices : moduleConfig.getAttachedDevices()) { if (attachedDevices.hasItem()) { attachedDeviceSet.insert(attachedDevices.getItem().begin(), attachedDevices.getItem().end()); } } } return attachedDeviceSet; } ConversionResult convertDeviceTypeToAidl(const std::string& xType) { audio_devices_t legacyDeviceType = AUDIO_DEVICE_NONE; ::android::DeviceConverter::fromString(xType, legacyDeviceType); ConversionResult result = legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyDeviceType); if ((legacyDeviceType == AUDIO_DEVICE_NONE) || !result.ok()) { LOG(ERROR) << __func__ << " Review Audio Policy config: " << xType << " is not a valid device type."; return unexpected(BAD_VALUE); } return result; } ConversionResult createAudioDevice( const ap_xsd::DevicePorts::DevicePort& xDevicePort) { AudioDevice device = { .type = VALUE_OR_FATAL(convertDeviceTypeToAidl(xDevicePort.getType())), .address = xDevicePort.hasAddress() ? AudioDeviceAddress::make( xDevicePort.getAddress()) : AudioDeviceAddress{}}; if (device.type.type == AudioDeviceType::IN_MICROPHONE && device.type.connection.empty()) { device.address = "bottom"; } else if (device.type.type == AudioDeviceType::IN_MICROPHONE_BACK && device.type.connection.empty()) { device.address = "back"; } return device; } ConversionResult createAudioPortExt( const ap_xsd::DevicePorts::DevicePort& xDevicePort, const std::string& xDefaultOutputDevice) { AudioPortDeviceExt deviceExt = { .device = VALUE_OR_FATAL(createAudioDevice(xDevicePort)), .flags = (xDevicePort.getTagName() == xDefaultOutputDevice) ? 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE : 0, .encodedFormats = xDevicePort.hasEncodedFormats() ? VALUE_OR_FATAL( (convertCollectionToAidl( xDevicePort.getEncodedFormats(), &convertAudioFormatToAidl))) : std::vector{}, }; return AudioPortExt::make(deviceExt); } ConversionResult createAudioPortExt(const ap_xsd::MixPorts::MixPort& xMixPort) { AudioPortMixExt mixExt = { .maxOpenStreamCount = xMixPort.hasMaxOpenCount() ? static_cast(xMixPort.getMaxOpenCount()) : 0, .maxActiveStreamCount = xMixPort.hasMaxActiveCount() ? static_cast(xMixPort.getMaxActiveCount()) : 1, .recommendedMuteDurationMs = xMixPort.hasRecommendedMuteDurationMs() ? static_cast(xMixPort.getRecommendedMuteDurationMs()) : 0}; return AudioPortExt::make(mixExt); } ConversionResult convertGainModeToAidl(const std::vector& gainModeVec) { int gainModeMask = 0; for (const ap_xsd::AudioGainMode& gainMode : gainModeVec) { audio_gain_mode_t legacyGainMode; if (::android::GainModeConverter::fromString(ap_xsd::toString(gainMode), legacyGainMode)) { gainModeMask |= static_cast(legacyGainMode); } } return gainModeMask; } ConversionResult convertChannelMaskToAidl( const ap_xsd::AudioChannelMask& xChannelMask) { std::string xChannelMaskLiteral = ap_xsd::toString(xChannelMask); audio_channel_mask_t legacyChannelMask = ::android::channelMaskFromString(xChannelMaskLiteral); ConversionResult result = legacy2aidl_audio_channel_mask_t_AudioChannelLayout( legacyChannelMask, /* isInput= */ xChannelMaskLiteral.find("AUDIO_CHANNEL_IN_") == 0); if ((legacyChannelMask == AUDIO_CHANNEL_INVALID) || !result.ok()) { LOG(ERROR) << __func__ << " Review Audio Policy config: " << xChannelMaskLiteral << " is not a valid audio channel mask."; return unexpected(BAD_VALUE); } return result; } ConversionResult convertGainToAidl(const ap_xsd::Gains::Gain& xGain) { return AudioGain{ .mode = VALUE_OR_FATAL(convertGainModeToAidl(xGain.getMode())), .channelMask = xGain.hasChannel_mask() ? VALUE_OR_FATAL(convertChannelMaskToAidl(xGain.getChannel_mask())) : AudioChannelLayout{}, .minValue = xGain.hasMinValueMB() ? xGain.getMinValueMB() : 0, .maxValue = xGain.hasMaxValueMB() ? xGain.getMaxValueMB() : 0, .defaultValue = xGain.hasDefaultValueMB() ? xGain.getDefaultValueMB() : 0, .stepValue = xGain.hasStepValueMB() ? xGain.getStepValueMB() : 0, .minRampMs = xGain.hasMinRampMs() ? xGain.getMinRampMs() : 0, .maxRampMs = xGain.hasMaxRampMs() ? xGain.getMaxRampMs() : 0, .useForVolume = xGain.hasUseForVolume() ? xGain.getUseForVolume() : false, }; } ConversionResult convertAudioProfileToAidl(const ap_xsd::Profile& xProfile) { return AudioProfile{ .format = xProfile.hasFormat() ? VALUE_OR_FATAL(convertAudioFormatToAidl(xProfile.getFormat())) : AudioFormatDescription{}, .channelMasks = xProfile.hasChannelMasks() ? VALUE_OR_FATAL((convertCollectionToAidl( xProfile.getChannelMasks(), &convertChannelMaskToAidl))) : std::vector{}, .sampleRates = xProfile.hasSamplingRates() ? VALUE_OR_FATAL((convertCollectionToAidl( xProfile.getSamplingRates(), [](const int64_t x) -> int { return x; }))) : std::vector{}}; } ConversionResult convertIoFlagsToAidl( const std::vector& flags, const ap_xsd::Role role, bool flagsForMixPort) { int legacyFlagMask = 0; if ((role == ap_xsd::Role::sink && flagsForMixPort) || (role == ap_xsd::Role::source && !flagsForMixPort)) { for (const ap_xsd::AudioInOutFlag& flag : flags) { audio_input_flags_t legacyFlag; if (::android::InputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) { legacyFlagMask |= static_cast(legacyFlag); } } return AudioIoFlags::make( VALUE_OR_FATAL(legacy2aidl_audio_input_flags_t_int32_t_mask( static_cast(legacyFlagMask)))); } else { for (const ap_xsd::AudioInOutFlag& flag : flags) { audio_output_flags_t legacyFlag; if (::android::OutputFlagConverter::fromString(ap_xsd::toString(flag), legacyFlag)) { legacyFlagMask |= static_cast(legacyFlag); } } return AudioIoFlags::make( VALUE_OR_FATAL(legacy2aidl_audio_output_flags_t_int32_t_mask( static_cast(legacyFlagMask)))); } } ConversionResult convertDevicePortToAidl( const ap_xsd::DevicePorts::DevicePort& xDevicePort, const std::string& xDefaultOutputDevice, int32_t& nextPortId) { return AudioPort{ .id = nextPortId++, .name = NON_EMPTY_STRING_OR_FATAL(xDevicePort.getTagName()), .profiles = VALUE_OR_FATAL((convertCollectionToAidl( xDevicePort.getProfile(), convertAudioProfileToAidl))), .flags = VALUE_OR_FATAL(convertIoFlagsToAidl({}, xDevicePort.getRole(), false)), .gains = VALUE_OR_FATAL( (convertWrappedCollectionToAidl( xDevicePort.getGains(), &ap_xsd::Gains::getGain, convertGainToAidl))), .ext = VALUE_OR_FATAL(createAudioPortExt(xDevicePort, xDefaultOutputDevice))}; } ConversionResult> convertDevicePortsInModuleToAidl( const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) { std::vector audioPortVec; std::vector xDevicePortsVec = xModuleConfig.getDevicePorts(); if (xDevicePortsVec.size() > 1) { LOG(ERROR) << __func__ << "Having multiple '' elements is not allowed, found: " << xDevicePortsVec.size(); return unexpected(BAD_VALUE); } if (!xDevicePortsVec.empty()) { const std::string xDefaultOutputDevice = xModuleConfig.hasDefaultOutputDevice() ? xModuleConfig.getDefaultOutputDevice() : ""; audioPortVec.reserve(xDevicePortsVec[0].getDevicePort().size()); for (const ap_xsd::DevicePorts& xDevicePortsType : xDevicePortsVec) { for (const ap_xsd::DevicePorts::DevicePort& xDevicePort : xDevicePortsType.getDevicePort()) { audioPortVec.push_back(VALUE_OR_FATAL( convertDevicePortToAidl(xDevicePort, xDefaultOutputDevice, nextPortId))); } } } const std::unordered_set xAttachedDeviceSet = getAttachedDevices(xModuleConfig); for (const auto& port : audioPortVec) { const auto& devicePort = port.ext.get(); if (xAttachedDeviceSet.count(port.name) != devicePort.device.type.connection.empty()) { LOG(ERROR) << __func__ << ": Review Audio Policy config: " << "list is incorrect or devicePort \"" << port.name << "\" type= " << devicePort.device.type.toString() << " is incorrect."; return unexpected(BAD_VALUE); } } return audioPortVec; } ConversionResult convertMixPortToAidl(const ap_xsd::MixPorts::MixPort& xMixPort, int32_t& nextPortId) { return AudioPort{ .id = nextPortId++, .name = NON_EMPTY_STRING_OR_FATAL(xMixPort.getName()), .profiles = VALUE_OR_FATAL((convertCollectionToAidl( xMixPort.getProfile(), convertAudioProfileToAidl))), .flags = xMixPort.hasFlags() ? VALUE_OR_FATAL(convertIoFlagsToAidl(xMixPort.getFlags(), xMixPort.getRole(), true)) : VALUE_OR_FATAL(convertIoFlagsToAidl({}, xMixPort.getRole(), true)), .gains = VALUE_OR_FATAL( (convertWrappedCollectionToAidl( xMixPort.getGains(), &ap_xsd::Gains::getGain, &convertGainToAidl))), .ext = VALUE_OR_FATAL(createAudioPortExt(xMixPort)), }; } ConversionResult> convertMixPortsInModuleToAidl( const ap_xsd::Modules::Module& xModuleConfig, int32_t& nextPortId) { std::vector audioPortVec; std::vector xMixPortsVec = xModuleConfig.getMixPorts(); if (xMixPortsVec.size() > 1) { LOG(ERROR) << __func__ << "Having multiple '' elements is not allowed, found: " << xMixPortsVec.size(); return unexpected(BAD_VALUE); } if (!xMixPortsVec.empty()) { audioPortVec.reserve(xMixPortsVec[0].getMixPort().size()); for (const ap_xsd::MixPorts& xMixPortsType : xMixPortsVec) { for (const ap_xsd::MixPorts::MixPort& xMixPort : xMixPortsType.getMixPort()) { audioPortVec.push_back(VALUE_OR_FATAL(convertMixPortToAidl(xMixPort, nextPortId))); } } } return audioPortVec; } ConversionResult getSinkPortId(const ap_xsd::Routes::Route& xRoute, const std::unordered_map& portMap) { auto portMapIter = portMap.find(xRoute.getSink()); if (portMapIter == portMap.end()) { LOG(ERROR) << __func__ << " Review Audio Policy config: audio route" << "has sink: " << xRoute.getSink() << " which is neither a device port nor mix port."; return unexpected(BAD_VALUE); } return portMapIter->second; } ConversionResult> getSourcePortIds( const ap_xsd::Routes::Route& xRoute, const std::unordered_map& portMap) { std::vector sourcePortIds; for (const std::string& rawSource : ::android::base::Split(xRoute.getSources(), ",")) { const std::string source = ::android::base::Trim(rawSource); auto portMapIter = portMap.find(source); if (portMapIter == portMap.end()) { LOG(ERROR) << __func__ << " Review Audio Policy config: audio route" << "has source \"" << source << "\" which is neither a device port nor mix port."; return unexpected(BAD_VALUE); } sourcePortIds.push_back(portMapIter->second); } return sourcePortIds; } ConversionResult convertRouteToAidl(const ap_xsd::Routes::Route& xRoute, const std::vector& aidlAudioPorts) { std::unordered_map portMap; for (const AudioPort& port : aidlAudioPorts) { portMap.insert({port.name, port.id}); } return AudioRoute{.sourcePortIds = VALUE_OR_FATAL(getSourcePortIds(xRoute, portMap)), .sinkPortId = VALUE_OR_FATAL(getSinkPortId(xRoute, portMap)), .isExclusive = (xRoute.getType() == ap_xsd::MixType::mux)}; } ConversionResult> convertRoutesInModuleToAidl( const ap_xsd::Modules::Module& xModuleConfig, const std::vector& aidlAudioPorts) { std::vector audioRouteVec; std::vector xRoutesVec = xModuleConfig.getRoutes(); if (!xRoutesVec.empty()) { /* * xRoutesVec likely only contains one element; that is, it's * likely that all ap_xsd::Routes::MixPort types that we need to convert * are inside of xRoutesVec[0]. */ audioRouteVec.reserve(xRoutesVec[0].getRoute().size()); for (const ap_xsd::Routes& xRoutesType : xRoutesVec) { for (const ap_xsd::Routes::Route& xRoute : xRoutesType.getRoute()) { audioRouteVec.push_back(VALUE_OR_FATAL(convertRouteToAidl(xRoute, aidlAudioPorts))); } } } return audioRouteVec; } ConversionResult> convertModuleConfigToAidl( const ap_xsd::Modules::Module& xModuleConfig) { auto result = std::make_unique(); auto& aidlModuleConfig = *result; std::vector devicePorts = VALUE_OR_FATAL( convertDevicePortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId)); // The XML config does not specify the default input device. // Assign the first attached input device as the default. for (auto& port : devicePorts) { if (port.flags.getTag() != AudioIoFlags::input) continue; auto& deviceExt = port.ext.get(); if (!deviceExt.device.type.connection.empty()) continue; deviceExt.flags |= 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE; break; } std::vector mixPorts = VALUE_OR_FATAL( convertMixPortsInModuleToAidl(xModuleConfig, aidlModuleConfig.nextPortId)); aidlModuleConfig.ports.reserve(devicePorts.size() + mixPorts.size()); aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), devicePorts.begin(), devicePorts.end()); aidlModuleConfig.ports.insert(aidlModuleConfig.ports.end(), mixPorts.begin(), mixPorts.end()); aidlModuleConfig.routes = VALUE_OR_FATAL(convertRoutesInModuleToAidl(xModuleConfig, aidlModuleConfig.ports)); return result; } ConversionResult convertTelephonyModeToAidl(const std::string& xsdcModeCriterionType) { const auto it = std::find_if(kValidAudioModes.begin(), kValidAudioModes.end(), [&xsdcModeCriterionType](const auto& mode) { return toString(mode) == xsdcModeCriterionType; }); if (it == kValidAudioModes.end()) { LOG(ERROR) << __func__ << " invalid mode " << xsdcModeCriterionType; return unexpected(BAD_VALUE); } return *it; } ConversionResult convertDeviceAddressToAidl(const std::string& xsdcAddress) { return AudioDeviceAddress::make(xsdcAddress); } ConversionResult getCriterionTypeByName( const std::string& name, const std::vector& xsdcCriterionTypesVec) { for (const auto& xsdCriterionTypes : xsdcCriterionTypesVec) { for (const auto& xsdcCriterionType : xsdCriterionTypes.getCriterion_type()) { if (xsdcCriterionType.getName() == name) { return xsdcCriterionType; } } } LOG(ERROR) << __func__ << " failed to find criterion type " << name; return unexpected(BAD_VALUE); } ConversionResult>> convertCapCriteriaCollectionToAidl( const std::vector& xsdcCriteriaVec, const std::vector& xsdcCriterionTypesVec) { std::vector> resultAidlCriterionVec; if (xsdcCriteriaVec.empty() || xsdcCriterionTypesVec.empty()) { LOG(ERROR) << __func__ << " empty criteria/criterionTypes"; return unexpected(BAD_VALUE); } for (const auto& xsdCriteria : xsdcCriteriaVec) { for (const auto& xsdcCriterion : xsdCriteria.getCriterion()) { resultAidlCriterionVec.push_back( std::optional(VALUE_OR_FATAL( convertCapCriterionV2ToAidl(xsdcCriterion, xsdcCriterionTypesVec)))); } } return resultAidlCriterionVec; } ConversionResult> convertDevicesToAidl( const eng_xsd::CriterionTypeType& xsdcDeviceCriterionType) { if (xsdcDeviceCriterionType.getValues().empty()) { LOG(ERROR) << __func__ << " no values provided"; return unexpected(BAD_VALUE); } std::vector aidlDevices; for (eng_xsd::ValuesType xsdcValues : xsdcDeviceCriterionType.getValues()) { aidlDevices.reserve(xsdcValues.getValue().size()); for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) { if (!xsdcValue.hasAndroid_type()) { LOG(ERROR) << __func__ << " empty android type"; return unexpected(BAD_VALUE); } uint32_t integerValue; if (!convertTo(xsdcValue.getAndroid_type(), integerValue)) { LOG(ERROR) << __func__ << " failed to convert android type " << xsdcValue.getAndroid_type(); return unexpected(BAD_VALUE); } aidlDevices.push_back( VALUE_OR_RETURN(legacy2aidl_audio_devices_t_AudioDeviceDescription( static_cast(integerValue)))); } } return aidlDevices; } ConversionResult> convertDeviceAddressesToAidl( const eng_xsd::CriterionTypeType& xsdcDeviceAddressesCriterionType) { if (xsdcDeviceAddressesCriterionType.getValues().empty()) { LOG(ERROR) << __func__ << " no values provided"; return unexpected(BAD_VALUE); } std::vector aidlDeviceAddresses; for (eng_xsd::ValuesType xsdcValues : xsdcDeviceAddressesCriterionType.getValues()) { aidlDeviceAddresses.reserve(xsdcValues.getValue().size()); for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) { aidlDeviceAddresses.push_back( AudioDeviceAddress::make(xsdcValue.getLiteral())); } } return aidlDeviceAddresses; } ConversionResult convertAudioModeToAidl(const std::string& xsdcAudioModeType) { const auto it = std::find_if(enum_range().begin(), enum_range().end(), [&](const auto v) { return toString(v) == xsdcAudioModeType; }); if (it == enum_range().end()) { LOG(ERROR) << __func__ << " invalid audio mode " << xsdcAudioModeType; return unexpected(BAD_VALUE); } return *it; } ConversionResult> convertTelephonyModesToAidl( const eng_xsd::CriterionTypeType& xsdcTelephonyModeCriterionType) { if (xsdcTelephonyModeCriterionType.getValues().empty()) { LOG(ERROR) << __func__ << " no values provided"; return unexpected(BAD_VALUE); } std::vector aidlAudioModes; for (eng_xsd::ValuesType xsdcValues : xsdcTelephonyModeCriterionType.getValues()) { aidlAudioModes.reserve(xsdcValues.getValue().size()); for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) { aidlAudioModes.push_back( VALUE_OR_RETURN(convertAudioModeToAidl(xsdcValue.getLiteral()))); } } return aidlAudioModes; } ConversionResult> convertForceUseConfigsToAidl( const std::string& criterionValue, const eng_xsd::CriterionTypeType& xsdcForcedConfigCriterionType) { if (xsdcForcedConfigCriterionType.getValues().empty()) { LOG(ERROR) << __func__ << " no values provided"; return unexpected(BAD_VALUE); } std::vector aidlForcedConfigs; for (eng_xsd::ValuesType xsdcValues : xsdcForcedConfigCriterionType.getValues()) { aidlForcedConfigs.reserve(xsdcValues.getValue().size()); for (const eng_xsd::ValueType& xsdcValue : xsdcValues.getValue()) { aidlForcedConfigs.push_back( VALUE_OR_RETURN(convertForceUseToAidl(criterionValue, xsdcValue.getLiteral()))); } } return aidlForcedConfigs; } template ConversionResult convertForceUseForcedConfigToAidl( const std::string& xsdcForcedConfigCriterionType) { const auto it = std::find_if(enum_range().begin(), enum_range().end(), [&](const auto v) { return toString(v) == xsdcForcedConfigCriterionType; }); if (it == enum_range().end()) { LOG(ERROR) << __func__ << " invalid forced config " << xsdcForcedConfigCriterionType; return unexpected(BAD_VALUE); } return *it; } ConversionResult convertForceUseToAidl(const std::string& xsdcCriterionName, const std::string& xsdcCriterionValue) { if (!fastcmp(xsdcCriterionName.c_str(), kXsdcForceConfigForCommunication, strlen(kXsdcForceConfigForCommunication))) { const auto deviceCategory = VALUE_OR_RETURN( convertForceUseForcedConfigToAidl( xsdcCriterionValue)); return AudioPolicyForceUse::make(deviceCategory); } if (!fasticmp(xsdcCriterionName.c_str(), kXsdcForceConfigForMedia, strlen(kXsdcForceConfigForMedia))) { const auto deviceCategory = VALUE_OR_RETURN( convertForceUseForcedConfigToAidl( xsdcCriterionValue)); return AudioPolicyForceUse::make(deviceCategory); } if (!fasticmp(xsdcCriterionName.c_str(), kXsdcForceConfigForRecord, strlen(kXsdcForceConfigForRecord))) { const auto deviceCategory = VALUE_OR_RETURN( convertForceUseForcedConfigToAidl( xsdcCriterionValue)); return AudioPolicyForceUse::make(deviceCategory); } if (!fasticmp(xsdcCriterionName.c_str(), kXsdcForceConfigForDock, strlen(kXsdcForceConfigForDock))) { const auto dockType = VALUE_OR_RETURN(convertForceUseForcedConfigToAidl( xsdcCriterionValue)); return AudioPolicyForceUse::make(dockType); } if (!fasticmp(xsdcCriterionName.c_str(), kXsdcForceConfigForSystem, strlen(kXsdcForceConfigForSystem))) { return AudioPolicyForceUse::make(xsdcCriterionValue == "SYSTEM_ENFORCED"); } if (!fasticmp(xsdcCriterionName.c_str(), kXsdcForceConfigForHdmiSystemAudio, strlen(kXsdcForceConfigForHdmiSystemAudio))) { return AudioPolicyForceUse::make( xsdcCriterionValue == "HDMI_SYSTEM_AUDIO_ENFORCED"); } if (!fasticmp(xsdcCriterionName.c_str(), kXsdcForceConfigForEncodedSurround, strlen(kXsdcForceConfigForEncodedSurround))) { const auto encodedSurround = VALUE_OR_RETURN( convertForceUseForcedConfigToAidl( xsdcCriterionValue)); return AudioPolicyForceUse::make(encodedSurround); } if (!fasticmp(xsdcCriterionName.c_str(), kXsdcForceConfigForVibrateRinging, strlen(kXsdcForceConfigForVibrateRinging))) { const auto deviceCategory = VALUE_OR_RETURN( convertForceUseForcedConfigToAidl( xsdcCriterionValue)); return AudioPolicyForceUse::make(deviceCategory); } LOG(ERROR) << __func__ << " unrecognized force use " << xsdcCriterionName; return unexpected(BAD_VALUE); } ConversionResult convertCapCriterionV2ToAidl( const eng_xsd::CriterionType& xsdcCriterion, const std::vector& xsdcCriterionTypesVec) { eng_xsd::CriterionTypeType xsdcCriterionType = VALUE_OR_RETURN(getCriterionTypeByName(xsdcCriterion.getType(), xsdcCriterionTypesVec)); std::string defaultLiteralValue = xsdcCriterion.has_default() ? xsdcCriterion.get_default() : ""; using Tag = AudioHalCapCriterionV2::Tag; if (iequals(xsdcCriterion.getName(), toString(Tag::availableInputDevices))) { return AudioHalCapCriterionV2::make( VALUE_OR_RETURN(convertDevicesToAidl(xsdcCriterionType))); } if (iequals(xsdcCriterion.getName(), toString(Tag::availableOutputDevices))) { return AudioHalCapCriterionV2::make( VALUE_OR_RETURN(convertDevicesToAidl(xsdcCriterionType))); } if (iequals(xsdcCriterion.getName(), toString(Tag::availableInputDevicesAddresses))) { return AudioHalCapCriterionV2::make( VALUE_OR_RETURN(convertDeviceAddressesToAidl(xsdcCriterionType))); } if (iequals(xsdcCriterion.getName(), toString(Tag::availableOutputDevicesAddresses))) { return AudioHalCapCriterionV2::make( VALUE_OR_RETURN(convertDeviceAddressesToAidl(xsdcCriterionType))); } if (iequals(xsdcCriterion.getName(), toString(Tag::telephonyMode))) { return AudioHalCapCriterionV2::make( VALUE_OR_RETURN(convertTelephonyModesToAidl(xsdcCriterionType))); } if (!fastcmp(xsdcCriterion.getName().c_str(), kXsdcForceConfigForUse, strlen(kXsdcForceConfigForUse))) { return AudioHalCapCriterionV2::make(VALUE_OR_RETURN( convertForceUseConfigsToAidl(xsdcCriterion.getName(), xsdcCriterionType))); } LOG(ERROR) << __func__ << " unrecognized criterion " << xsdcCriterion.getName(); return unexpected(BAD_VALUE); } ConversionResult convertCapCriterionToAidl( const eng_xsd::CriterionType& xsdcCriterion) { AudioHalCapCriterion aidlCapCriterion; aidlCapCriterion.name = xsdcCriterion.getName(); aidlCapCriterion.criterionTypeName = xsdcCriterion.getType(); aidlCapCriterion.defaultLiteralValue = xsdcCriterion.has_default() ? xsdcCriterion.get_default() : ""; return aidlCapCriterion; } ConversionResult convertCurvePointToAidl( const std::string& xsdcCurvePoint) { AudioHalVolumeCurve::CurvePoint aidlCurvePoint{}; if ((sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index, &aidlCurvePoint.attenuationMb) != 2) || (aidlCurvePoint.index < AudioHalVolumeCurve::CurvePoint::MIN_INDEX) || (aidlCurvePoint.index > AudioHalVolumeCurve::CurvePoint::MAX_INDEX)) { LOG(ERROR) << __func__ << " Review Audio Policy config: volume curve point:" << "\"" << xsdcCurvePoint << "\" is invalid"; return unexpected(BAD_VALUE); } return aidlCurvePoint; } } // namespace aidl::android::hardware::audio::core::internal