1 /*
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 */
35 namespace android {
36
37 using ::aidl::android::hardware::audio::effect::CommandId;
38 using ::aidl::android::hardware::audio::effect::Descriptor;
39 using ::aidl::android::hardware::audio::effect::Flags;
40 using ::aidl::android::hardware::audio::effect::IEffect;
41 using ::aidl::android::hardware::audio::effect::IFactory;
42 using ::aidl::android::hardware::audio::effect::Parameter;
43 using ::aidl::android::hardware::audio::effect::State;
44 using ::aidl::android::media::audio::common::AudioChannelLayout;
45 using ::aidl::android::media::audio::common::AudioFormatDescription;
46 using ::aidl::android::media::audio::common::AudioFormatType;
47 using ::aidl::android::media::audio::common::AudioUuid;
48 using ::aidl::android::media::audio::common::PcmType;
49 using ::android::effect::EffectProxy;
50
51 class EffectProxyTest : public testing::Test {
52 public:
SetUp()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 if (0ul == serviceName.size()) {
57 GTEST_SKIP() << "EffectFactory not available on device, skipping";
58 }
59 mFactory = IFactory::fromBinder(
60 ndk::SpAIBinder(AServiceManager_waitForService(serviceName[0].c_str())));
61 ASSERT_NE(nullptr, mFactory);
62 mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &mDescs);
63 for (const auto& desc : mDescs) {
64 if (desc.common.id.proxy.has_value()) {
65 mProxyDescs[desc.common.id.proxy.value()].emplace_back(desc);
66 }
67 }
68 }
69
TearDown()70 void TearDown() override {}
71
72 const AudioFormatDescription kDefaultFormatDescription = {
73 .type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
74
createParamCommon(int session=0,int ioHandle=-1,int iSampleRate=48000,int oSampleRate=48000,long iFrameCount=0x100,long oFrameCount=0x100,AudioChannelLayout inputChannelLayout=AudioChannelLayout::make<AudioChannelLayout::layoutMask> (AudioChannelLayout::LAYOUT_STEREO),AudioChannelLayout outputChannelLayout=AudioChannelLayout::make<AudioChannelLayout::layoutMask> (AudioChannelLayout::LAYOUT_STEREO))75 Parameter::Common createParamCommon(
76 int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
77 long iFrameCount = 0x100, long oFrameCount = 0x100,
78 AudioChannelLayout inputChannelLayout =
79 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
80 AudioChannelLayout::LAYOUT_STEREO),
81 AudioChannelLayout outputChannelLayout =
82 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
83 AudioChannelLayout::LAYOUT_STEREO)) {
84 Parameter::Common common;
85 common.session = session;
86 common.ioHandle = ioHandle;
87
88 auto& input = common.input;
89 auto& output = common.output;
90 input.base.sampleRate = iSampleRate;
91 input.base.channelMask = inputChannelLayout;
92 input.base.format = kDefaultFormatDescription;
93 input.frameCount = iFrameCount;
94 output.base.sampleRate = oSampleRate;
95 output.base.channelMask = outputChannelLayout;
96 output.base.format = kDefaultFormatDescription;
97 output.frameCount = oFrameCount;
98 return common;
99 }
100
101 enum TupleIndex { HANDLE, DESCRIPTOR };
102 using EffectProxyTuple = std::tuple<std::shared_ptr<EffectProxy>, std::vector<Descriptor>>;
103
createAllProxies()104 std::map<AudioUuid, EffectProxyTuple> createAllProxies() {
105 std::map<AudioUuid, EffectProxyTuple> proxyMap;
106 for (const auto& itor : mProxyDescs) {
107 const auto& uuid = itor.first;
108 if (proxyMap.end() == proxyMap.find(uuid)) {
109 std::get<TupleIndex::HANDLE>(proxyMap[uuid]) =
110 ndk::SharedRefBase::make<EffectProxy>(itor.first, itor.second, mFactory);
111 }
112 }
113 return proxyMap;
114 }
115
116 std::shared_ptr<IFactory> mFactory;
117 std::vector<Descriptor> mDescs;
118 std::map<const AudioUuid, std::vector<Descriptor>> mProxyDescs;
119 };
120
TEST_F(EffectProxyTest,createProxy)121 TEST_F(EffectProxyTest, createProxy) {
122 auto proxyMap = createAllProxies();
123 // if there are some descriptor defined with proxy, then proxyMap can not be empty
124 EXPECT_EQ(mProxyDescs.size() == 0, proxyMap.size() == 0);
125 }
126
TEST_F(EffectProxyTest,addSubEffectsCreateAndDestroy)127 TEST_F(EffectProxyTest, addSubEffectsCreateAndDestroy) {
128 auto proxyMap = createAllProxies();
129
130 for (const auto& itor : proxyMap) {
131 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
132 EXPECT_TRUE(proxy->destroy().isOk());
133 }
134 }
135
TEST_F(EffectProxyTest,addSubEffectsCreateOpenCloseDestroy)136 TEST_F(EffectProxyTest, addSubEffectsCreateOpenCloseDestroy) {
137 auto proxyMap = createAllProxies();
138
139 Parameter::Common common = createParamCommon();
140 IEffect::OpenEffectReturn ret;
141 for (const auto& itor : proxyMap) {
142 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
143 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
144 EXPECT_TRUE(proxy->close().isOk());
145 EXPECT_TRUE(proxy->destroy().isOk());
146 }
147 }
148
149 // Add sub-effects, set active sub-effect with different checkers
TEST_F(EffectProxyTest,setOffloadParam)150 TEST_F(EffectProxyTest, setOffloadParam) {
151 auto proxyMap = createAllProxies();
152
153 // Any flag exist should be able to set successfully
154 Parameter::Common common = createParamCommon();
155 IEffect::OpenEffectReturn ret;
156 for (const auto& itor : proxyMap) {
157 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
158 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
159 effect_offload_param_t offloadParam{false, 0};
160 EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
161 offloadParam.isOffload = true;
162 offloadParam.ioHandle++;
163 EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
164 EXPECT_TRUE(proxy->close().isOk());
165 EXPECT_TRUE(proxy->destroy().isOk());
166 }
167 }
TEST_F(EffectProxyTest,destroyWithoutCreate)168 TEST_F(EffectProxyTest, destroyWithoutCreate) {
169 auto proxyMap = createAllProxies();
170
171 for (const auto& itor : proxyMap) {
172 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
173 EXPECT_TRUE(proxy->destroy().isOk());
174 }
175 }
176
TEST_F(EffectProxyTest,closeWithoutOpen)177 TEST_F(EffectProxyTest, closeWithoutOpen) {
178 auto proxyMap = createAllProxies();
179
180 for (const auto& itor : proxyMap) {
181 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
182
183 EXPECT_TRUE(proxy->close().isOk());
184 EXPECT_TRUE(proxy->destroy().isOk());
185 }
186 }
187
188 // Add sub-effects, set active sub-effect, create, open, and send command, expect success handling
TEST_F(EffectProxyTest,normalSequency)189 TEST_F(EffectProxyTest, normalSequency) {
190 auto proxyMap = createAllProxies();
191
192 Parameter::Common common = createParamCommon();
193 IEffect::OpenEffectReturn ret;
194 Parameter::VolumeStereo volumeStereo({.left = .1f, .right = -0.8f});
195 Parameter expect = Parameter::make<Parameter::volumeStereo>(volumeStereo);
196 const Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
197 State state;
198 for (const auto& itor : proxyMap) {
199 Parameter getParam = Parameter::make<Parameter::offload>(true);
200 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
201 effect_offload_param_t offloadParam{true, 0};
202 EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
203
204 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
205
206 EXPECT_TRUE(proxy->setParameter(expect).isOk());
207 EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
208 EXPECT_EQ(expect, getParam)
209 << " EXPECTED: " << expect.toString() << "\nACTUAL: " << getParam.toString();
210
211 EXPECT_TRUE(proxy->command(CommandId::START).isOk());
212 EXPECT_TRUE(proxy->getState(&state).isOk());
213 EXPECT_EQ(State::PROCESSING, state);
214
215 EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
216 EXPECT_TRUE(proxy->getState(&state).isOk());
217 EXPECT_EQ(State::IDLE, state);
218
219 EXPECT_TRUE(proxy->close().isOk());
220 EXPECT_TRUE(proxy->destroy().isOk());
221 }
222 }
223
224 // setParameter, change active sub-effect, verify with getParameter
TEST_F(EffectProxyTest,changeActiveSubAndVerifyParameter)225 TEST_F(EffectProxyTest, changeActiveSubAndVerifyParameter) {
226 auto proxyMap = createAllProxies();
227
228 Parameter::Common common = createParamCommon();
229 IEffect::OpenEffectReturn ret;
230 Parameter::VolumeStereo volumeStereo({.left = .5f, .right = .8f});
231 Parameter expect = Parameter::make<Parameter::volumeStereo>(volumeStereo);
232 const Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
233 for (const auto& itor : proxyMap) {
234 Parameter getParam = Parameter::make<Parameter::offload>(true);
235 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
236 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
237 EXPECT_TRUE(proxy->setParameter(expect).isOk());
238 EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
239 EXPECT_EQ(expect, getParam);
240
241 effect_offload_param_t offloadParam{false, 0};
242 EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
243 EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
244 EXPECT_EQ(expect, getParam);
245
246 offloadParam.isOffload = true;
247 EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
248 EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
249 EXPECT_EQ(expect, getParam);
250
251 EXPECT_TRUE(proxy->close().isOk());
252 EXPECT_TRUE(proxy->destroy().isOk());
253 }
254 }
255
256 // send command, change active sub-effect, then verify the state with getState
TEST_F(EffectProxyTest,changeActiveSubAndVerifyState)257 TEST_F(EffectProxyTest, changeActiveSubAndVerifyState) {
258 auto proxyMap = createAllProxies();
259
260 Parameter::Common common = createParamCommon();
261 IEffect::OpenEffectReturn ret;
262 State state;
263 for (const auto& itor : proxyMap) {
264 Parameter expect;
265 auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
266 EXPECT_TRUE(proxy->getState(&state).isOk());
267 EXPECT_EQ(State::INIT, state);
268 EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
269 EXPECT_TRUE(proxy->getState(&state).isOk());
270 EXPECT_EQ(State::IDLE, state);
271 EXPECT_TRUE(proxy->command(CommandId::START).isOk());
272 EXPECT_TRUE(proxy->getState(&state).isOk());
273 EXPECT_EQ(State::PROCESSING, state);
274
275 effect_offload_param_t offloadParam{false, 0};
276 EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
277
278 offloadParam.isOffload = true;
279 EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
280
281 EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
282 EXPECT_TRUE(proxy->getState(&state).isOk());
283 EXPECT_EQ(State::IDLE, state);
284
285 EXPECT_TRUE(proxy->close().isOk());
286 EXPECT_TRUE(proxy->getState(&state).isOk());
287 EXPECT_EQ(State::INIT, state);
288 EXPECT_TRUE(proxy->destroy().isOk());
289 }
290 }
291
292 } // namespace android
293