diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING index dfd82c3d41..3c58324b66 100644 --- a/audio/aidl/TEST_MAPPING +++ b/audio/aidl/TEST_MAPPING @@ -15,6 +15,9 @@ { "name": "VtsHalEqualizerTargetTest" }, + { + "name": "VtsHalHapticGeneratorTargetTest" + }, { "name": "VtsHalLoudnessEnhancerTargetTest" }, diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp index 8004631c4f..f6211c467d 100644 --- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp +++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp @@ -84,16 +84,71 @@ ndk::ScopedAStatus HapticGeneratorSw::getDescriptor(Descriptor* _aidl_return) { ndk::ScopedAStatus HapticGeneratorSw::setParameterSpecific(const Parameter::Specific& specific) { RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT, "EffectNotSupported"); - mSpecificParam = specific.get(); - LOG(DEBUG) << __func__ << " success with: " << specific.toString(); - return ndk::ScopedAStatus::ok(); + RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); + + auto& hgParam = specific.get(); + auto tag = hgParam.getTag(); + + switch (tag) { + case HapticGenerator::hapticScale: { + RETURN_IF(mContext->setHgHapticScale(hgParam.get()) != + RetCode::SUCCESS, + EX_ILLEGAL_ARGUMENT, "HapticScaleNotSupported"); + return ndk::ScopedAStatus::ok(); + } + case HapticGenerator::vibratorInfo: { + RETURN_IF(mContext->setHgVibratorInformation( + hgParam.get()) != RetCode::SUCCESS, + EX_ILLEGAL_ARGUMENT, "VibratorInfoNotSupported"); + return ndk::ScopedAStatus::ok(); + } + default: { + LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); + return ndk::ScopedAStatus::fromExceptionCodeWithMessage( + EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported"); + } + } } ndk::ScopedAStatus HapticGeneratorSw::getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific) { auto tag = id.getTag(); RETURN_IF(Parameter::Id::hapticGeneratorTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag"); - specific->set(mSpecificParam); + auto hgId = id.get(); + auto hgIdTag = hgId.getTag(); + switch (hgIdTag) { + case HapticGenerator::Id::commonTag: + return getParameterHapticGenerator(hgId.get(), + specific); + default: + LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); + return ndk::ScopedAStatus::fromExceptionCodeWithMessage( + EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported"); + } +} + +ndk::ScopedAStatus HapticGeneratorSw::getParameterHapticGenerator(const HapticGenerator::Tag& tag, + Parameter::Specific* specific) { + RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext"); + + HapticGenerator hgParam; + switch (tag) { + case HapticGenerator::hapticScale: { + hgParam.set(mContext->getHgHapticScale()); + break; + } + case HapticGenerator::vibratorInfo: { + hgParam.set(mContext->getHgVibratorInformation()); + break; + } + default: { + LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag); + return ndk::ScopedAStatus::fromExceptionCodeWithMessage( + EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported"); + } + } + + specific->set(hgParam); return ndk::ScopedAStatus::ok(); } diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h index bf01bfbfc3..d9ec74471d 100644 --- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h +++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h @@ -32,7 +32,31 @@ class HapticGeneratorSwContext final : public EffectContext { : EffectContext(statusDepth, common) { LOG(DEBUG) << __func__; } - // TODO: add specific context here + + RetCode setHgHapticScale(const HapticGenerator::HapticScale& hapticScale) { + // All int values are valid for ID + mHapticScale = hapticScale; + return RetCode::SUCCESS; + } + HapticGenerator::HapticScale getHgHapticScale() const { return mHapticScale; } + + RetCode setHgVibratorInformation(const HapticGenerator::VibratorInformation& vibratorInfo) { + // All float values are valid for resonantFrequencyHz, qFactor, maxAmplitude + mVibratorInformation = vibratorInfo; + return RetCode::SUCCESS; + } + + HapticGenerator::VibratorInformation getHgVibratorInformation() const { + return mVibratorInformation; + } + + private: + static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f; + static constexpr float DEFAULT_Q_FACTOR = 1.0f; + static constexpr float DEFAULT_MAX_AMPLITUDE = 0.0f; + HapticGenerator::HapticScale mHapticScale = {0, HapticGenerator::VibratorScale::MUTE}; + HapticGenerator::VibratorInformation mVibratorInformation = { + DEFAULT_RESONANT_FREQUENCY, DEFAULT_Q_FACTOR, DEFAULT_MAX_AMPLITUDE}; }; class HapticGeneratorSw final : public EffectImpl { @@ -60,7 +84,8 @@ class HapticGeneratorSw final : public EffectImpl { private: std::shared_ptr mContext; - /* parameters */ - HapticGenerator mSpecificParam; + + ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::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 aeff615a5e..dcdecab4fe 100644 --- a/audio/aidl/vts/Android.bp +++ b/audio/aidl/vts/Android.bp @@ -85,6 +85,12 @@ cc_test { srcs: ["VtsHalEqualizerTargetTest.cpp"], } +cc_test { + name: "VtsHalHapticGeneratorTargetTest", + defaults: ["VtsHalAudioTargetTestDefaults"], + srcs: ["VtsHalHapticGeneratorTargetTest.cpp"], +} + cc_test { name: "VtsHalLoudnessEnhancerTargetTest", defaults: ["VtsHalAudioTargetTestDefaults"], diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp new file mode 100644 index 0000000000..a1daec2f04 --- /dev/null +++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp @@ -0,0 +1,245 @@ +/* + * 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 "VtsHalHapticGeneratorTargetTest" + +#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::HapticGenerator; +using aidl::android::hardware::audio::effect::IEffect; +using aidl::android::hardware::audio::effect::IFactory; +using aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID; +using aidl::android::hardware::audio::effect::Parameter; + +/** + * Here we focus on specific parameter checking, general IEffect interfaces testing performed in + * VtsAudioEffectTargetTest. + */ +enum ParamName { + PARAM_INSTANCE_NAME, + PARAM_HAPTIC_SCALE_ID, + PARAM_HAPTIC_SCALE_VIBRATOR_SCALE, + PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY, + PARAM_VIBRATION_INFORMATION_Q_FACTOR, + PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE, +}; +using HapticGeneratorParamTestParam = + std::tuple, Descriptor>, int, + HapticGenerator::VibratorScale, float, float, float>; + +/* + * 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. + */ + +// TODO : Update the test values once range/capability is updated by implementation +const int MIN_ID = std::numeric_limits::min(); +const int MAX_ID = std::numeric_limits::max(); +const float MIN_FLOAT = std::numeric_limits::min(); +const float MAX_FLOAT = std::numeric_limits::max(); + +const std::vector kHapticScaleIdValues = {MIN_ID, 0, MAX_ID}; +const std::vector kVibratorScaleValues = { + HapticGenerator::VibratorScale::MUTE, HapticGenerator::VibratorScale::VERY_LOW, + HapticGenerator::VibratorScale::LOW, HapticGenerator::VibratorScale::NONE, + HapticGenerator::VibratorScale::HIGH, HapticGenerator::VibratorScale::VERY_HIGH}; + +const std::vector kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT}; +const std::vector kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT}; +const std::vector kMaxAmplitude = {MIN_FLOAT, 100, MAX_FLOAT}; + +class HapticGeneratorParamTest : public ::testing::TestWithParam, + public EffectHelper { + public: + HapticGeneratorParamTest() + : mParamHapticScaleId(std::get(GetParam())), + mParamVibratorScale(std::get(GetParam())), + mParamResonantFrequency( + std::get(GetParam())), + mParamQFactor(std::get(GetParam())), + mParamMaxAmplitude(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() { + HapticGenerator::HapticScale hapticScale = {.id = 0, + .scale = HapticGenerator::VibratorScale::MUTE}; + HapticGenerator hg = HapticGenerator::make(hapticScale); + Parameter::Specific specific = + Parameter::Specific::make(hg); + return specific; + } + + static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100; + std::shared_ptr mFactory; + std::shared_ptr mEffect; + Descriptor mDescriptor; + int mParamHapticScaleId = 0; + HapticGenerator::VibratorScale mParamVibratorScale = HapticGenerator::VibratorScale::MUTE; + float mParamResonantFrequency = 0; + float mParamQFactor = 0; + float mParamMaxAmplitude = 0; + + void SetAndGetHapticGeneratorParameters() { + for (auto& it : mTags) { + auto& tag = it.first; + auto& hg = it.second; + + // set parameter + Parameter expectParam; + Parameter::Specific specific; + specific.set(hg); + expectParam.set(specific); + EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString(); + + // get parameter + Parameter getParam; + Parameter::Id id; + HapticGenerator::Id hgId; + hgId.set(tag); + id.set(hgId); + EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam)); + EXPECT_EQ(expectParam, getParam); + } + } + + void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) { + HapticGenerator hg; + HapticGenerator::HapticScale hapticScale = {.id = id, .scale = scale}; + hg.set(hapticScale); + mTags.push_back({HapticGenerator::hapticScale, hg}); + } + + void addVibratorInformationParam(float resonantFrequencyHz, float qFactor, float maxAmplitude) { + HapticGenerator hg; + HapticGenerator::VibratorInformation vibrationInfo = { + .resonantFrequencyHz = resonantFrequencyHz, + .qFactor = qFactor, + .maxAmplitude = maxAmplitude}; + hg.set(vibrationInfo); + mTags.push_back({HapticGenerator::vibratorInfo, hg}); + } + + private: + std::vector> mTags; + + void CleanUp() { mTags.clear(); } +}; + +TEST_P(HapticGeneratorParamTest, SetAndGetHapticScale) { + EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale)); + SetAndGetHapticGeneratorParameters(); +} + +TEST_P(HapticGeneratorParamTest, SetAndGetVibratorInformation) { + EXPECT_NO_FATAL_FAILURE(addVibratorInformationParam(mParamResonantFrequency, mParamQFactor, + mParamMaxAmplitude)); + SetAndGetHapticGeneratorParameters(); +} + +INSTANTIATE_TEST_SUITE_P( + HapticGeneratorValidTest, HapticGeneratorParamTest, + ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( + IFactory::descriptor, kHapticGeneratorTypeUUID)), + testing::ValuesIn(kHapticScaleIdValues), + testing::ValuesIn(kVibratorScaleValues), + testing::ValuesIn(kResonantFrequencyValues), + testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)), + [](const testing::TestParamInfo& info) { + auto descriptor = std::get(info.param).second; + std::string hapticScaleID = std::to_string(std::get(info.param)); + std::string hapticScaleVibScale = std::to_string( + static_cast(std::get(info.param))); + std::string resonantFrequency = std::to_string( + std::get(info.param)); + std::string qFactor = + std::to_string(std::get(info.param)); + std::string maxAmplitude = + std::to_string(std::get(info.param)); + std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + + descriptor.common.name + "_UUID_" + + descriptor.common.id.uuid.toString() + "_hapticScaleId" + + hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale + + "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor + + "_maxAmplitude" + maxAmplitude; + std::replace_if( + name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); + return name; + }); + +INSTANTIATE_TEST_SUITE_P( + HapticGeneratorInvalidTest, HapticGeneratorParamTest, + ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( + IFactory::descriptor, kHapticGeneratorTypeUUID)), + testing::Values(MIN_ID - 1), + testing::Values(HapticGenerator::VibratorScale::MUTE), + testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT), + testing::Values(MIN_FLOAT)), + [](const testing::TestParamInfo& info) { + auto descriptor = std::get(info.param).second; + std::string hapticScaleID = std::to_string(std::get(info.param)); + std::string hapticScaleVibScale = std::to_string( + static_cast(std::get(info.param))); + std::string resonantFrequency = std::to_string( + std::get(info.param)); + std::string qFactor = + std::to_string(std::get(info.param)); + std::string maxAmplitude = + std::to_string(std::get(info.param)); + std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + + descriptor.common.name + "_UUID_" + + descriptor.common.id.uuid.toString() + "_hapticScaleId" + + hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale + + "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor + + "_maxAmplitude" + maxAmplitude; + std::replace_if( + name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); + return name; + }); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorParamTest); + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); + return RUN_ALL_TESTS(); +}