Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5bd4a307 authored by Shunkai Yao's avatar Shunkai Yao
Browse files

Effect AIDL: Add AEC, AGC and NS AIDL vts

Bug: 238913361
Test: atest VtsHalAECTargetTest
Test: atest VtsHalAGCTargetTest
Test: atest VtsHalNSTargetTest
Change-Id: Ie28ceda35a7ed3fa7857b439bdd4180d9c202f92
parent bd862b82
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -20,6 +20,15 @@
    },
    {
      "name": "VtsHalVisualizerTargetTest"
    },
    {
      "name": "VtsHalAECTargetTest"
    },
    {
      "name": "VtsHalAGCTargetTest"
    },
    {
      "name": "VtsHalNSTargetTest"
    }
  ]
}
+18 −0
Original line number Diff line number Diff line
@@ -96,3 +96,21 @@ cc_test {
    defaults: ["VtsHalAudioTargetTestDefaults"],
    srcs: ["VtsHalVisualizerTargetTest.cpp"],
}

cc_test {
    name: "VtsHalAECTargetTest",
    defaults: ["VtsHalAudioTargetTestDefaults"],
    srcs: ["VtsHalAECTargetTest.cpp"],
}

cc_test {
    name: "VtsHalAGCTargetTest",
    defaults: ["VtsHalAudioTargetTestDefaults"],
    srcs: ["VtsHalAGCTargetTest.cpp"],
}

cc_test {
    name: "VtsHalNSTargetTest",
    defaults: ["VtsHalAudioTargetTestDefaults"],
    srcs: ["VtsHalNSTargetTest.cpp"],
}
+0 −1
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ class EffectFactoryHelper {
                }
            }
        }

        return result;
    }

+219 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <aidl/Vintf.h>
#include <algorithm>

#define LOG_TAG "VtsHalAECParamTest"

#include <Utils.h>
#include "EffectHelper.h"

using namespace android;

using aidl::android::hardware::audio::effect::AcousticEchoCanceler;
using aidl::android::hardware::audio::effect::Capability;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::hardware::audio::effect::kAcousticEchoCancelerTypeUUID;
using aidl::android::hardware::audio::effect::Parameter;

enum ParamName { PARAM_INSTANCE_NAME, PARAM_ECHO_DELAY, PARAM_MOBILE_MODE };
using AECParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
                                     int /* echoDelayUs */, bool /* mobileMode */>;

class AECParamTest : public ::testing::TestWithParam<AECParamTestParam>, public EffectHelper {
  public:
    AECParamTest()
        : mEchoDelay(std::get<PARAM_ECHO_DELAY>(GetParam())),
          mMobileMode(std::get<PARAM_MOBILE_MODE>(GetParam())) {
        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
    }

    void SetUp() override {
        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 */,
                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
        IEffect::OpenEffectReturn ret;
        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
        ASSERT_NE(nullptr, mEffect);
    }

    void TearDown() override {
        ASSERT_NO_FATAL_FAILURE(close(mEffect));
        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
    }

    Parameter::Specific getDefaultParamSpecific() {
        AcousticEchoCanceler aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(0);
        Parameter::Specific specific =
                Parameter::Specific::make<Parameter::Specific::acousticEchoCanceler>(aec);
        return specific;
    }

    static const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList;
    static const std::vector<int> kEchoDelayValues;
    static const std::vector<bool> kMobileModeValues;

    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
    std::shared_ptr<IFactory> mFactory;
    std::shared_ptr<IEffect> mEffect;
    Descriptor mDescriptor;

    int mEchoDelay;
    bool mMobileMode;

