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