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 #include <string>
18
19 #define LOG_TAG "VtsHalLoudnessEnhancerTest"
20 #include <android-base/logging.h>
21
22 #include "EffectHelper.h"
23
24 using namespace android;
25
26 using aidl::android::hardware::audio::effect::Descriptor;
27 using aidl::android::hardware::audio::effect::getEffectTypeUuidLoudnessEnhancer;
28 using aidl::android::hardware::audio::effect::IEffect;
29 using aidl::android::hardware::audio::effect::IFactory;
30 using aidl::android::hardware::audio::effect::LoudnessEnhancer;
31 using aidl::android::hardware::audio::effect::Parameter;
32 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
33
34 static constexpr float kMaxAudioSample = 1;
35 static constexpr int kZeroGain = 0;
36 static constexpr int kMaxGain = std::numeric_limits<int>::max();
37 static constexpr int kMinGain = std::numeric_limits<int>::min();
38 static constexpr float kAbsError = 0.0001;
39
40 // Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
41 // TODO : Update the test values once range/capability is updated by implementation.
42 static const std::vector<int> kGainMbValues = {kMinGain, -100, -50, kZeroGain, 50, 100, kMaxGain};
43
44 class LoudnessEnhancerEffectHelper : public EffectHelper {
45 public:
SetUpLoudnessEnhancer()46 void SetUpLoudnessEnhancer() {
47 ASSERT_NE(nullptr, mFactory);
48 ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
49
50 Parameter::Specific specific = getDefaultParamSpecific();
51 Parameter::Common common = createParamCommon(
52 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
53 kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
54 ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
55 ASSERT_NE(nullptr, mEffect);
56 mVersion = EffectFactoryHelper::getHalVersion(mFactory);
57 }
58
TearDownLoudnessEnhancer()59 void TearDownLoudnessEnhancer() {
60 ASSERT_NO_FATAL_FAILURE(close(mEffect));
61 ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
62 mOpenEffectReturn = IEffect::OpenEffectReturn{};
63 }
64
getDefaultParamSpecific()65 Parameter::Specific getDefaultParamSpecific() {
66 LoudnessEnhancer le = LoudnessEnhancer::make<LoudnessEnhancer::gainMb>(0);
67 Parameter::Specific specific =
68 Parameter::Specific::make<Parameter::Specific::loudnessEnhancer>(le);
69 return specific;
70 }
71
createLoudnessParam(int gainMb)72 Parameter createLoudnessParam(int gainMb) {
73 LoudnessEnhancer le;
74 le.set<LoudnessEnhancer::gainMb>(gainMb);
75 Parameter param;
76 Parameter::Specific specific;
77 specific.set<Parameter::Specific::loudnessEnhancer>(le);
78 param.set<Parameter::specific>(specific);
79 return param;
80 }
81
isGainValid(int gainMb)82 binder_exception_t isGainValid(int gainMb) {
83 LoudnessEnhancer le;
84 le.set<LoudnessEnhancer::gainMb>(gainMb);
85 if (isParameterValid<LoudnessEnhancer, Range::loudnessEnhancer>(le, mDescriptor)) {
86 return EX_NONE;
87 } else {
88 return EX_ILLEGAL_ARGUMENT;
89 }
90 }
91
setParameters(int gain,binder_exception_t expected)92 void setParameters(int gain, binder_exception_t expected) {
93 // set parameter
94 auto param = createLoudnessParam(gain);
95 EXPECT_STATUS(expected, mEffect->setParameter(param)) << param.toString();
96 }
97
validateParameters(int gain)98 void validateParameters(int gain) {
99 // get parameter
100 LoudnessEnhancer::Id leId;
101 Parameter getParam;
102 Parameter::Id id;
103
104 LoudnessEnhancer::Tag tag(LoudnessEnhancer::gainMb);
105 leId.set<LoudnessEnhancer::Id::commonTag>(tag);
106 id.set<Parameter::Id::loudnessEnhancerTag>(leId);
107 EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
108 auto expectedParam = createLoudnessParam(gain);
109 EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
110 << "\ngetParam:" << getParam.toString();
111 }
112
113 static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
114 IEffect::OpenEffectReturn mOpenEffectReturn;
115 std::shared_ptr<IFactory> mFactory;
116 std::shared_ptr<IEffect> mEffect;
117 Descriptor mDescriptor;
118 int mVersion = 0;
119 };
120
121 /**
122 * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
123 * VtsAudioEffectTargetTest.
124 */
125 enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
126 using LoudnessEnhancerParamTestParam =
127 std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
128
129 class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhancerParamTestParam>,
130 public LoudnessEnhancerEffectHelper {
131 public:
LoudnessEnhancerParamTest()132 LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
133 std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
134 }
135
SetUp()136 void SetUp() override { SetUpLoudnessEnhancer(); }
TearDown()137 void TearDown() override { TearDownLoudnessEnhancer(); }
138 int mParamGainMb = 0;
139 };
140
TEST_P(LoudnessEnhancerParamTest,SetAndGetGainMb)141 TEST_P(LoudnessEnhancerParamTest, SetAndGetGainMb) {
142 binder_exception_t expected = isGainValid(mParamGainMb);
143 setParameters(mParamGainMb, expected);
144 if (expected == EX_NONE) {
145 validateParameters(mParamGainMb);
146 }
147 }
148
149 using LoudnessEnhancerDataTestParam = std::pair<std::shared_ptr<IFactory>, Descriptor>;
150
151 class LoudnessEnhancerDataTest : public ::testing::TestWithParam<LoudnessEnhancerDataTestParam>,
152 public LoudnessEnhancerEffectHelper {
153 public:
LoudnessEnhancerDataTest()154 LoudnessEnhancerDataTest() {
155 std::tie(mFactory, mDescriptor) = GetParam();
156 generateInputBuffer();
157 mOutputBuffer.resize(kBufferSize);
158 }
159
SetUp()160 void SetUp() override {
161 SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
162 SetUpLoudnessEnhancer();
163
164 // Creating AidlMessageQueues
165 mStatusMQ = std::make_unique<EffectHelper::StatusMQ>(mOpenEffectReturn.statusMQ);
166 mInputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn.inputDataMQ);
167 mOutputMQ = std::make_unique<EffectHelper::DataMQ>(mOpenEffectReturn.outputDataMQ);
168 }
169
TearDown()170 void TearDown() override {
171 SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
172 TearDownLoudnessEnhancer();
173 }
174
175 // Fill inputBuffer with random values between -kMaxAudioSample to kMaxAudioSample
generateInputBuffer()176 void generateInputBuffer() {
177 for (size_t i = 0; i < kBufferSize; i++) {
178 mInputBuffer.push_back(((static_cast<float>(std::rand()) / RAND_MAX) * 2 - 1) *
179 kMaxAudioSample);
180 }
181 }
182
183 // Add gains to the mInputBuffer and store processed output to mOutputBuffer
processAndWriteToOutput()184 void processAndWriteToOutput() {
185 // Check AidlMessageQueues are not null
186 ASSERT_TRUE(mStatusMQ->isValid());
187 ASSERT_TRUE(mInputMQ->isValid());
188 ASSERT_TRUE(mOutputMQ->isValid());
189
190 // Enabling the process
191 ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
192 ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
193
194 // Write from buffer to message queues and calling process
195 EXPECT_NO_FATAL_FAILURE(
196 EffectHelper::writeToFmq(mStatusMQ, mInputMQ, mInputBuffer, mVersion));
197
198 // Read the updated message queues into buffer
199 EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(mStatusMQ, 1, mOutputMQ,
200 mOutputBuffer.size(), mOutputBuffer));
201
202 // Disable the process
203 ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
204 }
205
assertGreaterGain(const std::vector<float> & first,const std::vector<float> & second)206 void assertGreaterGain(const std::vector<float>& first, const std::vector<float>& second) {
207 for (size_t i = 0; i < first.size(); i++) {
208 if (first[i] != 0) {
209 ASSERT_GT(abs(first[i]), abs(second[i]));
210
211 } else {
212 ASSERT_EQ(first[i], second[i]);
213 }
214 }
215 }
216
assertSequentialGains(const std::vector<int> & gainValues,bool isIncreasing)217 void assertSequentialGains(const std::vector<int>& gainValues, bool isIncreasing) {
218 std::vector<float> baseOutput(kBufferSize);
219
220 // Process a reference output buffer with 0 gain which gives compressed input values
221 binder_exception_t expected;
222 expected = isGainValid(kZeroGain);
223 ASSERT_EQ(expected, EX_NONE);
224 setParameters(kZeroGain, expected);
225 ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
226 baseOutput = mOutputBuffer;
227
228 // Compare the outputs for increasing gain
229 for (int gain : gainValues) {
230 // Setting the parameters
231 binder_exception_t expected = isGainValid(gain);
232 if (expected != EX_NONE) {
233 GTEST_SKIP() << "Gains not supported.";
234 }
235 setParameters(gain, expected);
236 ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
237
238 // Compare the mOutputBuffer values with baseOutput and update it
239 if (isIncreasing) {
240 ASSERT_NO_FATAL_FAILURE(assertGreaterGain(mOutputBuffer, baseOutput));
241 } else {
242 ASSERT_NO_FATAL_FAILURE(assertGreaterGain(baseOutput, mOutputBuffer));
243 }
244
245 baseOutput = mOutputBuffer;
246 }
247 }
248
249 std::unique_ptr<StatusMQ> mStatusMQ;
250 std::unique_ptr<DataMQ> mInputMQ;
251 std::unique_ptr<DataMQ> mOutputMQ;
252
253 std::vector<float> mInputBuffer;
254 std::vector<float> mOutputBuffer;
255 static constexpr float kBufferSize = 128;
256 };
257
TEST_P(LoudnessEnhancerDataTest,IncreasingGains)258 TEST_P(LoudnessEnhancerDataTest, IncreasingGains) {
259 static const std::vector<int> kIncreasingGains = {50, 100};
260
261 assertSequentialGains(kIncreasingGains, true /*isIncreasing*/);
262 }
263
TEST_P(LoudnessEnhancerDataTest,DecreasingGains)264 TEST_P(LoudnessEnhancerDataTest, DecreasingGains) {
265 static const std::vector<int> kDecreasingGains = {-50, -100};
266
267 assertSequentialGains(kDecreasingGains, false /*isIncreasing*/);
268 }
269
TEST_P(LoudnessEnhancerDataTest,MinimumGain)270 TEST_P(LoudnessEnhancerDataTest, MinimumGain) {
271 // Setting the parameters
272 binder_exception_t expected = isGainValid(kMinGain);
273 if (expected != EX_NONE) {
274 GTEST_SKIP() << "Minimum integer value not supported";
275 }
276 setParameters(kMinGain, expected);
277 ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
278
279 // Validate that mOutputBuffer has 0 values for INT_MIN gain
280 for (size_t i = 0; i < mOutputBuffer.size(); i++) {
281 ASSERT_FLOAT_EQ(mOutputBuffer[i], 0);
282 }
283 }
284
TEST_P(LoudnessEnhancerDataTest,MaximumGain)285 TEST_P(LoudnessEnhancerDataTest, MaximumGain) {
286 // Setting the parameters
287 binder_exception_t expected = isGainValid(kMaxGain);
288 if (expected != EX_NONE) {
289 GTEST_SKIP() << "Maximum integer value not supported";
290 }
291 setParameters(kMaxGain, expected);
292 ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput());
293
294 // Validate that mOutputBuffer reaches to kMaxAudioSample for INT_MAX gain
295 for (size_t i = 0; i < mOutputBuffer.size(); i++) {
296 if (mInputBuffer[i] != 0) {
297 EXPECT_NEAR(kMaxAudioSample, abs(mOutputBuffer[i]), kAbsError);
298 } else {
299 ASSERT_EQ(mOutputBuffer[i], mInputBuffer[i]);
300 }
301 }
302 }
303
304 INSTANTIATE_TEST_SUITE_P(
305 LoudnessEnhancerTest, LoudnessEnhancerParamTest,
306 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
307 IFactory::descriptor, getEffectTypeUuidLoudnessEnhancer())),
308 testing::ValuesIn(kGainMbValues)),
__anon0eddfe400102(const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) 309 [](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
310 auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
311 std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
312 std::string name = getPrefix(descriptor) + "_gainMb_" + gainMb;
313 std::replace_if(
314 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
315 return name;
316 });
317
318 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerParamTest);
319
320 INSTANTIATE_TEST_SUITE_P(
321 LoudnessEnhancerTest, LoudnessEnhancerDataTest,
322 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
323 IFactory::descriptor, getEffectTypeUuidLoudnessEnhancer())),
__anon0eddfe400302(const testing::TestParamInfo<LoudnessEnhancerDataTest::ParamType>& info) 324 [](const testing::TestParamInfo<LoudnessEnhancerDataTest::ParamType>& info) {
325 auto descriptor = info.param;
326 std::string name = getPrefix(descriptor.second);
327 std::replace_if(
328 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
329 return name;
330 });
331
332 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerDataTest);
333
main(int argc,char ** argv)334 int main(int argc, char** argv) {
335 ::testing::InitGoogleTest(&argc, argv);
336 ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
337 ABinderProcess_setThreadPoolMaxThreadCount(1);
338 ABinderProcess_startThreadPool();
339 return RUN_ALL_TESTS();
340 }
341