blob: 43fa20615173bee00a6766a37c7cc776f4a918e1 [file] [log] [blame]
Shunkai Yao45905172022-08-24 18:14:02 +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
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000017#define LOG_TAG "AHAL_EqualizerSw"
18#include <Utils.h>
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +000019#include <algorithm>
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000020#include <unordered_set>
Shunkai Yao45905172022-08-24 18:14:02 +000021
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +000022#include <android-base/logging.h>
23#include <fmq/AidlMessageQueue.h>
24
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000025#include "equalizer-impl/EqualizerSw.h"
26
27using android::hardware::audio::common::getFrameSizeInBytes;
Shunkai Yao45905172022-08-24 18:14:02 +000028
29namespace aidl::android::hardware::audio::effect {
30
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000031extern "C" binder_exception_t createEffect(std::shared_ptr<IEffect>* instanceSpp) {
32 if (instanceSpp) {
33 *instanceSpp = ndk::SharedRefBase::make<EqualizerSw>();
34 LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
35 return EX_NONE;
36 } else {
37 LOG(ERROR) << __func__ << " invalid input parameter!";
38 return EX_ILLEGAL_ARGUMENT;
39 }
40}
41
42extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
43 State state;
44 ndk::ScopedAStatus status = instanceSp->getState(&state);
45 if (!status.isOk() || State::INIT != state) {
46 LOG(ERROR) << __func__ << " instance " << instanceSp.get()
47 << " in state: " << toString(state) << ", status: " << status.getDescription();
48 return EX_ILLEGAL_STATE;
49 }
50 LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
51 return EX_NONE;
52}
53
54ndk::ScopedAStatus EqualizerSw::open(const Parameter::Common& common,
55 const Parameter::Specific& specific,
56 OpenEffectReturn* _aidl_return) {
57 LOG(DEBUG) << __func__;
58 if (mState != State::INIT) {
59 LOG(WARNING) << __func__ << " eq already open";
60 return ndk::ScopedAStatus::ok();
61 }
62
63 // Set essential parameters before create worker thread.
64 setCommonParameter(common);
65 setSpecificParameter(specific);
66
67 LOG(DEBUG) << " common: " << common.toString() << " specific " << specific.toString();
68
69 auto& input = common.input;
70 auto& output = common.output;
71 size_t inputFrameSize = getFrameSizeInBytes(input.base.format, input.base.channelMask);
72 size_t outputFrameSize = getFrameSizeInBytes(output.base.format, output.base.channelMask);
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +000073 mContext = std::make_shared<EqualizerSwContext>(1, input.frameCount * inputFrameSize,
74 output.frameCount * outputFrameSize);
75 if (!mContext) {
76 LOG(ERROR) << __func__ << " created EqualizerSwContext failed";
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000077 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
78 "FailedToCreateFmq");
79 }
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +000080 setContext(mContext);
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000081
82 // create the worker thread
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +000083 if (RetCode::SUCCESS != createThread(LOG_TAG)) {
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000084 LOG(ERROR) << __func__ << " created worker thread failed";
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +000085 mContext.reset();
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000086 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +000087 "FailedToCreateWorker");
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000088 }
89
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +000090 _aidl_return->statusMQ = mContext->getStatusFmq()->dupeDesc();
91 _aidl_return->inputDataMQ = mContext->getInputDataFmq()->dupeDesc();
92 _aidl_return->outputDataMQ = mContext->getOutputDataFmq()->dupeDesc();
Shunkai Yaoea24c1a2022-09-28 17:39:23 +000093 mState = State::IDLE;
94 return ndk::ScopedAStatus::ok();
95}
96
97ndk::ScopedAStatus EqualizerSw::close() {
98 if (mState == State::INIT) {
99 LOG(WARNING) << __func__ << " instance already closed";
100 return ndk::ScopedAStatus::ok();
101 } else if (mState == State::PROCESSING) {
102 LOG(ERROR) << __func__ << " instance still processing";
103 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
104 "EqInstanceProcessing");
105 }
106
107 // stop the worker thread
108 mState = State::INIT;
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000109 destroyThread();
110 mContext.reset();
111
Shunkai Yao45905172022-08-24 18:14:02 +0000112 LOG(DEBUG) << __func__;
113 return ndk::ScopedAStatus::ok();
114}
115
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000116ndk::ScopedAStatus EqualizerSw::getDescriptor(Descriptor* _aidl_return) {
117 LOG(DEBUG) << __func__ << mDesc.toString();
Shunkai Yao45905172022-08-24 18:14:02 +0000118 *_aidl_return = mDesc;
119 return ndk::ScopedAStatus::ok();
120}
121
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000122ndk::ScopedAStatus EqualizerSw::command(CommandId in_commandId) {
123 LOG(DEBUG) << __func__ << ": receive command:" << toString(in_commandId);
124 if (mState == State::INIT) {
125 LOG(ERROR) << __func__ << ": instance not open yet";
126 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
127 "CommandStateError");
128 }
129 switch (in_commandId) {
130 case CommandId::START:
131 // start processing.
132 mState = State::PROCESSING;
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000133 startThread();
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000134 LOG(DEBUG) << __func__ << " state: " << toString(mState);
135 return ndk::ScopedAStatus::ok();
136 case CommandId::STOP:
137 // stop processing.
138 mState = State::IDLE;
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000139 stopThread();
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000140 LOG(DEBUG) << __func__ << " state: " << toString(mState);
141 return ndk::ScopedAStatus::ok();
142 case CommandId::RESET:
143 // TODO: reset buffer status.
144 mState = State::IDLE;
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000145 stopThread();
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000146 LOG(DEBUG) << __func__ << " state: " << toString(mState);
147 return ndk::ScopedAStatus::ok();
148 default:
149 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
150 "CommandIdNotSupported");
151 }
152 return ndk::ScopedAStatus::ok();
153}
154
155ndk::ScopedAStatus EqualizerSw::setParameter(const Parameter& in_param) {
156 if (mState == State::INIT) {
157 LOG(ERROR) << __func__ << ": instance not open yet";
158 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "StateError");
159 }
160 LOG(DEBUG) << __func__ << " with: " << in_param.toString();
161 auto tag = in_param.getTag();
162 switch (tag) {
163 case Parameter::common: {
164 return setCommonParameter(in_param.get<Parameter::common>());
165 }
166 case Parameter::specific: {
167 return setSpecificParameter(in_param.get<Parameter::specific>());
168 }
169 default:
170 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
171 "ParameterNotSupported");
172 }
173}
174
175ndk::ScopedAStatus EqualizerSw::getParameter(const Parameter::Id& in_paramId,
176 Parameter* _aidl_return) {
177 LOG(DEBUG) << __func__ << in_paramId.toString();
178 auto tag = in_paramId.getTag();
179 switch (tag) {
180 case Parameter::Id::commonTag: {
181 _aidl_return->set<Parameter::common>(mCommonParam);
182 LOG(DEBUG) << __func__ << " get: " << _aidl_return->toString();
183 return ndk::ScopedAStatus::ok();
184 }
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000185 case Parameter::Id::specificId: {
186 auto& id = in_paramId.get<Parameter::Id::specificId>();
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000187 Parameter::Specific specific;
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000188 ndk::ScopedAStatus status = getSpecificParameter(id, &specific);
189 if (!status.isOk()) {
190 LOG(ERROR) << __func__
191 << " getSpecificParameter error: " << status.getDescription();
192 return status;
193 }
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000194 _aidl_return->set<Parameter::specific>(specific);
195 LOG(DEBUG) << __func__ << _aidl_return->toString();
196 return ndk::ScopedAStatus::ok();
197 }
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000198 case Parameter::Id::vendorTag: {
199 LOG(DEBUG) << __func__ << " noop for vendor tag now";
200 return ndk::ScopedAStatus::ok();
201 }
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000202 }
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000203 LOG(ERROR) << " unsupported tag: " << toString(tag);
204 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
205 "Parameter:IdNotSupported");
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000206}
207
208ndk::ScopedAStatus EqualizerSw::getState(State* _aidl_return) {
209 *_aidl_return = mState;
210 return ndk::ScopedAStatus::ok();
211}
212
213/// Private methods.
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000214ndk::ScopedAStatus EqualizerSw::setCommonParameter(const Parameter::Common& common) {
215 mCommonParam = common;
216 LOG(DEBUG) << __func__ << " set: " << mCommonParam.toString();
217 return ndk::ScopedAStatus::ok();
218}
219
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000220ndk::ScopedAStatus EqualizerSw::setSpecificParameter(const Parameter::Specific& specific) {
221 if (Parameter::Specific::equalizer != specific.getTag()) {
222 LOG(ERROR) << " unsupported effect: " << specific.toString();
223 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
224 "EffectNotSupported");
225 }
226
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000227 auto& eqParam = specific.get<Parameter::Specific::equalizer>();
228 auto tag = eqParam.getTag();
229 switch (tag) {
230 case Equalizer::bandLevels: {
231 auto& bandLevels = eqParam.get<Equalizer::bandLevels>();
232 const auto& [minItem, maxItem] = std::minmax_element(
233 bandLevels.begin(), bandLevels.end(),
234 [](const auto& a, const auto& b) { return a.index < b.index; });
235 if (bandLevels.size() >= NUM_OF_BANDS || minItem->index < 0 ||
236 maxItem->index >= NUM_OF_BANDS) {
237 LOG(ERROR) << " bandLevels " << bandLevels.size() << "minIndex " << minItem->index
238 << "maxIndex " << maxItem->index << " illegal ";
239 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
240 "ExceedMaxBandNum");
241 }
242 mBandLevels = bandLevels;
243 return ndk::ScopedAStatus::ok();
244 }
245 case Equalizer::preset: {
246 int preset = eqParam.get<Equalizer::preset>();
247 if (preset < 0 || preset >= NUM_OF_PRESETS) {
248 LOG(ERROR) << " preset: " << preset << " invalid";
249 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
250 "ExceedMaxBandNum");
251 }
252 mPreset = preset;
253 LOG(DEBUG) << __func__ << " preset set to " << mPreset;
254 return ndk::ScopedAStatus::ok();
255 }
256 case Equalizer::vendor: {
257 LOG(DEBUG) << __func__ << " noop for vendor tag now";
258 return ndk::ScopedAStatus::ok();
259 }
260 }
261
262 LOG(ERROR) << __func__ << " unsupported eq param tag: " << toString(tag);
263 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
264 "ParamNotSupported");
265}
266
267ndk::ScopedAStatus EqualizerSw::getSpecificParameter(Parameter::Specific::Id id,
268 Parameter::Specific* specific) {
269 Equalizer eqParam;
270 auto tag = id.getTag();
271 if (tag != Parameter::Specific::Id::equalizerTag) {
272 LOG(ERROR) << " invalid tag: " << toString(tag);
273 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
274 "UnsupportedTag");
275 }
276 auto eqTag = id.get<Parameter::Specific::Id::equalizerTag>();
277 switch (eqTag) {
278 case Equalizer::bandLevels: {
279 eqParam.set<Equalizer::bandLevels>(mBandLevels);
280 specific->set<Parameter::Specific::equalizer>(eqParam);
281 return ndk::ScopedAStatus::ok();
282 }
283 case Equalizer::preset: {
284 eqParam.set<Equalizer::preset>(mPreset);
285 LOG(DEBUG) << __func__ << " preset " << mPreset;
286 specific->set<Parameter::Specific::equalizer>(eqParam);
287 return ndk::ScopedAStatus::ok();
288 }
289 case Equalizer::vendor: {
290 LOG(DEBUG) << __func__ << " noop for vendor tag now";
291 return ndk::ScopedAStatus::ok();
292 }
293 }
294 LOG(ERROR) << __func__ << " unsupported eq param: " << toString(eqTag);
295 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
296 "ParamNotSupported");
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000297}
298
299void EqualizerSw::cleanUp() {
300 if (State::PROCESSING == mState) {
301 command(CommandId::STOP);
302 }
303 if (State::INIT != mState) {
304 close();
305 }
306}
307
Shunkai Yaoa4ab38c2022-10-14 01:07:47 +0000308IEffect::Status EqualizerSw::status(binder_status_t status, size_t consumed, size_t produced) {
309 IEffect::Status ret;
310 ret.status = status;
311 ret.fmqByteConsumed = consumed;
312 ret.fmqByteProduced = produced;
313 return ret;
314}
315
316// Processing method running in EffectWorker thread.
317IEffect::Status EqualizerSw::effectProcessImpl() {
318 // TODO: get data buffer and process.
319 return status(STATUS_OK, mContext->availableToRead(), mContext->availableToWrite());
Shunkai Yaoea24c1a2022-09-28 17:39:23 +0000320}
321
Shunkai Yao45905172022-08-24 18:14:02 +0000322} // namespace aidl::android::hardware::audio::effect