blob: ca578eba554d258b9b55223cc312758990492a40 [file] [log] [blame]
Shunkai Yao725af212023-01-05 23:01:40 +00001/*
2 * Copyright (C) 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_TAG "AHAL_DynamicsProcessingLibEffects"
18
19#include <android-base/logging.h>
20
21#include "DynamicsProcessing.h"
22
23#include <dsp/DPBase.h>
24#include <dsp/DPFrequency.h>
25
26using aidl::android::hardware::audio::effect::Descriptor;
27using aidl::android::hardware::audio::effect::DynamicsProcessingImpl;
28using aidl::android::hardware::audio::effect::IEffect;
29using aidl::android::hardware::audio::effect::kDynamicsProcessingImplUUID;
30using aidl::android::hardware::audio::effect::State;
31using aidl::android::media::audio::common::AudioUuid;
32using aidl::android::media::audio::common::PcmType;
33
34extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
35 std::shared_ptr<IEffect>* instanceSpp) {
36 if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingImplUUID) {
37 LOG(ERROR) << __func__ << "uuid not supported";
38 return EX_ILLEGAL_ARGUMENT;
39 }
40 if (instanceSpp) {
41 *instanceSpp = ndk::SharedRefBase::make<DynamicsProcessingImpl>();
42 LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
43 return EX_NONE;
44 } else {
45 LOG(ERROR) << __func__ << " invalid input parameter!";
46 return EX_ILLEGAL_ARGUMENT;
47 }
48}
49
50extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
51 if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingImplUUID) {
52 LOG(ERROR) << __func__ << "uuid not supported";
53 return EX_ILLEGAL_ARGUMENT;
54 }
55 *_aidl_return = DynamicsProcessingImpl::kDescriptor;
56 return EX_NONE;
57}
58
59namespace aidl::android::hardware::audio::effect {
60
61const std::string DynamicsProcessingImpl::kEffectName = "DynamicsProcessing";
Shunkai Yao6b857c92023-02-13 17:44:52 +000062
63const DynamicsProcessing::EqBandConfig DynamicsProcessingImpl::kEqBandConfigMin =
64 DynamicsProcessing::EqBandConfig({.channel = 0,
65 .band = 0,
66 .enable = false,
67 .cutoffFrequencyHz = 220,
68 .gainDb = std::numeric_limits<float>::min()});
69const DynamicsProcessing::EqBandConfig DynamicsProcessingImpl::kEqBandConfigMax =
70 DynamicsProcessing::EqBandConfig({.channel = std::numeric_limits<int>::max(),
71 .band = std::numeric_limits<int>::max(),
72 .enable = true,
73 .cutoffFrequencyHz = 20000,
74 .gainDb = std::numeric_limits<float>::max()});
75const Range::DynamicsProcessingRange DynamicsProcessingImpl::kPreEqBandRange = {
76 .min = DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
77 {DynamicsProcessingImpl::kEqBandConfigMin}),
78 .max = DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
79 {DynamicsProcessingImpl::kEqBandConfigMax})};
80const Range::DynamicsProcessingRange DynamicsProcessingImpl::kPostEqBandRange = {
81 .min = DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
82 {DynamicsProcessingImpl::kEqBandConfigMin}),
83 .max = DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
84 {DynamicsProcessingImpl::kEqBandConfigMax})};
85const Range DynamicsProcessingImpl::kRange =
86 Range::make<Range::dynamicsProcessing>({DynamicsProcessingImpl::kPreEqBandRange});
87
88const Capability DynamicsProcessingImpl::kCapability = {.range = {DynamicsProcessingImpl::kRange}};
89
Shunkai Yao725af212023-01-05 23:01:40 +000090const Descriptor DynamicsProcessingImpl::kDescriptor = {
91 .common = {.id = {.type = kDynamicsProcessingTypeUUID,
92 .uuid = kDynamicsProcessingImplUUID,
93 .proxy = std::nullopt},
94 .flags = {.type = Flags::Type::INSERT,
95 .insert = Flags::Insert::LAST,
96 .volume = Flags::Volume::CTRL},
97 .name = DynamicsProcessingImpl::kEffectName,
98 .implementor = "The Android Open Source Project"},
Shunkai Yao6b857c92023-02-13 17:44:52 +000099 .capability = DynamicsProcessingImpl::kCapability};
Shunkai Yao725af212023-01-05 23:01:40 +0000100
101ndk::ScopedAStatus DynamicsProcessingImpl::open(const Parameter::Common& common,
102 const std::optional<Parameter::Specific>& specific,
103 OpenEffectReturn* ret) {
104 LOG(DEBUG) << __func__;
105 // effect only support 32bits float
106 RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
107 common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
108 EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
109 RETURN_OK_IF(mState != State::INIT);
110 auto context = createContext(common);
111 RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
112
113 RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
114 if (specific.has_value()) {
115 RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
116 } else {
117 Parameter::Specific defaultSpecific =
118 Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(
119 DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
120 mContext->getEngineArchitecture()));
121 RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(defaultSpecific), "setDefaultEngineErr");
122 }
123
124 mState = State::IDLE;
125 context->dupeFmq(ret);
126 RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
127 "FailedToCreateWorker");
128 return ndk::ScopedAStatus::ok();
129}
130
131ndk::ScopedAStatus DynamicsProcessingImpl::getDescriptor(Descriptor* _aidl_return) {
132 RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
133 LOG(DEBUG) << __func__ << kDescriptor.toString();
134 *_aidl_return = kDescriptor;
135 return ndk::ScopedAStatus::ok();
136}
137
138ndk::ScopedAStatus DynamicsProcessingImpl::commandImpl(CommandId command) {
139 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
140 switch (command) {
141 case CommandId::START:
142 mContext->enable();
143 return ndk::ScopedAStatus::ok();
144 case CommandId::STOP:
145 mContext->disable();
146 return ndk::ScopedAStatus::ok();
147 case CommandId::RESET:
148 mContext->disable();
149 mContext->resetBuffer();
150 return ndk::ScopedAStatus::ok();
151 default:
152 // Need this default handling for vendor extendable CommandId::VENDOR_COMMAND_*
153 LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
154 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
155 "commandIdNotSupported");
156 }
157}
158
159ndk::ScopedAStatus DynamicsProcessingImpl::setParameterSpecific(
160 const Parameter::Specific& specific) {
161 RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
162 "EffectNotSupported");
163 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
164
165 auto& param = specific.get<Parameter::Specific::dynamicsProcessing>();
Shunkai Yao6b857c92023-02-13 17:44:52 +0000166 // TODO: check range here, dynamicsProcessing need customized method for nested parameters.
Shunkai Yao725af212023-01-05 23:01:40 +0000167 auto tag = param.getTag();
168
169 switch (tag) {
170 case DynamicsProcessing::engineArchitecture: {
171 RETURN_IF(mContext->setEngineArchitecture(
172 param.get<DynamicsProcessing::engineArchitecture>()) !=
173 RetCode::SUCCESS,
174 EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
175 return ndk::ScopedAStatus::ok();
176 }
177 case DynamicsProcessing::preEq: {
178 RETURN_IF(
179 mContext->setPreEq(param.get<DynamicsProcessing::preEq>()) != RetCode::SUCCESS,
180 EX_ILLEGAL_ARGUMENT, "setPreEqFailed");
181 return ndk::ScopedAStatus::ok();
182 }
183 case DynamicsProcessing::postEq: {
184 RETURN_IF(mContext->setPostEq(param.get<DynamicsProcessing::postEq>()) !=
185 RetCode::SUCCESS,
186 EX_ILLEGAL_ARGUMENT, "setPostEqFailed");
187 return ndk::ScopedAStatus::ok();
188 }
189 case DynamicsProcessing::preEqBand: {
190 RETURN_IF(mContext->setPreEqBand(param.get<DynamicsProcessing::preEqBand>()) !=
191 RetCode::SUCCESS,
192 EX_ILLEGAL_ARGUMENT, "setPreEqBandFailed");
193 return ndk::ScopedAStatus::ok();
194 }
195 case DynamicsProcessing::postEqBand: {
196 RETURN_IF(mContext->setPostEqBand(param.get<DynamicsProcessing::postEqBand>()) !=
197 RetCode::SUCCESS,
198 EX_ILLEGAL_ARGUMENT, "setPostEqBandFailed");
199 return ndk::ScopedAStatus::ok();
200 }
201 case DynamicsProcessing::mbc: {
202 RETURN_IF(mContext->setMbc(param.get<DynamicsProcessing::mbc>()) != RetCode::SUCCESS,
203 EX_ILLEGAL_ARGUMENT, "setMbcFailed");
204 return ndk::ScopedAStatus::ok();
205 }
206 case DynamicsProcessing::mbcBand: {
207 RETURN_IF(mContext->setMbcBand(param.get<DynamicsProcessing::mbcBand>()) !=
208 RetCode::SUCCESS,
209 EX_ILLEGAL_ARGUMENT, "setMbcBandFailed");
210 return ndk::ScopedAStatus::ok();
211 }
212 case DynamicsProcessing::limiter: {
213 RETURN_IF(mContext->setLimiter(param.get<DynamicsProcessing::limiter>()) !=
214 RetCode::SUCCESS,
215 EX_ILLEGAL_ARGUMENT, "setLimiterFailed");
216 return ndk::ScopedAStatus::ok();
217 }
218 case DynamicsProcessing::inputGain: {
219 RETURN_IF(mContext->setInputGain(param.get<DynamicsProcessing::inputGain>()) !=
220 RetCode::SUCCESS,
221 EX_ILLEGAL_ARGUMENT, "setInputGainFailed");
222 return ndk::ScopedAStatus::ok();
223 }
Shunkai Yaoda4a6402023-03-03 19:38:17 +0000224 case DynamicsProcessing::vendor: {
Shunkai Yao725af212023-01-05 23:01:40 +0000225 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
226 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
227 EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagNotSupported");
228 }
229 }
230}
231
232ndk::ScopedAStatus DynamicsProcessingImpl::getParameterSpecific(const Parameter::Id& id,
233 Parameter::Specific* specific) {
234 RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
235 auto tag = id.getTag();
236 RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
237 auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
238 auto dpIdTag = dpId.getTag();
239 switch (dpIdTag) {
240 case DynamicsProcessing::Id::commonTag:
241 return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
242 specific);
243 case DynamicsProcessing::Id::vendorExtensionTag:
244 LOG(ERROR) << __func__ << " unsupported ID: " << toString(dpIdTag);
245 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
246 EX_ILLEGAL_ARGUMENT, "DPVendorExtensionIdNotSupported");
247 }
248}
249
250ndk::ScopedAStatus DynamicsProcessingImpl::getParameterDynamicsProcessing(
251 const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
252 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
253
254 switch (tag) {
255 case DynamicsProcessing::engineArchitecture: {
256 specific->set<Parameter::Specific::dynamicsProcessing>(
257 DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
258 mContext->getEngineArchitecture()));
259 return ndk::ScopedAStatus::ok();
260 }
261 case DynamicsProcessing::preEq: {
262 specific->set<Parameter::Specific::dynamicsProcessing>(
263 DynamicsProcessing::make<DynamicsProcessing::preEq>(mContext->getPreEq()));
264 return ndk::ScopedAStatus::ok();
265 }
266 case DynamicsProcessing::postEq: {
267 specific->set<Parameter::Specific::dynamicsProcessing>(
268 DynamicsProcessing::make<DynamicsProcessing::postEq>(mContext->getPostEq()));
269 return ndk::ScopedAStatus::ok();
270 }
271 case DynamicsProcessing::preEqBand: {
272 specific->set<Parameter::Specific::dynamicsProcessing>(
273 DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
274 mContext->getPreEqBand()));
275 return ndk::ScopedAStatus::ok();
276 }
277 case DynamicsProcessing::postEqBand: {
278 specific->set<Parameter::Specific::dynamicsProcessing>(
279 DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
280 mContext->getPostEqBand()));
281 return ndk::ScopedAStatus::ok();
282 }
283 case DynamicsProcessing::mbc: {
284 specific->set<Parameter::Specific::dynamicsProcessing>(
285 DynamicsProcessing::make<DynamicsProcessing::mbc>(mContext->getMbc()));
286 return ndk::ScopedAStatus::ok();
287 }
288 case DynamicsProcessing::mbcBand: {
289 specific->set<Parameter::Specific::dynamicsProcessing>(
290 DynamicsProcessing::make<DynamicsProcessing::mbcBand>(mContext->getMbcBand()));
291 return ndk::ScopedAStatus::ok();
292 }
293 case DynamicsProcessing::limiter: {
294 specific->set<Parameter::Specific::dynamicsProcessing>(
295 DynamicsProcessing::make<DynamicsProcessing::limiter>(mContext->getLimiter()));
296 return ndk::ScopedAStatus::ok();
297 }
298 case DynamicsProcessing::inputGain: {
299 specific->set<Parameter::Specific::dynamicsProcessing>(
300 DynamicsProcessing::make<DynamicsProcessing::inputGain>(
301 mContext->getInputGain()));
302 return ndk::ScopedAStatus::ok();
303 }
Shunkai Yaoda4a6402023-03-03 19:38:17 +0000304 case DynamicsProcessing::vendor: {
Shunkai Yao725af212023-01-05 23:01:40 +0000305 LOG(ERROR) << __func__ << " wrong vendor tag in CommonTag: " << toString(tag);
306 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
307 EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagInWrongId");
308 }
309 }
310}
311
312std::shared_ptr<EffectContext> DynamicsProcessingImpl::createContext(
313 const Parameter::Common& common) {
314 if (mContext) {
315 LOG(DEBUG) << __func__ << " context already exist";
316 return mContext;
317 }
318
319 mContext = std::make_shared<DynamicsProcessingContext>(1 /* statusFmqDepth */, common);
320 return mContext;
321}
322
323RetCode DynamicsProcessingImpl::releaseContext() {
324 if (mContext) {
325 mContext->disable();
326 mContext->resetBuffer();
327 mContext.reset();
328 }
329 return RetCode::SUCCESS;
330}
331
332// Processing method running in EffectWorker thread.
333IEffect::Status DynamicsProcessingImpl::effectProcessImpl(float* in, float* out, int samples) {
334 IEffect::Status status = {EX_NULL_POINTER, 0, 0};
335 RETURN_VALUE_IF(!mContext, status, "nullContext");
336 return mContext->lvmProcess(in, out, samples);
337}
338
339} // namespace aidl::android::hardware::audio::effect