/* * 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 #include #include #include #define LOG_TAG "VtsHalDynamicsProcessingTest" #include #include #include "EffectHelper.h" #include "EffectRangeSpecific.h" using namespace android; using namespace aidl::android::hardware::audio::effect::DynamicsProcessingRanges; using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::DynamicsProcessing; using aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing; using aidl::android::hardware::audio::effect::IEffect; using aidl::android::hardware::audio::effect::IFactory; 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, Descriptor> pair, int32_t channelLayOut = AudioChannelLayout::LAYOUT_STEREO) { std::tie(mFactory, mDescriptor) = pair; mChannelLayout = channelLayOut; mChannelCount = ::aidl::android::hardware::audio::common::getChannelCount( AudioChannelLayout::make(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(mChannelLayout), AudioChannelLayout::make(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( mEngineConfigPreset); Parameter::Specific specific = Parameter::Specific::make(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 isParamEqual(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dpRef, const DynamicsProcessing& dpTest); bool isEngineConfigEqual(const DynamicsProcessing::EngineArchitecture& refCfg, const DynamicsProcessing::EngineArchitecture& testCfg); template std::vector filterEnabledVector(const std::vector& vec); template bool isAidlVectorEqualAfterFilter(const std::vector& source, const std::vector& target); template bool isAidlVectorEqual(const std::vector& source, const std::vector& target); template bool isChannelConfigValid(const std::vector& cfgs) { auto& channelCount = mChannelCount; return std::all_of(cfgs.cbegin(), cfgs.cend(), [channelCount](const T& cfg) { return (cfg.channel >= 0 && cfg.channel < channelCount); }); } template bool isBandConfigValid(const std::vector& cfgs, int bandCount); bool isParamValid(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dp); // get set params and validate void SetAndGetDynamicsProcessingParameters(); // enqueue test parameters void addEngineConfig(const DynamicsProcessing::EngineArchitecture& cfg); void addPreEqChannelConfig(const std::vector& cfg); void addPostEqChannelConfig(const std::vector& cfg); void addMbcChannelConfig(const std::vector& cfg); void addPreEqBandConfigs(const std::vector& cfgs); void addPostEqBandConfigs(const std::vector& cfgs); void addMbcBandConfigs(const std::vector& cfgs); void addLimiterConfig(const std::vector& cfg); void addInputGain(const std::vector& inputGain); static constexpr float kPreferredProcessingDurationMs = 10.0f; static constexpr int kBandCount = 5; std::shared_ptr mFactory; std::shared_ptr 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 mPreEqChannelEnable; std::unordered_set mPostEqChannelEnable; std::unordered_set mMbcChannelEnable; std::unordered_set mLimiterChannelEnable; static const std::set> kChannelConfigTestSet; static const std::set kStageEnablementTestSet; static const std::set> kInputGainTestSet; protected: int mChannelCount; private: int32_t mChannelLayout; std::vector> mTags; void CleanUp() { mTags.clear(); mPreEqChannelEnable.clear(); mPostEqChannelEnable.clear(); mMbcChannelEnable.clear(); mLimiterChannelEnable.clear(); } }; // test value set for DynamicsProcessing::StageEnablement const std::set DynamicsProcessingTestHelper::kStageEnablementTestSet = { {.inUse = true, .bandCount = DynamicsProcessingTestHelper::kBandCount}, {.inUse = true, .bandCount = 0}, {.inUse = true, .bandCount = -1}, {.inUse = false, .bandCount = 0}, {.inUse = false, .bandCount = -1}, {.inUse = false, .bandCount = DynamicsProcessingTestHelper::kBandCount}}; // test value set for DynamicsProcessing::ChannelConfig const std::set> 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> 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}}, {{.channel = 0, .gainDb = 10.f}, {.channel = 1, .gainDb = -10.f}}}; template bool DynamicsProcessingTestHelper::isBandConfigValid(const std::vector& cfgs, int bandCount) { std::vector freqs(cfgs.size(), -1); for (auto cfg : cfgs) { if (cfg.channel < 0 || cfg.channel >= mChannelCount) return false; if (cfg.band < 0 || cfg.band >= bandCount) return false; freqs[cfg.band] = cfg.cutoffFrequencyHz; } if (std::count(freqs.begin(), freqs.end(), -1)) return false; return std::is_sorted(freqs.begin(), freqs.end()); } bool DynamicsProcessingTestHelper::isParamValid(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dp) { switch (tag) { case DynamicsProcessing::preEq: { if (!mEngineConfigApplied.preEqStage.inUse) return false; return isChannelConfigValid(dp.get()); } case DynamicsProcessing::postEq: { if (!mEngineConfigApplied.postEqStage.inUse) return false; return isChannelConfigValid(dp.get()); } case DynamicsProcessing::mbc: { if (!mEngineConfigApplied.mbcStage.inUse) return false; return isChannelConfigValid(dp.get()); } case DynamicsProcessing::preEqBand: { if (!mEngineConfigApplied.preEqStage.inUse) return false; return isBandConfigValid(dp.get(), mEngineConfigApplied.preEqStage.bandCount); } case DynamicsProcessing::postEqBand: { if (!mEngineConfigApplied.postEqStage.inUse) return false; return isBandConfigValid(dp.get(), mEngineConfigApplied.postEqStage.bandCount); } case DynamicsProcessing::mbcBand: { if (!mEngineConfigApplied.mbcStage.inUse) return false; return isBandConfigValid(dp.get(), mEngineConfigApplied.mbcStage.bandCount); } case DynamicsProcessing::limiter: { if (!mEngineConfigApplied.limiterInUse) return false; return isChannelConfigValid(dp.get()); } case DynamicsProcessing::inputGain: { return isChannelConfigValid(dp.get()); } default: { 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(), dpTest.get()); } case DynamicsProcessing::preEq: { const auto& source = dpRef.get(); const auto& target = dpTest.get(); return isAidlVectorEqualAfterFilter(source, target); } case DynamicsProcessing::postEq: { return isAidlVectorEqualAfterFilter( dpRef.get(), dpTest.get()); } case DynamicsProcessing::mbc: { return isAidlVectorEqualAfterFilter( dpRef.get(), dpTest.get()); } case DynamicsProcessing::preEqBand: { return isAidlVectorEqualAfterFilter( dpRef.get(), dpTest.get()); } case DynamicsProcessing::postEqBand: { return isAidlVectorEqualAfterFilter( dpRef.get(), dpTest.get()); } case DynamicsProcessing::mbcBand: { return isAidlVectorEqualAfterFilter( dpRef.get(), dpTest.get()); } case DynamicsProcessing::limiter: { return isAidlVectorEqualAfterFilter( dpRef.get(), dpTest.get()); } case DynamicsProcessing::inputGain: { return isAidlVectorEqual( dpRef.get(), dpTest.get()); } case DynamicsProcessing::vendor: { return false; } } } bool DynamicsProcessingTestHelper::isEngineConfigEqual( const DynamicsProcessing::EngineArchitecture& ref, const DynamicsProcessing::EngineArchitecture& test) { return ref == test; } template std::vector DynamicsProcessingTestHelper::filterEnabledVector(const std::vector& vec) { std::vector ret; std::copy_if(vec.begin(), vec.end(), std::back_inserter(ret), [](const auto& v) { return v.enable; }); return ret; } template bool DynamicsProcessingTestHelper::isAidlVectorEqual(const std::vector& source, const std::vector& 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 bool DynamicsProcessingTestHelper::isAidlVectorEqualAfterFilter(const std::vector& source, const std::vector& target) { return isAidlVectorEqual(filterEnabledVector(source), filterEnabledVector(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)); bool valid = isParamInRange(dp, desc.capability.range.get()); if (valid) valid = isParamValid(tag, dp); const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT; // set parameter Parameter expectParam; Parameter::Specific specific; specific.set(dp); expectParam.set(specific); ASSERT_STATUS(expected, mEffect->setParameter(expectParam)) << "\n" << expectParam.toString() << "\n" << desc.toString(); // only get if parameter in range and set success if (expected == EX_NONE) { Parameter getParam; Parameter::Id id; DynamicsProcessing::Id dpId; dpId.set(tag); id.set(dpId); // if set success, then get should match EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam)); Parameter::Specific specificTest = getParam.get(); const auto& target = specificTest.get(); EXPECT_TRUE(isParamEqual(tag, dp, target)) << dp.toString() << "\n" << target.toString(); // update mEngineConfigApplied after setting successfully if (tag == DynamicsProcessing::engineArchitecture) { mEngineConfigApplied = target.get(); } } } } void DynamicsProcessingTestHelper::addEngineConfig( const DynamicsProcessing::EngineArchitecture& cfg) { DynamicsProcessing dp; dp.set(cfg); mTags.push_back({DynamicsProcessing::engineArchitecture, dp}); } void DynamicsProcessingTestHelper::addPreEqChannelConfig( const std::vector& cfgs) { DynamicsProcessing dp; dp.set(cfgs); mTags.push_back({DynamicsProcessing::preEq, dp}); for (auto& cfg : cfgs) { if (cfg.enable) mPreEqChannelEnable.insert(cfg.channel); } } void DynamicsProcessingTestHelper::addPostEqChannelConfig( const std::vector& cfgs) { DynamicsProcessing dp; dp.set(cfgs); mTags.push_back({DynamicsProcessing::postEq, dp}); for (auto& cfg : cfgs) { if (cfg.enable) mPostEqChannelEnable.insert(cfg.channel); } } void DynamicsProcessingTestHelper::addMbcChannelConfig( const std::vector& cfgs) { DynamicsProcessing dp; dp.set(cfgs); mTags.push_back({DynamicsProcessing::mbc, dp}); for (auto& cfg : cfgs) { if (cfg.enable) mMbcChannelEnable.insert(cfg.channel); } } void DynamicsProcessingTestHelper::addPreEqBandConfigs( const std::vector& cfgs) { DynamicsProcessing dp; dp.set(cfgs); mTags.push_back({DynamicsProcessing::preEqBand, dp}); } void DynamicsProcessingTestHelper::addPostEqBandConfigs( const std::vector& cfgs) { DynamicsProcessing dp; dp.set(cfgs); mTags.push_back({DynamicsProcessing::postEqBand, dp}); } void DynamicsProcessingTestHelper::addMbcBandConfigs( const std::vector& cfgs) { DynamicsProcessing dp; dp.set(cfgs); mTags.push_back({DynamicsProcessing::mbcBand, dp}); } void DynamicsProcessingTestHelper::addLimiterConfig( const std::vector& cfgs) { DynamicsProcessing dp; dp.set(cfgs); mTags.push_back({DynamicsProcessing::limiter, dp}); for (auto& cfg : cfgs) { if (cfg.enable) mLimiterChannelEnable.insert(cfg.channel); } } void DynamicsProcessingTestHelper::addInputGain( const std::vector& inputGains) { DynamicsProcessing dp; dp.set(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, Descriptor>, DynamicsProcessing::ResolutionPreference, float, DynamicsProcessing::StageEnablement, bool>; void fillEngineArchConfig(DynamicsProcessing::EngineArchitecture& cfg, const EngineArchitectureTestParams& params) { cfg.resolutionPreference = std::get(params); cfg.preferredProcessingDurationMs = std::get(params); cfg.preEqStage = cfg.postEqStage = cfg.mbcStage = std::get(params); cfg.limiterInUse = std::get(params); } class DynamicsProcessingTestEngineArchitecture : public ::testing::TestWithParam, public DynamicsProcessingTestHelper { public: DynamicsProcessingTestEngineArchitecture() : DynamicsProcessingTestHelper(std::get(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, getEffectTypeUuidDynamicsProcessing())), testing::Values( DynamicsProcessing::ResolutionPreference::FAVOR_TIME_RESOLUTION, DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION, static_cast(-1)), // 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(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, Descriptor>, std::vector>>, public DynamicsProcessingTestHelper { public: DynamicsProcessingTestInputGain() : DynamicsProcessingTestHelper(std::get(GetParam())), mInputGain(std::get(GetParam())){}; void SetUp() override { SetUpDynamicsProcessingEffect(); } void TearDown() override { TearDownDynamicsProcessingEffect(); } const std::vector 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, getEffectTypeUuidDynamicsProcessing())), testing::ValuesIn(DynamicsProcessingTestInputGain::kInputGainTestSet)), [](const auto& info) { auto descriptor = std::get(info.param).second; std::string gains = ::android::internal::ToString(std::get(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; // attackTime, releaseTime, ratio, thresh, postGain static constexpr std::array 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, Descriptor>, int32_t, bool, int32_t, bool, LimiterConfigTestAdditional>; void fillLimiterConfig(DynamicsProcessing::LimiterConfig& cfg, const LimiterConfigTestParams& params) { const std::array additional = std::get(params); cfg.channel = std::get(params); cfg.enable = std::get(params); cfg.linkGroup = std::get(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, public DynamicsProcessingTestHelper { public: DynamicsProcessingTestLimiterConfig() : DynamicsProcessingTestHelper(std::get(GetParam())), mLimiterInUseEngine(std::get(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, getEffectTypeUuidDynamicsProcessing())), 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(info.param).second; DynamicsProcessing::LimiterConfig cfg; fillLimiterConfig(cfg, info.param); std::string engineLimiterInUse = std::to_string(std::get(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, Descriptor>, std::vector, bool>; class DynamicsProcessingTestChannelConfig : public ::testing::TestWithParam, public DynamicsProcessingTestHelper { public: DynamicsProcessingTestChannelConfig() : DynamicsProcessingTestHelper(std::get(GetParam())), mCfg(std::get(GetParam())), mInUseEngine(std::get(GetParam())) {} void SetUp() override { SetUpDynamicsProcessingEffect(); } void TearDown() override { TearDownDynamicsProcessingEffect(); } std::vector 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, getEffectTypeUuidDynamicsProcessing())), testing::ValuesIn( DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel config testing::Bool()), // Engine inUse [](const auto& info) { auto descriptor = std::get(info.param).second; std::string engineInUse = std::to_string(std::get(info.param)); std::string channelConfig = ::android::internal::ToString( std::get(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_ENABLE, EQ_BAND_CUT_OFF_FREQ, EQ_BAND_GAIN, EQ_BAND_STAGE_IN_USE }; using EqBandConfigTestParams = std::tuple, Descriptor>, int32_t, bool, std::vector>, float, bool>; void fillEqBandConfig(std::vector& cfgs, const EqBandConfigTestParams& params) { const std::vector> cutOffFreqs = std::get(params); int bandCount = cutOffFreqs.size(); cfgs.resize(bandCount); for (int i = 0; i < bandCount; i++) { cfgs[i].channel = std::get(params); cfgs[i].band = cutOffFreqs[i].first; cfgs[i].enable = std::get(params); cfgs[i].cutoffFrequencyHz = cutOffFreqs[i].second; cfgs[i].gainDb = std::get(params); } } class DynamicsProcessingTestEqBandConfig : public ::testing::TestWithParam, public DynamicsProcessingTestHelper { public: DynamicsProcessingTestEqBandConfig() : DynamicsProcessingTestHelper(std::get(GetParam())), mStageInUse(std::get(GetParam())) { fillEqBandConfig(mCfgs, GetParam()); } void SetUp() override { SetUpDynamicsProcessingEffect(); } void TearDown() override { TearDownDynamicsProcessingEffect(); } std::vector mCfgs; const bool mStageInUse; }; TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) { mEngineConfigPreset.preEqStage.inUse = mStageInUse; mEngineConfigPreset.preEqStage.bandCount = mCfgs.size(); EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset)); std::vector cfgs(mChannelCount); for (int i = 0; i < mChannelCount; i++) { cfgs[i].channel = i; cfgs[i].enable = true; } EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(cfgs)); 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)); std::vector cfgs(mChannelCount); for (int i = 0; i < mChannelCount; i++) { cfgs[i].channel = i; cfgs[i].enable = true; } EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(cfgs)); EXPECT_NO_FATAL_FAILURE(addPostEqBandConfigs(mCfgs)); SetAndGetDynamicsProcessingParameters(); } std::vector>> 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, getEffectTypeUuidDynamicsProcessing())), testing::Values(-1, 0, 10), // channel ID testing::Bool(), // band enable testing::ValuesIn(kBands), // cut off frequencies testing::Values(-3.14f, 3.14f), // gain testing::Values(true)), // stage in use [](const auto& info) { auto descriptor = std::get(info.param).second; std::vector cfgs; fillEqBandConfig(cfgs, info.param); std::string bands = ::android::internal::ToString(cfgs); std::string stageInUse = std::to_string(std::get(info.param)); std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + descriptor.common.name + "_UUID_" + descriptor.common.id.uuid.toString() + "_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_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; // attackTime, releaseTime, ratio, thresh, kneeWidth, noise, expander, preGain, postGain static constexpr std::array 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, Descriptor>, int32_t, bool, std::vector>, bool, TestParamsMbcBandConfigAdditional>; void fillMbcBandConfig(std::vector& cfgs, const TestParamsMbcBandConfig& params) { const std::vector> cutOffFreqs = std::get(params); const std::array additional = std::get(params); int bandCount = cutOffFreqs.size(); cfgs.resize(bandCount); for (int i = 0; i < bandCount; i++) { cfgs[i] = DynamicsProcessing::MbcBandConfig{ .channel = std::get(params), .band = cutOffFreqs[i].first, .enable = std::get(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, public DynamicsProcessingTestHelper { public: DynamicsProcessingTestMbcBandConfig() : DynamicsProcessingTestHelper(std::get(GetParam())), mStageInUse(std::get(GetParam())) { fillMbcBandConfig(mCfgs, GetParam()); } void SetUp() override { SetUpDynamicsProcessingEffect(); } void TearDown() override { TearDownDynamicsProcessingEffect(); } std::vector mCfgs; const bool mStageInUse; }; TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) { mEngineConfigPreset.mbcStage.inUse = mStageInUse; mEngineConfigPreset.mbcStage.bandCount = mCfgs.size(); EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset)); std::vector cfgs(mChannelCount); for (int i = 0; i < mChannelCount; i++) { cfgs[i].channel = i; cfgs[i].enable = true; } EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(cfgs)); EXPECT_NO_FATAL_FAILURE(addMbcBandConfigs(mCfgs)); SetAndGetDynamicsProcessingParameters(); } INSTANTIATE_TEST_SUITE_P( DynamicsProcessingTest, DynamicsProcessingTestMbcBandConfig, ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())), testing::Values(-1, 0, 10), // channel count 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(info.param).second; std::vector cfgs; fillMbcBandConfig(cfgs, info.param); std::string mbcBands = ::android::internal::ToString(cfgs); std::string stageInUse = std::to_string(std::get(info.param)); std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + descriptor.common.name + "_UUID_" + descriptor.common.id.uuid.toString() + "_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(); }