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
17 #define LOG_TAG "VtsHalPresetReverbTargetTest"
18 #include <android-base/logging.h>
19 #include <android/binder_enums.h>
20 #include <audio_utils/power.h>
21 #include <system/audio.h>
22
23 #include "EffectHelper.h"
24
25 using namespace android;
26
27 using aidl::android::hardware::audio::common::getChannelCount;
28 using aidl::android::hardware::audio::effect::Descriptor;
29 using aidl::android::hardware::audio::effect::getEffectTypeUuidPresetReverb;
30 using aidl::android::hardware::audio::effect::IEffect;
31 using aidl::android::hardware::audio::effect::IFactory;
32 using aidl::android::hardware::audio::effect::Parameter;
33 using aidl::android::hardware::audio::effect::PresetReverb;
34 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
35
36 class PresetReverbHelper : public EffectHelper {
37 public:
SetUpPresetReverb()38 void SetUpPresetReverb() {
39 ASSERT_NE(nullptr, mFactory);
40 ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
41 Parameter::Specific specific = getDefaultParamSpecific();
42 Parameter::Common common = createParamCommon(
43 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
44 kSamplingFrequency /* oSampleRate */, mFrameCount /* iFrameCount */,
45 mFrameCount /* oFrameCount */);
46 ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
47 ASSERT_NE(nullptr, mEffect);
48 }
49
TearDownPresetReverb()50 void TearDownPresetReverb() {
51 ASSERT_NO_FATAL_FAILURE(close(mEffect));
52 ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
53 mOpenEffectReturn = IEffect::OpenEffectReturn{};
54 }
55
getDefaultParamSpecific()56 Parameter::Specific getDefaultParamSpecific() {
57 PresetReverb pr = PresetReverb::make<PresetReverb::preset>(kDefaultPreset);
58 Parameter::Specific specific =
59 Parameter::Specific::make<Parameter::Specific::presetReverb>(pr);
60 return specific;
61 }
62
createPresetReverbParam(const PresetReverb::Presets & param)63 Parameter createPresetReverbParam(const PresetReverb::Presets& param) {
64 return Parameter::make<Parameter::specific>(
65 Parameter::Specific::make<Parameter::Specific::presetReverb>(
66 PresetReverb::make<PresetReverb::preset>(param)));
67 }
68
setAndVerifyPreset(const PresetReverb::Presets & param)69 void setAndVerifyPreset(const PresetReverb::Presets& param) {
70 auto expectedParam = createPresetReverbParam(param);
71 EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectedParam)) << expectedParam.toString();
72
73 PresetReverb::Id revId =
74 PresetReverb::Id::make<PresetReverb::Id::commonTag>(PresetReverb::preset);
75
76 auto id = Parameter::Id::make<Parameter::Id::presetReverbTag>(revId);
77 // get parameter
78 Parameter getParam;
79 EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
80 EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
81 << "\ngetParam:" << getParam.toString();
82 }
83
84 static constexpr int kDurationMilliSec = 500;
85 static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
86 int mStereoChannelCount =
87 getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
88 AudioChannelLayout::LAYOUT_STEREO));
89 PresetReverb::Presets kDefaultPreset = PresetReverb::Presets::NONE;
90 int mFrameCount = kBufferSize / mStereoChannelCount;
91 std::shared_ptr<IFactory> mFactory;
92 std::shared_ptr<IEffect> mEffect;
93 IEffect::OpenEffectReturn mOpenEffectReturn;
94 Descriptor mDescriptor;
95 };
96
97 /**
98 * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
99 * VtsAudioEffectTargetTest.
100 */
101 enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESETS };
102 using PresetReverbParamTestParam =
103 std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, PresetReverb::Presets>;
104
105 // Testing for enum values
106 const std::vector<PresetReverb::Presets> kPresetsValues{
107 ndk::enum_range<PresetReverb::Presets>().begin(),
108 ndk::enum_range<PresetReverb::Presets>().end()};
109
110 class PresetReverbParamTest : public ::testing::TestWithParam<PresetReverbParamTestParam>,
111 public PresetReverbHelper {
112 public:
PresetReverbParamTest()113 PresetReverbParamTest() : mParamPreset(std::get<PARAM_PRESETS>(GetParam())) {
114 std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
115 }
116
SetUp()117 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpPresetReverb()); }
118
TearDown()119 void TearDown() override { TearDownPresetReverb(); }
120
121 const PresetReverb::Presets mParamPreset;
122 };
123
TEST_P(PresetReverbParamTest,SetAndGetPresets)124 TEST_P(PresetReverbParamTest, SetAndGetPresets) {
125 ASSERT_NO_FATAL_FAILURE(setAndVerifyPreset(mParamPreset));
126 }
127
128 using PresetReverbProcessTestParam = std::pair<std::shared_ptr<IFactory>, Descriptor>;
129
130 class PresetReverbProcessTest : public ::testing::TestWithParam<PresetReverbProcessTestParam>,
131 public PresetReverbHelper {
132 public:
PresetReverbProcessTest()133 PresetReverbProcessTest() {
134 std::tie(mFactory, mDescriptor) = GetParam();
135 mInput.resize(kBufferSize);
136 generateSineWave(1000 /*Input Frequency*/, mInput);
137 }
138
SetUp()139 void SetUp() override {
140 SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
141 ASSERT_NO_FATAL_FAILURE(SetUpPresetReverb());
142 }
TearDown()143 void TearDown() override {
144 SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
145 ASSERT_NO_FATAL_FAILURE(TearDownPresetReverb());
146 }
147
isAuxiliary()148 bool isAuxiliary() {
149 return mDescriptor.common.flags.type ==
150 aidl::android::hardware::audio::effect::Flags::Type::AUXILIARY;
151 }
152
computeReverbOutputEnergy(std::vector<float> output)153 float computeReverbOutputEnergy(std::vector<float> output) {
154 if (!isAuxiliary()) {
155 // Extract auxiliary output
156 for (size_t i = 0; i < output.size(); i++) {
157 output[i] -= mInput[i];
158 }
159 }
160 return (audio_utils_compute_energy_mono(output.data(), AUDIO_FORMAT_PCM_FLOAT,
161 output.size()));
162 }
163
setPresetAndProcess(const PresetReverb::Presets & preset,std::vector<float> & output)164 void setPresetAndProcess(const PresetReverb::Presets& preset, std::vector<float>& output) {
165 ASSERT_NO_FATAL_FAILURE(setAndVerifyPreset(preset));
166 ASSERT_NO_FATAL_FAILURE(
167 processAndWriteToOutput(mInput, output, mEffect, &mOpenEffectReturn));
168 }
169
validateIncreasingEnergy(const std::vector<PresetReverb::Presets> & presets)170 void validateIncreasingEnergy(const std::vector<PresetReverb::Presets>& presets) {
171 float baseOutputEnergy = 0;
172
173 for (PresetReverb::Presets preset : presets) {
174 std::vector<float> output(kBufferSize);
175 setPresetAndProcess(preset, output);
176 float outputEnergy = computeReverbOutputEnergy(output);
177
178 ASSERT_GT(outputEnergy, baseOutputEnergy);
179 baseOutputEnergy = outputEnergy;
180 }
181 }
182
183 std::vector<float> mInput;
184 };
185
TEST_P(PresetReverbProcessTest,DecreasingRoomSize)186 TEST_P(PresetReverbProcessTest, DecreasingRoomSize) {
187 std::vector<PresetReverb::Presets> roomPresets = {PresetReverb::Presets::LARGEROOM,
188 PresetReverb::Presets::MEDIUMROOM,
189 PresetReverb::Presets::SMALLROOM};
190 validateIncreasingEnergy(roomPresets);
191 }
192
TEST_P(PresetReverbProcessTest,DecreasingHallSize)193 TEST_P(PresetReverbProcessTest, DecreasingHallSize) {
194 std::vector<PresetReverb::Presets> hallPresets = {PresetReverb::Presets::LARGEHALL,
195 PresetReverb::Presets::MEDIUMHALL};
196 validateIncreasingEnergy(hallPresets);
197 }
198
TEST_P(PresetReverbProcessTest,PresetPlate)199 TEST_P(PresetReverbProcessTest, PresetPlate) {
200 std::vector<float> output(kBufferSize);
201
202 setPresetAndProcess(PresetReverb::Presets::PLATE, output);
203 float outputEnergy = computeReverbOutputEnergy(output);
204 // Since there is no comparator preset, validating it is greater than zero
205 ASSERT_GT(outputEnergy, 0);
206 }
207
TEST_P(PresetReverbProcessTest,PresetNone)208 TEST_P(PresetReverbProcessTest, PresetNone) {
209 std::vector<float> output(kBufferSize);
210
211 setPresetAndProcess(kDefaultPreset, output);
212 float outputEnergy = computeReverbOutputEnergy(output);
213 // NONE type doesn't create reverb effect
214 ASSERT_EQ(outputEnergy, 0);
215 }
216
217 INSTANTIATE_TEST_SUITE_P(
218 PresetReverbTest, PresetReverbParamTest,
219 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
220 IFactory::descriptor, getEffectTypeUuidPresetReverb())),
221 testing::ValuesIn(kPresetsValues)),
__anon4356e2de0102(const testing::TestParamInfo<PresetReverbParamTest::ParamType>& info) 222 [](const testing::TestParamInfo<PresetReverbParamTest::ParamType>& info) {
223 auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
224 std::string preset =
225 std::to_string(static_cast<int>(std::get<PARAM_PRESETS>(info.param)));
226 std::string name = getPrefix(descriptor) + "_preset" + preset;
227 std::replace_if(
228 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
229 return name;
230 });
231
232 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PresetReverbParamTest);
233
234 INSTANTIATE_TEST_SUITE_P(
235 PresetReverbTest, PresetReverbProcessTest,
236 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
237 IFactory::descriptor, getEffectTypeUuidPresetReverb())),
__anon4356e2de0302(const testing::TestParamInfo<PresetReverbProcessTest::ParamType>& info) 238 [](const testing::TestParamInfo<PresetReverbProcessTest::ParamType>& info) {
239 auto descriptor = info.param;
240 return getPrefix(descriptor.second);
241 });
242
243 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PresetReverbProcessTest);
244
main(int argc,char ** argv)245 int main(int argc, char** argv) {
246 ::testing::InitGoogleTest(&argc, argv);
247 ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
248 ABinderProcess_setThreadPoolMaxThreadCount(1);
249 ABinderProcess_startThreadPool();
250 return RUN_ALL_TESTS();
251 }
252