    void SetAndGetParameters() {
        for (auto& it : mTags) {
            auto& tag = it.first;
            auto& aec = it.second;

            // validate parameter
            Descriptor desc;
            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
            const bool valid = isTagInRange(tag, aec, desc);
            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;

            // set parameter
            Parameter expectParam;
            Parameter::Specific specific;
            specific.set<Parameter::Specific::acousticEchoCanceler>(aec);
            expectParam.set<Parameter::specific>(specific);
            EXPECT_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;
                AcousticEchoCanceler::Id specificId;
                specificId.set<AcousticEchoCanceler::Id::commonTag>(tag);
                id.set<Parameter::Id::acousticEchoCancelerTag>(specificId);
                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));

                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
                                                 << "\ngetParam:" << getParam.toString();
            }
        }
    }

    void addEchoDelayParam(int delay) {
        AcousticEchoCanceler aec;
        aec.set<AcousticEchoCanceler::echoDelayUs>(delay);
        mTags.push_back({AcousticEchoCanceler::echoDelayUs, aec});
    }

    void addMobileModeParam(bool mode) {
        AcousticEchoCanceler aec;
        aec.set<AcousticEchoCanceler::mobileMode>(mode);
        mTags.push_back({AcousticEchoCanceler::mobileMode, aec});
    }

    bool isTagInRange(const AcousticEchoCanceler::Tag& tag, const AcousticEchoCanceler& aec,
                      const Descriptor& desc) const {
        const AcousticEchoCanceler::Capability& aecCap =
                desc.capability.get<Capability::acousticEchoCanceler>();
        switch (tag) {
            case AcousticEchoCanceler::echoDelayUs: {
                return isEchoDelayInRange(aecCap, aec.get<AcousticEchoCanceler::echoDelayUs>());
            }
            case AcousticEchoCanceler::mobileMode: {
                bool mode = aec.get<AcousticEchoCanceler::mobileMode>();
                return isMobileModeValid(aecCap, mode);
            }
            default:
                return false;
        }
    }

    bool isEchoDelayInRange(const AcousticEchoCanceler::Capability& cap, int delay) const {
        return (delay >= 0 && delay <= cap.maxEchoDelayUs);
    }

    bool isMobileModeValid(const AcousticEchoCanceler::Capability& cap, bool mode) const {
        if (cap.supportMobileMode) {
            return true;
        } else {
            return mode == false;
        }
    }

    static std::vector<int> getEchoDelayTestValues() {
        const auto max = std::max_element(
                kFactoryDescList.begin(), kFactoryDescList.end(),
                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
                    return a.second.capability.get<Capability::acousticEchoCanceler>()
                                   .maxEchoDelayUs <
                           b.second.capability.get<Capability::acousticEchoCanceler>()
                                   .maxEchoDelayUs;
                });
        if (max == kFactoryDescList.end()) {
            return {0};
        }
        int maxDelay =
                max->second.capability.get<Capability::acousticEchoCanceler>().maxEchoDelayUs;
        return {-1, 0, maxDelay - 1, maxDelay, maxDelay + 1};
    }

  private:
    std::vector<std::pair<AcousticEchoCanceler::Tag, AcousticEchoCanceler>> mTags;
    void CleanUp() { mTags.clear(); }
};

const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> AECParamTest::kFactoryDescList =
        EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
                                                     kAcousticEchoCancelerTypeUUID);
const std::vector<int> AECParamTest::kEchoDelayValues = AECParamTest::getEchoDelayTestValues();
const std::vector<bool> AECParamTest::kMobileModeValues = {true, false};

TEST_P(AECParamTest, SetAndGetEchoDelay) {
    EXPECT_NO_FATAL_FAILURE(addEchoDelayParam(mEchoDelay));
    SetAndGetParameters();
}

TEST_P(AECParamTest, SetAndGetMobileMode) {
    EXPECT_NO_FATAL_FAILURE(addMobileModeParam(mMobileMode));
    SetAndGetParameters();
}

INSTANTIATE_TEST_SUITE_P(AECParamTest, AECParamTest,
                         ::testing::Combine(testing::ValuesIn(AECParamTest::kFactoryDescList),
                                            testing::ValuesIn(AECParamTest::kEchoDelayValues),
                                            testing::ValuesIn(AECParamTest::kMobileModeValues)),
                         [](const testing::TestParamInfo<AECParamTest::ParamType>& info) {
                             auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
                             std::string name = "Implementor_" + descriptor.common.implementor +
                                                "_name_" + descriptor.common.name + "_UUID_" +
                                                descriptor.common.id.uuid.toString();
                             std::replace_if(
                                     name.begin(), name.end(),
                                     [](const char c) { return !std::isalnum(c); }, '_');
                             return name;
                         });

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AECParamTest);

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    ABinderProcess_setThreadPoolMaxThreadCount(1);
    ABinderProcess_startThreadPool();
    return RUN_ALL_TESTS();
}
 No newline at end of file
+256 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <aidl/Vintf.h>

#define LOG_TAG "VtsHalAGCParamTest"

#include <Utils.h>
#include "EffectHelper.h"

using namespace android;

