blob: 203a27bcfa6a691a2f163608c54fb9c86693bb45 [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";
62const DynamicsProcessing::Capability DynamicsProcessingImpl::kCapability = {.minCutOffFreq = 220,
63 .maxCutOffFreq = 20000};
64const Descriptor DynamicsProcessingImpl::kDescriptor = {
65 .common = {.id = {.type = kDynamicsProcessingTypeUUID,
66 .uuid = kDynamicsProcessingImplUUID,
67 .proxy = std::nullopt},
68 .flags = {.type = Flags::Type::INSERT,
69 .insert = Flags::Insert::LAST,
70 .volume = Flags::Volume::CTRL},
71 .name = DynamicsProcessingImpl::kEffectName,
72 .implementor = "The Android Open Source Project"},
73 .capability = Capability::make<Capability::dynamicsProcessing>(
74 DynamicsProcessingImpl::kCapability)};
75
76ndk::ScopedAStatus DynamicsProcessingImpl::open(const Parameter::Common& common,
77 const std::optional<Parameter::Specific>& specific,
78 OpenEffectReturn* ret) {
79 LOG(DEBUG) << __func__;
80 // effect only support 32bits float
81 RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
82 common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
83 EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
84 RETURN_OK_IF(mState != State::INIT);
85 auto context = createContext(common);
86 RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
87
88 RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
89 if (specific.has_value()) {
90 RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
91 } else {
92 Parameter::Specific defaultSpecific =
93 Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(
94 DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
95 mContext->getEngineArchitecture()));
96 RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(defaultSpecific), "setDefaultEngineErr");
97 }
98
99 mState = State::IDLE;
100 context->dupeFmq(ret);
101 RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
102 "FailedToCreateWorker");
103 return ndk::ScopedAStatus::ok();
104}
105
106ndk::ScopedAStatus DynamicsProcessingImpl::getDescriptor(Descriptor* _aidl_return) {
107 RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
108 LOG(DEBUG) << __func__ << kDescriptor.toString();
109 *_aidl_return = kDescriptor;
110 return ndk::ScopedAStatus::ok();
111}
112
113ndk::ScopedAStatus DynamicsProcessingImpl::commandImpl(CommandId command) {
114 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
115 switch (command) {
116 case CommandId::START:
117 mContext->enable();
118 return ndk::ScopedAStatus::ok();
119 case CommandId::STOP:
120 mContext->disable();
121 return ndk::ScopedAStatus::ok();
122 case CommandId::RESET:
123 mContext->disable();
124 mContext->resetBuffer();
125 return ndk::ScopedAStatus::ok();
126 default:
127 // Need this default handling for vendor extendable CommandId::VENDOR_COMMAND_*
128 LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
129 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
130 "commandIdNotSupported");
131 }
132}
133
134ndk::ScopedAStatus DynamicsProcessingImpl::setParameterSpecific(
135 const Parameter::Specific& specific) {
136 RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
137 "EffectNotSupported");
138 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
139
140 auto& param = specific.get<Parameter::Specific::dynamicsProcessing>();
141 auto tag = param.getTag();
142
143 switch (tag) {
144 case DynamicsProcessing::engineArchitecture: {
145 RETURN_IF(mContext->setEngineArchitecture(
146 param.get<DynamicsProcessing::engineArchitecture>()) !=
147 RetCode::SUCCESS,
148 EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
149 return ndk::ScopedAStatus::ok();
150 }
151 case DynamicsProcessing::preEq: {
152 RETURN_IF(
153 mContext->setPreEq(param.get<DynamicsProcessing::preEq>()) != RetCode::SUCCESS,
154 EX_ILLEGAL_ARGUMENT, "setPreEqFailed");
155 return ndk::ScopedAStatus::ok();
156 }
157 case DynamicsProcessing::postEq: {
158 RETURN_IF(mContext->setPostEq(param.get<DynamicsProcessing::postEq>()) !=
159 RetCode::SUCCESS,
160 EX_ILLEGAL_ARGUMENT, "setPostEqFailed");
161 return ndk::ScopedAStatus::ok();
162 }
163 case DynamicsProcessing::preEqBand: {
164 RETURN_IF(mContext->setPreEqBand(param.get<DynamicsProcessing::preEqBand>()) !=
165 RetCode::SUCCESS,
166 EX_ILLEGAL_ARGUMENT, "setPreEqBandFailed");
167 return ndk::ScopedAStatus::ok();
168 }
169 case DynamicsProcessing::postEqBand: {
170 RETURN_IF(mContext->setPostEqBand(param.get<DynamicsProcessing::postEqBand>()) !=
171 RetCode::SUCCESS,
172 EX_ILLEGAL_ARGUMENT, "setPostEqBandFailed");
173 return ndk::ScopedAStatus::ok();
174 }
175 case DynamicsProcessing::mbc: {
176 RETURN_IF(mContext->setMbc(param.get<DynamicsProcessing::mbc>()) != RetCode::SUCCESS,
177 EX_ILLEGAL_ARGUMENT, "setMbcFailed");
178 return ndk::ScopedAStatus::ok();
179 }
180 case DynamicsProcessing::mbcBand: {
181 RETURN_IF(mContext->setMbcBand(param.get<DynamicsProcessing::mbcBand>()) !=
182 RetCode::SUCCESS,
183 EX_ILLEGAL_ARGUMENT, "setMbcBandFailed");
184 return ndk::ScopedAStatus::ok();
185 }
186 case DynamicsProcessing::limiter: {
187 RETURN_IF(mContext->setLimiter(param.get<DynamicsProcessing::limiter>()) !=
188 RetCode::SUCCESS,
189 EX_ILLEGAL_ARGUMENT, "setLimiterFailed");
190 return ndk::ScopedAStatus::ok();
191 }
192 case DynamicsProcessing::inputGain: {
193 RETURN_IF(mContext->setInputGain(param.get<DynamicsProcessing::inputGain>()) !=
194 RetCode::SUCCESS,
195 EX_ILLEGAL_ARGUMENT, "setInputGainFailed");
196 return ndk::ScopedAStatus::ok();
197 }
198 case DynamicsProcessing::vendorExtension: {
199 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
200 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
201 EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagNotSupported");
202 }
203 }
204}
205
206ndk::ScopedAStatus DynamicsProcessingImpl::getParameterSpecific(const Parameter::Id& id,
207 Parameter::Specific* specific) {
208 RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
209 auto tag = id.getTag();
210 RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
211 auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
212 auto dpIdTag = dpId.getTag();
213 switch (dpIdTag) {
214 case DynamicsProcessing::Id::commonTag:
215 return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
216 specific);
217 case DynamicsProcessing::Id::vendorExtensionTag:
218 LOG(ERROR) << __func__ << " unsupported ID: " << toString(dpIdTag);
219 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
220 EX_ILLEGAL_ARGUMENT, "DPVendorExtensionIdNotSupported");
221 }
222}
223
224ndk::ScopedAStatus DynamicsProcessingImpl::getParameterDynamicsProcessing(
225 const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
226 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
227
228 switch (tag) {
229 case DynamicsProcessing::engineArchitecture: {
230 specific->set<Parameter::Specific::dynamicsProcessing>(
231 DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
232 mContext->getEngineArchitecture()));
233 return ndk::ScopedAStatus::ok();
234 }
235 case DynamicsProcessing::preEq: {
236 specific->set<Parameter::Specific::dynamicsProcessing>(
237 DynamicsProcessing::make<DynamicsProcessing::preEq>(mContext->getPreEq()));
238 return ndk::ScopedAStatus::ok();
239 }
240 case DynamicsProcessing::postEq: {
241 specific->set<Parameter::Specific::dynamicsProcessing>(
242 DynamicsProcessing::make<DynamicsProcessing::postEq>(mContext->getPostEq()));
243 return ndk::ScopedAStatus::ok();
244 }
245 case DynamicsProcessing::preEqBand: {
246 specific->set<Parameter::Specific::dynamicsProcessing>(
247 DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
248 mContext->getPreEqBand()));
249 return ndk::ScopedAStatus::ok();
250 }
251 case DynamicsProcessing::postEqBand: {
252 specific->set<Parameter::Specific::dynamicsProcessing>(
253 DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
254 mContext->getPostEqBand()));
255 return ndk::ScopedAStatus::ok();
256 }
257 case DynamicsProcessing::mbc: {
258 specific->set<Parameter::Specific::dynamicsProcessing>(
259 DynamicsProcessing::make<DynamicsProcessing::mbc>(mContext->getMbc()));
260 return ndk::ScopedAStatus::ok();
261 }
262 case DynamicsProcessing::mbcBand: {
263 specific->set<Parameter::Specific::dynamicsProcessing>(
264 DynamicsProcessing::make<DynamicsProcessing::mbcBand>(mContext->getMbcBand()));
265 return ndk::ScopedAStatus::ok();
266 }
267 case DynamicsProcessing::limiter: {
268 specific->set<Parameter::Specific::dynamicsProcessing>(
269 DynamicsProcessing::make<DynamicsProcessing::limiter>(mContext->getLimiter()));
270 return ndk::ScopedAStatus::ok();
271 }
272 case DynamicsProcessing::inputGain: {
273 specific->set<Parameter::Specific::dynamicsProcessing>(
274 DynamicsProcessing::make<DynamicsProcessing::inputGain>(
275 mContext->getInputGain()));
276 return ndk::ScopedAStatus::ok();
277 }
278 case DynamicsProcessing::vendorExtension: {
279 LOG(ERROR) << __func__ << " wrong vendor tag in CommonTag: " << toString(tag);
280 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
281 EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagInWrongId");
282 }
283 }
284}
285
286std::shared_ptr<EffectContext> DynamicsProcessingImpl::createContext(
287 const Parameter::Common& common) {
288 if (mContext) {
289 LOG(DEBUG) << __func__ << " context already exist";
290 return mContext;
291 }
292
293 mContext = std::make_shared<DynamicsProcessingContext>(1 /* statusFmqDepth */, common);
294 return mContext;
295}
296
297RetCode DynamicsProcessingImpl::releaseContext() {
298 if (mContext) {
299 mContext->disable();
300 mContext->resetBuffer();
301 mContext.reset();
302 }
303 return RetCode::SUCCESS;
304}
305
306// Processing method running in EffectWorker thread.
307IEffect::Status DynamicsProcessingImpl::effectProcessImpl(float* in, float* out, int samples) {
308 IEffect::Status status = {EX_NULL_POINTER, 0, 0};
309 RETURN_VALUE_IF(!mContext, status, "nullContext");
310 return mContext->lvmProcess(in, out, samples);
311}
312
313} // namespace aidl::android::hardware::audio::effect