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 "VtsHalVolumeTest"
18 #include <android-base/logging.h>
19 
20 #include "EffectHelper.h"
21 
22 using namespace android;
23 
24 using aidl::android::hardware::audio::common::getChannelCount;
25 using aidl::android::hardware::audio::effect::Descriptor;
26 using aidl::android::hardware::audio::effect::getEffectTypeUuidVolume;
27 using aidl::android::hardware::audio::effect::IEffect;
28 using aidl::android::hardware::audio::effect::IFactory;
29 using aidl::android::hardware::audio::effect::Parameter;
30 using aidl::android::hardware::audio::effect::Volume;
31 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
32 
33 class VolumeControlHelper : public EffectHelper {
34   public:
SetUpVolumeControl()35     void SetUpVolumeControl() {
36         ASSERT_NE(nullptr, mFactory);
37         ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
38         initFrameCount();
39         Parameter::Specific specific = getDefaultParamSpecific();
40         Parameter::Common common = createParamCommon(
41                 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */,
42                 kSamplingFrequency /* oSampleRate */, mInputFrameCount /* iFrameCount */,
43                 mInputFrameCount /* oFrameCount */);
44         ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &mOpenEffectReturn, EX_NONE));
45         ASSERT_NE(nullptr, mEffect);
46     }
47 
TearDownVolumeControl()48     void TearDownVolumeControl() {
49         ASSERT_NO_FATAL_FAILURE(close(mEffect));
50         ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
51         mOpenEffectReturn = IEffect::OpenEffectReturn{};
52     }
53 
getDefaultParamSpecific()54     Parameter::Specific getDefaultParamSpecific() {
55         Volume vol = Volume::make<Volume::levelDb>(kMinLevel);
56         Parameter::Specific specific = Parameter::Specific::make<Parameter::Specific::volume>(vol);
57         return specific;
58     }
59 
createVolumeParam(int param,Volume::Tag volTag)60     Parameter createVolumeParam(int param, Volume::Tag volTag) {
61         return Parameter::make<Parameter::specific>(
62                 Parameter::Specific::make<Parameter::Specific::volume>(
63                         (volTag == Volume::mute) ? Volume::make<Volume::mute>(param)
64                                                  : Volume::make<Volume::levelDb>(param)));
65     }
66 
initFrameCount()67     void initFrameCount() {
68         int channelCount = getChannelCount(
69                 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(kDefaultChannelLayout));
70         mInputFrameCount = kBufferSize / channelCount;
71         mOutputFrameCount = kBufferSize / channelCount;
72     }
73 
isLevelValid(int level)74     bool isLevelValid(int level) {
75         auto vol = Volume::make<Volume::levelDb>(level);
76         return isParameterValid<Volume, Range::volume>(vol, mDescriptor);
77     }
78 
setAndVerifyParameters(Volume::Tag volTag,int param,binder_exception_t expected)79     void setAndVerifyParameters(Volume::Tag volTag, int param, binder_exception_t expected) {
80         auto expectedParam = createVolumeParam(param, volTag);
81         EXPECT_STATUS(expected, mEffect->setParameter(expectedParam)) << expectedParam.toString();
82 
83         if (expected == EX_NONE) {
84             Volume::Id volId = Volume::Id::make<Volume::Id::commonTag>(volTag);
85 
86             auto id = Parameter::Id::make<Parameter::Id::volumeTag>(volId);
87             // get parameter
88             Parameter getParam;
89             // if set success, then get should match
90             EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
91             EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
92                                                << "\ngetParam:" << getParam.toString();
93         }
94     }
95 
96     static constexpr int kSamplingFrequency = 44100;
97     static constexpr int kDurationMilliSec = 720;
98     static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
99     static constexpr int kMinLevel = -96;
100     static constexpr int kDefaultChannelLayout = AudioChannelLayout::LAYOUT_STEREO;
101     long mInputFrameCount, mOutputFrameCount;
102     std::shared_ptr<IFactory> mFactory;
103     std::shared_ptr<IEffect> mEffect;
104     IEffect::OpenEffectReturn mOpenEffectReturn;
105     Descriptor mDescriptor;
106 };
107 /**
108  * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
109  * VtsAudioEffectTargetTest.
110  */
111 enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL, PARAM_MUTE };
112 using VolumeParamTestParam =
113         std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int, bool>;
114 
115 class VolumeParamTest : public ::testing::TestWithParam<VolumeParamTestParam>,
116                         public VolumeControlHelper {
117   public:
VolumeParamTest()118     VolumeParamTest()
119         : mParamLevel(std::get<PARAM_LEVEL>(GetParam())),
120           mParamMute(std::get<PARAM_MUTE>(GetParam())) {
121         std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
122     }
123 
SetUp()124     void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpVolumeControl()); }
TearDown()125     void TearDown() override { TearDownVolumeControl(); }
126 
127     int mParamLevel = 0;
128     bool mParamMute = false;
129 };
130 
TEST_P(VolumeParamTest,SetAndGetParams)131 TEST_P(VolumeParamTest, SetAndGetParams) {
132     ASSERT_NO_FATAL_FAILURE(
133             setAndVerifyParameters(Volume::levelDb, mParamLevel,
134                                    isLevelValid(mParamLevel) ? EX_NONE : EX_ILLEGAL_ARGUMENT));
135     ASSERT_NO_FATAL_FAILURE(setAndVerifyParameters(Volume::mute, mParamMute, EX_NONE));
136 }
137 
138 using VolumeDataTestParam = std::pair<std::shared_ptr<IFactory>, Descriptor>;
139 
140 class VolumeDataTest : public ::testing::TestWithParam<VolumeDataTestParam>,
141                        public VolumeControlHelper {
142   public:
VolumeDataTest()143     VolumeDataTest()
144         : kVsrApiLevel(
145                   android::base::GetIntProperty("ro.vendor.api_level", __ANDROID_API_FUTURE__)) {
146         std::tie(mFactory, mDescriptor) = GetParam();
147         mInput.resize(kBufferSize);
148         mInputMag.resize(mTestFrequencies.size());
149         mBinOffsets.resize(mTestFrequencies.size());
150         roundToFreqCenteredToFftBin(mTestFrequencies, mBinOffsets, kBinWidth);
151         generateMultiTone(mTestFrequencies, mInput, kSamplingFrequency);
152         mInputMag = calculateMagnitude(mInput, mBinOffsets, kNPointFFT);
153     }
154 
calculatePercentageDiff(const std::vector<float> & outputMag)155     std::vector<int> calculatePercentageDiff(const std::vector<float>& outputMag) {
156         std::vector<int> percentages(mTestFrequencies.size());
157 
158         for (size_t i = 0; i < mInputMag.size(); i++) {
159             float diff = mInputMag[i] - outputMag[i];
160             percentages[i] = std::round(diff / mInputMag[i] * 100);
161         }
162         return percentages;
163     }
164 
165     // Convert Decibel value to Percentage
percentageDb(float level)166     int percentageDb(float level) { return std::round((1 - (pow(10, level / 20))) * 100); }
167 
SetUp()168     void SetUp() override {
169         SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
170         // Skips test fixture if api_level <= 34 (__ANDROID_API_U__).
171         if (kVsrApiLevel <= __ANDROID_API_U__) GTEST_SKIP();
172         ASSERT_NO_FATAL_FAILURE(SetUpVolumeControl());
173     }
TearDown()174     void TearDown() override {
175         SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
176         if (kVsrApiLevel <= __ANDROID_API_U__) GTEST_SKIP();
177         TearDownVolumeControl();
178     }
179 
180     const int kVsrApiLevel;
181     static constexpr int kMaxAudioSample = 1;
182     static constexpr int kTransitionDuration = 300;
183     static constexpr int kNPointFFT = 16384;
184     static constexpr float kBinWidth = (float)kSamplingFrequency / kNPointFFT;
185     static constexpr size_t offset = kSamplingFrequency * kTransitionDuration / 1000;
186     static constexpr float kBaseLevel = 0;
187     std::vector<int> mTestFrequencies = {100, 1000};
188     std::vector<float> mInput;
189     std::vector<float> mInputMag;
190     std::vector<int> mBinOffsets;
191 };
192 
TEST_P(VolumeDataTest,ApplyLevelMuteUnmute)193 TEST_P(VolumeDataTest, ApplyLevelMuteUnmute) {
194     std::vector<float> output(kBufferSize);
195     std::vector<int> diffs(mTestFrequencies.size());
196     std::vector<float> outputMag(mTestFrequencies.size());
197 
198     if (!isLevelValid(kBaseLevel)) {
199         GTEST_SKIP() << "Volume Level not supported, skipping the test\n";
200     }
201 
202     // Apply Volume Level
203 
204     ASSERT_NO_FATAL_FAILURE(setAndVerifyParameters(Volume::levelDb, kBaseLevel, EX_NONE));
205     ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, output, mEffect, &mOpenEffectReturn));
206 
207     outputMag = calculateMagnitude(output, mBinOffsets, kNPointFFT);
208     diffs = calculatePercentageDiff(outputMag);
209 
210     for (size_t i = 0; i < diffs.size(); i++) {
211         ASSERT_EQ(diffs[i], percentageDb(kBaseLevel));
212     }
213 
214     // Apply Mute
215 
216     ASSERT_NO_FATAL_FAILURE(setAndVerifyParameters(Volume::mute, true /*mute*/, EX_NONE));
217     ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, output, mEffect, &mOpenEffectReturn));
218 
219     std::vector<float> subOutputMute(output.begin() + offset, output.end());
220     outputMag = calculateMagnitude(subOutputMute, mBinOffsets, kNPointFFT);
221     diffs = calculatePercentageDiff(outputMag);
222 
223     for (size_t i = 0; i < diffs.size(); i++) {
224         ASSERT_EQ(diffs[i], percentageDb(kMinLevel /*Mute*/));
225     }
226 
227     // Verifying Fade out
228     outputMag = calculateMagnitude(output, mBinOffsets, kNPointFFT);
229     diffs = calculatePercentageDiff(outputMag);
230 
231     for (size_t i = 0; i < diffs.size(); i++) {
232         ASSERT_LT(diffs[i], percentageDb(kMinLevel /*Mute*/));
233     }
234 
235     // Apply Unmute
236 
237     ASSERT_NO_FATAL_FAILURE(setAndVerifyParameters(Volume::mute, false /*unmute*/, EX_NONE));
238     ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, output, mEffect, &mOpenEffectReturn));
239 
240     std::vector<float> subOutputUnmute(output.begin() + offset, output.end());
241 
242     outputMag = calculateMagnitude(subOutputUnmute, mBinOffsets, kNPointFFT);
243     diffs = calculatePercentageDiff(outputMag);
244 
245     for (size_t i = 0; i < diffs.size(); i++) {
246         ASSERT_EQ(diffs[i], percentageDb(kBaseLevel));
247     }
248 
249     // Verifying Fade in
250     outputMag = calculateMagnitude(output, mBinOffsets, kNPointFFT);
251     diffs = calculatePercentageDiff(outputMag);
252 
253     for (size_t i = 0; i < diffs.size(); i++) {
254         ASSERT_GT(diffs[i], percentageDb(kBaseLevel));
255     }
256 }
257 
TEST_P(VolumeDataTest,DecreasingLevels)258 TEST_P(VolumeDataTest, DecreasingLevels) {
259     std::vector<int> decreasingLevels = {-24, -48, -96};
260     std::vector<float> baseOutput(kBufferSize);
261     std::vector<int> baseDiffs(mTestFrequencies.size());
262     std::vector<float> outputMag(mTestFrequencies.size());
263 
264     if (!isLevelValid(kBaseLevel)) {
265         GTEST_SKIP() << "Volume Level not supported, skipping the test\n";
266     }
267 
268     ASSERT_NO_FATAL_FAILURE(setAndVerifyParameters(Volume::levelDb, kBaseLevel, EX_NONE));
269     ASSERT_NO_FATAL_FAILURE(
270             processAndWriteToOutput(mInput, baseOutput, mEffect, &mOpenEffectReturn));
271 
272     outputMag = calculateMagnitude(baseOutput, mBinOffsets, kNPointFFT);
273     baseDiffs = calculatePercentageDiff(outputMag);
274 
275     for (int level : decreasingLevels) {
276         std::vector<float> output(kBufferSize);
277         std::vector<int> diffs(mTestFrequencies.size());
278 
279         // Skipping the further steps for unnsupported level values
280         if (!isLevelValid(level)) {
281             continue;
282         }
283         ASSERT_NO_FATAL_FAILURE(setAndVerifyParameters(Volume::levelDb, level, EX_NONE));
284         ASSERT_NO_FATAL_FAILURE(
285                 processAndWriteToOutput(mInput, output, mEffect, &mOpenEffectReturn));
286 
287         outputMag = calculateMagnitude(output, mBinOffsets, kNPointFFT);
288         diffs = calculatePercentageDiff(outputMag);
289 
290         // Decrease in volume level results in greater magnitude difference
291         for (size_t i = 0; i < diffs.size(); i++) {
292             ASSERT_GT(diffs[i], baseDiffs[i]);
293         }
294 
295         baseDiffs = diffs;
296     }
297 }
298 
299 std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
300 INSTANTIATE_TEST_SUITE_P(
301         VolumeTest, VolumeParamTest,
302         ::testing::Combine(
303                 testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
304                                           IFactory::descriptor, getEffectTypeUuidVolume())),
305                 testing::ValuesIn(
306                         EffectHelper::getTestValueSet<Volume, int, Range::volume, Volume::levelDb>(
307                                 kDescPair, EffectHelper::expandTestValueBasic<int>)),
308                 testing::Bool() /* mute */),
__anon64a1c8a70102(const testing::TestParamInfo<VolumeParamTest::ParamType>& info) 309         [](const testing::TestParamInfo<VolumeParamTest::ParamType>& info) {
310             auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
311             std::string level = std::to_string(std::get<PARAM_LEVEL>(info.param));
312             std::string mute = std::to_string(std::get<PARAM_MUTE>(info.param));
313             std::string name = getPrefix(descriptor) + "_level" + level + "_mute" + mute;
314             std::replace_if(
315                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
316             return name;
317         });
318 
319 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VolumeParamTest);
320 
321 INSTANTIATE_TEST_SUITE_P(VolumeTest, VolumeDataTest,
322                          testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
323                                  IFactory::descriptor, getEffectTypeUuidVolume())),
__anon64a1c8a70302(const testing::TestParamInfo<VolumeDataTest::ParamType>& info) 324                          [](const testing::TestParamInfo<VolumeDataTest::ParamType>& info) {
325                              auto descriptor = info.param;
326                              std::string name = getPrefix(descriptor.second);
327                              std::replace_if(
328                                      name.begin(), name.end(),
329                                      [](const char c) { return !std::isalnum(c); }, '_');
330                              return name;
331                          });
332 
333 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VolumeDataTest);
334 
main(int argc,char ** argv)335 int main(int argc, char** argv) {
336     ::testing::InitGoogleTest(&argc, argv);
337     ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
338     ABinderProcess_setThreadPoolMaxThreadCount(1);
339     ABinderProcess_startThreadPool();
340     return RUN_ALL_TESTS();
341 }
342