blob: e4edd100839cd95bca3dc941cd959181dad99855 [file] [log] [blame]
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +00001/*
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#pragma once
18
19#include <memory>
20#include <string>
21#include <unordered_map>
22#include <vector>
23
24#include <aidl/android/hardware/audio/effect/IEffect.h>
25#include <aidl/android/hardware/audio/effect/IFactory.h>
26#include <aidl/android/media/audio/common/AudioChannelLayout.h>
27#include <aidl/android/media/audio/common/AudioDeviceType.h>
28#include <android/binder_auto_utils.h>
29#include <fmq/AidlMessageQueue.h>
30
31#include "AudioHalBinderServiceUtil.h"
32#include "EffectFactoryHelper.h"
33#include "TestUtils.h"
34
35using namespace android;
36using aidl::android::hardware::audio::effect::CommandId;
37using aidl::android::hardware::audio::effect::Descriptor;
38using aidl::android::hardware::audio::effect::EffectNullUuid;
39using aidl::android::hardware::audio::effect::EffectZeroUuid;
40using aidl::android::hardware::audio::effect::IEffect;
41using aidl::android::hardware::audio::effect::Parameter;
42using aidl::android::hardware::audio::effect::State;
43using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
44using aidl::android::media::audio::common::AudioChannelLayout;
45using aidl::android::media::audio::common::AudioDeviceType;
46using aidl::android::media::audio::common::AudioFormatDescription;
47using aidl::android::media::audio::common::AudioFormatType;
48using aidl::android::media::audio::common::AudioUuid;
49using aidl::android::media::audio::common::PcmType;
50
51const AudioFormatDescription DefaultFormat = {
52 .type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT, .encoding = ""};
53
54class EffectHelper {
55 public:
56 explicit EffectHelper(const std::string& name) : mFactoryHelper(EffectFactoryHelper(name)) {
57 mFactoryHelper.ConnectToFactoryService();
58 }
59
60 void OpenEffects(const AudioUuid& type = EffectNullUuid) {
61 auto open = [&](const std::shared_ptr<IEffect>& effect) {
62 IEffect::OpenEffectReturn ret;
63 EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret));
64 EffectParam params;
65 params.statusMQ = std::make_unique<StatusMQ>(ret.statusMQ);
66 params.inputMQ = std::make_unique<DataMQ>(ret.inputDataMQ);
67 params.outputMQ = std::make_unique<DataMQ>(ret.outputDataMQ);
68 mEffectParams.push_back(std::move(params));
69 };
70 EXPECT_NO_FATAL_FAILURE(ForEachEffect(open, type));
71 }
72
73 void CloseEffects(const binder_status_t status = EX_NONE) {
74 auto close = [&](const std::shared_ptr<IEffect>& effect) {
75 EXPECT_STATUS(status, effect->close());
76 };
77
78 EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
79 }
80
81 void CreateEffects(const int n = 1) {
82 for (int i = 0; i < n; i++) {
83 ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects());
84 }
85 }
86
87 void CreateEffectsWithUUID(const AudioUuid& type = EffectNullUuid) {
88 ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateEffects(type));
89 }
90
91 void QueryEffects() { ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects()); }
92
93 void DestroyEffects(const binder_status_t status = EX_NONE, const int remaining = 0) {
94 ASSERT_NO_FATAL_FAILURE(mFactoryHelper.DestroyEffects(status, remaining));
95 mEffectDescriptors.clear();
96 }
97
98 void GetEffectDescriptors() {
99 auto get = [&](const std::shared_ptr<IEffect>& effect) {
100 Descriptor desc;
101 EXPECT_IS_OK(effect->getDescriptor(&desc));
102 mEffectDescriptors.push_back(std::move(desc));
103 };
104 EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
105 }
106
107 void CommandEffects(CommandId command) {
108 auto close = [&](const std::shared_ptr<IEffect>& effect) {
109 EXPECT_IS_OK(effect->command(command));
110 };
111 EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
112 }
113
114 void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
115 auto func = [&](const std::shared_ptr<IEffect>& effect) {
116 EXPECT_STATUS(status, effect->command(command));
117 };
118 EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
119 }
120
121 void ExpectState(State expected) {
122 auto get = [&](const std::shared_ptr<IEffect>& effect) {
123 State state = State::INIT;
124 EXPECT_IS_OK(effect->getState(&state));
125 EXPECT_EQ(expected, state);
126 };
127 EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
128 }
129
130 void SetParameter() {
131 auto func = [&](const std::shared_ptr<IEffect>& effect) {
132 Parameter param;
133 param.set<Parameter::common>(mCommon);
134 EXPECT_IS_OK(effect->setParameter(param));
135 };
136 EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
137 }
138
139 void VerifyParameters() {
140 auto func = [&](const std::shared_ptr<IEffect>& effect) {
141 Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
142 Parameter::Id id;
143 id.set<Parameter::Id::commonTag>(0);
144 paramCommonExpect.set<Parameter::common>(mCommon);
145 EXPECT_IS_OK(effect->getParameter(id, &paramCommonGet));
146 EXPECT_EQ(paramCommonExpect, paramCommonGet)
147 << paramCommonExpect.toString() << " vs " << paramCommonGet.toString();
148 };
149 EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
150 }
151
152 void QueryEffects(const std::optional<AudioUuid>& in_type,
153 const std::optional<AudioUuid>& in_instance,
154 std::vector<Descriptor::Identity>* _aidl_return) {
155 mFactoryHelper.QueryEffects(in_type, in_instance, _aidl_return);
156 }
157
158 template <typename Functor>
159 void ForEachEffect(Functor functor, const std::optional<AudioUuid>& type = EffectNullUuid) {
160 auto effectMap = mFactoryHelper.GetEffectMap();
161 for (const auto& it : effectMap) {
162 SCOPED_TRACE(it.second.toString());
163 if (type != EffectNullUuid && it.second.type != type) continue;
164 functor(it.first);
165 }
166 }
167
168 template <typename Functor>
169 void ForEachDescriptor(Functor functor) {
170 for (size_t i = 0; i < mEffectDescriptors.size(); i++) {
171 SCOPED_TRACE(mEffectDescriptors[i].toString());
172 functor(i, mEffectDescriptors[i]);
173 }
174 }
175
176 static const size_t mWriteMQSize = 0x400;
177
178 enum class IO : char { INPUT = 0, OUTPUT = 1, INOUT = 2 };
179
180 void initParamCommonFormat(IO io = IO::INOUT,
181 const AudioFormatDescription& format = DefaultFormat) {
182 if (io == IO::INPUT || io == IO::INOUT) {
183 mCommon.input.base.format = format;
184 }
185 if (io == IO::OUTPUT || io == IO::INOUT) {
186 mCommon.output.base.format = format;
187 }
188 }
189
190 void initParamCommonSampleRate(IO io = IO::INOUT, const int& sampleRate = 48000) {
191 if (io == IO::INPUT || io == IO::INOUT) {
192 mCommon.input.base.sampleRate = sampleRate;
193 }
194 if (io == IO::OUTPUT || io == IO::INOUT) {
195 mCommon.output.base.sampleRate = sampleRate;
196 }
197 }
198
199 void initParamCommonFrameCount(IO io = IO::INOUT, const long& frameCount = 48000) {
200 if (io == IO::INPUT || io == IO::INOUT) {
201 mCommon.input.frameCount = frameCount;
202 }
203 if (io == IO::OUTPUT || io == IO::INOUT) {
204 mCommon.output.frameCount = frameCount;
205 }
206 }
207 void initParamCommon(int session = -1, int ioHandle = -1, int iSampleRate = 48000,
208 int oSampleRate = 48000, long iFrameCount = 0x100,
209 long oFrameCount = 0x100) {
210 mCommon.session = session;
211 mCommon.ioHandle = ioHandle;
212
213 auto& input = mCommon.input;
214 auto& output = mCommon.output;
215 input.base.sampleRate = iSampleRate;
216 input.base.channelMask = mInputChannelLayout;
217 input.frameCount = iFrameCount;
218 output.base.sampleRate = oSampleRate;
219 output.base.channelMask = mOutputChannelLayout;
Shunkai Yao464775e2022-10-28 21:42:25 +0000220 output.base.format = DefaultFormat;
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000221 output.frameCount = oFrameCount;
222 inputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
223 input.base.format, input.base.channelMask);
224 outputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
225 output.base.format, output.base.channelMask);
226 }
227
228 void setSpecific(Parameter::Specific& specific) { mSpecific = specific; }
229
230 // usually this function only call once.
231 void PrepareInputData(size_t s = mWriteMQSize) {
232 size_t maxInputSize = s;
233 for (auto& it : mEffectParams) {
234 auto& mq = it.inputMQ;
235 EXPECT_NE(nullptr, mq);
236 EXPECT_TRUE(mq->isValid());
237 const size_t bytesToWrite = mq->availableToWrite();
238 EXPECT_EQ(inputFrameSize * mCommon.input.frameCount, bytesToWrite);
239 EXPECT_NE(0UL, bytesToWrite);
240 EXPECT_TRUE(s <= bytesToWrite);
241 maxInputSize = std::max(maxInputSize, bytesToWrite);
242 }
243 mInputBuffer.resize(maxInputSize);
244 std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0x5a);
245 }
246
247 void writeToFmq(size_t s = mWriteMQSize) {
248 for (auto& it : mEffectParams) {
249 auto& mq = it.inputMQ;
250 EXPECT_NE(nullptr, mq);
251 const size_t bytesToWrite = mq->availableToWrite();
252 EXPECT_NE(0Ul, bytesToWrite);
253 EXPECT_TRUE(s <= bytesToWrite);
254 EXPECT_TRUE(mq->write(mInputBuffer.data(), s));
255 }
256 }
257
258 void readFromFmq(size_t expectSize = mWriteMQSize) {
259 for (auto& it : mEffectParams) {
260 IEffect::Status status{};
261 auto& statusMq = it.statusMQ;
262 EXPECT_NE(nullptr, statusMq);
263 EXPECT_TRUE(statusMq->readBlocking(&status, 1));
264 EXPECT_EQ(STATUS_OK, status.status);
265 EXPECT_EQ(expectSize, (unsigned)status.fmqByteProduced);
266
267 auto& outputMq = it.outputMQ;
268 EXPECT_NE(nullptr, outputMq);
269 EXPECT_EQ(expectSize, outputMq->availableToRead());
270 }
271 }
272
273 void setInputChannelLayout(AudioChannelLayout input) { mInputChannelLayout = input; }
274 void setOutputChannelLayout(AudioChannelLayout output) { mOutputChannelLayout = output; }
275 const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
276 return mFactoryHelper.GetCompleteEffectIdList();
277 }
278 const std::vector<Descriptor>& getDescriptorVec() const { return mEffectDescriptors; }
279
280 private:
281 EffectFactoryHelper mFactoryHelper;
282
283 AudioChannelLayout mInputChannelLayout =
284 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
285 AudioChannelLayout::LAYOUT_STEREO);
286 AudioChannelLayout mOutputChannelLayout =
287 AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
288 AudioChannelLayout::LAYOUT_STEREO);
289
290 Parameter::Common mCommon;
291 Parameter::Specific mSpecific;
292
293 size_t inputFrameSize, outputFrameSize;
294 std::vector<int8_t> mInputBuffer; // reuse same buffer for all effects testing
295
296 typedef ::android::AidlMessageQueue<
297 IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
298 StatusMQ;
299 typedef ::android::AidlMessageQueue<
300 int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
301 DataMQ;
302
303 class EffectParam {
304 public:
305 std::unique_ptr<StatusMQ> statusMQ;
306 std::unique_ptr<DataMQ> inputMQ;
307 std::unique_ptr<DataMQ> outputMQ;
308 };
309 std::vector<EffectParam> mEffectParams;
310 std::vector<Descriptor> mEffectDescriptors;
311};