using aidl::android::hardware::audio::effect::AutomaticGainControl;
using aidl::android::hardware::audio::effect::Capability;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::hardware::audio::effect::kAutomaticGainControlTypeUUID;
using aidl::android::hardware::audio::effect::Parameter;

enum ParamName {
    PARAM_INSTANCE_NAME,
    PARAM_DIGITAL_GAIN,
    PARAM_SATURATION_MARGIN,
    PARAM_LEVEL_ESTIMATOR
};
using AGCParamTestParam =
        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int /* gain */,
                   int /* margin */, AutomaticGainControl::LevelEstimator>;

class AGCParamTest : public ::testing::TestWithParam<AGCParamTestParam>, public EffectHelper {
  public:
    AGCParamTest()
        : mGain(std::get<PARAM_DIGITAL_GAIN>(GetParam())),
          mMargin(std::get<PARAM_SATURATION_MARGIN>(GetParam())),
          mLevelEstimator(std::get<PARAM_LEVEL_ESTIMATOR>(GetParam())) {
        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
    }

    void SetUp() override {
        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 */,
                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
        IEffect::OpenEffectReturn ret;
        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
        ASSERT_NE(nullptr, mEffect);
    }

    void TearDown() override {
        ASSERT_NO_FATAL_FAILURE(close(mEffect));
        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
    }

    Parameter::Specific getDefaultParamSpecific() {
        AutomaticGainControl AGC =
                AutomaticGainControl::make<AutomaticGainControl::fixedDigitalGainMb>(0);
        Parameter::Specific specific =
                Parameter::Specific::make<Parameter::Specific::automaticGainControl>(AGC);
        return specific;
    }

    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
    static const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList;
    static const std::vector<int> kDigitalGainValues;
    static const std::vector<int> kSaturationMarginValues;
    static const std::vector<AutomaticGainControl::LevelEstimator> kLevelEstimatorValues;

    std::shared_ptr<IFactory> mFactory;
    std::shared_ptr<IEffect> mEffect;
    Descriptor mDescriptor;
    int mGain;
    int mMargin;
    AutomaticGainControl::LevelEstimator mLevelEstimator;

    void SetAndGetParameters() {
        for (auto& it : mTags) {
            auto& tag = it.first;
            auto& AGC = it.second;

            // validate parameter
            Descriptor desc;
            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
            const bool valid = isTagInRange(tag, AGC, desc);
            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;

            // set parameter
            Parameter expectParam;
            Parameter::Specific specific;
            specific.set<Parameter::Specific::automaticGainControl>(AGC);
            expectParam.set<Parameter::specific>(specific);
            EXPECT_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;
                AutomaticGainControl::Id specificId;
                specificId.set<AutomaticGainControl::Id::commonTag>(tag);
                id.set<Parameter::Id::automaticGainControlTag>(specificId);
                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));

                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
                                                 << "\ngetParam:" << getParam.toString();
            }
        }
    }

    void addDigitalGainParam(int gain) {
        AutomaticGainControl AGC;
        AGC.set<AutomaticGainControl::fixedDigitalGainMb>(gain);
        mTags.push_back({AutomaticGainControl::fixedDigitalGainMb, AGC});
    }
    void addSaturationMarginParam(int margin) {
        AutomaticGainControl AGC;
        AGC.set<AutomaticGainControl::saturationMarginMb>(margin);
        mTags.push_back({AutomaticGainControl::saturationMarginMb, AGC});
    }
    void addLevelEstimatorParam(AutomaticGainControl::LevelEstimator levelEstimator) {
        AutomaticGainControl AGC;
        AGC.set<AutomaticGainControl::levelEstimator>(levelEstimator);
        mTags.push_back({AutomaticGainControl::levelEstimator, AGC});
    }

    bool isTagInRange(const AutomaticGainControl::Tag& tag, const AutomaticGainControl& AGC,
                      const Descriptor& desc) const {
        const AutomaticGainControl::Capability& AGCCap =
                desc.capability.get<Capability::automaticGainControl>();
        switch (tag) {
            case AutomaticGainControl::fixedDigitalGainMb: {
                auto gain = AGC.get<AutomaticGainControl::fixedDigitalGainMb>();
                return gain >= 0 && gain <= AGCCap.maxFixedDigitalGainMb;
            }
            case AutomaticGainControl::levelEstimator: {
                return true;
            }
            case AutomaticGainControl::saturationMarginMb: {
                auto margin = AGC.get<AutomaticGainControl::saturationMarginMb>();
                return margin >= 0 && margin <= AGCCap.maxSaturationMarginMb;
            }
            default:
                return false;
        }
    }
    static std::vector<int> getDigitalGainValues() {
        const auto max = std::max_element(
                kFactoryDescList.begin(), kFactoryDescList.end(),
                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
                    return a.second.capability.get<Capability::automaticGainControl>()
                                   .maxFixedDigitalGainMb <
                           b.second.capability.get<Capability::automaticGainControl>()
                                   .maxFixedDigitalGainMb;
                });
        if (max == kFactoryDescList.end()) {
            return {0};
        }
        int maxGain = max->second.capability.get<Capability::automaticGainControl>()
                              .maxFixedDigitalGainMb;
        return {-1, 0, maxGain - 1, maxGain, maxGain + 1};
    }
    static std::vector<int> getSaturationMarginValues() {
        const auto max = std::max_element(
                kFactoryDescList.begin(), kFactoryDescList.end(),
                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
                    return a.second.capability.get<Capability::automaticGainControl>()
                                   .maxSaturationMarginMb <
                           b.second.capability.get<Capability::automaticGainControl>()
                                   .maxSaturationMarginMb;
                });
        if (max == kFactoryDescList.end()) {
            return {0};
        }
        int maxMargin = max->second.capability.get<Capability::automaticGainControl>()
                                .maxSaturationMarginMb;
        return {-1, 0, maxMargin - 1, maxMargin, maxMargin + 1};
    }

  private:
    std::vector<std::pair<AutomaticGainControl::Tag, AutomaticGainControl>> mTags;
    void CleanUp() { mTags.clear(); }
};

