diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING index a2c7966860..bf86d01572 100644 --- a/audio/aidl/TEST_MAPPING +++ b/audio/aidl/TEST_MAPPING @@ -24,6 +24,9 @@ { "name": "VtsHalLoudnessEnhancerTargetTest" }, + { + "name": "VtsHalVirtualizerTargetTest" + }, { "name": "VtsHalVisualizerTargetTest" }, diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl index d4fb9e0110..deaff9059e 100644 --- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl +++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl @@ -36,6 +36,8 @@ package android.hardware.audio.effect; union Virtualizer { android.hardware.audio.effect.VendorExtension vendor; int strengthPm; + const int MIN_PER_MILLE_STRENGTH = 0; + const int MAX_PER_MILLE_STRENGTH = 1000; @VintfStability union Id { int vendorExtensionTag; diff --git a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl index 9d039bc58f..90ec6f8352 100644 --- a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl +++ b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl @@ -59,6 +59,16 @@ union Virtualizer { boolean strengthSupported; } + /** + * Minimal possible per mille strength. + */ + const int MIN_PER_MILLE_STRENGTH = 0; + + /** + * Maximum possible per mille strength. + */ + const int MAX_PER_MILLE_STRENGTH = 1000; + /** * The per mille strength of the virtualizer effect. * diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp index faa630eb61..418010578e 100644 --- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp +++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp @@ -60,7 +60,9 @@ extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descrip namespace aidl::android::hardware::audio::effect { const std::string VirtualizerSw::kEffectName = "VirtualizerSw"; -const Virtualizer::Capability VirtualizerSw::kCapability; +const bool VirtualizerSw::kStrengthSupported = true; +const Virtualizer::Capability VirtualizerSw::kCapability = {.strengthSupported = + kStrengthSupported}; const Descriptor VirtualizerSw::kDescriptor = { .common = {.id = {.type = kVirtualizerTypeUUID, .uuid = kVirtualizerSwImplUUID, @@ -82,16 +84,60 @@ ndk::ScopedAStatus VirtualizerSw::setParameterSpecific(const Parameter::Specific RETURN_IF(Parameter::Specific::virtualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT, "EffectNotSupported"); - mSpecificParam = specific.get(); - LOG(DEBUG) << __func__ << " success with: " << specific.toString(); - return ndk::ScopedAStatus::ok(); + auto& vrParam = specific.get(); + auto tag = vrParam.getTag(); + + switch (tag) { + case Virtualizer::strengthPm: { + RETURN_IF(!kStrengthSupported, EX_ILLEGAL_ARGUMENT, "SettingStrengthNotSupported"); + + RETURN_IF(mContext->setVrStrength(vrParam.get()) != + RetCode::SUCCESS, + EX_ILLEGAL_ARGUMENT, "strengthPmNotSupported"); + return ndk::ScopedAStatus::ok(); + } + default: { + LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); + return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, + "VirtualizerTagNotSupported"); + } + } } ndk::ScopedAStatus VirtualizerSw::getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific) { auto tag = id.getTag(); RETURN_IF(Parameter::Id::virtualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag"); - specific->set(mSpecificParam); + auto vrId = id.get(); + auto vrIdTag = vrId.getTag(); + switch (vrIdTag) { + case Virtualizer::Id::commonTag: + return getParameterVirtualizer(vrId.get(), specific); + default: + LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); + return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, + "VirtualizerTagNotSupported"); + } +} + +ndk::ScopedAStatus VirtualizerSw::getParameterVirtualizer(const Virtualizer::Tag& tag, + Parameter::Specific* specific) { + RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); + + Virtualizer vrParam; + switch (tag) { + case Virtualizer::strengthPm: { + vrParam.set(mContext->getVrStrength()); + break; + } + default: { + LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); + return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, + "VirtualizerTagNotSupported"); + } + } + + specific->set(vrParam); return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h index 4a05678cf6..05974a8fed 100644 --- a/audio/aidl/default/virtualizer/VirtualizerSw.h +++ b/audio/aidl/default/virtualizer/VirtualizerSw.h @@ -32,12 +32,26 @@ class VirtualizerSwContext final : public EffectContext { : EffectContext(statusDepth, common) { LOG(DEBUG) << __func__; } - // TODO: add specific context here + RetCode setVrStrength(int strength) { + if (strength < Virtualizer::MIN_PER_MILLE_STRENGTH || + strength > Virtualizer::MAX_PER_MILLE_STRENGTH) { + LOG(ERROR) << __func__ << " invalid strength " << strength; + return RetCode::ERROR_ILLEGAL_PARAMETER; + } + // TODO : Add implementation to apply new strength + mStrength = strength; + return RetCode::SUCCESS; + } + int getVrStrength() const { return mStrength; } + + private: + int mStrength; }; class VirtualizerSw final : public EffectImpl { public: static const std::string kEffectName; + static const bool kStrengthSupported; static const Virtualizer::Capability kCapability; static const Descriptor kDescriptor; VirtualizerSw() { LOG(DEBUG) << __func__; } @@ -60,7 +74,8 @@ class VirtualizerSw final : public EffectImpl { private: std::shared_ptr mContext; - /* parameters */ - Virtualizer mSpecificParam; + + ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Tag& tag, + Parameter::Specific* specific); }; } // namespace aidl::android::hardware::audio::effect diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp index 4ca3d9e57c..f1e26acdaa 100644 --- a/audio/aidl/vts/Android.bp +++ b/audio/aidl/vts/Android.bp @@ -103,6 +103,12 @@ cc_test { srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"], } +cc_test { + name: "VtsHalVirtualizerTargetTest", + defaults: ["VtsHalAudioTargetTestDefaults"], + srcs: ["VtsHalVirtualizerTargetTest.cpp"], +} + cc_test { name: "VtsHalVisualizerTargetTest", defaults: ["VtsHalAudioTargetTestDefaults"], diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp new file mode 100644 index 0000000000..61776b2b6e --- /dev/null +++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp @@ -0,0 +1,181 @@ +/* + * 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. + */ + +#define LOG_TAG "VtsHalVirtualizerTest" + +#include +#include +#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::IEffect; +using aidl::android::hardware::audio::effect::IFactory; +using aidl::android::hardware::audio::effect::kVirtualizerTypeUUID; +using aidl::android::hardware::audio::effect::Parameter; +using aidl::android::hardware::audio::effect::Virtualizer; + +/** + * Here we focus on specific parameter checking, general IEffect interfaces testing performed in + * VtsAudioEffectTargetTest. + */ +enum ParamName { PARAM_INSTANCE_NAME, PARAM_STRENGTH }; +using VirtualizerParamTestParam = std::tuple, Descriptor>, int>; + +/* + * Testing parameter range, assuming the parameter supported by effect is in this range. + * Parameter should be within the valid range defined in the documentation, + * for any supported value test expects EX_NONE from IEffect.setParameter(), + * otherwise expect EX_ILLEGAL_ARGUMENT. + */ + +const std::vector kStrengthValues = { + std::numeric_limits::min(), Virtualizer::MIN_PER_MILLE_STRENGTH - 1, + Virtualizer::MIN_PER_MILLE_STRENGTH, Virtualizer::MAX_PER_MILLE_STRENGTH, + Virtualizer::MAX_PER_MILLE_STRENGTH + 1, std::numeric_limits::max()}; + +class VirtualizerParamTest : public ::testing::TestWithParam, + public EffectHelper { + public: + VirtualizerParamTest() : mParamStrength(std::get(GetParam())) { + std::tie(mFactory, mDescriptor) = std::get(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() { + Virtualizer vr = + Virtualizer::make(Virtualizer::MIN_PER_MILLE_STRENGTH); + Parameter::Specific specific = + Parameter::Specific::make(vr); + return specific; + } + + static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100; + std::shared_ptr mFactory; + std::shared_ptr mEffect; + Descriptor mDescriptor; + int mParamStrength = Virtualizer::MIN_PER_MILLE_STRENGTH; + + void SetAndGetVirtualizerParameters() { + for (auto& it : mTags) { + auto& tag = it.first; + auto& vr = it.second; + + // validate parameter + Descriptor desc; + ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc)); + const bool valid = isTagInRange(it.first, it.second, desc); + const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT; + + // set parameter + Parameter expectParam; + Parameter::Specific specific; + specific.set(vr); + expectParam.set(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; + Virtualizer::Id vrId; + vrId.set(tag); + id.set(vrId); + // if set success, then get should match + EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam)); + EXPECT_EQ(expectParam, getParam); + } + } + } + + void addStrengthParam(int strength) { + Virtualizer vr; + vr.set(strength); + mTags.push_back({Virtualizer::strengthPm, vr}); + } + + bool isTagInRange(const Virtualizer::Tag& tag, const Virtualizer& vr, + const Descriptor& desc) const { + const Virtualizer::Capability& vrCap = desc.capability.get(); + switch (tag) { + case Virtualizer::strengthPm: { + int strength = vr.get(); + return isStrengthInRange(vrCap, strength); + } + default: + return false; + } + return false; + } + + bool isStrengthInRange(const Virtualizer::Capability& cap, int strength) const { + return cap.strengthSupported && strength >= Virtualizer::MIN_PER_MILLE_STRENGTH && + strength <= Virtualizer::MAX_PER_MILLE_STRENGTH; + } + + private: + std::vector> mTags; + void CleanUp() { mTags.clear(); } +}; + +TEST_P(VirtualizerParamTest, SetAndGetStrength) { + EXPECT_NO_FATAL_FAILURE(addStrengthParam(mParamStrength)); + SetAndGetVirtualizerParameters(); +} + +INSTANTIATE_TEST_SUITE_P( + VirtualizerTest, VirtualizerParamTest, + ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( + IFactory::descriptor, kVirtualizerTypeUUID)), + testing::ValuesIn(kStrengthValues)), + [](const testing::TestParamInfo& info) { + auto descriptor = std::get(info.param).second; + std::string strength = std::to_string(std::get(info.param)); + std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + + descriptor.common.name + "_UUID_" + + descriptor.common.id.uuid.toString() + "_strength" + strength; + std::replace_if( + name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); + return name; + }); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VirtualizerParamTest); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); + return RUN_ALL_TESTS(); +}