/* * Copyright (C) 2022 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 #include #include #include #define LOG_TAG "AHAL_Config" #include #include #include #include #include "core-impl/EngineConfigXmlConverter.h" #include "core-impl/XsdcConversion.h" using aidl::android::media::audio::common::AudioAttributes; using aidl::android::media::audio::common::AudioContentType; using aidl::android::media::audio::common::AudioFlag; using aidl::android::media::audio::common::AudioHalAttributesGroup; using aidl::android::media::audio::common::AudioHalCapCriterion; using aidl::android::media::audio::common::AudioHalCapCriterionType; using aidl::android::media::audio::common::AudioHalEngineConfig; using aidl::android::media::audio::common::AudioHalProductStrategy; using aidl::android::media::audio::common::AudioHalVolumeCurve; using aidl::android::media::audio::common::AudioHalVolumeGroup; using aidl::android::media::audio::common::AudioProductStrategyType; 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; namespace eng_xsd = android::audio::policy::engine::configuration; namespace aidl::android::hardware::audio::core::internal { void EngineConfigXmlConverter::initProductStrategyMap() { #define STRATEGY_ENTRY(name) {"STRATEGY_" #name, static_cast(AudioProductStrategyType::name)} mProductStrategyMap = {STRATEGY_ENTRY(MEDIA), STRATEGY_ENTRY(PHONE), STRATEGY_ENTRY(SONIFICATION), STRATEGY_ENTRY(SONIFICATION_RESPECTFUL), STRATEGY_ENTRY(DTMF), STRATEGY_ENTRY(ENFORCED_AUDIBLE), STRATEGY_ENTRY(TRANSMITTED_THROUGH_SPEAKER), STRATEGY_ENTRY(ACCESSIBILITY)}; #undef STRATEGY_ENTRY } ConversionResult EngineConfigXmlConverter::convertProductStrategyNameToAidl( const std::string& xsdcProductStrategyName) { const auto [it, success] = mProductStrategyMap.insert( std::make_pair(xsdcProductStrategyName, mNextVendorStrategy)); if (success) { mNextVendorStrategy++; } return it->second; } bool isDefaultAudioAttributes(const AudioAttributes& attributes) { return ((attributes.contentType == AudioContentType::UNKNOWN) && (attributes.usage == AudioUsage::UNKNOWN) && (attributes.source == AudioSource::DEFAULT) && (attributes.flags == 0) && (attributes.tags.empty())); } ConversionResult EngineConfigXmlConverter::convertAudioAttributesToAidl( const eng_xsd::AttributesType& xsdcAudioAttributes) { if (xsdcAudioAttributes.hasAttributesRef()) { if (mAttributesReferenceMap.empty()) { mAttributesReferenceMap = generateReferenceMap( getXsdcConfig()->getAttributesRef()); } return convertAudioAttributesToAidl( *(mAttributesReferenceMap.at(xsdcAudioAttributes.getAttributesRef()) .getFirstAttributes())); } AudioAttributes aidlAudioAttributes; if (xsdcAudioAttributes.hasContentType()) { aidlAudioAttributes.contentType = static_cast( xsdcAudioAttributes.getFirstContentType()->getValue()); } if (xsdcAudioAttributes.hasUsage()) { aidlAudioAttributes.usage = static_cast(xsdcAudioAttributes.getFirstUsage()->getValue()); } if (xsdcAudioAttributes.hasSource()) { aidlAudioAttributes.source = static_cast(xsdcAudioAttributes.getFirstSource()->getValue()); } if (xsdcAudioAttributes.hasFlags()) { std::vector xsdcFlagTypeVec = xsdcAudioAttributes.getFirstFlags()->getValue(); for (const eng_xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) { if (xsdcFlagType != eng_xsd::FlagType::AUDIO_FLAG_NONE) { aidlAudioAttributes.flags |= 1 << (static_cast(xsdcFlagType) - 1); } } } if (xsdcAudioAttributes.hasBundle()) { const eng_xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle(); aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue(); } if (isDefaultAudioAttributes(aidlAudioAttributes)) { mDefaultProductStrategyId = std::optional{-1}; } return aidlAudioAttributes; } ConversionResult EngineConfigXmlConverter::convertAttributesGroupToAidl( const eng_xsd::AttributesGroup& xsdcAttributesGroup) { AudioHalAttributesGroup aidlAttributesGroup; static const int kStreamTypeEnumOffset = static_cast(eng_xsd::Stream::AUDIO_STREAM_VOICE_CALL) - static_cast(AudioStreamType::VOICE_CALL); aidlAttributesGroup.streamType = static_cast( static_cast(xsdcAttributesGroup.getStreamType()) - kStreamTypeEnumOffset); aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup(); if (xsdcAttributesGroup.hasAttributes_optional()) { aidlAttributesGroup.attributes = VALUE_OR_FATAL((convertCollectionToAidl( xsdcAttributesGroup.getAttributes_optional(), std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this, std::placeholders::_1)))); } else if (xsdcAttributesGroup.hasContentType_optional() || xsdcAttributesGroup.hasUsage_optional() || xsdcAttributesGroup.hasSource_optional() || xsdcAttributesGroup.hasFlags_optional() || xsdcAttributesGroup.hasBundle_optional()) { aidlAttributesGroup.attributes.push_back(VALUE_OR_FATAL(convertAudioAttributesToAidl( eng_xsd::AttributesType(xsdcAttributesGroup.getContentType_optional(), xsdcAttributesGroup.getUsage_optional(), xsdcAttributesGroup.getSource_optional(), xsdcAttributesGroup.getFlags_optional(), xsdcAttributesGroup.getBundle_optional(), std::nullopt)))); } else { LOG(ERROR) << __func__ << " Review Audio Policy config: no audio attributes provided for " << aidlAttributesGroup.toString(); return unexpected(BAD_VALUE); } return aidlAttributesGroup; } ConversionResult EngineConfigXmlConverter::convertProductStrategyToAidl( const eng_xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) { AudioHalProductStrategy aidlProductStrategy; aidlProductStrategy.id = VALUE_OR_FATAL(convertProductStrategyNameToAidl(xsdcProductStrategy.getName())); if (xsdcProductStrategy.hasAttributesGroup()) { aidlProductStrategy.attributesGroups = VALUE_OR_FATAL( (convertCollectionToAidl( xsdcProductStrategy.getAttributesGroup(), std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this, std::placeholders::_1)))); } if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) { mDefaultProductStrategyId = aidlProductStrategy.id; } return aidlProductStrategy; } ConversionResult EngineConfigXmlConverter::convertVolumeCurveToAidl( const eng_xsd::Volume& xsdcVolumeCurve) { AudioHalVolumeCurve aidlVolumeCurve; aidlVolumeCurve.deviceCategory = static_cast(xsdcVolumeCurve.getDeviceCategory()); if (xsdcVolumeCurve.hasRef()) { if (mVolumesReferenceMap.empty()) { mVolumesReferenceMap = generateReferenceMap( getXsdcConfig()->getVolumes()); } aidlVolumeCurve.curvePoints = VALUE_OR_FATAL( (convertCollectionToAidl( mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(), &convertCurvePointToAidl))); } else { aidlVolumeCurve.curvePoints = VALUE_OR_FATAL( (convertCollectionToAidl( xsdcVolumeCurve.getPoint(), &convertCurvePointToAidl))); } return aidlVolumeCurve; } ConversionResult EngineConfigXmlConverter::convertVolumeGroupToAidl( const eng_xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) { AudioHalVolumeGroup aidlVolumeGroup; aidlVolumeGroup.name = xsdcVolumeGroup.getName(); aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin(); aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax(); aidlVolumeGroup.volumeCurves = VALUE_OR_FATAL((convertCollectionToAidl( xsdcVolumeGroup.getVolume(), std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this, std::placeholders::_1)))); return aidlVolumeGroup; } AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() { return mAidlEngineConfig; } void EngineConfigXmlConverter::init() { initProductStrategyMap(); if (getXsdcConfig()->hasProductStrategies()) { mAidlEngineConfig.productStrategies = VALUE_OR_FATAL( (convertWrappedCollectionToAidl( getXsdcConfig()->getProductStrategies(), &eng_xsd::ProductStrategies::getProductStrategy, std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this, std::placeholders::_1)))); if (mDefaultProductStrategyId) { mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value(); } } if (getXsdcConfig()->hasVolumeGroups()) { mAidlEngineConfig.volumeGroups = VALUE_OR_FATAL( (convertWrappedCollectionToAidl( getXsdcConfig()->getVolumeGroups(), &eng_xsd::VolumeGroupsType::getVolumeGroup, std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this, std::placeholders::_1)))); } if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) { AudioHalEngineConfig::CapSpecificConfig capSpecificConfig; capSpecificConfig.criteria = VALUE_OR_FATAL( (convertWrappedCollectionToAidl( getXsdcConfig()->getCriteria(), &eng_xsd::CriteriaType::getCriterion, &convertCapCriterionToAidl))); capSpecificConfig.criterionTypes = VALUE_OR_FATAL((convertWrappedCollectionToAidl( getXsdcConfig()->getCriterion_types(), &eng_xsd::CriterionTypesType::getCriterion_type, &convertCapCriterionTypeToAidl))); } } } // namespace aidl::android::hardware::audio::core::internal