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