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 kSamplingFrequency = 44100;
85     static constexpr int kDurationMilliSec = 500;
86     static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
87     int mStereoChannelCount =
88             getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
89                     AudioChannelLayout::LAYOUT_STEREO));
90     PresetReverb::Presets kDefaultPreset = PresetReverb::Presets::NONE;
91     int mFrameCount = kBufferSize / mStereoChannelCount;
92     std::shared_ptr<IFactory> mFactory;
93     std::shared_ptr<IEffect> mEffect;
94     IEffect::OpenEffectReturn mOpenEffectReturn;
95     Descriptor mDescriptor;
96 };
97 
98 /**
99  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
100  * VtsAudioEffectTargetTest.
101  */
102 enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESETS };
103 using PresetReverbParamTestParam =
104         std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, PresetReverb::Presets>;
105 
106 // Testing for enum values
107 const std::vector<PresetReverb::Presets> kPresetsValues{
108         ndk::enum_range<PresetReverb::Presets>().begin(),
109         ndk::enum_range<PresetReverb::Presets>().end()};
110 
111 class PresetReverbParamTest : public ::testing::TestWithParam<PresetReverbParamTestParam>,
112                               public PresetReverbHelper {
113   public:
PresetReverbParamTest()114     PresetReverbParamTest() : mParamPreset(std::get<PARAM_PRESETS>(GetParam())) {
115         std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
116     }
117 
SetUp()118     void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpPresetReverb()); }
119 
TearDown()120     void TearDown() override { TearDownPresetReverb(); }
121 
122     const PresetReverb::Presets mParamPreset;
123 };
124 
TEST_P(PresetReverbParamTest,SetAndGetPresets)125 TEST_P(PresetReverbParamTest, SetAndGetPresets) {
126     ASSERT_NO_FATAL_FAILURE(setAndVerifyPreset(mParamPreset));
127 }
128 
129 using PresetReverbProcessTestParam = std::pair<std::shared_ptr<IFactory>, Descriptor>;
130 
131 class PresetReverbProcessTest : public ::testing::TestWithParam<PresetReverbProcessTestParam>,
132                                 public PresetReverbHelper {
133   public:
PresetReverbProcessTest()134     PresetReverbProcessTest() {
135         std::tie(mFactory, mDescriptor) = GetParam();
136         generateSineWaveInput();
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 
generateSineWaveInput()148     void generateSineWaveInput() {
149         int frequency = 1000;
150         for (size_t i = 0; i < kBufferSize; i++) {
151             mInput.push_back(sin(2 * M_PI * frequency * i / kSamplingFrequency));
152         }
153     }
154 
isAuxiliary()155     bool isAuxiliary() {
156         return mDescriptor.common.flags.type ==
157                aidl::android::hardware::audio::effect::Flags::Type::AUXILIARY;
158     }
159 
computeReverbOutputEnergy(std::vector<float> output)160     float computeReverbOutputEnergy(std::vector<float> output) {
161         if (!isAuxiliary()) {
162             // Extract auxiliary output
163             for (size_t i = 0; i < output.size(); i++) {
164                 output[i] -= mInput[i];
165             }
166         }
167         return (audio_utils_compute_energy_mono(output.data(), AUDIO_FORMAT_PCM_FLOAT,
168                                                 output.size()));
169     }
170 
setPresetAndProcess(const PresetReverb::Presets & preset,std::vector<float> & output)171     void setPresetAndProcess(const PresetReverb::Presets& preset, std::vector<float>& output) {
172         ASSERT_NO_FATAL_FAILURE(setAndVerifyPreset(preset));
173         ASSERT_NO_FATAL_FAILURE(
174                 processAndWriteToOutput(mInput, output, mEffect, &mOpenEffectReturn));
175     }
176 
validateIncreasingEnergy(const std::vector<PresetReverb::Presets> & presets)177     void validateIncreasingEnergy(const std::vector<PresetReverb::Presets>& presets) {
178         float baseOutputEnergy = 0;
179 
180         for (PresetReverb::Presets preset : presets) {
181             std::vector<float> output(kBufferSize);
182             setPresetAndProcess(preset, output);
183             float outputEnergy = computeReverbOutputEnergy(output);
184 
185             ASSERT_GT(outputEnergy, baseOutputEnergy);
186             baseOutputEnergy = outputEnergy;
187         }
188     }
189 
190     std::vector<float> mInput;
191 };
192 
TEST_P(PresetReverbProcessTest,DecreasingRoomSize)193 TEST_P(PresetReverbProcessTest, DecreasingRoomSize) {
194     std::vector<PresetReverb::Presets> roomPresets = {PresetReverb::Presets::LARGEROOM,
195                                                       PresetReverb::Presets::MEDIUMROOM,
196                                                       PresetReverb::Presets::SMALLROOM};
197     validateIncreasingEnergy(roomPresets);
198 }
199 
TEST_P(PresetReverbProcessTest,DecreasingHallSize)200 TEST_P(PresetReverbProcessTest, DecreasingHallSize) {
201     std::vector<PresetReverb::Presets> hallPresets = {PresetReverb::Presets::LARGEHALL,
202                                                       PresetReverb::Presets::MEDIUMHALL};
203     validateIncreasingEnergy(hallPresets);
204 }
205 
TEST_P(PresetReverbProcessTest,PresetPlate)206 TEST_P(PresetReverbProcessTest, PresetPlate) {
207     std::vector<float> output(kBufferSize);
208 
209     setPresetAndProcess(PresetReverb::Presets::PLATE, output);
210     float outputEnergy = computeReverbOutputEnergy(output);
211     // Since there is no comparator preset, validating it is greater than zero
212     ASSERT_GT(outputEnergy, 0);
213 }
214 
TEST_P(PresetReverbProcessTest,PresetNone)215 TEST_P(PresetReverbProcessTest, PresetNone) {
216     std::vector<float> output(kBufferSize);
217 
218     setPresetAndProcess(kDefaultPreset, output);
219     float outputEnergy = computeReverbOutputEnergy(output);
220     // NONE type doesn't create reverb effect
221     ASSERT_EQ(outputEnergy, 0);
222 }
223 
224 INSTANTIATE_TEST_SUITE_P(
225         PresetReverbTest, PresetReverbParamTest,
226         ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
227                                    IFactory::descriptor, getEffectTypeUuidPresetReverb())),
228                            testing::ValuesIn(kPresetsValues)),
__anon618d9b680102(const testing::TestParamInfo<PresetReverbParamTest::ParamType>& info) 229         [](const testing::TestParamInfo<PresetReverbParamTest::ParamType>& info) {
230             auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
231             std::string preset =
232                     std::to_string(static_cast<int>(std::get<PARAM_PRESETS>(info.param)));
233             std::string name = getPrefix(descriptor) + "_preset" + preset;
234             std::replace_if(
235                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
236             return name;
237         });
238 
239 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PresetReverbParamTest);
240 
241 INSTANTIATE_TEST_SUITE_P(
242         PresetReverbTest, PresetReverbProcessTest,
243         testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
244                 IFactory::descriptor, getEffectTypeUuidPresetReverb())),
__anon618d9b680302(const testing::TestParamInfo<PresetReverbProcessTest::ParamType>& info) 245         [](const testing::TestParamInfo<PresetReverbProcessTest::ParamType>& info) {
246             auto descriptor = info.param;
247             return getPrefix(descriptor.second);
248         });
249 
250 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PresetReverbProcessTest);
251 
main(int argc,char ** argv)252 int main(int argc, char** argv) {
253     ::testing::InitGoogleTest(&argc, argv);
254     ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
255     ABinderProcess_setThreadPoolMaxThreadCount(1);
256     ABinderProcess_startThreadPool();
257     return RUN_ALL_TESTS();
258 }
259