const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> AGCParamTest::kFactoryDescList =
        EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
                                                     kAutomaticGainControlTypeUUID);
const std::vector<int> AGCParamTest::kDigitalGainValues = AGCParamTest::getDigitalGainValues();
const std::vector<int> AGCParamTest::kSaturationMarginValues =
        AGCParamTest::getSaturationMarginValues();
const std::vector<AutomaticGainControl::LevelEstimator> AGCParamTest::kLevelEstimatorValues = {
        AutomaticGainControl::LevelEstimator::RMS, AutomaticGainControl::LevelEstimator::PEAK};

TEST_P(AGCParamTest, SetAndGetDigitalGainParam) {
    EXPECT_NO_FATAL_FAILURE(addDigitalGainParam(mGain));
    SetAndGetParameters();
}

TEST_P(AGCParamTest, SetAndGetSaturationMargin) {
    EXPECT_NO_FATAL_FAILURE(addSaturationMarginParam(mMargin));
    SetAndGetParameters();
}

TEST_P(AGCParamTest, SetAndGetLevelEstimator) {
    EXPECT_NO_FATAL_FAILURE(addLevelEstimatorParam(mLevelEstimator));
    SetAndGetParameters();
}

INSTANTIATE_TEST_SUITE_P(
        AGCParamTest, AGCParamTest,
        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
                                   IFactory::descriptor, kAutomaticGainControlTypeUUID)),
                           testing::ValuesIn(AGCParamTest::kDigitalGainValues),
                           testing::ValuesIn(AGCParamTest::kSaturationMarginValues),
                           testing::ValuesIn(AGCParamTest::kLevelEstimatorValues)),
        [](const testing::TestParamInfo<AGCParamTest::ParamType>& info) {
            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
            std::string gain = std::to_string(std::get<PARAM_DIGITAL_GAIN>(info.param));
            std::string estimator = aidl::android::hardware::audio::effect::toString(
                    std::get<PARAM_LEVEL_ESTIMATOR>(info.param));
            std::string margin =
                    std::to_string(static_cast<int>(std::get<PARAM_SATURATION_MARGIN>(info.param)));

            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
                               descriptor.common.name + "_UUID_" +
                               descriptor.common.id.uuid.toString() + "_digital_gain_" + gain +
                               "_level_estimator_" + estimator + "_margin_" + margin;
            std::replace_if(
                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
            return name;
        });

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AGCParamTest);

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    ABinderProcess_setThreadPoolMaxThreadCount(1);
    ABinderProcess_startThreadPool();
    return RUN_ALL_TESTS();
}
 No newline at end of file
Loading