1 /*
2 * Copyright (C) 2023 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 <set>
18 #include <string>
19 #include <unordered_set>
20
21 #define LOG_TAG "VtsHalDynamicsProcessingTest"
22 #include <android-base/logging.h>
23 #include <audio_utils/power.h>
24 #include <audio_utils/primitives.h>
25
26 #include <Utils.h>
27
28 #include "EffectHelper.h"
29 #include "EffectRangeSpecific.h"
30
31 using namespace android;
32 using namespace aidl::android::hardware::audio::effect::DynamicsProcessingRanges;
33
34 using aidl::android::hardware::audio::effect::Descriptor;
35 using aidl::android::hardware::audio::effect::DynamicsProcessing;
36 using aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing;
37 using aidl::android::hardware::audio::effect::IEffect;
38 using aidl::android::hardware::audio::effect::IFactory;
39 using aidl::android::hardware::audio::effect::Parameter;
40 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
41
42 constexpr int32_t kMinDataTestHalVersion = 3;
43
44 /**
45 * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
46 * VtsAudioEffectTargetTest.
47 */
48 class DynamicsProcessingTestHelper : public EffectHelper {
49 public:
DynamicsProcessingTestHelper(std::pair<std::shared_ptr<IFactory>,Descriptor> pair,int32_t channelLayout=kDefaultChannelLayout)50 DynamicsProcessingTestHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair,
51 int32_t channelLayout = kDefaultChannelLayout)
52 : mChannelLayout(channelLayout),
53 mChannelCount(::aidl::android::hardware::audio::common::getChannelCount(
54 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout))) {
55 std::tie(mFactory, mDescriptor) = pair;
56 }
57
58 // setup
SetUpDynamicsProcessingEffect()59 void SetUpDynamicsProcessingEffect() {
60 ASSERT_NE(nullptr, mFactory);
61 ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
62 Parameter::Specific specific = getDefaultParamSpecific();
63 Parameter::Common common = createParamCommon(
64 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
65 kSamplingFrequency /* oSampleRate */, kFrameCount /* iFrameCount */,
66 kFrameCount /* oFrameCount */,
67 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout),
68 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
69 ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
70 ASSERT_NE(nullptr, mEffect);
71 mEngineConfigApplied = mEngineConfigPreset;
72 }
73
getDefaultParamSpecific()74 Parameter::Specific getDefaultParamSpecific() {
75 DynamicsProcessing dp = DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
76 mEngineConfigPreset);
77 Parameter::Specific specific =
78 Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(dp);
79 return specific;
80 }
81
82 // teardown
TearDownDynamicsProcessingEffect()83 void TearDownDynamicsProcessingEffect() {
84 ASSERT_NO_FATAL_FAILURE(close(mEffect));
85 ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
86 }
87
88 // utils functions for parameter checking
89 bool isParamEqual(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dpRef,
90 const DynamicsProcessing& dpTest);
91 bool isEngineConfigEqual(const DynamicsProcessing::EngineArchitecture& refCfg,
92 const DynamicsProcessing::EngineArchitecture& testCfg);
93
94 template <typename T>
95 std::vector<T> filterEnabledVector(const std::vector<T>& vec);
96
97 template <typename T>
98 bool isAidlVectorEqualAfterFilter(const std::vector<T>& source, const std::vector<T>& target);
99
100 template <typename T>
101 bool isAidlVectorEqual(const std::vector<T>& source, const std::vector<T>& target);
102
103 template <typename T>
isChannelConfigValid(const std::vector<T> & cfgs)104 bool isChannelConfigValid(const std::vector<T>& cfgs) {
105 auto& channelCount = mChannelCount;
106 return std::all_of(cfgs.cbegin(), cfgs.cend(), [channelCount](const T& cfg) {
107 return (cfg.channel >= 0 && cfg.channel < channelCount);
108 });
109 }
110
111 template <typename T>
112 bool isBandConfigValid(const std::vector<T>& cfgs, int bandCount);
113
114 bool isParamValid(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dp);
115
116 // get set params and validate
117 void SetAndGetDynamicsProcessingParameters();
118
119 bool isAllParamsValid();
120
121 void setParamsAndProcess(std::vector<float>& input, std::vector<float>& output);
122
123 float calculateDb(const std::vector<float>& input, size_t startSamplePos);
124
125 void getMagnitudeValue(const std::vector<float>& output, std::vector<float>& bufferMag);
126
127 void checkInputAndOutputEquality(const std::vector<float>& outputMag);
128
129 void setUpDataTest(const std::vector<int>& testFrequencies, float fullScaleSineDb);
130 void tearDownDataTest();
131
132 void createChannelConfig();
133
134 // enqueue test parameters
135 void addEngineConfig(const DynamicsProcessing::EngineArchitecture& cfg);
136 void addPreEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
137 void addPostEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
138 void addMbcChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
139 void addPreEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
140 void addPostEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
141 void addMbcBandConfigs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
142 void addLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig>& cfg);
143 void addInputGain(const std::vector<DynamicsProcessing::InputGain>& inputGain);
144
145 static constexpr float kPreferredProcessingDurationMs = 10.0f;
146 static constexpr int kBandCount = 5;
147 static constexpr int kSamplingFrequency = 44100;
148 static constexpr int kFrameCount = 2048;
149 static constexpr int kInputFrequency = 1000;
150 static constexpr size_t kStartIndex = 15 * kSamplingFrequency / 1000; // skip 15ms
151 static constexpr float kToleranceDb = 0.5;
152 static constexpr int kNPointFFT = 1024;
153 static constexpr float kBinWidth = (float)kSamplingFrequency / kNPointFFT;
154 // Full scale sine wave with 1000 Hz frequency is -3 dB
155 static constexpr float kSineFullScaleDb = -3;
156 // Full scale sine wave with 100 Hz and 1000 Hz frequency is -6 dB
157 static constexpr float kSineMultitoneFullScaleDb = -6;
158 const std::vector<int> kCutoffFreqHz = {200 /*0th band cutoff*/, 2000 /*1st band cutoff*/};
159 std::vector<int> mMultitoneTestFrequencies = {100, 1000};
160 // Calculating normalizing factor by dividing the number of FFT points by half and the number of
161 // test frequencies. The normalization accounts for the FFT splitting the signal into positive
162 // and negative frequencies. Additionally, during multi-tone input generation, sample values are
163 // normalized to the range [-1, 1] by dividing them by the number of test frequencies.
164 float mNormalizingFactor = (kNPointFFT / (2 * mMultitoneTestFrequencies.size()));
165 std::vector<int> mBinOffsets;
166 std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
167 std::vector<float> mInput;
168 float mInputDb;
169 std::shared_ptr<IFactory> mFactory;
170 std::shared_ptr<IEffect> mEffect;
171 Descriptor mDescriptor;
172 IEffect::OpenEffectReturn mOpenEffectReturn;
173 DynamicsProcessing::EngineArchitecture mEngineConfigApplied;
174 DynamicsProcessing::EngineArchitecture mEngineConfigPreset{
175 .resolutionPreference =
176 DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
177 .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
178 .preEqStage = {.inUse = true, .bandCount = kBandCount},
179 .postEqStage = {.inUse = true, .bandCount = kBandCount},
180 .mbcStage = {.inUse = true, .bandCount = kBandCount},
181 .limiterInUse = true,
182 };
183
184 std::unordered_set<int /* channelId */> mPreEqChannelEnable;
185 std::unordered_set<int /* channelId */> mPostEqChannelEnable;
186 std::unordered_set<int /* channelId */> mMbcChannelEnable;
187 std::unordered_set<int /* channelId */> mLimiterChannelEnable;
188 static const std::set<std::vector<DynamicsProcessing::ChannelConfig>> kChannelConfigTestSet;
189 static const std::set<DynamicsProcessing::StageEnablement> kStageEnablementTestSet;
190 static const std::set<std::vector<DynamicsProcessing::InputGain>> kInputGainTestSet;
191
192 private:
193 std::vector<std::pair<DynamicsProcessing::Tag, DynamicsProcessing>> mTags;
194
195 protected:
196 const int32_t mChannelLayout;
197 const int mChannelCount;
198
CleanUp()199 void CleanUp() {
200 mTags.clear();
201 mPreEqChannelEnable.clear();
202 mPostEqChannelEnable.clear();
203 mMbcChannelEnable.clear();
204 mLimiterChannelEnable.clear();
205 }
206 };
207
208 // test value set for DynamicsProcessing::StageEnablement
209 const std::set<DynamicsProcessing::StageEnablement>
210 DynamicsProcessingTestHelper::kStageEnablementTestSet = {
211 {.inUse = true, .bandCount = DynamicsProcessingTestHelper::kBandCount},
212 {.inUse = true, .bandCount = 0},
213 {.inUse = true, .bandCount = -1},
214 {.inUse = false, .bandCount = 0},
215 {.inUse = false, .bandCount = -1},
216 {.inUse = false, .bandCount = DynamicsProcessingTestHelper::kBandCount}};
217
218 // test value set for DynamicsProcessing::ChannelConfig
219 const std::set<std::vector<DynamicsProcessing::ChannelConfig>>
220 DynamicsProcessingTestHelper::kChannelConfigTestSet = {
221 {{.channel = -1, .enable = false},
222 {.channel = 0, .enable = true},
223 {.channel = 1, .enable = false},
224 {.channel = 2, .enable = true}},
225 {{.channel = -1, .enable = false}, {.channel = 2, .enable = true}},
226 {{.channel = 0, .enable = true}, {.channel = 1, .enable = true}}};
227
228 // test value set for DynamicsProcessing::InputGain
229 const std::set<std::vector<DynamicsProcessing::InputGain>>
230 DynamicsProcessingTestHelper::kInputGainTestSet = {
231 {{.channel = 0, .gainDb = 10.f},
232 {.channel = 1, .gainDb = 0.f},
233 {.channel = 2, .gainDb = -10.f}},
234 {{.channel = -1, .gainDb = -10.f}, {.channel = -2, .gainDb = 10.f}},
235 {{.channel = -1, .gainDb = 10.f}, {.channel = 0, .gainDb = -10.f}},
236 {{.channel = 0, .gainDb = 10.f}, {.channel = 1, .gainDb = -10.f}}};
237
238 template <typename T>
isBandConfigValid(const std::vector<T> & cfgs,int bandCount)239 bool DynamicsProcessingTestHelper::isBandConfigValid(const std::vector<T>& cfgs, int bandCount) {
240 std::unordered_set<int> freqs;
241 for (auto cfg : cfgs) {
242 if (cfg.channel < 0 || cfg.channel >= mChannelCount) return false;
243 if (cfg.band < 0 || cfg.band >= bandCount) return false;
244 // duplicated band index
245 if (freqs.find(cfg.band) != freqs.end()) return false;
246 freqs.insert(cfg.band);
247 }
248 return true;
249 }
250
isParamValid(const DynamicsProcessing::Tag & tag,const DynamicsProcessing & dp)251 bool DynamicsProcessingTestHelper::isParamValid(const DynamicsProcessing::Tag& tag,
252 const DynamicsProcessing& dp) {
253 switch (tag) {
254 case DynamicsProcessing::preEq: {
255 return isChannelConfigValid(dp.get<DynamicsProcessing::preEq>());
256 }
257 case DynamicsProcessing::postEq: {
258 return isChannelConfigValid(dp.get<DynamicsProcessing::postEq>());
259 }
260 case DynamicsProcessing::mbc: {
261 return isChannelConfigValid(dp.get<DynamicsProcessing::mbc>());
262 }
263 case DynamicsProcessing::preEqBand: {
264 return isBandConfigValid(dp.get<DynamicsProcessing::preEqBand>(),
265 mEngineConfigApplied.preEqStage.bandCount);
266 }
267 case DynamicsProcessing::postEqBand: {
268 return isBandConfigValid(dp.get<DynamicsProcessing::postEqBand>(),
269 mEngineConfigApplied.postEqStage.bandCount);
270 }
271 case DynamicsProcessing::mbcBand: {
272 return isBandConfigValid(dp.get<DynamicsProcessing::mbcBand>(),
273 mEngineConfigApplied.mbcStage.bandCount);
274 }
275 case DynamicsProcessing::limiter: {
276 return isChannelConfigValid(dp.get<DynamicsProcessing::limiter>());
277 }
278 case DynamicsProcessing::inputGain: {
279 return isChannelConfigValid(dp.get<DynamicsProcessing::inputGain>());
280 }
281 default: {
282 return true;
283 }
284 }
285 return true;
286 }
287
isParamEqual(const DynamicsProcessing::Tag & tag,const DynamicsProcessing & dpRef,const DynamicsProcessing & dpTest)288 bool DynamicsProcessingTestHelper::isParamEqual(const DynamicsProcessing::Tag& tag,
289 const DynamicsProcessing& dpRef,
290 const DynamicsProcessing& dpTest) {
291 switch (tag) {
292 case DynamicsProcessing::engineArchitecture: {
293 return isEngineConfigEqual(dpRef.get<DynamicsProcessing::engineArchitecture>(),
294 dpTest.get<DynamicsProcessing::engineArchitecture>());
295 }
296 case DynamicsProcessing::preEq: {
297 const auto& source = dpRef.get<DynamicsProcessing::preEq>();
298 const auto& target = dpTest.get<DynamicsProcessing::preEq>();
299 return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(source, target);
300 }
301 case DynamicsProcessing::postEq: {
302 return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
303 dpRef.get<DynamicsProcessing::postEq>(),
304 dpTest.get<DynamicsProcessing::postEq>());
305 }
306 case DynamicsProcessing::mbc: {
307 return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
308 dpRef.get<DynamicsProcessing::mbc>(), dpTest.get<DynamicsProcessing::mbc>());
309 }
310 case DynamicsProcessing::preEqBand: {
311 return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
312 dpRef.get<DynamicsProcessing::preEqBand>(),
313 dpTest.get<DynamicsProcessing::preEqBand>());
314 }
315 case DynamicsProcessing::postEqBand: {
316 return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
317 dpRef.get<DynamicsProcessing::postEqBand>(),
318 dpTest.get<DynamicsProcessing::postEqBand>());
319 }
320 case DynamicsProcessing::mbcBand: {
321 return isAidlVectorEqualAfterFilter<DynamicsProcessing::MbcBandConfig>(
322 dpRef.get<DynamicsProcessing::mbcBand>(),
323 dpTest.get<DynamicsProcessing::mbcBand>());
324 }
325 case DynamicsProcessing::limiter: {
326 return isAidlVectorEqualAfterFilter<DynamicsProcessing::LimiterConfig>(
327 dpRef.get<DynamicsProcessing::limiter>(),
328 dpTest.get<DynamicsProcessing::limiter>());
329 }
330 case DynamicsProcessing::inputGain: {
331 return isAidlVectorEqual<DynamicsProcessing::InputGain>(
332 dpRef.get<DynamicsProcessing::inputGain>(),
333 dpTest.get<DynamicsProcessing::inputGain>());
334 }
335 case DynamicsProcessing::vendor: {
336 return false;
337 }
338 }
339 }
340
isEngineConfigEqual(const DynamicsProcessing::EngineArchitecture & ref,const DynamicsProcessing::EngineArchitecture & test)341 bool DynamicsProcessingTestHelper::isEngineConfigEqual(
342 const DynamicsProcessing::EngineArchitecture& ref,
343 const DynamicsProcessing::EngineArchitecture& test) {
344 return ref == test;
345 }
346
347 template <typename T>
filterEnabledVector(const std::vector<T> & vec)348 std::vector<T> DynamicsProcessingTestHelper::filterEnabledVector(const std::vector<T>& vec) {
349 std::vector<T> ret;
350 std::copy_if(vec.begin(), vec.end(), std::back_inserter(ret),
351 [](const auto& v) { return v.enable; });
352 return ret;
353 }
354
355 template <typename T>
isAidlVectorEqual(const std::vector<T> & source,const std::vector<T> & target)356 bool DynamicsProcessingTestHelper::isAidlVectorEqual(const std::vector<T>& source,
357 const std::vector<T>& target) {
358 if (source.size() != target.size()) return false;
359
360 auto tempS = source;
361 auto tempT = target;
362 std::sort(tempS.begin(), tempS.end());
363 std::sort(tempT.begin(), tempT.end());
364 return tempS == tempT;
365 }
366
367 template <typename T>
isAidlVectorEqualAfterFilter(const std::vector<T> & source,const std::vector<T> & target)368 bool DynamicsProcessingTestHelper::isAidlVectorEqualAfterFilter(const std::vector<T>& source,
369 const std::vector<T>& target) {
370 return isAidlVectorEqual<T>(filterEnabledVector<T>(source), filterEnabledVector<T>(target));
371 }
372
SetAndGetDynamicsProcessingParameters()373 void DynamicsProcessingTestHelper::SetAndGetDynamicsProcessingParameters() {
374 for (const auto& [tag, dp] : mTags) {
375 // validate parameter
376 Descriptor desc;
377 ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
378 bool valid = isParamInRange(dp, desc.capability.range.get<Range::dynamicsProcessing>());
379 if (valid) valid = isParamValid(tag, dp);
380 const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
381
382 // set parameter
383 Parameter expectParam;
384 Parameter::Specific specific;
385 specific.set<Parameter::Specific::dynamicsProcessing>(dp);
386 expectParam.set<Parameter::specific>(specific);
387 ASSERT_STATUS(expected, mEffect->setParameter(expectParam))
388 << "\n"
389 << expectParam.toString() << "\n"
390 << desc.toString();
391
392 // only get if parameter in range and set success
393 if (expected == EX_NONE) {
394 Parameter getParam;
395 Parameter::Id id;
396 DynamicsProcessing::Id dpId;
397 dpId.set<DynamicsProcessing::Id::commonTag>(tag);
398 id.set<Parameter::Id::dynamicsProcessingTag>(dpId);
399 // if set success, then get should match
400 EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
401 Parameter::Specific specificTest = getParam.get<Parameter::specific>();
402 const auto& target = specificTest.get<Parameter::Specific::dynamicsProcessing>();
403 EXPECT_TRUE(isParamEqual(tag, dp, target)) << dp.toString() << "\n"
404 << target.toString();
405 // update mEngineConfigApplied after setting successfully
406 if (tag == DynamicsProcessing::engineArchitecture) {
407 mEngineConfigApplied = target.get<DynamicsProcessing::engineArchitecture>();
408 }
409 }
410 }
411 }
412
isAllParamsValid()413 bool DynamicsProcessingTestHelper::isAllParamsValid() {
414 if (mTags.empty()) {
415 return false;
416 }
417 for (const auto& [tag, dp] : mTags) {
418 // validate parameter
419 if (!isParamInRange(dp, mDescriptor.capability.range.get<Range::dynamicsProcessing>())) {
420 return false;
421 }
422 if (!isParamValid(tag, dp)) {
423 return false;
424 }
425 }
426 return true;
427 }
428
429 // This function calculates power for both and mono and stereo data as the total power for
430 // interleaved multichannel data can be calculated by treating it as a continuous mono input.
calculateDb(const std::vector<float> & input,size_t startSamplePos=0)431 float DynamicsProcessingTestHelper::calculateDb(const std::vector<float>& input,
432 size_t startSamplePos = 0) {
433 return audio_utils_compute_power_mono(input.data() + startSamplePos, AUDIO_FORMAT_PCM_FLOAT,
434 input.size() - startSamplePos);
435 }
436
setParamsAndProcess(std::vector<float> & input,std::vector<float> & output)437 void DynamicsProcessingTestHelper::setParamsAndProcess(std::vector<float>& input,
438 std::vector<float>& output) {
439 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
440 if (isAllParamsValid()) {
441 ASSERT_NO_FATAL_FAILURE(
442 processAndWriteToOutput(input, output, mEffect, &mOpenEffectReturn));
443 ASSERT_GT(output.size(), kStartIndex);
444 }
445 }
446
getMagnitudeValue(const std::vector<float> & output,std::vector<float> & bufferMag)447 void DynamicsProcessingTestHelper::getMagnitudeValue(const std::vector<float>& output,
448 std::vector<float>& bufferMag) {
449 std::vector<float> subOutput(output.begin() + kStartIndex, output.end());
450 EXPECT_NO_FATAL_FAILURE(calculateMagnitudeMono(bufferMag, subOutput, mBinOffsets, kNPointFFT));
451 }
452
checkInputAndOutputEquality(const std::vector<float> & outputMag)453 void DynamicsProcessingTestHelper::checkInputAndOutputEquality(
454 const std::vector<float>& outputMag) {
455 std::vector<float> inputMag(mBinOffsets.size());
456 EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(mInput, inputMag));
457 for (size_t i = 0; i < inputMag.size(); i++) {
458 EXPECT_NEAR(calculateDb({inputMag[i] / mNormalizingFactor}),
459 calculateDb({outputMag[i] / mNormalizingFactor}), kToleranceDb);
460 }
461 }
462
setUpDataTest(const std::vector<int> & testFrequencies,float fullScaleSineDb)463 void DynamicsProcessingTestHelper::setUpDataTest(const std::vector<int>& testFrequencies,
464 float fullScaleSineDb) {
465 ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect());
466 SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
467 SKIP_TEST_IF_VERSION_UNSUPPORTED(mEffect, kMinDataTestHalVersion);
468
469 mInput.resize(kFrameCount * mChannelCount);
470 ASSERT_NO_FATAL_FAILURE(
471 generateSineWave(testFrequencies, mInput, 1.0, kSamplingFrequency, mChannelLayout));
472 mInputDb = calculateDb(mInput);
473 ASSERT_NEAR(mInputDb, fullScaleSineDb, kToleranceDb);
474 }
475
tearDownDataTest()476 void DynamicsProcessingTestHelper::tearDownDataTest() {
477 ASSERT_NO_FATAL_FAILURE(TearDownDynamicsProcessingEffect());
478 }
479
createChannelConfig()480 void DynamicsProcessingTestHelper::createChannelConfig() {
481 for (int i = 0; i < mChannelCount; i++) {
482 mChannelConfig.push_back(DynamicsProcessing::ChannelConfig(i, true));
483 }
484 }
485
addEngineConfig(const DynamicsProcessing::EngineArchitecture & cfg)486 void DynamicsProcessingTestHelper::addEngineConfig(
487 const DynamicsProcessing::EngineArchitecture& cfg) {
488 DynamicsProcessing dp;
489 dp.set<DynamicsProcessing::engineArchitecture>(cfg);
490 mTags.push_back({DynamicsProcessing::engineArchitecture, dp});
491 }
492
addPreEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig> & cfgs)493 void DynamicsProcessingTestHelper::addPreEqChannelConfig(
494 const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
495 DynamicsProcessing dp;
496 dp.set<DynamicsProcessing::preEq>(cfgs);
497 mTags.push_back({DynamicsProcessing::preEq, dp});
498 for (auto& cfg : cfgs) {
499 if (cfg.enable) mPreEqChannelEnable.insert(cfg.channel);
500 }
501 }
502
addPostEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig> & cfgs)503 void DynamicsProcessingTestHelper::addPostEqChannelConfig(
504 const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
505 DynamicsProcessing dp;
506 dp.set<DynamicsProcessing::postEq>(cfgs);
507 mTags.push_back({DynamicsProcessing::postEq, dp});
508 for (auto& cfg : cfgs) {
509 if (cfg.enable) mPostEqChannelEnable.insert(cfg.channel);
510 }
511 }
512
addMbcChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig> & cfgs)513 void DynamicsProcessingTestHelper::addMbcChannelConfig(
514 const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
515 DynamicsProcessing dp;
516 dp.set<DynamicsProcessing::mbc>(cfgs);
517 mTags.push_back({DynamicsProcessing::mbc, dp});
518 for (auto& cfg : cfgs) {
519 if (cfg.enable) mMbcChannelEnable.insert(cfg.channel);
520 }
521 }
522
addPreEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig> & cfgs)523 void DynamicsProcessingTestHelper::addPreEqBandConfigs(
524 const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
525 DynamicsProcessing dp;
526 dp.set<DynamicsProcessing::preEqBand>(cfgs);
527 mTags.push_back({DynamicsProcessing::preEqBand, dp});
528 }
529
addPostEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig> & cfgs)530 void DynamicsProcessingTestHelper::addPostEqBandConfigs(
531 const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
532 DynamicsProcessing dp;
533 dp.set<DynamicsProcessing::postEqBand>(cfgs);
534 mTags.push_back({DynamicsProcessing::postEqBand, dp});
535 }
536
addMbcBandConfigs(const std::vector<DynamicsProcessing::MbcBandConfig> & cfgs)537 void DynamicsProcessingTestHelper::addMbcBandConfigs(
538 const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
539 DynamicsProcessing dp;
540 dp.set<DynamicsProcessing::mbcBand>(cfgs);
541 mTags.push_back({DynamicsProcessing::mbcBand, dp});
542 }
543
addLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig> & cfgs)544 void DynamicsProcessingTestHelper::addLimiterConfig(
545 const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
546 DynamicsProcessing dp;
547 dp.set<DynamicsProcessing::limiter>(cfgs);
548 mTags.push_back({DynamicsProcessing::limiter, dp});
549 for (auto& cfg : cfgs) {
550 if (cfg.enable) mLimiterChannelEnable.insert(cfg.channel);
551 }
552 }
553
addInputGain(const std::vector<DynamicsProcessing::InputGain> & inputGains)554 void DynamicsProcessingTestHelper::addInputGain(
555 const std::vector<DynamicsProcessing::InputGain>& inputGains) {
556 DynamicsProcessing dp;
557 dp.set<DynamicsProcessing::inputGain>(inputGains);
558 mTags.push_back({DynamicsProcessing::inputGain, dp});
559 }
560
fillLimiterConfig(std::vector<DynamicsProcessing::LimiterConfig> & limiterConfigList,int channelIndex,bool enable,int linkGroup,float attackTime,float releaseTime,float ratio,float threshold,float postGain)561 void fillLimiterConfig(std::vector<DynamicsProcessing::LimiterConfig>& limiterConfigList,
562 int channelIndex, bool enable, int linkGroup, float attackTime,
563 float releaseTime, float ratio, float threshold, float postGain) {
564 DynamicsProcessing::LimiterConfig cfg;
565 cfg.channel = channelIndex;
566 cfg.enable = enable;
567 cfg.linkGroup = linkGroup;
568 cfg.attackTimeMs = attackTime;
569 cfg.releaseTimeMs = releaseTime;
570 cfg.ratio = ratio;
571 cfg.thresholdDb = threshold;
572 cfg.postGainDb = postGain;
573 limiterConfigList.push_back(cfg);
574 }
575
createMbcBandConfig(int channel,int band,float cutoffFreqHz,float attackTimeMs,float releaseTimeMs,float ratio,float thresholdDb,float kneeWidthDb,float noiseGate,float expanderRatio,float preGainDb,float postGainDb)576 DynamicsProcessing::MbcBandConfig createMbcBandConfig(int channel, int band, float cutoffFreqHz,
577 float attackTimeMs, float releaseTimeMs,
578 float ratio, float thresholdDb,
579 float kneeWidthDb, float noiseGate,
580 float expanderRatio, float preGainDb,
581 float postGainDb) {
582 return DynamicsProcessing::MbcBandConfig{.channel = channel,
583 .band = band,
584 .enable = true,
585 .cutoffFrequencyHz = cutoffFreqHz,
586 .attackTimeMs = attackTimeMs,
587 .releaseTimeMs = releaseTimeMs,
588 .ratio = ratio,
589 .thresholdDb = thresholdDb,
590 .kneeWidthDb = kneeWidthDb,
591 .noiseGateThresholdDb = noiseGate,
592 .expanderRatio = expanderRatio,
593 .preGainDb = preGainDb,
594 .postGainDb = postGainDb};
595 }
596
creatEqBandConfig(int channel,int band,float cutOffFreqHz,float gainDb,bool enable)597 DynamicsProcessing::EqBandConfig creatEqBandConfig(int channel, int band, float cutOffFreqHz,
598 float gainDb, bool enable) {
599 return DynamicsProcessing::EqBandConfig{.channel = channel,
600 .band = band,
601 .enable = enable,
602 .cutoffFrequencyHz = cutOffFreqHz,
603 .gainDb = gainDb};
604 }
605
606 /**
607 * Test DynamicsProcessing Engine Configuration
608 */
609 enum EngineArchitectureTestParamName {
610 ENGINE_TEST_INSTANCE_NAME,
611 ENGINE_TEST_RESOLUTION_PREFERENCE,
612 ENGINE_TEST_PREFERRED_DURATION,
613 ENGINE_TEST_STAGE_ENABLEMENT
614 };
615 using EngineArchitectureTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
616 DynamicsProcessing::ResolutionPreference, float,
617 DynamicsProcessing::StageEnablement>;
618
fillEngineArchConfig(DynamicsProcessing::EngineArchitecture & cfg,const EngineArchitectureTestParams & params)619 void fillEngineArchConfig(DynamicsProcessing::EngineArchitecture& cfg,
620 const EngineArchitectureTestParams& params) {
621 cfg.resolutionPreference = std::get<ENGINE_TEST_RESOLUTION_PREFERENCE>(params);
622 cfg.preferredProcessingDurationMs = std::get<ENGINE_TEST_PREFERRED_DURATION>(params);
623 cfg.preEqStage = cfg.postEqStage = cfg.mbcStage =
624 std::get<ENGINE_TEST_STAGE_ENABLEMENT>(params);
625 cfg.limiterInUse = true;
626 }
627
628 class DynamicsProcessingTestEngineArchitecture
629 : public ::testing::TestWithParam<EngineArchitectureTestParams>,
630 public DynamicsProcessingTestHelper {
631 public:
DynamicsProcessingTestEngineArchitecture()632 DynamicsProcessingTestEngineArchitecture()
633 : DynamicsProcessingTestHelper(std::get<ENGINE_TEST_INSTANCE_NAME>(GetParam())) {
634 fillEngineArchConfig(mCfg, GetParam());
635 };
636
SetUp()637 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
638
TearDown()639 void TearDown() override { TearDownDynamicsProcessingEffect(); }
640
641 DynamicsProcessing::EngineArchitecture mCfg;
642 };
643
TEST_P(DynamicsProcessingTestEngineArchitecture,SetAndGetEngineArch)644 TEST_P(DynamicsProcessingTestEngineArchitecture, SetAndGetEngineArch) {
645 addEngineConfig(mCfg);
646 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
647 }
648
649 INSTANTIATE_TEST_SUITE_P(
650 DynamicsProcessingTest, DynamicsProcessingTestEngineArchitecture,
651 ::testing::Combine(
652 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
653 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
654 testing::Values(
655 DynamicsProcessing::ResolutionPreference::FAVOR_TIME_RESOLUTION,
656 DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
657 static_cast<DynamicsProcessing::ResolutionPreference>(-1)), // variant
658 testing::Values(-10.f, 0.f, 10.f), // processing duration
659 testing::ValuesIn(
660 DynamicsProcessingTestHelper::kStageEnablementTestSet) // preEQ/postEQ/mbc
661 ),
__anon6e9317b30302(const auto& info) 662 [](const auto& info) {
663 auto descriptor = std::get<ENGINE_TEST_INSTANCE_NAME>(info.param).second;
664 DynamicsProcessing::EngineArchitecture cfg;
665 fillEngineArchConfig(cfg, info.param);
666 std::string name = getPrefix(descriptor) + "_Cfg_" + cfg.toString();
667 std::replace_if(
668 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
669 return name;
670 });
671 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEngineArchitecture);
672
673 /**
674 * Test DynamicsProcessing Input Gain
675 */
676 enum InputGainTestParamName {
677 INPUT_GAIN_INSTANCE_NAME,
678 INPUT_GAIN_PARAM,
679 };
680 class DynamicsProcessingTestInputGain
681 : public ::testing::TestWithParam<std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
682 std::vector<DynamicsProcessing::InputGain>>>,
683 public DynamicsProcessingTestHelper {
684 public:
DynamicsProcessingTestInputGain()685 DynamicsProcessingTestInputGain()
686 : DynamicsProcessingTestHelper(std::get<INPUT_GAIN_INSTANCE_NAME>(GetParam())),
687 mInputGain(std::get<INPUT_GAIN_PARAM>(GetParam())) {};
688
SetUp()689 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
690
TearDown()691 void TearDown() override { TearDownDynamicsProcessingEffect(); }
692
693 const std::vector<DynamicsProcessing::InputGain> mInputGain;
694 };
695
TEST_P(DynamicsProcessingTestInputGain,SetAndGetInputGain)696 TEST_P(DynamicsProcessingTestInputGain, SetAndGetInputGain) {
697 addInputGain(mInputGain);
698 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
699 }
700
701 INSTANTIATE_TEST_SUITE_P(
702 DynamicsProcessingTest, DynamicsProcessingTestInputGain,
703 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
704 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
705 testing::ValuesIn(DynamicsProcessingTestInputGain::kInputGainTestSet)),
__anon6e9317b30502(const auto& info) 706 [](const auto& info) {
707 auto descriptor = std::get<INPUT_GAIN_INSTANCE_NAME>(info.param).second;
708 std::string gains =
709 ::android::internal::ToString(std::get<INPUT_GAIN_PARAM>(info.param));
710 std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
711 descriptor.common.name + "_UUID_" +
712 toString(descriptor.common.id.uuid) + "_inputGains_" + gains;
713 std::replace_if(
714 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
715 return name;
716 });
717 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestInputGain);
718
719 class DynamicsProcessingInputGainDataTest
720 : public ::testing::TestWithParam<std::pair<std::shared_ptr<IFactory>, Descriptor>>,
721 public DynamicsProcessingTestHelper {
722 public:
DynamicsProcessingInputGainDataTest()723 DynamicsProcessingInputGainDataTest()
724 : DynamicsProcessingTestHelper((GetParam()), AudioChannelLayout::LAYOUT_MONO) {}
725
SetUp()726 void SetUp() override {
727 ASSERT_NO_FATAL_FAILURE(setUpDataTest({kInputFrequency}, kSineFullScaleDb));
728 }
729
TearDown()730 void TearDown() override { ASSERT_NO_FATAL_FAILURE(tearDownDataTest()); }
731
cleanUpInputGainConfig()732 void cleanUpInputGainConfig() {
733 CleanUp();
734 mInputGain.clear();
735 }
736
737 std::vector<DynamicsProcessing::InputGain> mInputGain;
738 };
739
TEST_P(DynamicsProcessingInputGainDataTest,SetAndGetInputGain)740 TEST_P(DynamicsProcessingInputGainDataTest, SetAndGetInputGain) {
741 std::vector<float> gainDbValues = {-85, -40, 0, 40, 85};
742 for (float gainDb : gainDbValues) {
743 cleanUpInputGainConfig();
744 for (int i = 0; i < mChannelCount; i++) {
745 mInputGain.push_back(DynamicsProcessing::InputGain(i, gainDb));
746 }
747 std::vector<float> output(mInput.size());
748 addInputGain(mInputGain);
749 EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
750 if (!isAllParamsValid()) {
751 continue;
752 }
753 float outputDb = calculateDb(output, kStartIndex);
754 EXPECT_NEAR(outputDb, mInputDb + gainDb, kToleranceDb)
755 << "InputGain: " << gainDb << ", OutputDb: " << outputDb;
756 }
757 }
758
759 INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingInputGainDataTest,
760 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
761 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
__anon6e9317b30702(const auto& info) 762 [](const auto& info) {
763 auto descriptor = info.param;
764 std::string name = getPrefix(descriptor.second);
765 std::replace_if(
766 name.begin(), name.end(),
767 [](const char c) { return !std::isalnum(c); }, '_');
768 return name;
769 });
770 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingInputGainDataTest);
771
772 /**
773 * Test DynamicsProcessing Limiter Config
774 */
775 enum LimiterConfigTestParamName {
776 LIMITER_INSTANCE_NAME,
777 LIMITER_CHANNEL,
778 LIMITER_LINK_GROUP,
779 LIMITER_ATTACK_TIME,
780 LIMITER_RELEASE_TIME,
781 LIMITER_RATIO,
782 LIMITER_THRESHOLD,
783 LIMITER_POST_GAIN,
784 };
785
786 using LimiterConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
787 int32_t, int32_t, float, float, float, float, float>;
788
fillLimiterConfig(std::vector<DynamicsProcessing::LimiterConfig> & cfg,const LimiterConfigTestParams & params)789 void fillLimiterConfig(std::vector<DynamicsProcessing::LimiterConfig>& cfg,
790 const LimiterConfigTestParams& params) {
791 fillLimiterConfig(cfg, std::get<LIMITER_CHANNEL>(params), true,
792 std::get<LIMITER_LINK_GROUP>(params), std::get<LIMITER_ATTACK_TIME>(params),
793 std::get<LIMITER_RELEASE_TIME>(params), std::get<LIMITER_RATIO>(params),
794 std::get<LIMITER_THRESHOLD>(params), std::get<LIMITER_POST_GAIN>(params));
795 }
796
797 class DynamicsProcessingTestLimiterConfig
798 : public ::testing::TestWithParam<LimiterConfigTestParams>,
799 public DynamicsProcessingTestHelper {
800 public:
DynamicsProcessingTestLimiterConfig()801 DynamicsProcessingTestLimiterConfig()
802 : DynamicsProcessingTestHelper(std::get<LIMITER_INSTANCE_NAME>(GetParam())) {
803 fillLimiterConfig(mLimiterConfigList, GetParam());
804 }
805
SetUp()806 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
807
TearDown()808 void TearDown() override { TearDownDynamicsProcessingEffect(); }
809
810 DynamicsProcessing::LimiterConfig mCfg;
811 std::vector<DynamicsProcessing::LimiterConfig> mLimiterConfigList;
812 };
813
TEST_P(DynamicsProcessingTestLimiterConfig,SetAndGetLimiterConfig)814 TEST_P(DynamicsProcessingTestLimiterConfig, SetAndGetLimiterConfig) {
815 addEngineConfig(mEngineConfigPreset);
816 addLimiterConfig(mLimiterConfigList);
817 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
818 }
819
820 INSTANTIATE_TEST_SUITE_P(
821 DynamicsProcessingTest, DynamicsProcessingTestLimiterConfig,
822 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
823 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
824 testing::Values(-1, 0, 1, 2), // channel index
825 testing::Values(3), // link group
826 testing::Values(-1, 1), // attackTime
827 testing::Values(-60, 60), // releaseTime
828 testing::Values(-2.5, 2.5), // ratio
829 testing::Values(-2, 2), // thresh
830 testing::Values(-3.14, 3.14) // postGain
831 ),
__anon6e9317b30902(const auto& info) 832 [](const auto& info) {
833 auto descriptor = std::get<LIMITER_INSTANCE_NAME>(info.param).second;
834 std::vector<DynamicsProcessing::LimiterConfig> cfg;
835 fillLimiterConfig(cfg, info.param);
836 std::string name =
837 "Implementer_" + getPrefix(descriptor) + "_limiterConfig_" + cfg[0].toString();
838 std::replace_if(
839 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
840 return name;
841 });
842 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestLimiterConfig);
843
844 using LimiterConfigDataTestParams = std::pair<std::shared_ptr<IFactory>, Descriptor>;
845
846 class DynamicsProcessingLimiterConfigDataTest
847 : public ::testing::TestWithParam<LimiterConfigDataTestParams>,
848 public DynamicsProcessingTestHelper {
849 public:
DynamicsProcessingLimiterConfigDataTest(LimiterConfigDataTestParams param=GetParam (),int32_t layout=AudioChannelLayout::LAYOUT_MONO)850 DynamicsProcessingLimiterConfigDataTest(LimiterConfigDataTestParams param = GetParam(),
851 int32_t layout = AudioChannelLayout::LAYOUT_MONO)
852 : DynamicsProcessingTestHelper(param, layout) {}
853
SetUp()854 void SetUp() override {
855 ASSERT_NO_FATAL_FAILURE(setUpDataTest({kInputFrequency}, kSineFullScaleDb));
856 }
857
TearDown()858 void TearDown() override { ASSERT_NO_FATAL_FAILURE(tearDownDataTest()); }
859
computeThreshold(float ratio,float outputDb,float & threshold)860 void computeThreshold(float ratio, float outputDb, float& threshold) {
861 EXPECT_NE(ratio, 0);
862 threshold = (mInputDb - (ratio * outputDb)) / (1 - ratio);
863 }
864
computeRatio(float threshold,float outputDb,float & ratio)865 void computeRatio(float threshold, float outputDb, float& ratio) {
866 float inputOverThreshold = mInputDb - threshold;
867 float outputOverThreshold = outputDb - threshold;
868 EXPECT_NE(outputOverThreshold, 0);
869 ratio = inputOverThreshold / outputOverThreshold;
870 }
871
setLimiterParamsAndProcess(std::vector<float> & input,std::vector<float> & output,bool isEngineLimiterEnabled=true)872 void setLimiterParamsAndProcess(std::vector<float>& input, std::vector<float>& output,
873 bool isEngineLimiterEnabled = true) {
874 mEngineConfigPreset.limiterInUse = isEngineLimiterEnabled;
875 addEngineConfig(mEngineConfigPreset);
876 addLimiterConfig(mLimiterConfigList);
877 EXPECT_NO_FATAL_FAILURE(setParamsAndProcess(input, output));
878 }
879
testEnableDisableConfiguration(bool isLimiterEnabled,bool isEngineLimiterEnabled)880 void testEnableDisableConfiguration(bool isLimiterEnabled, bool isEngineLimiterEnabled) {
881 cleanUpLimiterConfig();
882 std::vector<float> output(mInput.size());
883 for (int i = 0; i < mChannelCount; i++) {
884 // Set non-default values
885 fillLimiterConfig(mLimiterConfigList, i, isLimiterEnabled, kDefaultLinkerGroup,
886 5 /*attack time*/, 5 /*release time*/, 10 /*ratio*/,
887 -20 /*threshold*/, 5 /*postgain*/);
888 }
889 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output, isEngineLimiterEnabled));
890 float outputdB = calculateDb(output, kStartIndex);
891 if (isAllParamsValid()) {
892 if (isLimiterEnabled && isEngineLimiterEnabled) {
893 EXPECT_GT(std::abs(mInputDb - outputdB), kMinDifferenceDb)
894 << "Input level: " << mInputDb << " Output level: " << outputdB;
895 } else {
896 EXPECT_NEAR(mInputDb, outputdB, kLimiterTestToleranceDb);
897 }
898 }
899 }
900
cleanUpLimiterConfig()901 void cleanUpLimiterConfig() {
902 CleanUp();
903 mLimiterConfigList.clear();
904 }
905 static constexpr float kDefaultLinkerGroup = 3;
906 static constexpr float kDefaultAttackTime = 0;
907 static constexpr float kDefaultReleaseTime = 0;
908 static constexpr float kDefaultRatio = 4;
909 static constexpr float kDefaultThreshold = -10;
910 static constexpr float kDefaultPostGain = 0;
911 static constexpr float kLimiterTestToleranceDb = 0.05;
912 static constexpr float kMinDifferenceDb = 5;
913 const std::vector<bool> kEnableValues = {true, false, true};
914 std::vector<DynamicsProcessing::LimiterConfig> mLimiterConfigList;
915 int mBufferSize;
916 };
917
TEST_P(DynamicsProcessingLimiterConfigDataTest,IncreasingThresholdDb)918 TEST_P(DynamicsProcessingLimiterConfigDataTest, IncreasingThresholdDb) {
919 std::vector<float> thresholdValues = {-200, -150, -100, -50, -5, 0};
920 std::vector<float> output(mInput.size());
921 float previousThreshold = -FLT_MAX;
922 for (float threshold : thresholdValues) {
923 cleanUpLimiterConfig();
924 for (int i = 0; i < mChannelCount; i++) {
925 fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
926 kDefaultReleaseTime, kDefaultRatio, threshold, kDefaultPostGain);
927 }
928 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
929 if (!isAllParamsValid()) {
930 continue;
931 }
932 float outputDb = calculateDb(output, kStartIndex);
933 if (threshold >= mInputDb || kDefaultRatio == 1) {
934 EXPECT_NEAR(mInputDb, outputDb, kLimiterTestToleranceDb);
935 } else {
936 float calculatedThreshold = 0;
937 ASSERT_NO_FATAL_FAILURE(computeThreshold(kDefaultRatio, outputDb, calculatedThreshold));
938 ASSERT_GT(calculatedThreshold, previousThreshold);
939 previousThreshold = calculatedThreshold;
940 }
941 }
942 }
943
TEST_P(DynamicsProcessingLimiterConfigDataTest,IncreasingRatio)944 TEST_P(DynamicsProcessingLimiterConfigDataTest, IncreasingRatio) {
945 std::vector<float> ratioValues = {1, 10, 20, 30, 40, 50};
946 std::vector<float> output(mInput.size());
947 float previousRatio = 0;
948 for (float ratio : ratioValues) {
949 cleanUpLimiterConfig();
950 for (int i = 0; i < mChannelCount; i++) {
951 fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
952 kDefaultReleaseTime, ratio, kDefaultThreshold, kDefaultPostGain);
953 }
954 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
955 if (!isAllParamsValid()) {
956 continue;
957 }
958 float outputDb = calculateDb(output, kStartIndex);
959
960 if (kDefaultThreshold >= mInputDb) {
961 EXPECT_NEAR(mInputDb, outputDb, kLimiterTestToleranceDb);
962 } else {
963 float calculatedRatio = 0;
964 ASSERT_NO_FATAL_FAILURE(computeRatio(kDefaultThreshold, outputDb, calculatedRatio));
965 ASSERT_GT(calculatedRatio, previousRatio);
966 previousRatio = calculatedRatio;
967 }
968 }
969 }
970
TEST_P(DynamicsProcessingLimiterConfigDataTest,IncreasingPostGain)971 TEST_P(DynamicsProcessingLimiterConfigDataTest, IncreasingPostGain) {
972 std::vector<float> postGainDbValues = {-85, -40, 0, 40, 85};
973 std::vector<float> output(mInput.size());
974 for (float postGainDb : postGainDbValues) {
975 cleanUpLimiterConfig();
976 ASSERT_NO_FATAL_FAILURE(generateSineWave(kInputFrequency, mInput, dBToAmplitude(postGainDb),
977 kSamplingFrequency, mChannelLayout));
978 mInputDb = calculateDb(mInput);
979 EXPECT_NEAR(mInputDb, kSineFullScaleDb - postGainDb, kLimiterTestToleranceDb);
980 for (int i = 0; i < mChannelCount; i++) {
981 fillLimiterConfig(mLimiterConfigList, i, true, kDefaultLinkerGroup, kDefaultAttackTime,
982 kDefaultReleaseTime, 1, kDefaultThreshold, postGainDb);
983 }
984 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
985 if (!isAllParamsValid()) {
986 continue;
987 }
988 float outputDb = calculateDb(output, kStartIndex);
989 EXPECT_NEAR(outputDb, mInputDb + postGainDb, kLimiterTestToleranceDb)
990 << "PostGain: " << postGainDb << ", OutputDb: " << outputDb;
991 }
992 }
993
TEST_P(DynamicsProcessingLimiterConfigDataTest,LimiterEnableDisable)994 TEST_P(DynamicsProcessingLimiterConfigDataTest, LimiterEnableDisable) {
995 for (bool isLimiterEnabled : kEnableValues) {
996 ASSERT_NO_FATAL_FAILURE(
997 testEnableDisableConfiguration(isLimiterEnabled, true /*Engine Enabled*/));
998 }
999 }
1000
TEST_P(DynamicsProcessingLimiterConfigDataTest,LimiterEnableDisableViaEngine)1001 TEST_P(DynamicsProcessingLimiterConfigDataTest, LimiterEnableDisableViaEngine) {
1002 for (bool isEngineLimiterEnabled : kEnableValues) {
1003 ASSERT_NO_FATAL_FAILURE(
1004 testEnableDisableConfiguration(true /*Limiter Enabled*/, isEngineLimiterEnabled));
1005 }
1006 }
1007
1008 INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingLimiterConfigDataTest,
1009 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1010 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
__anon6e9317b30b02(const auto& info) 1011 [](const auto& info) {
1012 auto descriptor = info.param;
1013 std::string name = getPrefix(descriptor.second);
1014 std::replace_if(
1015 name.begin(), name.end(),
1016 [](const char c) { return !std::isalnum(c); }, '_');
1017 return name;
1018 });
1019 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingLimiterConfigDataTest);
1020
1021 class DynamicsProcessingLimiterLinkerDataTest : public DynamicsProcessingLimiterConfigDataTest {
1022 public:
DynamicsProcessingLimiterLinkerDataTest()1023 DynamicsProcessingLimiterLinkerDataTest()
1024 : DynamicsProcessingLimiterConfigDataTest(GetParam(), AudioChannelLayout::LAYOUT_STEREO) {}
1025
calculateExpectedOutputDb(std::vector<float> & expectedOutputDb)1026 void calculateExpectedOutputDb(std::vector<float>& expectedOutputDb) {
1027 std::vector<float> inputDbValues = calculateStereoDb(mInput, kStartIndex);
1028 ASSERT_EQ(inputDbValues.size(), kRatioThresholdPairValues.size());
1029 EXPECT_NEAR(inputDbValues[0], inputDbValues[1], kToleranceDb);
1030 for (size_t i = 0; i < kRatioThresholdPairValues.size(); i++) {
1031 const auto& [ratio, threshold] = kRatioThresholdPairValues[i];
1032 expectedOutputDb.push_back((inputDbValues[i] - threshold) / ratio + threshold);
1033 }
1034 }
1035
calculateStereoDb(const std::vector<float> & input,size_t startSamplePos=0)1036 std::vector<float> calculateStereoDb(const std::vector<float>& input,
1037 size_t startSamplePos = 0) {
1038 std::vector<float> leftChannel;
1039 std::vector<float> rightChannel;
1040 for (size_t i = 0; i < input.size(); i += 2) {
1041 leftChannel.push_back(input[i]);
1042 if (i + 1 < input.size()) {
1043 rightChannel.push_back(input[i + 1]);
1044 }
1045 }
1046 return {calculateDb(leftChannel, startSamplePos),
1047 calculateDb(rightChannel, startSamplePos)};
1048 }
1049
setLinkGroupAndProcess(std::vector<float> & output,bool hasSameLinkGroup)1050 void setLinkGroupAndProcess(std::vector<float>& output, bool hasSameLinkGroup) {
1051 for (int i = 0; i < mChannelCount; i++) {
1052 const auto& [ratio, threshold] = kRatioThresholdPairValues[i];
1053 ASSERT_NE(ratio, 0);
1054 int linkGroup = hasSameLinkGroup ? kDefaultLinkerGroup : i;
1055 fillLimiterConfig(mLimiterConfigList, i, true, linkGroup, kDefaultAttackTime,
1056 kDefaultReleaseTime, ratio, threshold, kDefaultPostGain);
1057 }
1058
1059 ASSERT_NO_FATAL_FAILURE(setLimiterParamsAndProcess(mInput, output));
1060
1061 if (!isAllParamsValid()) {
1062 GTEST_SKIP() << "Invalid parameters. Skipping the test\n";
1063 }
1064 }
1065
1066 const std::vector<std::pair<float, float>> kRatioThresholdPairValues = {{2, -10}, {5, -20}};
1067 };
1068
TEST_P(DynamicsProcessingLimiterLinkerDataTest,SameLinkGroupDifferentConfigs)1069 TEST_P(DynamicsProcessingLimiterLinkerDataTest, SameLinkGroupDifferentConfigs) {
1070 std::vector<float> output(mInput.size());
1071
1072 ASSERT_NO_FATAL_FAILURE(setLinkGroupAndProcess(output, true));
1073
1074 std::vector<float> outputDbValues = calculateStereoDb(output, kStartIndex);
1075
1076 std::vector<float> expectedOutputDbValues;
1077 ASSERT_NO_FATAL_FAILURE(calculateExpectedOutputDb(expectedOutputDbValues));
1078
1079 // Verify that the actual output dB is same as the calculated maximum attenuation.
1080 float expectedOutputDb = std::min(expectedOutputDbValues[0], expectedOutputDbValues[1]);
1081 EXPECT_NEAR(outputDbValues[0], expectedOutputDb, kToleranceDb);
1082 EXPECT_NEAR(outputDbValues[1], expectedOutputDb, kToleranceDb);
1083 }
1084
TEST_P(DynamicsProcessingLimiterLinkerDataTest,DifferentLinkGroupDifferentConfigs)1085 TEST_P(DynamicsProcessingLimiterLinkerDataTest, DifferentLinkGroupDifferentConfigs) {
1086 std::vector<float> output(mInput.size());
1087
1088 ASSERT_NO_FATAL_FAILURE(setLinkGroupAndProcess(output, false));
1089
1090 std::vector<float> outputDbValues = calculateStereoDb(output, kStartIndex);
1091
1092 std::vector<float> expectedOutputDbValues;
1093 ASSERT_NO_FATAL_FAILURE(calculateExpectedOutputDb(expectedOutputDbValues));
1094
1095 // Verify that both channels have different compression levels
1096 EXPECT_GT(abs(expectedOutputDbValues[0] - expectedOutputDbValues[1]), kMinDifferenceDb)
1097 << "Left channel level: " << expectedOutputDbValues[0]
1098 << " Right channel level: " << expectedOutputDbValues[1];
1099
1100 // Verify that the actual output and the calculated dB values are same
1101 EXPECT_NEAR(outputDbValues[0], expectedOutputDbValues[0], kToleranceDb);
1102 EXPECT_NEAR(outputDbValues[1], expectedOutputDbValues[1], kToleranceDb);
1103 }
1104
1105 INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingLimiterLinkerDataTest,
1106 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1107 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
__anon6e9317b30d02(const auto& info) 1108 [](const auto& info) {
1109 auto descriptor = info.param;
1110 std::string name = getPrefix(descriptor.second);
1111 std::replace_if(
1112 name.begin(), name.end(),
1113 [](const char c) { return !std::isalnum(c); }, '_');
1114 return name;
1115 });
1116 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingLimiterLinkerDataTest);
1117
1118 /**
1119 * Test DynamicsProcessing ChannelConfig
1120 */
1121 enum ChannelConfigTestParamName {
1122 BAND_CHANNEL_TEST_INSTANCE_NAME,
1123 BAND_CHANNEL_TEST_CHANNEL_CONFIG
1124 };
1125 using ChannelConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
1126 std::vector<DynamicsProcessing::ChannelConfig>>;
1127
1128 class DynamicsProcessingTestChannelConfig
1129 : public ::testing::TestWithParam<ChannelConfigTestParams>,
1130 public DynamicsProcessingTestHelper {
1131 public:
DynamicsProcessingTestChannelConfig()1132 DynamicsProcessingTestChannelConfig()
1133 : DynamicsProcessingTestHelper(std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(GetParam())),
1134 mCfg(std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(GetParam())) {}
1135
SetUp()1136 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
1137
TearDown()1138 void TearDown() override { TearDownDynamicsProcessingEffect(); }
1139
1140 std::vector<DynamicsProcessing::ChannelConfig> mCfg;
1141 };
1142
TEST_P(DynamicsProcessingTestChannelConfig,SetAndGetPreEqChannelConfig)1143 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPreEqChannelConfig) {
1144 addEngineConfig(mEngineConfigPreset);
1145 addPreEqChannelConfig(mCfg);
1146 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
1147 }
1148
TEST_P(DynamicsProcessingTestChannelConfig,SetAndGetPostEqChannelConfig)1149 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPostEqChannelConfig) {
1150 addEngineConfig(mEngineConfigPreset);
1151 addPostEqChannelConfig(mCfg);
1152 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
1153 }
1154
TEST_P(DynamicsProcessingTestChannelConfig,SetAndGetMbcChannelConfig)1155 TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetMbcChannelConfig) {
1156 addEngineConfig(mEngineConfigPreset);
1157 addMbcChannelConfig(mCfg);
1158 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
1159 }
1160
1161 INSTANTIATE_TEST_SUITE_P(
1162 DynamicsProcessingTest, DynamicsProcessingTestChannelConfig,
1163 ::testing::Combine(
1164 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1165 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
1166 testing::ValuesIn(
1167 DynamicsProcessingTestHelper::kChannelConfigTestSet)), // channel config
__anon6e9317b30f02(const auto& info) 1168 [](const auto& info) {
1169 auto descriptor = std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(info.param).second;
1170 std::string channelConfig = ::android::internal::ToString(
1171 std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(info.param));
1172
1173 std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
1174 descriptor.common.name + "_UUID_" +
1175 toString(descriptor.common.id.uuid) + "_" + channelConfig;
1176 std::replace_if(
1177 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
1178 return name;
1179 });
1180 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestChannelConfig);
1181
1182 /**
1183 * Test DynamicsProcessing EqBandConfig
1184 */
1185 enum EqBandConfigTestParamName {
1186 EQ_BAND_INSTANCE_NAME,
1187 EQ_BAND_CHANNEL,
1188 EQ_BAND_CUT_OFF_FREQ,
1189 EQ_BAND_GAIN
1190 };
1191 using EqBandConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
1192 std::vector<std::pair<int, float>>, float>;
1193
fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig> & cfgs,const EqBandConfigTestParams & params)1194 void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
1195 const EqBandConfigTestParams& params) {
1196 const std::vector<std::pair<int, float>> cutOffFreqs = std::get<EQ_BAND_CUT_OFF_FREQ>(params);
1197 int bandCount = cutOffFreqs.size();
1198 for (int i = 0; i < bandCount; i++) {
1199 cfgs.push_back(creatEqBandConfig(std::get<EQ_BAND_CHANNEL>(params), cutOffFreqs[i].first,
1200 cutOffFreqs[i].second, std::get<EQ_BAND_GAIN>(params),
1201 true));
1202 }
1203 }
1204
1205 class DynamicsProcessingTestEqBandConfig : public ::testing::TestWithParam<EqBandConfigTestParams>,
1206 public DynamicsProcessingTestHelper {
1207 public:
DynamicsProcessingTestEqBandConfig()1208 DynamicsProcessingTestEqBandConfig()
1209 : DynamicsProcessingTestHelper(std::get<EQ_BAND_INSTANCE_NAME>(GetParam())) {
1210 fillEqBandConfig(mCfgs, GetParam());
1211 }
1212
SetUp()1213 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
1214
TearDown()1215 void TearDown() override { TearDownDynamicsProcessingEffect(); }
1216
1217 std::vector<DynamicsProcessing::EqBandConfig> mCfgs;
1218 };
1219
TEST_P(DynamicsProcessingTestEqBandConfig,SetAndGetPreEqBandConfig)1220 TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) {
1221 mEngineConfigPreset.preEqStage.bandCount = mCfgs.size();
1222 addEngineConfig(mEngineConfigPreset);
1223 std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
1224 for (int i = 0; i < mChannelCount; i++) {
1225 cfgs[i].channel = i;
1226 cfgs[i].enable = true;
1227 }
1228 addPreEqChannelConfig(cfgs);
1229 addPreEqBandConfigs(mCfgs);
1230 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
1231 }
1232
TEST_P(DynamicsProcessingTestEqBandConfig,SetAndGetPostEqBandConfig)1233 TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPostEqBandConfig) {
1234 SKIP_TEST_IF_VERSION_UNSUPPORTED(mEffect, kMinDataTestHalVersion);
1235
1236 mEngineConfigPreset.postEqStage.bandCount = mCfgs.size();
1237 addEngineConfig(mEngineConfigPreset);
1238 std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
1239 for (int i = 0; i < mChannelCount; i++) {
1240 cfgs[i].channel = i;
1241 cfgs[i].enable = true;
1242 }
1243 addPostEqChannelConfig(cfgs);
1244 addPostEqBandConfigs(mCfgs);
1245 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
1246 }
1247
1248 std::vector<std::vector<std::pair<int, float>>> kBands{
1249 {
1250 {0, 600},
1251 {1, 2000},
1252 {2, 6000},
1253 {3, 10000},
1254 {4, 16000},
1255 {5, 20000},
1256 {6, 26000},
1257 {7, 30000},
1258 {8, 36000},
1259 {9, 40000},
1260 }, // 10 bands
1261 {
1262 {0, 800},
1263 {3, 15000},
1264 {2, 6000},
1265 {1, 2000},
1266 }, // 4 bands, unsorted
1267 {
1268 {0, 650},
1269 {1, 2000},
1270 {2, 6000},
1271 {3, 10000},
1272 {3, 16000},
1273 }, // 5 bands, missing band
1274 {
1275 {0, 900},
1276 {1, 8000},
1277 {2, 4000},
1278 {3, 12000},
1279 }, // 4 bands, cutoff freq not increasing
1280 {
1281 {0, 450},
1282 {1, 2000},
1283 {7, 6000},
1284 {3, 10000},
1285 {4, 16000},
1286 }, // bad band index
1287 {
1288 {0, 1},
1289 {1, 8000},
1290 }, // too low cutoff freq
1291 {
1292 {0, 1200},
1293 {1, 80000},
1294 }, // too high cutoff freq
1295 };
1296
1297 INSTANTIATE_TEST_SUITE_P(
1298 DynamicsProcessingTest, DynamicsProcessingTestEqBandConfig,
1299 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1300 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
1301 testing::Values(-1, 0, 10), // channel index
1302 testing::ValuesIn(kBands), // band index, cut off frequencies
1303 testing::Values(-3.14f, 3.14f) // gain
1304 ),
__anon6e9317b31102(const auto& info) 1305 [](const auto& info) {
1306 auto descriptor = std::get<EQ_BAND_INSTANCE_NAME>(info.param).second;
1307 std::vector<DynamicsProcessing::EqBandConfig> cfgs;
1308 fillEqBandConfig(cfgs, info.param);
1309 std::string bands = ::android::internal::ToString(cfgs);
1310 std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
1311 descriptor.common.name + "_UUID_" +
1312 toString(descriptor.common.id.uuid) + "_bands_" + bands;
1313 std::replace_if(
1314 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
1315 return name;
1316 });
1317 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEqBandConfig);
1318
1319 class DynamicsProcessingEqBandConfigDataTest
1320 : public ::testing::TestWithParam<std::pair<std::shared_ptr<IFactory>, Descriptor>>,
1321 public DynamicsProcessingTestHelper {
1322 public:
DynamicsProcessingEqBandConfigDataTest()1323 DynamicsProcessingEqBandConfigDataTest()
1324 : DynamicsProcessingTestHelper(GetParam(), AudioChannelLayout::LAYOUT_MONO) {
1325 mBinOffsets.resize(mMultitoneTestFrequencies.size());
1326 }
1327
SetUp()1328 void SetUp() override {
1329 ASSERT_NO_FATAL_FAILURE(
1330 setUpDataTest(mMultitoneTestFrequencies, kSineMultitoneFullScaleDb));
1331 }
1332
TearDown()1333 void TearDown() override { ASSERT_NO_FATAL_FAILURE(tearDownDataTest()); }
1334
addEqParam(bool isPreEq)1335 void addEqParam(bool isPreEq) {
1336 createChannelConfig();
1337 auto stage = isPreEq ? mEngineConfigPreset.preEqStage : mEngineConfigPreset.postEqStage;
1338 stage.bandCount = mCfgs.size();
1339 addEngineConfig(mEngineConfigPreset);
1340 isPreEq ? addPreEqChannelConfig(mChannelConfig) : addPostEqChannelConfig(mChannelConfig);
1341 isPreEq ? addPreEqBandConfigs(mCfgs) : addPostEqBandConfigs(mCfgs);
1342 }
1343
setEqParamAndProcess(std::vector<float> & output,bool isPreEq)1344 void setEqParamAndProcess(std::vector<float>& output, bool isPreEq) {
1345 addEqParam(isPreEq);
1346 ASSERT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
1347 }
1348
fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig> & cfgs,int channelIndex,int bandIndex,int cutOffFreqHz,float gainDb,bool enable)1349 void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs, int channelIndex,
1350 int bandIndex, int cutOffFreqHz, float gainDb, bool enable) {
1351 cfgs.push_back(creatEqBandConfig(channelIndex, bandIndex, static_cast<float>(cutOffFreqHz),
1352 gainDb, enable));
1353 }
1354
validateOutput(const std::vector<float> & output,float gainDb,size_t bandIndex,bool enable)1355 void validateOutput(const std::vector<float>& output, float gainDb, size_t bandIndex,
1356 bool enable) {
1357 std::vector<float> outputMag(mBinOffsets.size());
1358 EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(output, outputMag));
1359 if (gainDb == 0 || !enable) {
1360 EXPECT_NO_FATAL_FAILURE(checkInputAndOutputEquality(outputMag));
1361 } else if (gainDb > 0) {
1362 // For positive gain, current band's magnitude is greater than the other band's
1363 // magnitude
1364 EXPECT_GT(outputMag[bandIndex], outputMag[bandIndex ^ 1]);
1365 } else {
1366 // For negative gain, current band's magnitude is less than the other band's magnitude
1367 EXPECT_LT(outputMag[bandIndex], outputMag[bandIndex ^ 1]);
1368 }
1369 }
1370
analyseMultiBandOutput(float gainDb,bool isPreEq,bool enable=true)1371 void analyseMultiBandOutput(float gainDb, bool isPreEq, bool enable = true) {
1372 std::vector<float> output(mInput.size());
1373 roundToFreqCenteredToFftBin(mMultitoneTestFrequencies, mBinOffsets, kBinWidth);
1374 // Set Equalizer values for two bands
1375 for (size_t i = 0; i < kCutoffFreqHz.size(); i++) {
1376 for (int channelIndex = 0; channelIndex < mChannelCount; channelIndex++) {
1377 fillEqBandConfig(mCfgs, channelIndex, i, kCutoffFreqHz[i], gainDb, enable);
1378 fillEqBandConfig(mCfgs, channelIndex, i ^ 1, kCutoffFreqHz[i ^ 1], 0, enable);
1379 }
1380 ASSERT_NO_FATAL_FAILURE(setEqParamAndProcess(output, isPreEq));
1381
1382 if (isAllParamsValid()) {
1383 ASSERT_NO_FATAL_FAILURE(validateOutput(output, gainDb, i, enable));
1384 }
1385 cleanUpEqConfig();
1386 }
1387 }
1388
cleanUpEqConfig()1389 void cleanUpEqConfig() {
1390 CleanUp();
1391 mCfgs.clear();
1392 mChannelConfig.clear();
1393 }
1394
1395 const std::vector<float> kTestGainDbValues = {-200, -100, 0, 100, 200};
1396 std::vector<DynamicsProcessing::EqBandConfig> mCfgs;
1397 };
1398
TEST_P(DynamicsProcessingEqBandConfigDataTest,IncreasingPreEqGain)1399 TEST_P(DynamicsProcessingEqBandConfigDataTest, IncreasingPreEqGain) {
1400 for (float gainDb : kTestGainDbValues) {
1401 ASSERT_NO_FATAL_FAILURE(generateSineWave(mMultitoneTestFrequencies, mInput,
1402 dBToAmplitude(gainDb), kSamplingFrequency,
1403 mChannelLayout));
1404 cleanUpEqConfig();
1405 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(gainDb, true /*pre-equalizer*/));
1406 }
1407 }
1408
TEST_P(DynamicsProcessingEqBandConfigDataTest,IncreasingPostEqGain)1409 TEST_P(DynamicsProcessingEqBandConfigDataTest, IncreasingPostEqGain) {
1410 for (float gainDb : kTestGainDbValues) {
1411 ASSERT_NO_FATAL_FAILURE(generateSineWave(mMultitoneTestFrequencies, mInput,
1412 dBToAmplitude(gainDb), kSamplingFrequency,
1413 mChannelLayout));
1414 cleanUpEqConfig();
1415 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(gainDb, false /*post-equalizer*/));
1416 }
1417 }
1418
TEST_P(DynamicsProcessingEqBandConfigDataTest,PreEqEnableDisable)1419 TEST_P(DynamicsProcessingEqBandConfigDataTest, PreEqEnableDisable) {
1420 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(10 /*gain dB*/, true /*pre-equalizer*/,
1421 false /*disable equalizer*/));
1422 }
1423
TEST_P(DynamicsProcessingEqBandConfigDataTest,PostEqEnableDisable)1424 TEST_P(DynamicsProcessingEqBandConfigDataTest, PostEqEnableDisable) {
1425 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(10 /*gain dB*/, false /*post-equalizer*/,
1426 false /*disable equalizer*/));
1427 }
1428
1429 INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingEqBandConfigDataTest,
1430 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1431 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
__anon6e9317b31302(const auto& info) 1432 [](const auto& info) {
1433 auto descriptor = info.param;
1434 std::string name = getPrefix(descriptor.second);
1435 std::replace_if(
1436 name.begin(), name.end(),
1437 [](const char c) { return !std::isalnum(c); }, '_');
1438 return name;
1439 });
1440 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingEqBandConfigDataTest);
1441
1442 /**
1443 * Test DynamicsProcessing MbcBandConfig
1444 */
1445
1446 enum MbcBandConfigParamName {
1447 MBC_BAND_INSTANCE_NAME,
1448 MBC_BAND_CHANNEL,
1449 MBC_BAND_CUTOFF_FREQ,
1450 MBC_BAND_ADDITIONAL
1451 };
1452 enum MbcBandConfigAdditional {
1453 MBC_ADD_ATTACK_TIME,
1454 MBC_ADD_RELEASE_TIME,
1455 MBC_ADD_RATIO,
1456 MBC_ADD_THRESHOLD,
1457 MBC_ADD_KNEE_WIDTH,
1458 MBC_ADD_NOISE_GATE_THRESHOLD,
1459 MBC_ADD_EXPENDER_RATIO,
1460 MBC_ADD_PRE_GAIN,
1461 MBC_ADD_POST_GAIN,
1462 MBC_ADD_MAX_NUM
1463 };
1464 using TestParamsMbcBandConfigAdditional = std::array<float, MBC_ADD_MAX_NUM>;
1465
1466 // attackTime, releaseTime, ratio, thresh, kneeWidth, noise, expander, preGain, postGain
1467 static constexpr std::array<TestParamsMbcBandConfigAdditional, 4> kMbcBandConfigAdditionalParam = {
1468 {{-3, -10, -2, -2, -5, -90, -2.5, -2, -2},
1469 {0, 0, 0, 0, 0, 0, 0, 0, 0},
1470 {-3, 10, -2, 2, -5, 90, -2.5, 2, -2},
1471 {3, 10, 2, -2, -5, 90, 2.5, 2, 2}}};
1472
1473 using TestParamsMbcBandConfig =
1474 std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
1475 std::vector<std::pair<int, float>>, TestParamsMbcBandConfigAdditional>;
1476
fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig> & cfgs,const TestParamsMbcBandConfig & params)1477 void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
1478 const TestParamsMbcBandConfig& params) {
1479 const auto& cutOffFreqs = std::get<MBC_BAND_CUTOFF_FREQ>(params);
1480 const auto& additional = std::get<MBC_BAND_ADDITIONAL>(params);
1481
1482 cfgs.resize(cutOffFreqs.size());
1483
1484 for (size_t i = 0; i < cutOffFreqs.size(); ++i) {
1485 cfgs[i] = createMbcBandConfig(std::get<MBC_BAND_CHANNEL>(params),
1486 cutOffFreqs[i].first, // band channel
1487 cutOffFreqs[i].second, // band cutoff frequency
1488 additional[MBC_ADD_ATTACK_TIME],
1489 additional[MBC_ADD_RELEASE_TIME], additional[MBC_ADD_RATIO],
1490 additional[MBC_ADD_THRESHOLD], additional[MBC_ADD_KNEE_WIDTH],
1491 additional[MBC_ADD_NOISE_GATE_THRESHOLD],
1492 additional[MBC_ADD_EXPENDER_RATIO],
1493 additional[MBC_ADD_PRE_GAIN], additional[MBC_ADD_POST_GAIN]);
1494 }
1495 }
1496
1497 class DynamicsProcessingTestMbcBandConfig
1498 : public ::testing::TestWithParam<TestParamsMbcBandConfig>,
1499 public DynamicsProcessingTestHelper {
1500 public:
DynamicsProcessingTestMbcBandConfig()1501 DynamicsProcessingTestMbcBandConfig()
1502 : DynamicsProcessingTestHelper(std::get<MBC_BAND_INSTANCE_NAME>(GetParam())) {
1503 fillMbcBandConfig(mCfgs, GetParam());
1504 }
1505
SetUp()1506 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpDynamicsProcessingEffect()); }
1507
TearDown()1508 void TearDown() override { TearDownDynamicsProcessingEffect(); }
1509
1510 std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
1511 };
1512
TEST_P(DynamicsProcessingTestMbcBandConfig,SetAndGetMbcBandConfig)1513 TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) {
1514 mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
1515 addEngineConfig(mEngineConfigPreset);
1516 std::vector<DynamicsProcessing::ChannelConfig> cfgs(mChannelCount);
1517 for (int i = 0; i < mChannelCount; i++) {
1518 cfgs[i].channel = i;
1519 cfgs[i].enable = true;
1520 }
1521 addMbcChannelConfig(cfgs);
1522 addMbcBandConfigs(mCfgs);
1523 ASSERT_NO_FATAL_FAILURE(SetAndGetDynamicsProcessingParameters());
1524 }
1525
1526 INSTANTIATE_TEST_SUITE_P(
1527 DynamicsProcessingTest, DynamicsProcessingTestMbcBandConfig,
1528 ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1529 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
1530 testing::Values(-1, 0, 10), // channel index
1531 testing::ValuesIn(kBands), // band index, cut off frequencies
1532 testing::ValuesIn(kMbcBandConfigAdditionalParam)), // Additional
__anon6e9317b31502(const auto& info) 1533 [](const auto& info) {
1534 auto descriptor = std::get<MBC_BAND_INSTANCE_NAME>(info.param).second;
1535 std::vector<DynamicsProcessing::MbcBandConfig> cfgs;
1536 fillMbcBandConfig(cfgs, info.param);
1537 std::string mbcBands = ::android::internal::ToString(cfgs);
1538 std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
1539 descriptor.common.name + "_UUID_" +
1540 toString(descriptor.common.id.uuid) + "_bands_" + mbcBands;
1541 std::replace_if(
1542 name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
1543 return name;
1544 });
1545 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestMbcBandConfig);
1546
1547 class DynamicsProcessingMbcBandConfigDataTest
1548 : public ::testing::TestWithParam<std::pair<std::shared_ptr<IFactory>, Descriptor>>,
1549 public DynamicsProcessingTestHelper {
1550 public:
DynamicsProcessingMbcBandConfigDataTest()1551 DynamicsProcessingMbcBandConfigDataTest()
1552 : DynamicsProcessingTestHelper(GetParam(), AudioChannelLayout::LAYOUT_MONO) {
1553 mBinOffsets.resize(mMultitoneTestFrequencies.size());
1554 }
1555
SetUp()1556 void SetUp() override {
1557 ASSERT_NO_FATAL_FAILURE(
1558 setUpDataTest(mMultitoneTestFrequencies, kSineMultitoneFullScaleDb));
1559 }
1560
TearDown()1561 void TearDown() override { ASSERT_NO_FATAL_FAILURE(tearDownDataTest()); }
1562
setMbcParamsAndProcess(std::vector<float> & output)1563 void setMbcParamsAndProcess(std::vector<float>& output) {
1564 createChannelConfig();
1565 mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
1566 addEngineConfig(mEngineConfigPreset);
1567 addMbcChannelConfig(mChannelConfig);
1568 addMbcBandConfigs(mCfgs);
1569 ASSERT_NO_FATAL_FAILURE(setParamsAndProcess(mInput, output));
1570 }
1571
fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig> & cfgs,int channelIndex,float threshold,float ratio,float noiseGate,float expanderRatio,int bandIndex,int cutoffFreqHz,float preGain,float postGain)1572 void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs, int channelIndex,
1573 float threshold, float ratio, float noiseGate, float expanderRatio,
1574 int bandIndex, int cutoffFreqHz, float preGain, float postGain) {
1575 cfgs.push_back(createMbcBandConfig(channelIndex, bandIndex,
1576 static_cast<float>(cutoffFreqHz), kDefaultAttackTime,
1577 kDefaultReleaseTime, ratio, threshold, kDefaultKneeWidth,
1578 noiseGate, expanderRatio, preGain, postGain));
1579 }
1580
validateOutput(const std::vector<float> & output,float threshold,float ratio,size_t bandIndex)1581 void validateOutput(const std::vector<float>& output, float threshold, float ratio,
1582 size_t bandIndex) {
1583 std::vector<float> outputMag(mBinOffsets.size());
1584 EXPECT_NO_FATAL_FAILURE(getMagnitudeValue(output, outputMag));
1585 if (threshold >= mInputDb || ratio == 1) {
1586 EXPECT_NO_FATAL_FAILURE(checkInputAndOutputEquality(outputMag));
1587 } else {
1588 // Current band's magnitude is less than the other band's magnitude
1589 EXPECT_LT(outputMag[bandIndex], outputMag[bandIndex ^ 1]);
1590 }
1591 }
1592
analyseMultiBandOutput(float threshold,float ratio)1593 void analyseMultiBandOutput(float threshold, float ratio) {
1594 std::vector<float> output(mInput.size());
1595 roundToFreqCenteredToFftBin(mMultitoneTestFrequencies, mBinOffsets, kBinWidth);
1596 // Set MBC values for two bands
1597 for (size_t i = 0; i < kCutoffFreqHz.size(); i++) {
1598 for (int channelIndex = 0; channelIndex < mChannelCount; channelIndex++) {
1599 fillMbcBandConfig(mCfgs, channelIndex, threshold, ratio, kDefaultNoiseGateDb,
1600 kDefaultExpanderRatio, i, kCutoffFreqHz[i], kDefaultPreGainDb,
1601 kDefaultPostGainDb);
1602 fillMbcBandConfig(mCfgs, channelIndex, kDefaultThresholdDb, kDefaultRatio,
1603 kDefaultNoiseGateDb, kDefaultExpanderRatio, i ^ 1,
1604 kCutoffFreqHz[i ^ 1], kDefaultPreGainDb, kDefaultPostGainDb);
1605 }
1606 ASSERT_NO_FATAL_FAILURE(setMbcParamsAndProcess(output));
1607
1608 if (isAllParamsValid()) {
1609 ASSERT_NO_FATAL_FAILURE(validateOutput(output, threshold, ratio, i));
1610 }
1611 cleanUpMbcConfig();
1612 }
1613 }
1614
cleanUpMbcConfig()1615 void cleanUpMbcConfig() {
1616 CleanUp();
1617 mCfgs.clear();
1618 mChannelConfig.clear();
1619 }
1620
1621 static constexpr float kDefaultPostGainDb = 0;
1622 static constexpr float kDefaultPreGainDb = 0;
1623 static constexpr float kDefaultAttackTime = 0;
1624 static constexpr float kDefaultReleaseTime = 0;
1625 static constexpr float kDefaultKneeWidth = 0;
1626 static constexpr float kDefaultThresholdDb = 0;
1627 static constexpr float kDefaultNoiseGateDb = -10;
1628 static constexpr float kDefaultExpanderRatio = 1;
1629 static constexpr float kDefaultRatio = 1;
1630 std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
1631 };
1632
TEST_P(DynamicsProcessingMbcBandConfigDataTest,IncreasingThreshold)1633 TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingThreshold) {
1634 float ratio = 20;
1635 std::vector<float> thresholdValues = {-200, -100, 0, 100, 200};
1636
1637 for (float threshold : thresholdValues) {
1638 cleanUpMbcConfig();
1639 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(threshold, ratio));
1640 }
1641 }
1642
TEST_P(DynamicsProcessingMbcBandConfigDataTest,IncreasingRatio)1643 TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingRatio) {
1644 float threshold = -20;
1645 std::vector<float> ratioValues = {1, 10, 20, 30, 40, 50};
1646
1647 for (float ratio : ratioValues) {
1648 cleanUpMbcConfig();
1649 ASSERT_NO_FATAL_FAILURE(analyseMultiBandOutput(threshold, ratio));
1650 }
1651 }
1652
TEST_P(DynamicsProcessingMbcBandConfigDataTest,IncreasingPostGain)1653 TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingPostGain) {
1654 std::vector<float> postGainDbValues = {-55, -30, 0, 30, 55};
1655 std::vector<float> output(mInput.size());
1656 for (float postGainDb : postGainDbValues) {
1657 ASSERT_NO_FATAL_FAILURE(generateSineWave(mMultitoneTestFrequencies, mInput,
1658 dBToAmplitude(postGainDb), kSamplingFrequency,
1659 mChannelLayout));
1660 mInputDb = calculateDb(mInput);
1661 EXPECT_NEAR(mInputDb, kSineMultitoneFullScaleDb - postGainDb, kToleranceDb);
1662 cleanUpMbcConfig();
1663 for (int i = 0; i < mChannelCount; i++) {
1664 fillMbcBandConfig(mCfgs, i, kDefaultThresholdDb, kDefaultRatio, kDefaultNoiseGateDb,
1665 kDefaultExpanderRatio, 0 /*band index*/, 2000 /*cutoffFrequency*/,
1666 kDefaultPreGainDb, postGainDb);
1667 }
1668 EXPECT_NO_FATAL_FAILURE(setMbcParamsAndProcess(output));
1669 if (!isAllParamsValid()) {
1670 continue;
1671 }
1672 float outputDb = calculateDb(output, kStartIndex);
1673 EXPECT_NEAR(outputDb, mInputDb + postGainDb, kToleranceDb)
1674 << "PostGain: " << postGainDb << ", OutputDb: " << outputDb;
1675 }
1676 }
1677
TEST_P(DynamicsProcessingMbcBandConfigDataTest,IncreasingPreGain)1678 TEST_P(DynamicsProcessingMbcBandConfigDataTest, IncreasingPreGain) {
1679 /*
1680 Depending on the pregain values, samples undergo either compression or expansion process.
1681 At -6 dB input,
1682 - Expansion is expected at -60 dB,
1683 - Compression at 10, 34 and 60 dB
1684 - No compression or expansion at -34, -10, -1 dB.
1685 */
1686 std::vector<float> preGainDbValues = {-60, -34, -10, -1, 10, 34, 60};
1687 std::vector<float> output(mInput.size());
1688 float thresholdDb = -7;
1689 float noiseGateDb = -40;
1690 std::vector<float> ratioValues = {1, 1.5, 2, 2.5, 3};
1691 for (float ratio : ratioValues) {
1692 for (float preGainDb : preGainDbValues) {
1693 float expectedOutputDb;
1694 float inputWithPreGain = mInputDb + preGainDb;
1695 if (inputWithPreGain > thresholdDb) {
1696 SCOPED_TRACE("Compressor ratio: " + std::to_string(ratio));
1697 expectedOutputDb =
1698 (inputWithPreGain - thresholdDb) / ratio + thresholdDb - preGainDb;
1699 } else if (inputWithPreGain < noiseGateDb) {
1700 SCOPED_TRACE("Expander ratio: " + std::to_string(ratio));
1701 expectedOutputDb =
1702 (inputWithPreGain - noiseGateDb) * ratio + noiseGateDb - preGainDb;
1703 } else {
1704 expectedOutputDb = mInputDb;
1705 }
1706 cleanUpMbcConfig();
1707 for (int i = 0; i < mChannelCount; i++) {
1708 fillMbcBandConfig(mCfgs, i, thresholdDb, ratio /*compressor ratio*/, noiseGateDb,
1709 ratio /*expander ratio*/, 0 /*band index*/,
1710 2000 /*cutoffFrequency*/, preGainDb, kDefaultPostGainDb);
1711 }
1712 EXPECT_NO_FATAL_FAILURE(setMbcParamsAndProcess(output));
1713 if (!isAllParamsValid()) {
1714 continue;
1715 }
1716 float outputDb = calculateDb(output, kStartIndex);
1717 EXPECT_NEAR(outputDb, expectedOutputDb, kToleranceDb)
1718 << "PreGain: " << preGainDb << ", OutputDb: " << outputDb;
1719 }
1720 }
1721 }
1722
1723 INSTANTIATE_TEST_SUITE_P(DynamicsProcessingTest, DynamicsProcessingMbcBandConfigDataTest,
1724 testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
1725 IFactory::descriptor, getEffectTypeUuidDynamicsProcessing())),
__anon6e9317b31702(const auto& info) 1726 [](const auto& info) {
1727 auto descriptor = info.param;
1728 std::string name = getPrefix(descriptor.second);
1729 std::replace_if(
1730 name.begin(), name.end(),
1731 [](const char c) { return !std::isalnum(c); }, '_');
1732 return name;
1733 });
1734
1735 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingMbcBandConfigDataTest);
1736
main(int argc,char ** argv)1737 int main(int argc, char** argv) {
1738 ::testing::InitGoogleTest(&argc, argv);
1739 ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
1740 ABinderProcess_setThreadPoolMaxThreadCount(1);
1741 ABinderProcess_startThreadPool();
1742 return RUN_ALL_TESTS();
1743 }
1744