blob: 92e3dce1047c4b2d6468fdf74ce4f96c0732f949 [file] [log] [blame]
Shunkai Yao5c718342023-02-23 23:49:51 +00001/*
2 * Copyright 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//#define LOG_NDEBUG 0
18#include <cstddef>
19#include <cstdint>
20#include <memory>
21#include <utility>
22#define LOG_TAG "EffectProxyTest"
23
24#include <aidl/android/media/audio/common/AudioUuid.h>
25#include <aidl/Vintf.h>
26#include <android/binder_manager.h>
27#include <gtest/gtest.h>
28#include <utils/RefBase.h>
29
30#include "EffectProxy.h"
31
32/**
33 * This test suite is depending on audio effect AIDL service.
34 */
35namespace android {
36
37using ::aidl::android::hardware::audio::effect::CommandId;
38using ::aidl::android::hardware::audio::effect::Descriptor;
39using ::aidl::android::hardware::audio::effect::Flags;
40using ::aidl::android::hardware::audio::effect::IEffect;
41using ::aidl::android::hardware::audio::effect::IFactory;
42using ::aidl::android::hardware::audio::effect::Parameter;
43using ::aidl::android::hardware::audio::effect::State;
44using ::aidl::android::media::audio::common::AudioChannelLayout;
45using ::aidl::android::media::audio::common::AudioFormatDescription;
46using ::aidl::android::media::audio::common::AudioFormatType;
47using ::aidl::android::media::audio::common::AudioUuid;
48using ::aidl::android::media::audio::common::PcmType;
49using ::android::effect::EffectProxy;
50
51class EffectProxyTest : public testing::Test {
52 public:
53 void SetUp() override {
54 auto serviceName = android::getAidlHalInstanceNames(IFactory::descriptor);
55 // only unit test with the first one in case more than one EffectFactory service exist
56 ASSERT_NE(0ul, serviceName.size());
57 mFactory = IFactory::fromBinder(
58 ndk::SpAIBinder(AServiceManager_waitForService(serviceName[0].c_str())));
59 ASSERT_NE(nullptr, mFactory);
60 mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &mDescs);
61 for (const auto& desc : mDescs) {
62 if (desc.common.id.proxy.has_value()) {
63 mProxyDescs.insert({desc.common.id, desc});
64 }
65 }
66 }
67
68 void TearDown() override {}
69
70 const AudioFormatDescription kDefaultFormatDescription = {
71 .type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
72
73 Parameter::Common createParamCommon(
74 int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
75 long iFrameCount = 0x100, long oFrameCount = 0x100,
76 AudioChannelLayout inputChannelLayout =
77 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
78 AudioChannelLayout::LAYOUT_STEREO),
79 AudioChannelLayout outputChannelLayout =
80 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
81 AudioChannelLayout::LAYOUT_STEREO)) {
82 Parameter::Common common;
83 common.session = session;
84 common.ioHandle = ioHandle;
85
86 auto& input = common.input;
87 auto& output = common.output;
88 input.base.sampleRate = iSampleRate;
89 input.base.channelMask = inputChannelLayout;
90 input.base.format = kDefaultFormatDescription;
91 input.frameCount = iFrameCount;
92 output.base.sampleRate = oSampleRate;
93 output.base.channelMask = outputChannelLayout;
94 output.base.format = kDefaultFormatDescription;
95 output.frameCount = oFrameCount;
96 return common;
97 }
98
99 static bool isFlagSet(const ::aidl::android::hardware::audio::effect::Descriptor& desc,
100 Flags::HardwareAccelerator flag) {
101 return desc.common.flags.hwAcceleratorMode == flag;
102 }
103
104 enum TupleIndex { HANDLE, DESCRIPTOR };
105 using EffectProxyTuple = std::tuple<std::shared_ptr<EffectProxy>, std::vector<Descriptor>>;
106
107 std::map<AudioUuid, EffectProxyTuple> createAllProxies() {
108 std::map<AudioUuid, EffectProxyTuple> proxyMap;
109 for (const auto& itor : mProxyDescs) {
110 const auto& uuid = itor.first.proxy.value();
111 if (proxyMap.end() == proxyMap.find(uuid)) {
112 std::get<TupleIndex::HANDLE>(proxyMap[uuid]) =
113 ndk::SharedRefBase::make<EffectProxy>(itor.first, mFactory);
114 }
115 }
116 return proxyMap;
117 }
118
119 bool addAllSubEffects(std::map<AudioUuid, EffectProxyTuple> proxyMap) {
120 for (auto& itor : mProxyDescs) {
121 const auto& uuid = itor.first.proxy.value();
122 if (proxyMap.end() == proxyMap.find(uuid)) {
123 return false;
124 }
125 auto& proxy = std::get<TupleIndex::HANDLE>(proxyMap[uuid]);
126 if (!proxy->addSubEffect(itor.second).isOk()) {
127 return false;
128 }
129 std::get<TupleIndex::DESCRIPTOR>(proxyMap[uuid]).emplace_back(itor.second);
130 }
131 return true;
132 }
133
134 std::shared_ptr<IFactory> mFactory;
135 std::vector<Descriptor> mDescs;
136 std::map<Descriptor::Identity, Descriptor> mProxyDescs;
137};
138
139TEST_F(EffectProxyTest, createProxy) {
140 auto proxyMap = createAllProxies();
141 // if there are some descriptor defined with proxy, then proxyMap can not be empty
142 EXPECT_EQ(mProxyDescs.size() == 0, proxyMap.size() == 0);
143}
144
145TEST_F(EffectProxyTest, addSubEffectsCreateAndDestroy) {
146 auto proxyMap = createAllProxies();
147 ASSERT_TRUE(addAllSubEffects(proxyMap));
148
149 for (const auto& itor : proxyMap) {
150 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
151 EXPECT_TRUE(proxy->create().isOk());
152 EXPECT_TRUE(proxy->destroy().isOk());
153 }
154}
155
156TEST_F(EffectProxyTest, addSubEffectsCreateOpenCloseDestroy) {
157 auto proxyMap = createAllProxies();
158 EXPECT_TRUE(addAllSubEffects(proxyMap));
159
160 Parameter::Common common = createParamCommon();
161 IEffect::OpenEffectReturn ret;
162 for (const auto& itor : proxyMap) {
163 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
164 EXPECT_TRUE(proxy->create().isOk());
165 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
166 EXPECT_TRUE(proxy->close().isOk());
167 EXPECT_TRUE(proxy->destroy().isOk());
168 }
169}
170
171// Add sub-effects, set active sub-effect with different checkers
172TEST_F(EffectProxyTest, setOffloadParam) {
173 auto proxyMap = createAllProxies();
174 EXPECT_TRUE(addAllSubEffects(proxyMap));
175
176 // Any flag exist should be able to set successfully
177 bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
178 for (const auto& itor : mProxyDescs) {
179 isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
180 isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
181 isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
182 }
183
184 Parameter::Common common = createParamCommon();
185 IEffect::OpenEffectReturn ret;
186 for (const auto& itor : proxyMap) {
187 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
188 EXPECT_TRUE(proxy->create().isOk());
189 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
190 effect_offload_param_t offloadParam{false, 0};
191 EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
192 offloadParam.isOffload = true;
193 EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
194 EXPECT_TRUE(proxy->close().isOk());
195 EXPECT_TRUE(proxy->destroy().isOk());
196 }
197}
198TEST_F(EffectProxyTest, destroyWithoutCreate) {
199 auto proxyMap = createAllProxies();
200 ASSERT_TRUE(addAllSubEffects(proxyMap));
201
202 for (const auto& itor : proxyMap) {
203 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
204 EXPECT_TRUE(proxy->destroy().isOk());
205 }
206}
207
208TEST_F(EffectProxyTest, closeWithoutOpen) {
209 auto proxyMap = createAllProxies();
210 ASSERT_TRUE(addAllSubEffects(proxyMap));
211
212 for (const auto& itor : proxyMap) {
213 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
214 EXPECT_TRUE(proxy->create().isOk());
215
216 EXPECT_TRUE(proxy->close().isOk());
217 EXPECT_TRUE(proxy->destroy().isOk());
218 }
219}
220
221// Add sub-effects, set active sub-effect, create, open, and send command, expect success handling
222TEST_F(EffectProxyTest, normalSequency) {
223 auto proxyMap = createAllProxies();
224 ASSERT_TRUE(addAllSubEffects(proxyMap));
225
226 bool isTunnelExist = [&]() {
227 for (const auto& itor : mProxyDescs) {
228 if (isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL)) {
229 return true;
230 }
231 }
232 return false;
233 }();
234
235 Parameter::Common common = createParamCommon();
236 IEffect::OpenEffectReturn ret;
237 Parameter::VolumeStereo volumeStereo({.left = .1f, .right = -0.8f});
238 Parameter param = Parameter::make<Parameter::volumeStereo>(volumeStereo);
239 Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
240 State state;
241 for (const auto& itor : proxyMap) {
242 Parameter expect;
243 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
244 effect_offload_param_t offloadParam{true, 0};
245 EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
246
247 EXPECT_TRUE(proxy->create().isOk());
248 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
249
250 EXPECT_TRUE(proxy->setParameter(param).isOk());
251 EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
252 EXPECT_EQ(expect, param);
253
254 EXPECT_TRUE(proxy->command(CommandId::START).isOk());
255 EXPECT_TRUE(proxy->getState(&state).isOk());
256 EXPECT_EQ(State::PROCESSING, state);
257
258 EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
259 EXPECT_TRUE(proxy->getState(&state).isOk());
260 EXPECT_EQ(State::IDLE, state);
261
262 EXPECT_TRUE(proxy->close().isOk());
263 EXPECT_TRUE(proxy->destroy().isOk());
264 }
265}
266
267// setParameter, change active sub-effect, verify with getParameter
268TEST_F(EffectProxyTest, changeActiveSubAndVerifyParameter) {
269 auto proxyMap = createAllProxies();
270 EXPECT_TRUE(addAllSubEffects(proxyMap));
271
272 bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
273 for (const auto& itor : mProxyDescs) {
274 isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
275 isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
276 isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
277 }
278
279 Parameter::Common common = createParamCommon();
280 IEffect::OpenEffectReturn ret;
281 Parameter::VolumeStereo volumeStereo({.left = .5f, .right = .8f});
282 Parameter param = Parameter::make<Parameter::volumeStereo>(volumeStereo);
283 Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
284 for (const auto& itor : proxyMap) {
285 Parameter expect;
286 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
287 EXPECT_TRUE(proxy->create().isOk());
288 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
289 EXPECT_TRUE(proxy->setParameter(param).isOk());
290 EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
291 EXPECT_EQ(expect, param);
292
293 effect_offload_param_t offloadParam{false, 0};
294 EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
295 EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
296 EXPECT_EQ(expect, param);
297
298 offloadParam.isOffload = true;
299 EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
300 EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
301 EXPECT_EQ(expect, param);
302
303 EXPECT_TRUE(proxy->close().isOk());
304 EXPECT_TRUE(proxy->destroy().isOk());
305 }
306}
307
308// send command, change active sub-effect, then verify the state with getState
309TEST_F(EffectProxyTest, changeActiveSubAndVerifyState) {
310 auto proxyMap = createAllProxies();
311 ASSERT_TRUE(addAllSubEffects(proxyMap));
312
313 bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
314 for (const auto& itor : mProxyDescs) {
315 isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
316 isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
317 isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
318 }
319
320 Parameter::Common common = createParamCommon();
321 IEffect::OpenEffectReturn ret;
322 State state;
323 for (const auto& itor : proxyMap) {
324 Parameter expect;
325 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
326 EXPECT_TRUE(proxy->create().isOk());
327 EXPECT_TRUE(proxy->getState(&state).isOk());
328 EXPECT_EQ(State::INIT, state);
329 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
330 EXPECT_TRUE(proxy->getState(&state).isOk());
331 EXPECT_EQ(State::IDLE, state);
332 EXPECT_TRUE(proxy->command(CommandId::START).isOk());
333 EXPECT_TRUE(proxy->getState(&state).isOk());
334 EXPECT_EQ(State::PROCESSING, state);
335
336 effect_offload_param_t offloadParam{false, 0};
337 EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
338 EXPECT_TRUE(proxy->getState(&state).isOk());
339 EXPECT_EQ(State::PROCESSING, state);
340
341 offloadParam.isOffload = true;
342 EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
343 EXPECT_TRUE(proxy->getState(&state).isOk());
344 EXPECT_EQ(State::PROCESSING, state);
345
346 EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
347 EXPECT_TRUE(proxy->getState(&state).isOk());
348 EXPECT_EQ(State::IDLE, state);
349
350 EXPECT_TRUE(proxy->close().isOk());
351 EXPECT_TRUE(proxy->getState(&state).isOk());
352 EXPECT_EQ(State::INIT, state);
353 EXPECT_TRUE(proxy->destroy().isOk());
354 }
355}
356
357} // namespace android