0f4d68964c
Bug: 262594867 Merged-In: Idf2546030d6ea6cd43acab8f93e3b479aae6a9db Change-Id: Idf2546030d6ea6cd43acab8f93e3b479aae6a9db Test: m android.hardware.audio.service-aidl.example
305 lines
No EOL
14 KiB
C++
305 lines
No EOL
14 KiB
C++
/*
|
|
* 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 <fcntl.h>
|
|
#include <inttypes.h>
|
|
#include <unistd.h>
|
|
#include <functional>
|
|
#include <unordered_map>
|
|
|
|
#include <aidl/android/media/audio/common/AudioFlag.h>
|
|
#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
|
|
#include <aidl/android/media/audio/common/AudioProductStrategyType.h>
|
|
|
|
#include "core-impl/EngineConfigXmlConverter.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;
|
|
|
|
namespace xsd = android::audio::policy::engine::configuration;
|
|
|
|
namespace aidl::android::hardware::audio::core::internal {
|
|
|
|
/**
|
|
* Valid curve points take the form "<index>,<attenuationMb>", where the index
|
|
* must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
|
|
* that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
|
|
* '.' instead of a ',' in their XML)-- using such a curve point will result in
|
|
* failed VTS tests.
|
|
*/
|
|
static const int8_t kInvalidCurvePointIndex = -1;
|
|
|
|
void EngineConfigXmlConverter::initProductStrategyMap() {
|
|
#define STRATEGY_ENTRY(name) {"STRATEGY_" #name, static_cast<int>(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
|
|
}
|
|
|
|
int 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()));
|
|
}
|
|
|
|
AudioAttributes EngineConfigXmlConverter::convertAudioAttributesToAidl(
|
|
const xsd::AttributesType& xsdcAudioAttributes) {
|
|
if (xsdcAudioAttributes.hasAttributesRef()) {
|
|
if (mAttributesReferenceMap.empty()) {
|
|
mAttributesReferenceMap =
|
|
generateReferenceMap<xsd::AttributesRef, xsd::AttributesRefType>(
|
|
getXsdcConfig()->getAttributesRef());
|
|
}
|
|
return convertAudioAttributesToAidl(
|
|
*(mAttributesReferenceMap.at(xsdcAudioAttributes.getAttributesRef())
|
|
.getFirstAttributes()));
|
|
}
|
|
AudioAttributes aidlAudioAttributes;
|
|
if (xsdcAudioAttributes.hasContentType()) {
|
|
aidlAudioAttributes.contentType = static_cast<AudioContentType>(
|
|
xsdcAudioAttributes.getFirstContentType()->getValue());
|
|
}
|
|
if (xsdcAudioAttributes.hasUsage()) {
|
|
aidlAudioAttributes.usage =
|
|
static_cast<AudioUsage>(xsdcAudioAttributes.getFirstUsage()->getValue());
|
|
}
|
|
if (xsdcAudioAttributes.hasSource()) {
|
|
aidlAudioAttributes.source =
|
|
static_cast<AudioSource>(xsdcAudioAttributes.getFirstSource()->getValue());
|
|
}
|
|
if (xsdcAudioAttributes.hasFlags()) {
|
|
std::vector<xsd::FlagType> xsdcFlagTypeVec =
|
|
xsdcAudioAttributes.getFirstFlags()->getValue();
|
|
for (const xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
|
|
if (xsdcFlagType != xsd::FlagType::AUDIO_FLAG_NONE) {
|
|
aidlAudioAttributes.flags |= 1 << (static_cast<int>(xsdcFlagType) - 1);
|
|
}
|
|
}
|
|
}
|
|
if (xsdcAudioAttributes.hasBundle()) {
|
|
const xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
|
|
aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue();
|
|
}
|
|
if (isDefaultAudioAttributes(aidlAudioAttributes)) {
|
|
mDefaultProductStrategyId = std::optional<int>{-1};
|
|
}
|
|
return aidlAudioAttributes;
|
|
}
|
|
|
|
AudioHalAttributesGroup EngineConfigXmlConverter::convertAttributesGroupToAidl(
|
|
const xsd::AttributesGroup& xsdcAttributesGroup) {
|
|
AudioHalAttributesGroup aidlAttributesGroup;
|
|
static const int kStreamTypeEnumOffset =
|
|
static_cast<int>(xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
|
|
static_cast<int>(AudioStreamType::VOICE_CALL);
|
|
aidlAttributesGroup.streamType = static_cast<AudioStreamType>(
|
|
static_cast<int>(xsdcAttributesGroup.getStreamType()) - kStreamTypeEnumOffset);
|
|
aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup();
|
|
if (xsdcAttributesGroup.hasAttributes_optional()) {
|
|
aidlAttributesGroup.attributes =
|
|
convertCollectionToAidl<xsd::AttributesType, AudioAttributes>(
|
|
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(convertAudioAttributesToAidl(xsd::AttributesType(
|
|
xsdcAttributesGroup.getContentType_optional(),
|
|
xsdcAttributesGroup.getUsage_optional(), xsdcAttributesGroup.getSource_optional(),
|
|
xsdcAttributesGroup.getFlags_optional(), xsdcAttributesGroup.getBundle_optional(),
|
|
std::nullopt)));
|
|
|
|
} else {
|
|
// do nothing;
|
|
// TODO: check if this is valid or if we should treat as an error.
|
|
// Currently, attributes are not mandatory in schema, but an AttributesGroup
|
|
// without attributes does not make much sense.
|
|
}
|
|
return aidlAttributesGroup;
|
|
}
|
|
|
|
AudioHalProductStrategy EngineConfigXmlConverter::convertProductStrategyToAidl(
|
|
const xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
|
|
AudioHalProductStrategy aidlProductStrategy;
|
|
|
|
aidlProductStrategy.id = convertProductStrategyNameToAidl(xsdcProductStrategy.getName());
|
|
|
|
if (xsdcProductStrategy.hasAttributesGroup()) {
|
|
aidlProductStrategy.attributesGroups =
|
|
convertCollectionToAidl<xsd::AttributesGroup, AudioHalAttributesGroup>(
|
|
xsdcProductStrategy.getAttributesGroup(),
|
|
std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this,
|
|
std::placeholders::_1));
|
|
}
|
|
if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) {
|
|
mDefaultProductStrategyId = aidlProductStrategy.id;
|
|
}
|
|
return aidlProductStrategy;
|
|
}
|
|
|
|
AudioHalVolumeCurve::CurvePoint EngineConfigXmlConverter::convertCurvePointToAidl(
|
|
const std::string& xsdcCurvePoint) {
|
|
AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
|
|
if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
|
|
&aidlCurvePoint.attenuationMb) != 2) {
|
|
aidlCurvePoint.index = kInvalidCurvePointIndex;
|
|
}
|
|
return aidlCurvePoint;
|
|
}
|
|
|
|
AudioHalVolumeCurve EngineConfigXmlConverter::convertVolumeCurveToAidl(
|
|
const xsd::Volume& xsdcVolumeCurve) {
|
|
AudioHalVolumeCurve aidlVolumeCurve;
|
|
aidlVolumeCurve.deviceCategory =
|
|
static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
|
|
if (xsdcVolumeCurve.hasRef()) {
|
|
if (mVolumesReferenceMap.empty()) {
|
|
mVolumesReferenceMap = generateReferenceMap<xsd::VolumesType, xsd::VolumeRef>(
|
|
getXsdcConfig()->getVolumes());
|
|
}
|
|
aidlVolumeCurve.curvePoints =
|
|
convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
|
|
mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
|
|
std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
|
|
std::placeholders::_1));
|
|
} else {
|
|
aidlVolumeCurve.curvePoints =
|
|
convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
|
|
xsdcVolumeCurve.getPoint(),
|
|
std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
|
|
std::placeholders::_1));
|
|
}
|
|
return aidlVolumeCurve;
|
|
}
|
|
|
|
AudioHalVolumeGroup EngineConfigXmlConverter::convertVolumeGroupToAidl(
|
|
const xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
|
|
AudioHalVolumeGroup aidlVolumeGroup;
|
|
aidlVolumeGroup.name = xsdcVolumeGroup.getName();
|
|
aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin();
|
|
aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax();
|
|
aidlVolumeGroup.volumeCurves = convertCollectionToAidl<xsd::Volume, AudioHalVolumeCurve>(
|
|
xsdcVolumeGroup.getVolume(),
|
|
std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this,
|
|
std::placeholders::_1));
|
|
return aidlVolumeGroup;
|
|
}
|
|
|
|
AudioHalCapCriterion EngineConfigXmlConverter::convertCapCriterionToAidl(
|
|
const xsd::CriterionType& xsdcCriterion) {
|
|
AudioHalCapCriterion aidlCapCriterion;
|
|
aidlCapCriterion.name = xsdcCriterion.getName();
|
|
aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
|
|
aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
|
|
return aidlCapCriterion;
|
|
}
|
|
|
|
std::string EngineConfigXmlConverter::convertCriterionTypeValueToAidl(
|
|
const xsd::ValueType& xsdcCriterionTypeValue) {
|
|
return xsdcCriterionTypeValue.getLiteral();
|
|
}
|
|
|
|
AudioHalCapCriterionType EngineConfigXmlConverter::convertCapCriterionTypeToAidl(
|
|
const xsd::CriterionTypeType& xsdcCriterionType) {
|
|
AudioHalCapCriterionType aidlCapCriterionType;
|
|
aidlCapCriterionType.name = xsdcCriterionType.getName();
|
|
aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
|
|
aidlCapCriterionType.values =
|
|
convertWrappedCollectionToAidl<xsd::ValuesType, xsd::ValueType, std::string>(
|
|
xsdcCriterionType.getValues(), &xsd::ValuesType::getValue,
|
|
std::bind(&EngineConfigXmlConverter::convertCriterionTypeValueToAidl, this,
|
|
std::placeholders::_1));
|
|
return aidlCapCriterionType;
|
|
}
|
|
|
|
AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() {
|
|
return mAidlEngineConfig;
|
|
}
|
|
|
|
void EngineConfigXmlConverter::init() {
|
|
initProductStrategyMap();
|
|
if (getXsdcConfig()->hasProductStrategies()) {
|
|
mAidlEngineConfig.productStrategies =
|
|
convertWrappedCollectionToAidl<xsd::ProductStrategies,
|
|
xsd::ProductStrategies::ProductStrategy,
|
|
AudioHalProductStrategy>(
|
|
getXsdcConfig()->getProductStrategies(),
|
|
&xsd::ProductStrategies::getProductStrategy,
|
|
std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this,
|
|
std::placeholders::_1));
|
|
if (mDefaultProductStrategyId) {
|
|
mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value();
|
|
}
|
|
}
|
|
if (getXsdcConfig()->hasVolumeGroups()) {
|
|
mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidl<
|
|
xsd::VolumeGroupsType, xsd::VolumeGroupsType::VolumeGroup, AudioHalVolumeGroup>(
|
|
getXsdcConfig()->getVolumeGroups(), &xsd::VolumeGroupsType::getVolumeGroup,
|
|
std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
|
|
std::placeholders::_1));
|
|
}
|
|
if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
|
|
AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
|
|
capSpecificConfig.criteria =
|
|
convertWrappedCollectionToAidl<xsd::CriteriaType, xsd::CriterionType,
|
|
AudioHalCapCriterion>(
|
|
getXsdcConfig()->getCriteria(), &xsd::CriteriaType::getCriterion,
|
|
std::bind(&EngineConfigXmlConverter::convertCapCriterionToAidl, this,
|
|
std::placeholders::_1));
|
|
capSpecificConfig.criterionTypes =
|
|
convertWrappedCollectionToAidl<xsd::CriterionTypesType, xsd::CriterionTypeType,
|
|
AudioHalCapCriterionType>(
|
|
getXsdcConfig()->getCriterion_types(),
|
|
&xsd::CriterionTypesType::getCriterion_type,
|
|
std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this,
|
|
std::placeholders::_1));
|
|
mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
|
|
}
|
|
}
|
|
} // namespace aidl::android::hardware::audio::core::internal
|