1 /*
2 * Copyright (C) 2024 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 <array>
18
19 #define LOG_TAG "AidlEffectsUtilsTest"
20
21 #include <aidl/android/hardware/audio/effect/IEffect.h>
22 #include <gtest/gtest.h>
23 #include <log/log.h>
24 #include <system/audio_effects/aidl_effects_utils.h>
25
26 using ::aidl::android::hardware::audio::effect::Capability;
27 using ::aidl::android::hardware::audio::effect::Downmix;
28 using ::aidl::android::hardware::audio::effect::DynamicsProcessing;
29 using ::aidl::android::hardware::audio::effect::Parameter;
30 using ::aidl::android::hardware::audio::effect::Range;
31
32 // Helper function to create a DynamicsProcessing parameter with custom tag
33 template <typename DynamicsProcessing::Tag TAG = DynamicsProcessing::engineArchitecture>
dynamicsProcessing(int v,int n=0)34 static DynamicsProcessing dynamicsProcessing(int v, int n = 0) {
35 if constexpr (TAG == DynamicsProcessing::engineArchitecture) {
36 const DynamicsProcessing::EngineArchitecture engine{
37 .preferredProcessingDurationMs = static_cast<float>(v),
38 .preEqStage = DynamicsProcessing::StageEnablement{.bandCount = v},
39 .postEqStage = DynamicsProcessing::StageEnablement{.bandCount = v},
40 .mbcStage = DynamicsProcessing::StageEnablement{.bandCount = v},
41 };
42 return DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(engine);
43 } else if constexpr (TAG == DynamicsProcessing::inputGain) {
44 std::vector<DynamicsProcessing::InputGain> gain;
45 for (int i = 0; i < n; i++) {
46 gain.emplace_back(DynamicsProcessing::InputGain{
47 .channel = i, .gainDb = static_cast<float>(v)});
48 }
49 return DynamicsProcessing::make<DynamicsProcessing::inputGain>(gain);
50 } else {
51 static_assert(false, "tag not supported");
52 }
53 }
54
parameter(int v)55 static Parameter parameter(int v) {
56 return Parameter::make<Parameter::specific>(
57 Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(dynamicsProcessing(v)));
58 }
59
capability(int min,int max)60 static Capability capability(int min, int max) {
61 return Capability{
62 .range =
63 Range::make<Range::dynamicsProcessing>({Range::DynamicsProcessingRange{
64 .min = dynamicsProcessing(min), .max = dynamicsProcessing(max),
65 }}),
66 };
67 }
68
multiCapability(int min,int max)69 static Capability multiCapability(int min, int max) {
70 return Capability{
71 .range = Range::make<Range::dynamicsProcessing>({
72 Range::DynamicsProcessingRange{
73 .min = dynamicsProcessing(min), .max = dynamicsProcessing(max),
74 },
75 Range::DynamicsProcessingRange{
76 .min = dynamicsProcessing<DynamicsProcessing::inputGain>(min),
77 .max = dynamicsProcessing<DynamicsProcessing::inputGain>(max),
78 },
79 }),
80 };
81 }
82
83 // construct an invalid capability with different vector size
capabilityWithDifferentVecSize(int min,int minVecSize,int max,int maxVecSize)84 static Capability capabilityWithDifferentVecSize(int min, int minVecSize, int max, int maxVecSize) {
85 return Capability{
86 .range = Range::make<Range::dynamicsProcessing>({
87 Range::DynamicsProcessingRange{
88 .min = dynamicsProcessing<DynamicsProcessing::inputGain>(min, minVecSize),
89 .max = dynamicsProcessing<DynamicsProcessing::inputGain>(max, maxVecSize),
90 },
91 }),
92 };
93 }
94
downmixCapability()95 static Capability downmixCapability() {
96 return Capability{.range = Range::make<Range::downmix>({Range::DownmixRange{}})};
97 }
98
99 // static Range::DynamicsProcessingRange createMultiRange(int min, int max) {
100 // return Range::DynamicsProcessingRange{.min = min, .max = max};
101 // }
102
103 using FindSharedCapabilityTestParam =
104 std::tuple<int /* a_min */, int /* a_max */, int /*b_min*/, int /*b_max*/>;
105 class FindSharedCapabilityTest
106 : public ::testing::TestWithParam<FindSharedCapabilityTestParam> {
107 public:
FindSharedCapabilityTest()108 FindSharedCapabilityTest()
109 : a_min(std::get<0>(GetParam())),
110 a_max(std::get<1>(GetParam())),
111 b_min(std::get<2>(GetParam())),
112 b_max(std::get<3>(GetParam())) {}
113
114 protected:
115 const int a_min, a_max, b_min, b_max;
116 };
117
118 /**
119 * Find shared capability with all elements in the predefined capability array `kCapArray`.
120 */
TEST_P(FindSharedCapabilityTest,basic)121 TEST_P(FindSharedCapabilityTest, basic) {
122 std::optional<Capability> cap =
123 findSharedCapability(capability(a_min, a_max), capability(b_min, b_max));
124 ASSERT_NE(std::nullopt, cap);
125 EXPECT_EQ(capability(std::max(a_min, b_min), std::min(a_max, b_max)).range, cap->range);
126 }
127
TEST_P(FindSharedCapabilityTest,multi_tags)128 TEST_P(FindSharedCapabilityTest, multi_tags) {
129 std::optional<Capability> cap = findSharedCapability(
130 multiCapability(a_min, a_max), multiCapability(b_min, b_max));
131 ASSERT_NE(std::nullopt, cap);
132 EXPECT_EQ(multiCapability(std::max(a_min, b_min), std::min(a_max, b_max)).range, cap->range);
133 }
134
TEST(FindSharedCapabilityTest,diff_effects)135 TEST(FindSharedCapabilityTest, diff_effects) {
136 EXPECT_EQ(std::nullopt, findSharedCapability(capability(0, 1), downmixCapability()));
137 }
138
TEST(FindSharedCapabilityTest,capability_with_diff_vec)139 TEST(FindSharedCapabilityTest, capability_with_diff_vec) {
140 auto target = capabilityWithDifferentVecSize(1, 5, 2, 6);
141 auto shared = findSharedCapability(
142 capabilityWithDifferentVecSize(0 /*min*/, 5 /*minVacSize*/, 3 /*max*/, 6 /*maxVacSize*/),
143 capabilityWithDifferentVecSize(1 /*min*/, 5 /*minVacSize*/, 2 /*max*/, 6 /*maxVacSize*/));
144 ASSERT_NE(std::nullopt, shared);
145 EXPECT_EQ(target.range, shared->range);
146
147 // the shared min is invalid because the vector size is different
148 target = capabilityWithDifferentVecSize(0, 0, 1, 3);
149 shared = findSharedCapability(
150 capabilityWithDifferentVecSize(0 /*min*/, 2 /*minVacSize*/, 1 /*max*/, 3 /*maxVacSize*/),
151 capabilityWithDifferentVecSize(0 /*min*/, 3 /*minVacSize*/, 1 /*max*/, 3 /*maxVacSize*/));
152 ASSERT_NE(std::nullopt, shared);
153 ASSERT_EQ(Range::dynamicsProcessing, shared->range.getTag());
154 auto dpRanges = shared->range.get<Range::dynamicsProcessing>();
155 ASSERT_EQ(1ul, dpRanges.size());
156 EXPECT_EQ(DynamicsProcessing::vendor, dpRanges[0].min.getTag());
157 const auto targetRanges = target.range.get<Range::dynamicsProcessing>();
158 EXPECT_EQ(targetRanges[0].max, dpRanges[0].max);
159
160 // the shared min and max both invalid because the vector size is different
161 target = capabilityWithDifferentVecSize(0, 0, 1, 3);
162 shared = findSharedCapability(
163 capabilityWithDifferentVecSize(0 /*min*/, 2 /*minVacSize*/, 1 /*max*/, 5 /*maxVacSize*/),
164 capabilityWithDifferentVecSize(0 /*min*/, 3 /*minVacSize*/, 1 /*max*/, 3 /*maxVacSize*/));
165 EXPECT_EQ(std::nullopt, shared);
166 }
167
168 using ClampParameterTestParam = std::tuple<int /* a */, int /* b */>;
169 class ClampParameterTest
170 : public ::testing::TestWithParam<ClampParameterTestParam> {
171 public:
ClampParameterTest()172 ClampParameterTest()
173 : a(std::get<0>(GetParam())), b(std::get<1>(GetParam())) {}
174
175 protected:
176 const int a, b;
177 };
178
TEST_P(ClampParameterTest,basic)179 TEST_P(ClampParameterTest, basic) {
180 const std::optional<Parameter> clamped =
181 clampParameter<Range::dynamicsProcessing, Parameter::Specific::dynamicsProcessing>(
182 parameter(a), capability(a, b));
183 if (a <= b) {
184 ASSERT_NE(std::nullopt, clamped);
185 EXPECT_EQ(parameter(a), clamped.value());
186 } else {
187 EXPECT_EQ(std::nullopt, clamped);
188 }
189 }
190
TEST_P(ClampParameterTest,clamp_to_min)191 TEST_P(ClampParameterTest, clamp_to_min) {
192 const std::optional<Parameter> clamped =
193 clampParameter<Range::dynamicsProcessing, Parameter::Specific::dynamicsProcessing>(
194 parameter(a - 1), capability(a, b));
195 if (a <= b) {
196 ASSERT_NE(std::nullopt, clamped);
197 EXPECT_EQ(parameter(a), clamped.value());
198 } else {
199 EXPECT_EQ(std::nullopt, clamped);
200 }
201 }
202
TEST_P(ClampParameterTest,clamp_to_max)203 TEST_P(ClampParameterTest, clamp_to_max) {
204 const std::optional<Parameter> clamped =
205 clampParameter<Range::dynamicsProcessing, Parameter::Specific::dynamicsProcessing>(
206 parameter(b + 1), capability(a, b));
207 if (a <= b) {
208 ASSERT_NE(std::nullopt, clamped);
209 EXPECT_EQ(parameter(b), clamped.value());
210 } else {
211 EXPECT_EQ(std::nullopt, clamped);
212 }
213 }
214
215 // minimum and maximum value used to initialize effect parameters for comparison
216 static constexpr int kParameterStartValue = 1;
217 static constexpr int kParameterEndValue = 4; // end will not included in the generated values
218
219 INSTANTIATE_TEST_SUITE_P(
220 AidlEffectsUtilsTest, FindSharedCapabilityTest,
221 ::testing::Combine(testing::Range(kParameterStartValue, kParameterEndValue),
222 testing::Range(kParameterStartValue, kParameterEndValue),
223 testing::Range(kParameterStartValue, kParameterEndValue),
224 testing::Range(kParameterStartValue, kParameterEndValue)),
__anon30a6e0730102(const testing::TestParamInfo<FindSharedCapabilityTest::ParamType>& info) 225 [](const testing::TestParamInfo<FindSharedCapabilityTest::ParamType>& info) {
226 return std::to_string(std::get<0>(info.param)) + "_" +
227 std::to_string(std::get<1>(info.param)) + "_" +
228 std::to_string(std::get<2>(info.param)) + "_" +
229 std::to_string(std::get<3>(info.param));
230 });
231
232 INSTANTIATE_TEST_SUITE_P(
233 AidlEffectsUtilsTest, ClampParameterTest,
234 ::testing::Combine(testing::Range(kParameterStartValue, kParameterEndValue),
235 testing::Range(kParameterStartValue, kParameterEndValue)),
__anon30a6e0730202(const testing::TestParamInfo<ClampParameterTest::ParamType>& info) 236 [](const testing::TestParamInfo<ClampParameterTest::ParamType>& info) {
237 return std::to_string(std::get<0>(info.param)) + "_" +
238 std::to_string(std::get<1>(info.param));
239 });