Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 17 | #include <map> |
| 18 | #include <utility> |
| 19 | #include <vector> |
Shunkai Yao | ab59e6d | 2022-12-22 00:45:23 +0000 | [diff] [blame] | 20 | |
Mikhail Naganov | 872d4a6 | 2023-03-09 18:19:01 -0800 | [diff] [blame] | 21 | #define LOG_TAG "VtsHalHapticGeneratorTargetTest" |
| 22 | #include <android-base/logging.h> |
| 23 | #include <android/binder_enums.h> |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 24 | #include <audio_utils/power.h> |
Mikhail Naganov | 872d4a6 | 2023-03-09 18:19:01 -0800 | [diff] [blame] | 25 | |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 26 | #include "EffectHelper.h" |
| 27 | |
| 28 | using namespace android; |
| 29 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 30 | using aidl::android::hardware::audio::common::getChannelCount; |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 31 | using aidl::android::hardware::audio::effect::Descriptor; |
Shunkai Yao | f8be1ac | 2023-03-06 18:41:27 +0000 | [diff] [blame] | 32 | using aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator; |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 33 | using aidl::android::hardware::audio::effect::HapticGenerator; |
| 34 | using aidl::android::hardware::audio::effect::IEffect; |
| 35 | using aidl::android::hardware::audio::effect::IFactory; |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 36 | using aidl::android::hardware::audio::effect::Parameter; |
Jaideep Sharma | 7449841 | 2023-09-13 15:25:25 +0530 | [diff] [blame] | 37 | using android::hardware::audio::common::testing::detail::TestExecutionTracer; |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 38 | |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 39 | const int MIN_ID = std::numeric_limits<int>::min(); |
| 40 | const int MAX_ID = std::numeric_limits<int>::max(); |
| 41 | const float MIN_FLOAT = std::numeric_limits<float>::min(); |
| 42 | const float MAX_FLOAT = std::numeric_limits<float>::max(); |
| 43 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 44 | std::vector<HapticGenerator::VibratorScale> kScaleValues = { |
Shunkai Yao | ab59e6d | 2022-12-22 00:45:23 +0000 | [diff] [blame] | 45 | ndk::enum_range<HapticGenerator::VibratorScale>().begin(), |
| 46 | ndk::enum_range<HapticGenerator::VibratorScale>().end()}; |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 47 | |
Lais Andrade | 90381a3 | 2024-08-09 18:04:14 +0100 | [diff] [blame] | 48 | const std::vector<float> kScaleFactorValues = {HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR, |
| 49 | 0.0f, 0.5f, 1.0f, MAX_FLOAT}; |
| 50 | const std::vector<float> kAdaptiveScaleFactorValues = { |
| 51 | HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR, 0.0f, 0.5f, 1.0f, MAX_FLOAT}; |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 52 | |
| 53 | const std::vector<float> kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT}; |
| 54 | const std::vector<float> kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT}; |
| 55 | const std::vector<float> kMaxAmplitude = {MIN_FLOAT, 100, MAX_FLOAT}; |
| 56 | |
Lais Andrade | 87d179b | 2024-09-04 13:57:45 +0100 | [diff] [blame] | 57 | constexpr int HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION = 3; |
| 58 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 59 | static const std::vector<int32_t> kHapticOutputLayouts = { |
| 60 | AudioChannelLayout::LAYOUT_MONO_HAPTIC_A, AudioChannelLayout::LAYOUT_MONO_HAPTIC_AB, |
| 61 | AudioChannelLayout::LAYOUT_STEREO_HAPTIC_A, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_AB}; |
| 62 | |
| 63 | class HapticGeneratorHelper : public EffectHelper { |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 64 | public: |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 65 | void SetUpHapticGenerator(int32_t chMask = AudioChannelLayout::CHANNEL_HAPTIC_A) { |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 66 | ASSERT_NE(nullptr, mFactory); |
| 67 | ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); |
Lais Andrade | 87d179b | 2024-09-04 13:57:45 +0100 | [diff] [blame] | 68 | EXPECT_STATUS(EX_NONE, mEffect->getInterfaceVersion(&mEffectInterfaceVersion)); |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 69 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 70 | AudioChannelLayout layout = |
| 71 | AudioChannelLayout::make<AudioChannelLayout::layoutMask>(chMask); |
| 72 | |
Shunkai Yao | 61f9dd2 | 2024-05-08 22:34:36 +0000 | [diff] [blame] | 73 | Parameter::Common common = createParamCommon( |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 74 | 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */, |
| 75 | kSamplingFrequency /* oSampleRate */, kFrameCount /* iFrameCount */, |
| 76 | kFrameCount /* oFrameCount */, layout, layout); |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 77 | ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE)); |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 78 | ASSERT_NE(nullptr, mEffect); |
| 79 | } |
| 80 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 81 | void TearDownHapticGenerator() { |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 82 | ASSERT_NO_FATAL_FAILURE(close(mEffect)); |
| 83 | ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect)); |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 84 | ret = IEffect::OpenEffectReturn{}; |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 85 | } |
| 86 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 87 | Parameter createScaleParam(const std::vector<HapticGenerator::HapticScale>& hapticScales) { |
| 88 | return Parameter::make<Parameter::specific>( |
| 89 | Parameter::Specific::make<Parameter::Specific::hapticGenerator>( |
| 90 | HapticGenerator::make<HapticGenerator::hapticScales>(hapticScales))); |
| 91 | } |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 92 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 93 | Parameter createVibratorParam(HapticGenerator::VibratorInformation vibrationInfo) { |
| 94 | return Parameter::make<Parameter::specific>( |
| 95 | Parameter::Specific::make<Parameter::Specific::hapticGenerator>( |
| 96 | HapticGenerator::make<HapticGenerator::vibratorInfo>(vibrationInfo))); |
| 97 | } |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 98 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 99 | void setAndVerifyParameter(Parameter hapticParameter, HapticGenerator::Tag tag, |
| 100 | binder_exception_t expected = EX_NONE) { |
| 101 | EXPECT_STATUS(expected, mEffect->setParameter(hapticParameter)) |
| 102 | << hapticParameter.toString(); |
| 103 | if (expected == EX_NONE) { |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 104 | // get parameter |
| 105 | Parameter getParam; |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 106 | auto second = Parameter::Id::make<Parameter::Id::hapticGeneratorTag>( |
| 107 | HapticGenerator::Id::make<HapticGenerator::Id::commonTag>( |
| 108 | HapticGenerator::Tag(tag))); |
| 109 | // If the set is successful, get param should match |
| 110 | EXPECT_STATUS(expected, mEffect->getParameter(second, &getParam)); |
| 111 | EXPECT_EQ(hapticParameter, getParam) << "\nexpectedParam:" << hapticParameter.toString() |
| 112 | << "\ngetParam:" << getParam.toString(); |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 116 | HapticGenerator::VibratorInformation createVibratorInfo(float resonantFrequency, float qFactor, |
| 117 | float amplitude) { |
| 118 | return HapticGenerator::VibratorInformation(resonantFrequency, qFactor, amplitude); |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 119 | } |
| 120 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 121 | static const long kFrameCount = 10000; |
| 122 | static constexpr int kSamplingFrequency = 44100; |
| 123 | static constexpr int kDefaultScaleID = 0; |
| 124 | static constexpr float kDefaultMaxAmp = 1; |
| 125 | static constexpr float kDefaultResonantFrequency = 150; |
| 126 | static constexpr float kDefaultQfactor = 8; |
| 127 | static constexpr HapticGenerator::VibratorScale kDefaultScale = |
| 128 | HapticGenerator::VibratorScale::NONE; |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 129 | std::shared_ptr<IFactory> mFactory; |
| 130 | std::shared_ptr<IEffect> mEffect; |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 131 | IEffect::OpenEffectReturn ret; |
| 132 | Parameter mHapticSpecificParameter; |
| 133 | Parameter::Id mHapticIdParameter; |
| 134 | int mEffectInterfaceVersion; |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 135 | }; |
| 136 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 137 | /** |
| 138 | *Tests do the following: |
| 139 | * -Testing parameter range supported by the effect. |
| 140 | * -For any supported value test expects EX_NONE from IEffect.setParameter(), |
| 141 | * otherwise expect EX_ILLEGAL_ARGUMENT. |
| 142 | * -Validating the effect by comparing the output energies of the supported parameters. |
| 143 | **/ |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 144 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 145 | using EffectInstance = std::pair<std::shared_ptr<IFactory>, Descriptor>; |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 146 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 147 | class HapticGeneratorScaleParamTest : public ::testing::TestWithParam<EffectInstance>, |
| 148 | public HapticGeneratorHelper { |
| 149 | public: |
| 150 | HapticGeneratorScaleParamTest() { std::tie(mFactory, mDescriptor) = GetParam(); } |
| 151 | void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator()); } |
| 152 | void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); } |
| 153 | }; |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 154 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 155 | TEST_P(HapticGeneratorScaleParamTest, SetAndGetScales) { |
| 156 | std::vector<HapticGenerator::HapticScale> hapticScales; |
| 157 | for (int i = 0; i < static_cast<int>(kScaleValues.size()); i++) { |
| 158 | hapticScales.push_back({.id = i, .scale = kScaleValues[i]}); |
| 159 | } |
| 160 | ASSERT_NO_FATAL_FAILURE( |
| 161 | setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales)); |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 162 | } |
| 163 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 164 | TEST_P(HapticGeneratorScaleParamTest, SetAndGetScaleFactors) { |
| 165 | if (mEffectInterfaceVersion < HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) { |
| 166 | GTEST_SKIP() << "Skipping HapticGenerator ScaleFactors test for effect version " |
| 167 | << std::to_string(mEffectInterfaceVersion); |
| 168 | } |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 169 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 170 | std::vector<HapticGenerator::HapticScale> hapticScales; |
| 171 | for (int i = 0; i < static_cast<int>(kScaleFactorValues.size()); i++) { |
| 172 | hapticScales.push_back( |
| 173 | {.id = i, .scale = kScaleValues[0], .scaleFactor = kScaleFactorValues[i]}); |
| 174 | } |
| 175 | ASSERT_NO_FATAL_FAILURE( |
| 176 | setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales)); |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 177 | } |
| 178 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 179 | TEST_P(HapticGeneratorScaleParamTest, SetAndGetAdaptiveScaleFactors) { |
| 180 | if (mEffectInterfaceVersion < HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) { |
| 181 | GTEST_SKIP() << "Skipping HapticGenerator AdaptiveScaleFactors test for effect version " |
| 182 | << std::to_string(mEffectInterfaceVersion); |
| 183 | } |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 184 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 185 | std::vector<HapticGenerator::HapticScale> hapticScales; |
| 186 | for (int i = 0; i < static_cast<int>(kAdaptiveScaleFactorValues.size()); i++) { |
| 187 | hapticScales.push_back({.id = i, |
| 188 | .scale = kScaleValues[0], |
| 189 | .scaleFactor = kScaleFactorValues[3], |
| 190 | .adaptiveScaleFactor = kAdaptiveScaleFactorValues[i]}); |
| 191 | } |
| 192 | ASSERT_NO_FATAL_FAILURE( |
| 193 | setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales)); |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 194 | } |
| 195 | |
| 196 | INSTANTIATE_TEST_SUITE_P( |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 197 | HapticGeneratorValidTest, HapticGeneratorScaleParamTest, |
| 198 | testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( |
| 199 | IFactory::descriptor, getEffectTypeUuidHapticGenerator())), |
| 200 | [](const testing::TestParamInfo<HapticGeneratorScaleParamTest::ParamType>& info) { |
| 201 | auto descriptor = info.param; |
| 202 | return getPrefix(descriptor.second); |
| 203 | }); |
| 204 | |
| 205 | GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScaleParamTest); |
| 206 | |
| 207 | enum VibratorParamName { |
| 208 | VIBRATOR_PARAM_INSTANCE, |
| 209 | VIBRATOR_PARAM_RESONANT_FREQUENCY, |
| 210 | VIBRATOR_PARAM_Q_FACTOR, |
| 211 | VIBRATOR_PARAM_MAX_AMPLITUDE, |
| 212 | }; |
| 213 | |
| 214 | using HapticGeneratorVibratorInfoTestParam = std::tuple<EffectInstance, float, float, float>; |
| 215 | |
| 216 | class HapticGeneratorVibratorInfoParamTest |
| 217 | : public ::testing::TestWithParam<HapticGeneratorVibratorInfoTestParam>, |
| 218 | public HapticGeneratorHelper { |
| 219 | public: |
| 220 | HapticGeneratorVibratorInfoParamTest() |
| 221 | : mParamResonantFrequency(std::get<VIBRATOR_PARAM_RESONANT_FREQUENCY>(GetParam())), |
| 222 | mParamQFactor(std::get<VIBRATOR_PARAM_Q_FACTOR>(GetParam())), |
| 223 | mParamMaxAmplitude(std::get<VIBRATOR_PARAM_MAX_AMPLITUDE>(GetParam())) { |
| 224 | std::tie(mFactory, mDescriptor) = std::get<VIBRATOR_PARAM_INSTANCE>(GetParam()); |
| 225 | } |
| 226 | void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator()); } |
| 227 | void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); } |
| 228 | |
| 229 | float mParamResonantFrequency = kDefaultResonantFrequency; |
| 230 | float mParamQFactor = kDefaultQfactor; |
| 231 | float mParamMaxAmplitude = kDefaultMaxAmp; |
| 232 | }; |
| 233 | |
| 234 | TEST_P(HapticGeneratorVibratorInfoParamTest, SetAndGetVibratorInformation) { |
| 235 | auto vibratorInfo = |
| 236 | createVibratorInfo(mParamResonantFrequency, mParamQFactor, mParamMaxAmplitude); |
| 237 | if (isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) { |
| 238 | ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo), |
| 239 | HapticGenerator::vibratorInfo)); |
| 240 | } else { |
| 241 | ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo), |
| 242 | HapticGenerator::vibratorInfo, |
| 243 | EX_ILLEGAL_ARGUMENT)); |
| 244 | } |
| 245 | } |
| 246 | GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorVibratorInfoParamTest); |
| 247 | |
| 248 | INSTANTIATE_TEST_SUITE_P( |
| 249 | HapticGeneratorValidTest, HapticGeneratorVibratorInfoParamTest, |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 250 | ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 251 | IFactory::descriptor, getEffectTypeUuidHapticGenerator())), |
| 252 | testing::ValuesIn(kResonantFrequencyValues), |
| 253 | testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)), |
| 254 | [](const testing::TestParamInfo<HapticGeneratorVibratorInfoParamTest::ParamType>& info) { |
| 255 | auto descriptor = std::get<VIBRATOR_PARAM_INSTANCE>(info.param).second; |
| 256 | std::string resonantFrequency = |
| 257 | std::to_string(std::get<VIBRATOR_PARAM_RESONANT_FREQUENCY>(info.param)); |
| 258 | std::string qFactor = std::to_string(std::get<VIBRATOR_PARAM_Q_FACTOR>(info.param)); |
| 259 | std::string maxAmplitude = |
| 260 | std::to_string(std::get<VIBRATOR_PARAM_MAX_AMPLITUDE>(info.param)); |
| 261 | std::string name = getPrefix(descriptor) + "_resonantFrequency" + resonantFrequency + |
| 262 | "_qFactor" + qFactor + "_maxAmplitude" + maxAmplitude; |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 263 | std::replace_if( |
| 264 | name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); |
| 265 | return name; |
| 266 | }); |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 267 | |
| 268 | /** |
| 269 | * The data tests do the following |
| 270 | * -Generate test input. |
| 271 | * -Check if the parameters are supported. Skip the unsupported parameter values. |
| 272 | * -Validate increase in haptic output energy energy. |
| 273 | **/ |
| 274 | |
| 275 | enum DataTestParam { EFFECT_INSTANCE, LAYOUT }; |
| 276 | using HapticGeneratorDataTestParam = std::tuple<EffectInstance, int32_t>; |
| 277 | |
Shunkai Yao | b1fb115 | 2025-02-20 22:59:30 +0000 | [diff] [blame] | 278 | // minimal HAL interface version to run the data path test |
| 279 | constexpr int32_t kMinDataTestHalVersion = 3; |
| 280 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 281 | class HapticGeneratorDataTest : public ::testing::TestWithParam<HapticGeneratorDataTestParam>, |
| 282 | public HapticGeneratorHelper { |
| 283 | public: |
| 284 | HapticGeneratorDataTest() : mChMask(std::get<LAYOUT>(GetParam())) { |
| 285 | std::tie(mFactory, mDescriptor) = std::get<EFFECT_INSTANCE>(GetParam()); |
| 286 | mAudioChannelCount = |
| 287 | getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChMask), |
| 288 | ~AudioChannelLayout::LAYOUT_HAPTIC_AB); |
| 289 | mHapticChannelCount = |
| 290 | getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChMask), |
| 291 | AudioChannelLayout::LAYOUT_HAPTIC_AB); |
| 292 | |
| 293 | mAudioSamples = kFrameCount * mAudioChannelCount; |
| 294 | mHapticSamples = kFrameCount * mHapticChannelCount; |
| 295 | mInput.resize(mHapticSamples + mAudioSamples, 0); |
| 296 | mOutput.resize(mHapticSamples + mAudioSamples, 0); |
| 297 | } |
| 298 | |
Shunkai Yao | b1fb115 | 2025-02-20 22:59:30 +0000 | [diff] [blame] | 299 | void SetUp() override { |
| 300 | ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator(mChMask)); |
| 301 | if (int32_t version; |
| 302 | mEffect->getInterfaceVersion(&version).isOk() && version < kMinDataTestHalVersion) { |
| 303 | GTEST_SKIP() << "Skipping the data test for version: " << version << "\n"; |
| 304 | } |
| 305 | } |
| 306 | |
Sneha Patil | 393369b | 2024-07-16 13:50:05 +0000 | [diff] [blame] | 307 | void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); } |
| 308 | |
| 309 | void generateSinePeriod() { |
| 310 | size_t cycleSize = kSamplingFrequency / kInputFrequency; |
| 311 | size_t startSize = 0; |
| 312 | while (startSize < mAudioSamples) { |
| 313 | for (size_t i = 0; i < cycleSize; i++) { |
| 314 | mInput[i + startSize] = sin(2 * M_PI * kInputFrequency * i / kSamplingFrequency); |
| 315 | } |
| 316 | startSize += mAudioSamples / 4; |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | void setBaseVibratorParam() { |
| 321 | auto vibratorInfo = |
| 322 | createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, kDefaultMaxAmp); |
| 323 | if (isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) { |
| 324 | ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo), |
| 325 | HapticGenerator::vibratorInfo)); |
| 326 | } else { |
| 327 | GTEST_SKIP() << "Invalid base vibrator values, skipping the test\n"; |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | void setBaseScaleParam() { |
| 332 | ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter( |
| 333 | createScaleParam({HapticGenerator::HapticScale(kDefaultScaleID, kDefaultScale)}), |
| 334 | HapticGenerator::hapticScales)); |
| 335 | } |
| 336 | |
| 337 | void validateIncreasingEnergy(HapticGenerator::Tag tag) { |
| 338 | float baseEnergy = -1; |
| 339 | for (auto param : mHapticParam) { |
| 340 | ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(param, tag)); |
| 341 | SCOPED_TRACE("Param: " + param.toString()); |
| 342 | ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, mOutput, mEffect, &ret)); |
| 343 | float hapticOutputEnergy = audio_utils_compute_energy_mono( |
| 344 | mOutput.data() + mAudioSamples, AUDIO_FORMAT_PCM_FLOAT, mHapticSamples); |
| 345 | EXPECT_GT(hapticOutputEnergy, baseEnergy); |
| 346 | baseEnergy = hapticOutputEnergy; |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | float findAbsMax(auto begin, auto end) { |
| 351 | return *std::max_element(begin, end, |
| 352 | [](float a, float b) { return std::abs(a) < std::abs(b); }); |
| 353 | } |
| 354 | |
| 355 | void findMaxAmplitude() { |
| 356 | for (float amp = 0.1; amp <= 1; amp += 0.1) { |
| 357 | auto vibratorInfo = createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, amp); |
| 358 | if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, |
| 359 | mDescriptor)) { |
| 360 | continue; |
| 361 | } |
| 362 | ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo), |
| 363 | HapticGenerator::vibratorInfo)); |
| 364 | ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, mOutput, mEffect, &ret)); |
| 365 | float outAmplitude = findAbsMax(mOutput.begin() + mAudioSamples, mOutput.end()); |
| 366 | if (outAmplitude > mMaxAmplitude) { |
| 367 | mMaxAmplitude = outAmplitude; |
| 368 | } else { |
| 369 | break; |
| 370 | } |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | const int kInputFrequency = 1000; |
| 375 | float mMaxAmplitude = 0; |
| 376 | size_t mHapticSamples; |
| 377 | int32_t mChMask; |
| 378 | int32_t mAudioChannelCount; |
| 379 | int32_t mHapticChannelCount; |
| 380 | size_t mAudioSamples; |
| 381 | float mBaseHapticOutputEnergy; |
| 382 | std::vector<Parameter> mHapticParam; |
| 383 | // both input and output buffer includes audio and haptic samples |
| 384 | std::vector<float> mInput; |
| 385 | std::vector<float> mOutput; |
| 386 | }; |
| 387 | |
| 388 | TEST_P(HapticGeneratorDataTest, IncreasingVibratorScaleTest) { |
| 389 | generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples); |
| 390 | ASSERT_NO_FATAL_FAILURE(setBaseVibratorParam()); |
| 391 | for (HapticGenerator::VibratorScale scale : kScaleValues) { |
| 392 | mHapticParam.push_back( |
| 393 | createScaleParam({HapticGenerator::HapticScale(kDefaultScaleID, scale)})); |
| 394 | } |
| 395 | ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::hapticScales)); |
| 396 | } |
| 397 | |
| 398 | TEST_P(HapticGeneratorDataTest, IncreasingMaxAmplitudeTest) { |
| 399 | generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples); |
| 400 | ASSERT_NO_FATAL_FAILURE(setBaseScaleParam()); |
| 401 | findMaxAmplitude(); |
| 402 | std::vector<float> increasingAmplitudeValues = {0.25f * mMaxAmplitude, 0.5f * mMaxAmplitude, |
| 403 | 0.75f * mMaxAmplitude, mMaxAmplitude}; |
| 404 | for (float amplitude : increasingAmplitudeValues) { |
| 405 | auto vibratorInfo = |
| 406 | createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, amplitude); |
| 407 | if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) { |
| 408 | continue; |
| 409 | } |
| 410 | mHapticParam.push_back(createVibratorParam(vibratorInfo)); |
| 411 | } |
| 412 | ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo)); |
| 413 | } |
| 414 | |
| 415 | TEST_P(HapticGeneratorDataTest, DescreasingResonantFrequencyTest) { |
| 416 | std::vector<float> descreasingResonantFrequency = {800, 600, 400, 200}; |
| 417 | generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples); |
| 418 | ASSERT_NO_FATAL_FAILURE(setBaseScaleParam()); |
| 419 | for (float resonantFrequency : descreasingResonantFrequency) { |
| 420 | auto vibratorInfo = createVibratorInfo(resonantFrequency, kDefaultQfactor, kDefaultMaxAmp); |
| 421 | if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) { |
| 422 | continue; |
| 423 | } |
| 424 | mHapticParam.push_back(createVibratorParam(vibratorInfo)); |
| 425 | } |
| 426 | ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo)); |
| 427 | } |
| 428 | |
| 429 | TEST_P(HapticGeneratorDataTest, IncreasingQfactorTest) { |
| 430 | std::vector<float> increasingQfactor = {16, 24, 32, 40}; |
| 431 | generateSinePeriod(); |
| 432 | ASSERT_NO_FATAL_FAILURE(setBaseScaleParam()); |
| 433 | for (float qFactor : increasingQfactor) { |
| 434 | auto vibratorInfo = createVibratorInfo(kDefaultResonantFrequency, qFactor, kDefaultMaxAmp); |
| 435 | if (!isParameterValid<HapticGenerator, Range::hapticGenerator>(vibratorInfo, mDescriptor)) { |
| 436 | continue; |
| 437 | } |
| 438 | mHapticParam.push_back(createVibratorParam(vibratorInfo)); |
| 439 | } |
| 440 | ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo)); |
| 441 | } |
| 442 | |
| 443 | INSTANTIATE_TEST_SUITE_P( |
| 444 | DataTest, HapticGeneratorDataTest, |
| 445 | ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( |
| 446 | IFactory::descriptor, getEffectTypeUuidHapticGenerator())), |
| 447 | testing::ValuesIn(kHapticOutputLayouts)), |
| 448 | [](const testing::TestParamInfo<HapticGeneratorDataTest::ParamType>& info) { |
| 449 | auto descriptor = std::get<EFFECT_INSTANCE>(info.param).second; |
| 450 | std::string layout = "0x" + std::format("{:x}", std::get<LAYOUT>(info.param)); |
| 451 | std::string name = getPrefix(descriptor) + "_layout_" + layout; |
| 452 | return name; |
| 453 | }); |
| 454 | GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorDataTest); |
Shraddha Basantwani | c7d237d | 2022-12-18 15:01:14 +0530 | [diff] [blame] | 455 | |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 456 | int main(int argc, char** argv) { |
| 457 | ::testing::InitGoogleTest(&argc, argv); |
Jaideep Sharma | 7449841 | 2023-09-13 15:25:25 +0530 | [diff] [blame] | 458 | ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer()); |
Sham Rathod | d4f15e3 | 2022-11-18 14:25:52 +0530 | [diff] [blame] | 459 | ABinderProcess_setThreadPoolMaxThreadCount(1); |
| 460 | ABinderProcess_startThreadPool(); |
| 461 | return RUN_ALL_TESTS(); |
| 462 | } |