DynamicsProcessing: Add AIDL placeholder implementation and its unit test
Update audio_effects_config.xml to use libeffect dynamicsProcessing
implementation.
Bug: 258124419
Test: atest VtsHalDynamicsProcessingTargetTest
Test: atest VtsHalAudioEffectTargetTest
Change-Id: If93d084be383b716ff950faf1c3e23d6c1edaa66
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index a166e61..486c13d 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -13,6 +13,9 @@
"name": "VtsHalDownmixTargetTest"
},
{
+ "name": "VtsHalDynamicProcessingTargetTest"
+ },
+ {
"name": "VtsHalEnvironmentalReverbTargetTest"
},
{
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 6f23636..1e6785f 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -156,7 +156,7 @@
"libbassboostsw",
"libbundleaidl",
"libdownmixaidl",
- "libdynamicsprocessingsw",
+ "libdynamicsprocessingaidl",
"libenvreverbsw",
"libequalizersw",
"libhapticgeneratoraidl",
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
index 7f06013..40b46e0 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -54,7 +54,6 @@
return EX_ILLEGAL_ARGUMENT;
}
*_aidl_return = AcousticEchoCancelerSw::kDescriptor;
- LOG(ERROR) << __func__ << "xxx " << _aidl_return->toString();
return EX_NONE;
}
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 9670e9c..e460f89 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -33,7 +33,7 @@
<library name="bassboostsw" path="libbassboostsw.so"/>
<library name="bundle" path="libbundleaidl.so"/>
<library name="downmix" path="libdownmixaidl.so"/>
- <library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
+ <library name="dynamics_processing" path="libdynamicsprocessingaidl.so"/>
<library name="equalizersw" path="libequalizersw.so"/>
<library name="haptic_generator" path="libhapticgeneratoraidl.so"/>
<library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
@@ -72,7 +72,7 @@
<libsw library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
</effectProxy>
<effect name="downmix" library="downmix" uuid="93f04452-e4fe-41cc-91f9-e475b6d1d69f"/>
- <effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="dynamics_processing" library="dynamics_processing" uuid="e0e6539b-1781-7261-676f-6d7573696340"/>
<effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
<effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
<effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index 39345a9..0ffbaa1 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "AHAL_DynamicsProcessingSw"
#include <Utils.h>
#include <algorithm>
+#include <set>
#include <unordered_set>
#include <android-base/logging.h>
@@ -60,7 +61,8 @@
namespace aidl::android::hardware::audio::effect {
const std::string DynamicsProcessingSw::kEffectName = "DynamicsProcessingSw";
-const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability;
+const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability = {.minCutOffFreq = 220,
+ .maxCutOffFreq = 20000};
const Descriptor DynamicsProcessingSw::kDescriptor = {
.common = {.id = {.type = kDynamicsProcessingTypeUUID,
.uuid = kDynamicsProcessingSwImplUUID,
@@ -83,16 +85,143 @@
RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ LOG(INFO) << __func__ << specific.toString();
+ auto& dpParam = specific.get<Parameter::Specific::dynamicsProcessing>();
+ auto tag = dpParam.getTag();
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ RETURN_IF(mContext->setEngineArchitecture(
+ dpParam.get<DynamicsProcessing::engineArchitecture>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEq: {
+ RETURN_IF(mContext->setPreEqChannelCfgs(dpParam.get<DynamicsProcessing::preEq>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPreEqChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEq: {
+ RETURN_IF(mContext->setPostEqChannelCfgs(dpParam.get<DynamicsProcessing::postEq>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPostEqChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbc: {
+ RETURN_IF(mContext->setMbcChannelCfgs(dpParam.get<DynamicsProcessing::mbc>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMbcChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEqBand: {
+ RETURN_IF(mContext->setPreEqBandCfgs(dpParam.get<DynamicsProcessing::preEqBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPreEqBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEqBand: {
+ RETURN_IF(mContext->setPostEqBandCfgs(dpParam.get<DynamicsProcessing::postEqBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPostEqBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbcBand: {
+ RETURN_IF(mContext->setMbcBandCfgs(dpParam.get<DynamicsProcessing::mbcBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMbcBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::limiter: {
+ RETURN_IF(mContext->setLimiterCfgs(dpParam.get<DynamicsProcessing::limiter>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "limiterCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::inputGain: {
+ RETURN_IF(mContext->setInputGainCfgs(dpParam.get<DynamicsProcessing::inputGain>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "inputGainCfgFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::vendorExtension: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus DynamicsProcessingSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::dynamicsProcessing>(mSpecificParam);
+ auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
+ auto dpIdTag = dpId.getTag();
+ switch (dpIdTag) {
+ case DynamicsProcessing::Id::commonTag:
+ return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
+ specific);
+ case DynamicsProcessing::Id::vendorExtensionTag:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(dpIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus DynamicsProcessingSw::getParameterDynamicsProcessing(
+ const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ DynamicsProcessing dpParam;
+ switch (tag) {
+ case DynamicsProcessing::Tag::engineArchitecture: {
+ dpParam.set<DynamicsProcessing::engineArchitecture>(mContext->getEngineArchitecture());
+ break;
+ }
+ case DynamicsProcessing::Tag::preEq: {
+ dpParam.set<DynamicsProcessing::preEq>(mContext->getPreEqChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::postEq: {
+ dpParam.set<DynamicsProcessing::postEq>(mContext->getPostEqChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::mbc: {
+ dpParam.set<DynamicsProcessing::mbc>(mContext->getMbcChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::preEqBand: {
+ dpParam.set<DynamicsProcessing::preEqBand>(mContext->getPreEqBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::postEqBand: {
+ dpParam.set<DynamicsProcessing::postEqBand>(mContext->getPostEqBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::mbcBand: {
+ dpParam.set<DynamicsProcessing::mbcBand>(mContext->getMbcBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::limiter: {
+ dpParam.set<DynamicsProcessing::limiter>(mContext->getLimiterCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::inputGain: {
+ dpParam.set<DynamicsProcessing::inputGain>(mContext->getInputGainCfgs());
+ break;
+ }
+ case DynamicsProcessing::vendorExtension: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::dynamicsProcessing>(dpParam);
+ LOG(INFO) << __func__ << specific->toString();
return ndk::ScopedAStatus::ok();
}
@@ -127,4 +256,252 @@
return {STATUS_OK, samples, samples};
}
+RetCode DynamicsProcessingSwContext::setCommon(const Parameter::Common& common) {
+ mCommon = common;
+ mChannelCount =
+ ::android::hardware::audio::common::getChannelCount(common.input.base.channelMask);
+ resizeChannels();
+ resizeBands();
+ LOG(INFO) << __func__ << mCommon.toString();
+ return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingSwContext::setEngineArchitecture(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ RETURN_VALUE_IF(!validateEngineConfig(cfg), RetCode::ERROR_ILLEGAL_PARAMETER,
+ "illegalEngineConfig");
+
+ if (mEngineSettings == cfg) {
+ LOG(INFO) << __func__ << " not change in engine, do nothing";
+ return RetCode::SUCCESS;
+ }
+ mEngineSettings = cfg;
+ resizeBands();
+ return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingSwContext::setChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage) {
+ RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "stageNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::unordered_set<int> channelSet;
+ for (auto& cfg : cfgs) {
+ if (cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount) {
+ LOG(ERROR) << __func__ << " skip illegal channel config " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ if (0 != channelSet.count(cfg.channel)) {
+ LOG(WARNING) << __func__ << " duplicated channel " << cfg.channel;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ channelSet.insert(cfg.channel);
+ }
+ targetCfgs[cfg.channel] = cfg;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setPreEqChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mPreEqChCfgs, mEngineSettings.preEqStage);
+}
+
+RetCode DynamicsProcessingSwContext::setPostEqChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mPostEqChCfgs, mEngineSettings.postEqStage);
+}
+
+RetCode DynamicsProcessingSwContext::setMbcChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mMbcChCfgs, mEngineSettings.mbcStage);
+}
+
+RetCode DynamicsProcessingSwContext::setEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "eqStageNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+ for (auto& cfg : cfgs) {
+ if (0 != bandSet.count({cfg.channel, cfg.band})) {
+ LOG(WARNING) << __func__ << " duplicated band " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ if (!validateEqBandConfig(cfg, mChannelCount, stage.bandCount, channelConfig)) {
+ LOG(WARNING) << __func__ << " skip invalid band " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ ;
+ }
+ targetCfgs[cfg.channel * stage.bandCount + cfg.band] = cfg;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setPreEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ return setEqBandCfgs(cfgs, mPreEqChBands, mEngineSettings.preEqStage, mPreEqChCfgs);
+}
+
+RetCode DynamicsProcessingSwContext::setPostEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ return setEqBandCfgs(cfgs, mPostEqChBands, mEngineSettings.postEqStage, mPostEqChCfgs);
+}
+
+RetCode DynamicsProcessingSwContext::setMbcBandCfgs(
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
+ RETURN_VALUE_IF(!mEngineSettings.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "mbcNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+ int bandCount = mEngineSettings.mbcStage.bandCount;
+ std::vector<bool> filled(mChannelCount * bandCount, false);
+ for (auto& it : cfgs) {
+ if (0 != bandSet.count({it.channel, it.band})) {
+ LOG(WARNING) << __func__ << " duplicated band " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ bandSet.insert({it.channel, it.band});
+ }
+ if (!validateMbcBandConfig(it, mChannelCount, mEngineSettings.mbcStage.bandCount,
+ mMbcChCfgs)) {
+ LOG(WARNING) << __func__ << " skip invalid band " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ ;
+ }
+ mMbcChBands[it.channel * bandCount + it.band] = it;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setLimiterCfgs(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
+ RETURN_VALUE_IF(!mEngineSettings.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "limiterNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::unordered_set<int> channelSet;
+
+ for (auto& it : cfgs) {
+ if (0 != channelSet.count(it.channel)) {
+ LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ channelSet.insert(it.channel);
+ }
+ if (!validateLimiterConfig(it, mChannelCount)) {
+ LOG(WARNING) << __func__ << " skip invalid limiter " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ mLimiterCfgs[it.channel] = it;
+ }
+ return ret;
+}
+
+void DynamicsProcessingSwContext::resizeChannels() {
+ if (mPreEqChCfgs.size() != mChannelCount) {
+ mPreEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mPostEqChCfgs.size() != mChannelCount) {
+ mPostEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mMbcChCfgs.size() != mChannelCount) {
+ mMbcChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mLimiterCfgs.size() != mChannelCount) {
+ mLimiterCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mInputGainCfgs.size() != mChannelCount) {
+ mInputGainCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+}
+
+void DynamicsProcessingSwContext::resizeBands() {
+ if (mPreEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.preEqStage.bandCount)) {
+ mPreEqChBands.resize(mChannelCount * mEngineSettings.preEqStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+ if (mPostEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.postEqStage.bandCount)) {
+ mPostEqChBands.resize(mChannelCount * mEngineSettings.postEqStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+ if (mMbcChBands.size() != (size_t)(mChannelCount * mEngineSettings.mbcStage.bandCount)) {
+ mMbcChBands.resize(mChannelCount * mEngineSettings.mbcStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+}
+
+RetCode DynamicsProcessingSwContext::setInputGainCfgs(
+ const std::vector<DynamicsProcessing::InputGain>& cfgs) {
+ for (const auto& cfg : cfgs) {
+ RETURN_VALUE_IF(cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount,
+ RetCode::ERROR_ILLEGAL_PARAMETER, "invalidChannel");
+ mInputGainCfgs[cfg.channel] = cfg;
+ }
+ return RetCode::SUCCESS;
+}
+
+std::vector<DynamicsProcessing::InputGain> DynamicsProcessingSwContext::getInputGainCfgs() {
+ std::vector<DynamicsProcessing::InputGain> ret;
+ std::copy_if(mInputGainCfgs.begin(), mInputGainCfgs.end(), std::back_inserter(ret),
+ [&](const auto& gain) { return gain.channel != kInvalidChannelId; });
+ return ret;
+}
+
+bool DynamicsProcessingSwContext::validateCutoffFrequency(float freq) {
+ return freq >= DynamicsProcessingSw::kCapability.minCutOffFreq &&
+ freq <= DynamicsProcessingSw::kCapability.maxCutOffFreq;
+}
+
+bool DynamicsProcessingSwContext::validateStageEnablement(
+ const DynamicsProcessing::StageEnablement& enablement) {
+ return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingSwContext::validateEngineConfig(
+ const DynamicsProcessing::EngineArchitecture& engine) {
+ return engine.preferredProcessingDurationMs >= 0 &&
+ validateStageEnablement(engine.preEqStage) &&
+ validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
+}
+
+bool DynamicsProcessingSwContext::validateEqBandConfig(
+ const DynamicsProcessing::EqBandConfig& band, int maxChannel, int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ return band.channel >= 0 && band.channel < maxChannel &&
+ (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
+ band.band >= 0 && band.band < maxBand && validateCutoffFrequency(band.cutoffFrequencyHz);
+}
+
+bool DynamicsProcessingSwContext::validateMbcBandConfig(
+ const DynamicsProcessing::MbcBandConfig& band, int maxChannel, int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ return band.channel >= 0 && band.channel < maxChannel &&
+ (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
+ band.band >= 0 && band.band < maxBand &&
+ validateCutoffFrequency(band.cutoffFrequencyHz) && band.attackTimeMs >= 0 &&
+ band.releaseTimeMs >= 0 && band.ratio >= 0 && band.thresholdDb <= 0 &&
+ band.kneeWidthDb <= 0 && band.noiseGateThresholdDb <= 0 && band.expanderRatio >= 0;
+}
+
+bool DynamicsProcessingSwContext::validateLimiterConfig(
+ const DynamicsProcessing::LimiterConfig& limiter, int maxChannel) {
+ return limiter.channel >= 0 && limiter.channel < maxChannel && limiter.attackTimeMs >= 0 &&
+ limiter.releaseTimeMs >= 0 && limiter.ratio >= 0 && limiter.thresholdDb <= 0;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 2ae46c5..e336df7 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -29,11 +29,77 @@
class DynamicsProcessingSwContext final : public EffectContext {
public:
DynamicsProcessingSwContext(int statusDepth, const Parameter::Common& common)
- : EffectContext(statusDepth, common) {
+ : EffectContext(statusDepth, common),
+ mChannelCount(::android::hardware::audio::common::getChannelCount(
+ common.input.base.channelMask)),
+ mPreEqChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mPostEqChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mMbcChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mLimiterCfgs(mChannelCount, {.channel = kInvalidChannelId}) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
-};
+
+ // utils
+ RetCode setChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& engineSetting);
+
+ RetCode setEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+
+ // set params
+ RetCode setCommon(const Parameter::Common& common) override;
+ RetCode setEngineArchitecture(const DynamicsProcessing::EngineArchitecture& cfg);
+ RetCode setPreEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setPostEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setMbcChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setPreEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ RetCode setPostEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ RetCode setMbcBandCfgs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
+ RetCode setLimiterCfgs(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs);
+ RetCode setInputGainCfgs(const std::vector<DynamicsProcessing::InputGain>& cfgs);
+
+ // get params
+ DynamicsProcessing::EngineArchitecture getEngineArchitecture() { return mEngineSettings; }
+ std::vector<DynamicsProcessing::ChannelConfig> getPreEqChannelCfgs() { return mPreEqChCfgs; }
+ std::vector<DynamicsProcessing::ChannelConfig> getPostEqChannelCfgs() { return mPostEqChCfgs; }
+ std::vector<DynamicsProcessing::ChannelConfig> getMbcChannelCfgs() { return mMbcChCfgs; }
+ std::vector<DynamicsProcessing::EqBandConfig> getPreEqBandCfgs() { return mPreEqChBands; }
+ std::vector<DynamicsProcessing::EqBandConfig> getPostEqBandCfgs() { return mPostEqChBands; }
+ std::vector<DynamicsProcessing::MbcBandConfig> getMbcBandCfgs() { return mMbcChBands; }
+ std::vector<DynamicsProcessing::LimiterConfig> getLimiterCfgs() { return mLimiterCfgs; }
+ std::vector<DynamicsProcessing::InputGain> getInputGainCfgs();
+
+ private:
+ static constexpr int32_t kInvalidChannelId = -1;
+ size_t mChannelCount = 0;
+ DynamicsProcessing::EngineArchitecture mEngineSettings;
+ // Channel config vector with size of mChannelCount
+ std::vector<DynamicsProcessing::ChannelConfig> mPreEqChCfgs;
+ std::vector<DynamicsProcessing::ChannelConfig> mPostEqChCfgs;
+ std::vector<DynamicsProcessing::ChannelConfig> mMbcChCfgs;
+ std::vector<DynamicsProcessing::LimiterConfig> mLimiterCfgs;
+ std::vector<DynamicsProcessing::InputGain> mInputGainCfgs;
+ // Band config vector with size of mChannelCount * bandCount
+ std::vector<DynamicsProcessing::EqBandConfig> mPreEqChBands;
+ std::vector<DynamicsProcessing::EqBandConfig> mPostEqChBands;
+ std::vector<DynamicsProcessing::MbcBandConfig> mMbcChBands;
+
+ bool validateCutoffFrequency(float freq);
+ bool validateStageEnablement(const DynamicsProcessing::StageEnablement& enablement);
+ bool validateEngineConfig(const DynamicsProcessing::EngineArchitecture& engine);
+ bool validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band, int maxChannel,
+ int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+ bool validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band, int maxChannel,
+ int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+ bool validateLimiterConfig(const DynamicsProcessing::LimiterConfig& limiter, int maxChannel);
+ void resizeChannels();
+ void resizeBands();
+}; // DynamicsProcessingSwContext
class DynamicsProcessingSw final : public EffectImpl {
public:
@@ -60,7 +126,9 @@
private:
std::shared_ptr<DynamicsProcessingSwContext> mContext;
- /* parameters */
- DynamicsProcessing mSpecificParam;
-};
+ ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
+ Parameter::Specific* specific);
+
+}; // DynamicsProcessingSw
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 1f39db0..a3e7ff2 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -119,11 +119,11 @@
virtual RetCode setCommon(const Parameter::Common& common) {
mCommon = common;
- LOG(ERROR) << __func__ << mCommon.toString();
+ LOG(INFO) << __func__ << mCommon.toString();
return RetCode::SUCCESS;
}
virtual Parameter::Common getCommon() {
- LOG(ERROR) << __func__ << mCommon.toString();
+ LOG(INFO) << __func__ << mCommon.toString();
return mCommon;
}
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index 58c8672..b100a2e 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -98,12 +98,13 @@
} \
} while (0)
-#define RETURN_VALUE_IF(expr, ret, log) \
- do { \
- if (expr) { \
- LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr << (log); \
- return ret; \
- } \
+#define RETURN_VALUE_IF(expr, ret, log) \
+ do { \
+ if (expr) { \
+ LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr \"" << #expr \
+ << "\":" << (log); \
+ return ret; \
+ } \
} while (0)
#define RETURN_IF_BINDER_EXCEPTION(functor) \
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 6eec29e..1a60829 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -135,6 +135,12 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// e0e6539b-1781-7261-676f-6d7573696340
+static const AudioUuid kDynamicsProcessingImplUUID = {static_cast<int32_t>(0xe0e6539b),
+ 0x1781,
+ 0x7261,
+ 0x676f,
+ {0x6d, 0x75, 0x73, 0x69, 0x63, 0x40}};
// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
0xaecd,
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index becdf1b..f9d12dd 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -81,6 +81,12 @@
}
cc_test {
+ name: "VtsHalDynamicsProcessingTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalDynamicsProcessingTest.cpp"],
+}
+
+cc_test {
name: "VtsHalEnvironmentalReverbTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
new file mode 100644
index 0000000..9feff91
--- /dev/null
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) 2023 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 <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalDynamicsProcessingTest"
+
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <Utils.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DynamicsProcessing;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+class DynamicsProcessingTestHelper : public EffectHelper {
+ public:
+ DynamicsProcessingTestHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair,
+ int32_t channelLayOut = AudioChannelLayout::LAYOUT_STEREO) {
+ std::tie(mFactory, mDescriptor) = pair;
+ mChannelLayout = channelLayOut;
+ mChannelCount = ::android::hardware::audio::common::getChannelCount(
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
+ }
+
+ // setup
+ void SetUpDynamicsProcessingEffect() {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+ Parameter::Specific specific = getDefaultParamSpecific();
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ 0x100 /* iFrameCount */, 0x100 /* oFrameCount */,
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout),
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ mEngineConfigApplied = mEngineConfigPreset;
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ DynamicsProcessing dp = DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
+ mEngineConfigPreset);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(dp);
+ return specific;
+ }
+
+ // teardown
+ void TearDownDynamicsProcessingEffect() {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ // utils functions for parameter checking
+ bool isParamValid(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dp,
+ const Descriptor& desc);
+ bool isParamEqual(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dpRef,
+ const DynamicsProcessing& dpTest);
+
+ bool isEnablementValid(const DynamicsProcessing::StageEnablement& enablement);
+ bool isEngineConfigValid(const DynamicsProcessing::EngineArchitecture& cfg);
+
+ bool isCutoffFrequencyValid(float freq, const DynamicsProcessing::Capability& cap);
+ bool isChannelConfigValid(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ bool stageInUse);
+
+ bool isPreEqBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isPostEqBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isMbcBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isLimiterConfigValid(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs,
+ bool stageInUse);
+ bool isInputGainValid(const std::vector<DynamicsProcessing::InputGain>& cfgs);
+
+ bool isEngineConfigEqual(const DynamicsProcessing::EngineArchitecture& refCfg,
+ const DynamicsProcessing::EngineArchitecture& testCfg);
+
+ template <typename T>
+ std::vector<T> filterEnabledVector(const std::vector<T>& vec);
+
+ template <typename T>
+ bool isAidlVectorEqualAfterFilter(const std::vector<T>& source, const std::vector<T>& target);
+
+ template <typename T>
+ bool isAidlVectorEqual(const std::vector<T>& source, const std::vector<T>& target);
+
+ // get set params and validate
+ void SetAndGetDynamicsProcessingParameters();
+
+ // enqueue test parameters
+ void addEngineConfig(const DynamicsProcessing::EngineArchitecture& cfg);
+ void addPreEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addPostEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addMbcChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addPreEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ void addPostEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ void addMbcBandConfigs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
+ void addLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig>& cfg);
+ void addInputGain(const std::vector<DynamicsProcessing::InputGain>& inputGain);
+
+ static constexpr float kPreferredProcessingDurationMs = 10.0f;
+ static constexpr int kBandCount = 5;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+ DynamicsProcessing::EngineArchitecture mEngineConfigApplied;
+ DynamicsProcessing::EngineArchitecture mEngineConfigPreset{
+ .resolutionPreference =
+ DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
+ .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
+ .preEqStage = {.inUse = true, .bandCount = kBandCount},
+ .postEqStage = {.inUse = true, .bandCount = kBandCount},
+ .mbcStage = {.inUse = true, .bandCount = kBandCount},
+ .limiterInUse = true,
+ };
+
+ std::unordered_set<int /* channelId */> mPreEqChannelEnable;
+ std::unordered_set<int /* channelId */> mPostEqChannelEnable;
+ std::unordered_set<int /* channelId */> mMbcChannelEnable;
+ std::unordered_set<int /* channelId */> mLimiterChannelEnable;
+ static const std::set<std::vector<DynamicsProcessing::ChannelConfig>> kChannelConfigTestSet;
+ static const std::set<DynamicsProcessing::StageEnablement> kStageEnablementTestSet;
+ static const std::set<std::vector<DynamicsProcessing::InputGain>> kInputGainTestSet;
+
+ private:
+ int32_t mChannelLayout;
+ int mChannelCount;
+ std::vector<std::pair<DynamicsProcessing::Tag, DynamicsProcessing>> mTags;
+ void CleanUp() {
+ mTags.clear();
+ mPreEqChannelEnable.clear();
+ mPostEqChannelEnable.clear();
+ mMbcChannelEnable.clear();
+ mLimiterChannelEnable.clear();
+ }
+};
+
+// test value set for DynamicsProcessing::StageEnablement
+const std::set<DynamicsProcessing::StageEnablement>
+ DynamicsProcessingTestHelper::kStageEnablementTestSet = {
+ {.inUse = true, .bandCount = DynamicsProcessingTestHelper::kBandCount},
+ {.inUse = true, .bandCount = 0},
+ {.inUse = true, .bandCount = -1},
+ {.inUse = false, .bandCount = DynamicsProcessingTestHelper::kBandCount}};
+
+// test value set for DynamicsProcessing::ChannelConfig
+const std::set<std::vector<DynamicsProcessing::ChannelConfig>>
+ DynamicsProcessingTestHelper::kChannelConfigTestSet = {
+ {{.channel = -1, .enable = false},
+ {.channel = 0, .enable = true},
+ {.channel = 1, .enable = false},
+ {.channel = 2, .enable = true}},
+
+ {{.channel = -1, .enable = false}, {.channel = 2, .enable = true}},
+
+ {{.channel = 0, .enable = true}, {.channel = 1, .enable = true}}};
+
+// test value set for DynamicsProcessing::InputGain
+const std::set<std::vector<DynamicsProcessing::InputGain>>
+ DynamicsProcessingTestHelper::kInputGainTestSet = {
+ {{.channel = 0, .gainDb = 10.f},
+ {.channel = 1, .gainDb = 0.f},
+ {.channel = 2, .gainDb = -10.f}},
+
+ {{.channel = -1, .gainDb = -10.f}, {.channel = -2, .gainDb = 10.f}},
+
+ {{.channel = -1, .gainDb = 10.f}, {.channel = 0, .gainDb = -10.f}}};
+
+bool DynamicsProcessingTestHelper::isParamValid(const DynamicsProcessing::Tag& tag,
+ const DynamicsProcessing& dp,
+ const Descriptor& desc) {
+ const DynamicsProcessing::Capability& dpCap =
+ desc.capability.get<Capability::dynamicsProcessing>();
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ return isEngineConfigValid(dp.get<DynamicsProcessing::engineArchitecture>());
+ }
+ case DynamicsProcessing::preEq: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::preEq>(),
+ mEngineConfigApplied.preEqStage.inUse);
+ }
+ case DynamicsProcessing::postEq: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::postEq>(),
+ mEngineConfigApplied.postEqStage.inUse);
+ }
+ case DynamicsProcessing::mbc: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::mbc>(),
+ mEngineConfigApplied.mbcStage.inUse);
+ }
+ case DynamicsProcessing::preEqBand: {
+ return isPreEqBandConfigValid(dpCap, dp.get<DynamicsProcessing::preEqBand>(),
+ mEngineConfigApplied.preEqStage.inUse,
+ mEngineConfigApplied.preEqStage.bandCount);
+ }
+ case DynamicsProcessing::postEqBand: {
+ return isPostEqBandConfigValid(dpCap, dp.get<DynamicsProcessing::postEqBand>(),
+ mEngineConfigApplied.postEqStage.inUse,
+ mEngineConfigApplied.postEqStage.bandCount);
+ }
+ case DynamicsProcessing::mbcBand: {
+ return isMbcBandConfigValid(dpCap, dp.get<DynamicsProcessing::mbcBand>(),
+ mEngineConfigApplied.mbcStage.inUse,
+ mEngineConfigApplied.mbcStage.bandCount);
+ }
+ case DynamicsProcessing::limiter: {
+ return isLimiterConfigValid(dp.get<DynamicsProcessing::limiter>(),
+ mEngineConfigApplied.limiterInUse);
+ }
+ case DynamicsProcessing::inputGain: {
+ return isInputGainValid(dp.get<DynamicsProcessing::inputGain>());
+ }
+ case DynamicsProcessing::vendorExtension: {
+ return true;
+ }
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isParamEqual(const DynamicsProcessing::Tag& tag,
+ const DynamicsProcessing& dpRef,
+ const DynamicsProcessing& dpTest) {
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ return isEngineConfigEqual(dpRef.get<DynamicsProcessing::engineArchitecture>(),
+ dpTest.get<DynamicsProcessing::engineArchitecture>());
+ }
+ case DynamicsProcessing::preEq: {
+ const auto& source = dpRef.get<DynamicsProcessing::preEq>();
+ const auto& target = dpTest.get<DynamicsProcessing::preEq>();
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(source, target);
+ }
+ case DynamicsProcessing::postEq: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
+ dpRef.get<DynamicsProcessing::postEq>(),
+ dpTest.get<DynamicsProcessing::postEq>());
+ }
+ case DynamicsProcessing::mbc: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
+ dpRef.get<DynamicsProcessing::mbc>(), dpTest.get<DynamicsProcessing::mbc>());
+ }
+ case DynamicsProcessing::preEqBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
+ dpRef.get<DynamicsProcessing::preEqBand>(),
+ dpTest.get<DynamicsProcessing::preEqBand>());
+ }
+ case DynamicsProcessing::postEqBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
+ dpRef.get<DynamicsProcessing::postEqBand>(),
+ dpTest.get<DynamicsProcessing::postEqBand>());
+ }
+ case DynamicsProcessing::mbcBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::MbcBandConfig>(
+ dpRef.get<DynamicsProcessing::mbcBand>(),
+ dpTest.get<DynamicsProcessing::mbcBand>());
+ }
+ case DynamicsProcessing::limiter: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::LimiterConfig>(
+ dpRef.get<DynamicsProcessing::limiter>(),
+ dpTest.get<DynamicsProcessing::limiter>());
+ }
+ case DynamicsProcessing::inputGain: {
+ return isAidlVectorEqual<DynamicsProcessing::InputGain>(
+ dpRef.get<DynamicsProcessing::inputGain>(),
+ dpTest.get<DynamicsProcessing::inputGain>());
+ }
+ case DynamicsProcessing::vendorExtension: {
+ return false;
+ }
+ }
+}
+
+bool DynamicsProcessingTestHelper::isEnablementValid(
+ const DynamicsProcessing::StageEnablement& enablement) {
+ return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingTestHelper::isEngineConfigValid(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ return cfg.preferredProcessingDurationMs >= 0 && isEnablementValid(cfg.preEqStage) &&
+ isEnablementValid(cfg.postEqStage) && isEnablementValid(cfg.mbcStage);
+}
+
+bool DynamicsProcessingTestHelper::isChannelConfigValid(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs, bool stageInUse) {
+ std::unordered_set<int> channelSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (cfg.channel < 0 || cfg.channel >= mChannelCount || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isCutoffFrequencyValid(
+ float freq, const DynamicsProcessing::Capability& cap) {
+ return freq >= cap.minCutOffFreq && freq <= cap.maxCutOffFreq;
+}
+
+bool DynamicsProcessingTestHelper::isPreEqBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs, bool stageInUse, int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mPreEqChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isPostEqBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs, bool stageInUse, int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ // not able to set/get parameter when stage not in use.
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mPostEqChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isMbcBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs, bool stageInUse,
+ int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mMbcChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ (cfg.attackTimeMs < 0) || cfg.releaseTimeMs < 0 || cfg.ratio < 0 ||
+ cfg.thresholdDb > 0 || cfg.kneeWidthDb < 0 || cfg.noiseGateThresholdDb > 0 ||
+ cfg.expanderRatio < 0 || !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isLimiterConfigValid(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs, bool stageInUse) {
+ std::set<int> channelSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mLimiterChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.attackTimeMs < 0 || cfg.releaseTimeMs < 0 ||
+ cfg.ratio < 0 || cfg.thresholdDb > 0 || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isInputGainValid(
+ const std::vector<DynamicsProcessing::InputGain>& cfgs) {
+ std::set<int> channelSet;
+ for (auto cfg : cfgs) {
+ if (cfg.channel < 0 || cfg.channel >= mChannelCount || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isEngineConfigEqual(
+ const DynamicsProcessing::EngineArchitecture& ref,
+ const DynamicsProcessing::EngineArchitecture& test) {
+ return ref == test;
+}
+
+template <typename T>
+std::vector<T> DynamicsProcessingTestHelper::filterEnabledVector(const std::vector<T>& vec) {
+ std::vector<T> ret;
+ std::copy_if(vec.begin(), vec.end(), std::back_inserter(ret),
+ [](const auto& v) { return v.enable; });
+ return ret;
+}
+
+template <typename T>
+bool DynamicsProcessingTestHelper::isAidlVectorEqual(const std::vector<T>& source,
+ const std::vector<T>& target) {
+ if (source.size() != target.size()) return false;
+
+ auto tempS = source;
+ auto tempT = target;
+ std::sort(tempS.begin(), tempS.end());
+ std::sort(tempT.begin(), tempT.end());
+ return tempS == tempT;
+}
+
+template <typename T>
+bool DynamicsProcessingTestHelper::isAidlVectorEqualAfterFilter(const std::vector<T>& source,
+ const std::vector<T>& target) {
+ return isAidlVectorEqual<T>(filterEnabledVector<T>(source), filterEnabledVector<T>(target));
+}
+
+void DynamicsProcessingTestHelper::SetAndGetDynamicsProcessingParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& dp = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isParamValid(tag, dp, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::dynamicsProcessing>(dp);
+ expectParam.set<Parameter::specific>(specific);
+ ASSERT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // only get if parameter in range and set success
+ if (expected == EX_NONE) {
+ Parameter getParam;
+ Parameter::Id id;
+ DynamicsProcessing::Id dpId;
+ dpId.set<DynamicsProcessing::Id::commonTag>(tag);
+ id.set<Parameter::Id::dynamicsProcessingTag>(dpId);
+ // if set success, then get should match
+ EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+ Parameter::Specific specificTest = getParam.get<Parameter::specific>();
+ const auto& target = specificTest.get<Parameter::Specific::dynamicsProcessing>();
+ EXPECT_TRUE(isParamEqual(tag, dp, target)) << dp.toString() << "\n"
+ << target.toString();
+ // update mEngineConfigApplied after setting successfully
+ if (tag == DynamicsProcessing::engineArchitecture) {
+ mEngineConfigApplied = target.get<DynamicsProcessing::engineArchitecture>();
+ }
+ }
+ }
+}
+
+void DynamicsProcessingTestHelper::addEngineConfig(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::engineArchitecture>(cfg);
+ mTags.push_back({DynamicsProcessing::engineArchitecture, dp});
+}
+
+void DynamicsProcessingTestHelper::addPreEqChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::preEq>(cfgs);
+ mTags.push_back({DynamicsProcessing::preEq, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mPreEqChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addPostEqChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::postEq>(cfgs);
+ mTags.push_back({DynamicsProcessing::postEq, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mPostEqChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addMbcChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::mbc>(cfgs);
+ mTags.push_back({DynamicsProcessing::mbc, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mMbcChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addPreEqBandConfigs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::preEqBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::preEqBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addPostEqBandConfigs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::postEqBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::postEqBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addMbcBandConfigs(
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::mbcBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::mbcBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addLimiterConfig(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::limiter>(cfgs);
+ mTags.push_back({DynamicsProcessing::limiter, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mLimiterChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addInputGain(
+ const std::vector<DynamicsProcessing::InputGain>& inputGains) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::inputGain>(inputGains);
+ mTags.push_back({DynamicsProcessing::inputGain, dp});
+}
+
+/**
+ * Test DynamicsProcessing Engine Configuration
+ */
+enum EngineArchitectureTestParamName {
+ ENGINE_TEST_INSTANCE_NAME,
+ ENGINE_TEST_RESOLUTION_PREFERENCE,
+ ENGINE_TEST_PREFERRED_DURATION,
+ ENGINE_TEST_STAGE_ENABLEMENT,
+ ENGINE_TEST_LIMITER_IN_USE
+};
+using EngineArchitectureTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ DynamicsProcessing::ResolutionPreference, float,
+ DynamicsProcessing::StageEnablement, bool>;
+
+void fillEngineArchConfig(DynamicsProcessing::EngineArchitecture& cfg,
+ const EngineArchitectureTestParams& params) {
+ cfg.resolutionPreference = std::get<ENGINE_TEST_RESOLUTION_PREFERENCE>(params);
+ cfg.preferredProcessingDurationMs = std::get<ENGINE_TEST_PREFERRED_DURATION>(params);
+ cfg.preEqStage = cfg.postEqStage = cfg.mbcStage =
+ std::get<ENGINE_TEST_STAGE_ENABLEMENT>(params);
+ cfg.limiterInUse = std::get<ENGINE_TEST_LIMITER_IN_USE>(params);
+}
+
+class DynamicsProcessingTestEngineArchitecture
+ : public ::testing::TestWithParam<EngineArchitectureTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestEngineArchitecture()
+ : DynamicsProcessingTestHelper(std::get<ENGINE_TEST_INSTANCE_NAME>(GetParam())) {
+ fillEngineArchConfig(mCfg, GetParam());
+ };
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ DynamicsProcessing::EngineArchitecture mCfg;
+};
+
+TEST_P(DynamicsProcessingTestEngineArchitecture, SetAndGetEngineArch) {
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestEngineArchitecture,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(DynamicsProcessing::ResolutionPreference::FAVOR_TIME_RESOLUTION,
+ DynamicsProcessing::ResolutionPreference::
+ FAVOR_FREQUENCY_RESOLUTION), // variant
+ testing::Values(-10.f, 0.f, 10.f), // processing duration
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kStageEnablementTestSet), // preEQ/postEQ/mbc
+ testing::Bool()), // limiter enable
+ [](const auto& info) {
+ auto descriptor = std::get<ENGINE_TEST_INSTANCE_NAME>(info.param).second;
+ DynamicsProcessing::EngineArchitecture cfg;
+ fillEngineArchConfig(cfg, info.param);
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_Cfg_" + cfg.toString();
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEngineArchitecture);
+
+/**
+ * Test DynamicsProcessing Input Gain
+ */
+enum InputGainTestParamName {
+ INPUT_GAIN_INSTANCE_NAME,
+ INPUT_GAIN_PARAM,
+};
+class DynamicsProcessingTestInputGain
+ : public ::testing::TestWithParam<std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ std::vector<DynamicsProcessing::InputGain>>>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestInputGain()
+ : DynamicsProcessingTestHelper(std::get<INPUT_GAIN_INSTANCE_NAME>(GetParam())),
+ mInputGain(std::get<INPUT_GAIN_PARAM>(GetParam())){};
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ const std::vector<DynamicsProcessing::InputGain> mInputGain;
+};
+
+TEST_P(DynamicsProcessingTestInputGain, SetAndGetInputGain) {
+ EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestInputGain,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::ValuesIn(DynamicsProcessingTestInputGain::kInputGainTestSet)),
+ [](const auto& info) {
+ auto descriptor = std::get<INPUT_GAIN_INSTANCE_NAME>(info.param).second;
+ std::string gains =
+ ::android::internal::ToString(std::get<INPUT_GAIN_PARAM>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_inputGains_" + gains;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestInputGain);
+
+/**
+ * Test DynamicsProcessing Limiter Config
+ */
+enum LimiterConfigTestParamName {
+ LIMITER_INSTANCE_NAME,
+ LIMITER_CHANNEL,
+ LIMITER_ENABLE,
+ LIMITER_LINK_GROUP,
+ LIMITER_ENGINE_IN_USE,
+ LIMITER_ADDITIONAL,
+};
+enum LimiterConfigTestAdditionalParam {
+ LIMITER_ATTACK_TIME,
+ LIMITER_RELEASE_TIME,
+ LIMITER_RATIO,
+ LIMITER_THRESHOLD,
+ LIMITER_POST_GAIN,
+ LIMITER_MAX_NUM,
+};
+using LimiterConfigTestAdditional = std::array<float, LIMITER_MAX_NUM>;
+// attachTime, releaseTime, ratio, thresh, postGain
+static constexpr std::array<LimiterConfigTestAdditional, 4> kLimiterConfigTestAdditionalParam = {
+ {{-1, -60, -2.5, -2, -3.14},
+ {-1, 60, -2.5, 2, -3.14},
+ {1, -60, 2.5, -2, 3.14},
+ {1, 60, 2.5, 2, 3.14}}};
+
+using LimiterConfigTestParams =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t, bool, int32_t, bool,
+ LimiterConfigTestAdditional>;
+
+void fillLimiterConfig(DynamicsProcessing::LimiterConfig& cfg,
+ const LimiterConfigTestParams& params) {
+ const std::array<float, LIMITER_MAX_NUM> additional = std::get<LIMITER_ADDITIONAL>(params);
+ cfg.channel = std::get<LIMITER_CHANNEL>(params);
+ cfg.enable = std::get<LIMITER_ENABLE>(params);
+ cfg.linkGroup = std::get<LIMITER_LINK_GROUP>(params);
+ cfg.attackTimeMs = additional[LIMITER_ATTACK_TIME];
+ cfg.releaseTimeMs = additional[LIMITER_RELEASE_TIME];
+ cfg.ratio = additional[LIMITER_RATIO];
+ cfg.thresholdDb = additional[LIMITER_THRESHOLD];
+ cfg.postGainDb = additional[LIMITER_POST_GAIN];
+}
+
+class DynamicsProcessingTestLimiterConfig
+ : public ::testing::TestWithParam<LimiterConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestLimiterConfig()
+ : DynamicsProcessingTestHelper(std::get<LIMITER_INSTANCE_NAME>(GetParam())),
+ mLimiterInUseEngine(std::get<LIMITER_ENGINE_IN_USE>(GetParam())) {
+ fillLimiterConfig(mCfg, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ DynamicsProcessing::LimiterConfig mCfg;
+ bool mLimiterInUseEngine;
+};
+
+TEST_P(DynamicsProcessingTestLimiterConfig, SetAndGetLimiterConfig) {
+ mEngineConfigPreset.limiterInUse = mLimiterInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addLimiterConfig({mCfg}));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestLimiterConfig,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 1, 2), // channel count
+ testing::Bool(), // enable
+ testing::Values(3), // link group
+ testing::Bool(), // engine limiter enable
+ testing::ValuesIn(kLimiterConfigTestAdditionalParam)), // Additional
+ [](const auto& info) {
+ auto descriptor = std::get<LIMITER_INSTANCE_NAME>(info.param).second;
+ DynamicsProcessing::LimiterConfig cfg;
+ fillLimiterConfig(cfg, info.param);
+ std::string engineLimiterInUse =
+ std::to_string(std::get<LIMITER_ENGINE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_limiterConfig_" +
+ cfg.toString() + "_engineSetting_" + engineLimiterInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestLimiterConfig);
+
+/**
+ * Test DynamicsProcessing ChannelConfig
+ */
+enum ChannelConfigTestParamName {
+ BAND_CHANNEL_TEST_INSTANCE_NAME,
+ BAND_CHANNEL_TEST_CHANNEL_CONFIG,
+ BAND_CHANNEL_TEST_ENGINE_IN_USE
+};
+using ChannelConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool>;
+
+class DynamicsProcessingTestChannelConfig
+ : public ::testing::TestWithParam<ChannelConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestChannelConfig()
+ : DynamicsProcessingTestHelper(std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(GetParam())),
+ mCfg(std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(GetParam())),
+ mInUseEngine(std::get<BAND_CHANNEL_TEST_ENGINE_IN_USE>(GetParam())) {}
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::ChannelConfig> mCfg;
+ const bool mInUseEngine;
+};
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPreEqChannelConfig) {
+ mEngineConfigPreset.preEqStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPostEqChannelConfig) {
+ mEngineConfigPreset.postEqStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetMbcChannelConfig) {
+ mEngineConfigPreset.mbcStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestChannelConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel config
+ testing::Bool()), // Engine inUse
+ [](const auto& info) {
+ auto descriptor = std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(info.param).second;
+ std::string engineInUse =
+ std::to_string(std::get<BAND_CHANNEL_TEST_ENGINE_IN_USE>(info.param));
+ std::string channelConfig = ::android::internal::ToString(
+ std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(info.param));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_" + channelConfig +
+ "_engineInUse_" + engineInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestChannelConfig);
+
+/**
+ * Test DynamicsProcessing EqBandConfig
+ */
+enum EqBandConfigTestParamName {
+ EQ_BAND_INSTANCE_NAME,
+ EQ_BAND_CHANNEL,
+ EQ_BAND_CHANNEL_ENABLE,
+ EQ_BAND_ENABLE,
+ EQ_BAND_CUT_OFF_FREQ,
+ EQ_BAND_GAIN,
+ EQ_BAND_STAGE_IN_USE
+};
+using EqBandConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool,
+ std::vector<std::pair<int, float>>, float, bool>;
+
+void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ const EqBandConfigTestParams& params) {
+ const std::vector<std::pair<int, float>> cutOffFreqs = std::get<EQ_BAND_CUT_OFF_FREQ>(params);
+ int bandCount = cutOffFreqs.size();
+ cfgs.resize(bandCount);
+ for (int i = 0; i < bandCount; i++) {
+ cfgs[i].channel = std::get<EQ_BAND_CHANNEL>(params);
+ cfgs[i].band = cutOffFreqs[i].first;
+ cfgs[i].enable = std::get<EQ_BAND_ENABLE>(params);
+ cfgs[i].cutoffFrequencyHz = cutOffFreqs[i].second;
+ cfgs[i].gainDb = std::get<EQ_BAND_GAIN>(params);
+ }
+}
+
+class DynamicsProcessingTestEqBandConfig : public ::testing::TestWithParam<EqBandConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestEqBandConfig()
+ : DynamicsProcessingTestHelper(std::get<EQ_BAND_INSTANCE_NAME>(GetParam())),
+ mStageInUse(std::get<EQ_BAND_STAGE_IN_USE>(GetParam())),
+ mChannelConfig(std::get<EQ_BAND_CHANNEL_ENABLE>(GetParam())) {
+ fillEqBandConfig(mCfgs, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::EqBandConfig> mCfgs;
+ const bool mStageInUse;
+ const std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+};
+
+TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) {
+ mEngineConfigPreset.preEqStage.inUse = mStageInUse;
+ mEngineConfigPreset.preEqStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addPreEqBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPostEqBandConfig) {
+ mEngineConfigPreset.postEqStage.inUse = mStageInUse;
+ mEngineConfigPreset.postEqStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addPostEqBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+std::vector<std::vector<std::pair<int, float>>> kBands{
+ {
+ {0, 600},
+ {1, 2000},
+ {2, 6000},
+ {3, 10000},
+ {4, 16000},
+ }, // 5 bands
+ {
+ {0, 800},
+ {3, 15000},
+ {2, 6000},
+ {1, 2000},
+ }, // 4 bands, unsorted
+ {
+ {0, 650},
+ {1, 2000},
+ {2, 6000},
+ {3, 10000},
+ {3, 16000},
+ }, // 5 bands, missing band
+ {
+ {0, 900},
+ {1, 8000},
+ {2, 4000},
+ {3, 12000},
+ }, // 4 bands, cutoff freq not increasing
+ {
+ {0, 450},
+ {1, 2000},
+ {7, 6000},
+ {3, 10000},
+ {4, 16000},
+ }, // bad band index
+ {
+ {0, 1},
+ {1, 8000},
+ }, // too low cutoff freq
+ {
+ {0, 1200},
+ {1, 80000},
+ }, // too high cutoff freq
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestEqBandConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 10), // channel ID
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel enable
+ testing::Bool(), // band enable
+ testing::ValuesIn(kBands), // cut off frequencies
+ testing::Values(-3.14f, 3.14f), // gain
+ testing::Bool()), // stage in use
+ [](const auto& info) {
+ auto descriptor = std::get<EQ_BAND_INSTANCE_NAME>(info.param).second;
+ std::vector<DynamicsProcessing::EqBandConfig> cfgs;
+ fillEqBandConfig(cfgs, info.param);
+ std::string enable =
+ ::android::internal::ToString(std::get<EQ_BAND_CHANNEL_ENABLE>(info.param));
+ std::string bands = ::android::internal::ToString(cfgs);
+ std::string stageInUse = std::to_string(std::get<EQ_BAND_STAGE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_" + enable + "_bands_" +
+ bands + "_stageInUse_" + stageInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEqBandConfig);
+
+/**
+ * Test DynamicsProcessing MbcBandConfig
+ */
+
+enum MbcBandConfigParamName {
+ MBC_BAND_INSTANCE_NAME,
+ MBC_BAND_CHANNEL,
+ MBC_BAND_CHANNEL_CONFIG,
+ MBC_BAND_ENABLE,
+ MBC_BAND_CUTOFF_FREQ,
+ MBC_BAND_STAGE_IN_USE,
+ MBC_BAND_ADDITIONAL
+};
+enum MbcBandConfigAdditional {
+ MBC_ADD_ATTACK_TIME,
+ MBC_ADD_RELEASE_TIME,
+ MBC_ADD_RATIO,
+ MBC_ADD_THRESHOLD,
+ MBC_ADD_KNEE_WIDTH,
+ MBC_ADD_NOISE_GATE_THRESHOLD,
+ MBC_ADD_EXPENDER_RATIO,
+ MBC_ADD_PRE_GAIN,
+ MBC_ADD_POST_GAIN,
+ MBC_ADD_MAX_NUM
+};
+using TestParamsMbcBandConfigAdditional = std::array<float, MBC_ADD_MAX_NUM>;
+
+// attachTime, releaseTime, ratio, thresh, kneeWidth, noise, expander, preGain, postGain
+static constexpr std::array<TestParamsMbcBandConfigAdditional, 4> kMbcBandConfigAdditionalParam = {
+ {{-3, -10, -2, -2, -5, -90, -2.5, -2, -2},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {-3, 10, -2, 2, -5, 90, -2.5, 2, -2},
+ {3, 10, 2, 2, 5, 90, 2.5, 2, 2}}};
+
+using TestParamsMbcBandConfig =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool,
+ std::vector<std::pair<int, float>>, bool, TestParamsMbcBandConfigAdditional>;
+
+void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
+ const TestParamsMbcBandConfig& params) {
+ const std::vector<std::pair<int, float>> cutOffFreqs = std::get<MBC_BAND_CUTOFF_FREQ>(params);
+ const std::array<float, MBC_ADD_MAX_NUM> additional = std::get<MBC_BAND_ADDITIONAL>(params);
+ int bandCount = cutOffFreqs.size();
+ cfgs.resize(bandCount);
+ for (int i = 0; i < bandCount; i++) {
+ cfgs[i] = DynamicsProcessing::MbcBandConfig{
+ .channel = std::get<MBC_BAND_CHANNEL>(params),
+ .band = cutOffFreqs[i].first,
+ .enable = std::get<MBC_BAND_ENABLE>(params),
+ .cutoffFrequencyHz = cutOffFreqs[i].second,
+ .attackTimeMs = additional[MBC_ADD_ATTACK_TIME],
+ .releaseTimeMs = additional[MBC_ADD_RELEASE_TIME],
+ .ratio = additional[MBC_ADD_RATIO],
+ .thresholdDb = additional[MBC_ADD_THRESHOLD],
+ .kneeWidthDb = additional[MBC_ADD_KNEE_WIDTH],
+ .noiseGateThresholdDb = additional[MBC_ADD_NOISE_GATE_THRESHOLD],
+ .expanderRatio = additional[MBC_ADD_EXPENDER_RATIO],
+ .preGainDb = additional[MBC_ADD_PRE_GAIN],
+ .postGainDb = additional[MBC_ADD_POST_GAIN]};
+ }
+}
+
+class DynamicsProcessingTestMbcBandConfig
+ : public ::testing::TestWithParam<TestParamsMbcBandConfig>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestMbcBandConfig()
+ : DynamicsProcessingTestHelper(std::get<MBC_BAND_INSTANCE_NAME>(GetParam())),
+ mStageInUse(std::get<MBC_BAND_STAGE_IN_USE>(GetParam())),
+ mChannelConfig(std::get<MBC_BAND_CHANNEL_CONFIG>(GetParam())) {
+ fillMbcBandConfig(mCfgs, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
+ const bool mStageInUse;
+ const std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+};
+
+TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) {
+ mEngineConfigPreset.mbcStage.inUse = mStageInUse;
+ mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addMbcBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestMbcBandConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 10), // channel count
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel config
+ testing::Bool(), // enable
+ testing::ValuesIn(kBands), // cut off frequencies
+ testing::Bool(), // stage in use
+ testing::ValuesIn(kMbcBandConfigAdditionalParam)), // Additional
+ [](const auto& info) {
+ auto descriptor = std::get<MBC_BAND_INSTANCE_NAME>(info.param).second;
+ std::vector<DynamicsProcessing::MbcBandConfig> cfgs;
+ fillMbcBandConfig(cfgs, info.param);
+ std::string enable =
+ ::android::internal::ToString(std::get<MBC_BAND_CHANNEL_CONFIG>(info.param));
+ std::string mbcBands = ::android::internal::ToString(cfgs);
+ std::string stageInUse = std::to_string(std::get<MBC_BAND_STAGE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_enable_" + enable +
+ "_bands_" + mbcBands + "_stageInUse_" + stageInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestMbcBandConfig);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}