blob: e8ae8b3df7389752bc7e607e275b34b80932dfec [file] [log] [blame]
Shraddha Basantwanice054522023-01-20 23:36:54 +05301/*
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 "EffectPreProcessing"
18#include <algorithm>
19#include <unordered_set>
20
21#include <Utils.h>
22#include <android-base/logging.h>
23#include <fmq/AidlMessageQueue.h>
24
25#include "EffectPreProcessing.h"
26
Shunkai Yao399be682023-03-06 18:54:18 +000027using aidl::android::hardware::audio::effect::getEffectImplUuidAcousticEchoCancelerSw;
28using aidl::android::hardware::audio::effect::getEffectImplUuidAutomaticGainControlV1Sw;
29using aidl::android::hardware::audio::effect::getEffectImplUuidAutomaticGainControlV2Sw;
30using aidl::android::hardware::audio::effect::getEffectImplUuidNoiseSuppressionSw;
31
Shraddha Basantwanice054522023-01-20 23:36:54 +053032using aidl::android::hardware::audio::effect::Descriptor;
33using aidl::android::hardware::audio::effect::EffectPreProcessing;
34using aidl::android::hardware::audio::effect::IEffect;
Shraddha Basantwanice054522023-01-20 23:36:54 +053035using aidl::android::hardware::audio::effect::State;
36using aidl::android::media::audio::common::AudioUuid;
37
38bool isPreProcessingUuidSupported(const AudioUuid& uuid) {
Shunkai Yao399be682023-03-06 18:54:18 +000039 return uuid == getEffectImplUuidAcousticEchoCancelerSw() ||
40 uuid == getEffectImplUuidAutomaticGainControlV1Sw() ||
41 uuid == getEffectImplUuidAutomaticGainControlV2Sw() ||
42 uuid == getEffectImplUuidNoiseSuppressionSw();
Shraddha Basantwanice054522023-01-20 23:36:54 +053043}
44
45extern "C" binder_exception_t createEffect(const AudioUuid* uuid,
46 std::shared_ptr<IEffect>* instanceSpp) {
47 if (!uuid || !isPreProcessingUuidSupported(*uuid)) {
48 LOG(ERROR) << __func__ << "uuid not supported";
49 return EX_ILLEGAL_ARGUMENT;
50 }
51 if (instanceSpp) {
52 *instanceSpp = ndk::SharedRefBase::make<EffectPreProcessing>(*uuid);
53 LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
54 return EX_NONE;
55 } else {
56 LOG(ERROR) << __func__ << " invalid input parameter!";
57 return EX_ILLEGAL_ARGUMENT;
58 }
59}
60
61extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
62 if (!in_impl_uuid || !isPreProcessingUuidSupported(*in_impl_uuid)) {
63 LOG(ERROR) << __func__ << "uuid not supported";
64 return EX_ILLEGAL_ARGUMENT;
65 }
Shunkai Yao399be682023-03-06 18:54:18 +000066 if (*in_impl_uuid == getEffectImplUuidAcousticEchoCancelerSw()) {
Shraddha Basantwanice054522023-01-20 23:36:54 +053067 *_aidl_return = aidl::android::hardware::audio::effect::kAcousticEchoCancelerDesc;
Shunkai Yao399be682023-03-06 18:54:18 +000068 } else if (*in_impl_uuid == getEffectImplUuidAutomaticGainControlV1Sw()) {
Shraddha Basantwanice054522023-01-20 23:36:54 +053069 *_aidl_return = aidl::android::hardware::audio::effect::kAutomaticGainControlV1Desc;
Shunkai Yao399be682023-03-06 18:54:18 +000070 } else if (*in_impl_uuid == getEffectImplUuidAutomaticGainControlV2Sw()) {
Shraddha Basantwanice054522023-01-20 23:36:54 +053071 *_aidl_return = aidl::android::hardware::audio::effect::kAutomaticGainControlV2Desc;
Shunkai Yao399be682023-03-06 18:54:18 +000072 } else if (*in_impl_uuid == getEffectImplUuidNoiseSuppressionSw()) {
Shraddha Basantwanice054522023-01-20 23:36:54 +053073 *_aidl_return = aidl::android::hardware::audio::effect::kNoiseSuppressionDesc;
74 }
75 return EX_NONE;
76}
77
78namespace aidl::android::hardware::audio::effect {
79
80EffectPreProcessing::EffectPreProcessing(const AudioUuid& uuid) {
81 LOG(DEBUG) << __func__ << uuid.toString();
Shunkai Yao399be682023-03-06 18:54:18 +000082 if (uuid == getEffectImplUuidAcousticEchoCancelerSw()) {
Shraddha Basantwanice054522023-01-20 23:36:54 +053083 mType = PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION;
84 mDescriptor = &kAcousticEchoCancelerDesc;
85 mEffectName = &kAcousticEchoCancelerEffectName;
Shunkai Yao399be682023-03-06 18:54:18 +000086 } else if (uuid == getEffectImplUuidAutomaticGainControlV1Sw()) {
Shraddha Basantwanice054522023-01-20 23:36:54 +053087 mType = PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1;
88 mDescriptor = &kAutomaticGainControlV1Desc;
89 mEffectName = &kAutomaticGainControlV1EffectName;
Shunkai Yao399be682023-03-06 18:54:18 +000090 } else if (uuid == getEffectImplUuidAutomaticGainControlV2Sw()) {
Shraddha Basantwanice054522023-01-20 23:36:54 +053091 mType = PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2;
92 mDescriptor = &kAutomaticGainControlV2Desc;
93 mEffectName = &kAutomaticGainControlV2EffectName;
Shunkai Yao399be682023-03-06 18:54:18 +000094 } else if (uuid == getEffectImplUuidNoiseSuppressionSw()) {
Shraddha Basantwanice054522023-01-20 23:36:54 +053095 mType = PreProcessingEffectType::NOISE_SUPPRESSION;
96 mDescriptor = &kNoiseSuppressionDesc;
97 mEffectName = &kNoiseSuppressionEffectName;
98 } else {
99 LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
100 }
101}
102
103EffectPreProcessing::~EffectPreProcessing() {
104 cleanUp();
105 LOG(DEBUG) << __func__;
106}
107
108ndk::ScopedAStatus EffectPreProcessing::getDescriptor(Descriptor* _aidl_return) {
109 RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
110 LOG(DEBUG) << _aidl_return->toString();
111 *_aidl_return = *mDescriptor;
112 return ndk::ScopedAStatus::ok();
113}
114
115ndk::ScopedAStatus EffectPreProcessing::setParameterSpecific(const Parameter::Specific& specific) {
116 LOG(DEBUG) << __func__ << " specific " << specific.toString();
117 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
118
119 auto tag = specific.getTag();
120 switch (tag) {
121 case Parameter::Specific::acousticEchoCanceler:
122 return setParameterAcousticEchoCanceler(specific);
123 case Parameter::Specific::automaticGainControlV1:
124 return setParameterAutomaticGainControlV1(specific);
125 case Parameter::Specific::automaticGainControlV2:
126 return setParameterAutomaticGainControlV2(specific);
127 case Parameter::Specific::noiseSuppression:
128 return setParameterNoiseSuppression(specific);
129 default:
130 LOG(ERROR) << __func__ << " unsupported tag " << toString(tag);
131 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
132 "specificParamNotSupported");
133 }
134}
135
136ndk::ScopedAStatus EffectPreProcessing::setParameterAcousticEchoCanceler(
137 const Parameter::Specific& specific) {
138 auto& param = specific.get<Parameter::Specific::acousticEchoCanceler>();
139 RETURN_IF(!inRange(param, kAcousticEchoCancelerRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
140 auto tag = param.getTag();
141
142 switch (tag) {
143 case AcousticEchoCanceler::echoDelayUs: {
144 RETURN_IF(mContext->setAcousticEchoCancelerEchoDelay(
145 param.get<AcousticEchoCanceler::echoDelayUs>()) != RetCode::SUCCESS,
146 EX_ILLEGAL_ARGUMENT, "echoDelayNotSupported");
147 return ndk::ScopedAStatus::ok();
148 }
149 case AcousticEchoCanceler::mobileMode: {
150 RETURN_IF(mContext->setAcousticEchoCancelerMobileMode(
151 param.get<AcousticEchoCanceler::mobileMode>()) != RetCode::SUCCESS,
152 EX_ILLEGAL_ARGUMENT, "SettingMobileModeNotSupported");
153 return ndk::ScopedAStatus::ok();
154 }
155 default: {
156 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
157 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
158 EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
159 }
160 }
161}
162
163ndk::ScopedAStatus EffectPreProcessing::setParameterAutomaticGainControlV1(
164 const Parameter::Specific& specific) {
165 auto& param = specific.get<Parameter::Specific::automaticGainControlV1>();
166 RETURN_IF(!inRange(param, kAutomaticGainControlV1Ranges), EX_ILLEGAL_ARGUMENT, "outOfRange");
167 auto tag = param.getTag();
168
169 switch (tag) {
170 case AutomaticGainControlV1::targetPeakLevelDbFs: {
171 RETURN_IF(mContext->setAutomaticGainControlV1TargetPeakLevel(
172 param.get<AutomaticGainControlV1::targetPeakLevelDbFs>()) !=
173 RetCode::SUCCESS,
174 EX_ILLEGAL_ARGUMENT, "targetPeakLevelNotSupported");
175 return ndk::ScopedAStatus::ok();
176 }
177 case AutomaticGainControlV1::maxCompressionGainDb: {
178 RETURN_IF(mContext->setAutomaticGainControlV1MaxCompressionGain(
179 param.get<AutomaticGainControlV1::maxCompressionGainDb>()) !=
180 RetCode::SUCCESS,
181 EX_ILLEGAL_ARGUMENT, "maxCompressionGainNotSupported");
182 return ndk::ScopedAStatus::ok();
183 }
184 case AutomaticGainControlV1::enableLimiter: {
185 RETURN_IF(
186 mContext->setAutomaticGainControlV1EnableLimiter(
187 param.get<AutomaticGainControlV1::enableLimiter>()) != RetCode::SUCCESS,
188 EX_ILLEGAL_ARGUMENT, "enableLimiterNotSupported");
189 return ndk::ScopedAStatus::ok();
190 }
191 default: {
192 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
193 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
194 EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV1TagNotSupported");
195 }
196 }
197}
198
199ndk::ScopedAStatus EffectPreProcessing::setParameterAutomaticGainControlV2(
200 const Parameter::Specific& specific) {
201 auto& param = specific.get<Parameter::Specific::automaticGainControlV2>();
202 RETURN_IF(!inRange(param, kAutomaticGainControlV2Ranges), EX_ILLEGAL_ARGUMENT, "outOfRange");
203 auto tag = param.getTag();
204
205 switch (tag) {
206 case AutomaticGainControlV2::fixedDigitalGainMb: {
207 RETURN_IF(mContext->setAutomaticGainControlV2DigitalGain(
208 param.get<AutomaticGainControlV2::fixedDigitalGainMb>()) !=
209 RetCode::SUCCESS,
210 EX_ILLEGAL_ARGUMENT, "digitalGainNotSupported");
211 return ndk::ScopedAStatus::ok();
212 }
213 case AutomaticGainControlV2::levelEstimator: {
214 RETURN_IF(mContext->setAutomaticGainControlV2LevelEstimator(
215 param.get<AutomaticGainControlV2::levelEstimator>()) !=
216 RetCode::SUCCESS,
217 EX_ILLEGAL_ARGUMENT, "levelEstimatorNotSupported");
218 return ndk::ScopedAStatus::ok();
219 }
220 case AutomaticGainControlV2::saturationMarginMb: {
221 RETURN_IF(mContext->setAutomaticGainControlV2SaturationMargin(
222 param.get<AutomaticGainControlV2::saturationMarginMb>()) !=
223 RetCode::SUCCESS,
224 EX_ILLEGAL_ARGUMENT, "saturationMarginNotSupported");
225 return ndk::ScopedAStatus::ok();
226 }
227 default: {
228 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
229 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
230 EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV2TagNotSupported");
231 }
232 }
233}
234
235ndk::ScopedAStatus EffectPreProcessing::setParameterNoiseSuppression(
236 const Parameter::Specific& specific) {
237 auto& param = specific.get<Parameter::Specific::noiseSuppression>();
238 auto tag = param.getTag();
239
240 switch (tag) {
241 case NoiseSuppression::level: {
242 RETURN_IF(mContext->setNoiseSuppressionLevel(param.get<NoiseSuppression::level>()) !=
243 RetCode::SUCCESS,
244 EX_ILLEGAL_ARGUMENT, "levelNotSupported");
245 return ndk::ScopedAStatus::ok();
246 }
247 default: {
248 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
249 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
250 EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
251 }
252 }
253}
254
255ndk::ScopedAStatus EffectPreProcessing::getParameterSpecific(const Parameter::Id& id,
256 Parameter::Specific* specific) {
257 RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
258 auto tag = id.getTag();
259
260 switch (tag) {
261 case Parameter::Id::acousticEchoCancelerTag:
262 return getParameterAcousticEchoCanceler(
263 id.get<Parameter::Id::acousticEchoCancelerTag>(), specific);
264 case Parameter::Id::automaticGainControlV1Tag:
265 return getParameterAutomaticGainControlV1(
266 id.get<Parameter::Id::automaticGainControlV1Tag>(), specific);
267 case Parameter::Id::automaticGainControlV2Tag:
268 return getParameterAutomaticGainControlV2(
269 id.get<Parameter::Id::automaticGainControlV2Tag>(), specific);
270 case Parameter::Id::noiseSuppressionTag:
271 return getParameterNoiseSuppression(id.get<Parameter::Id::noiseSuppressionTag>(),
272 specific);
273 default:
274 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
275 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
276 "wrongIdTag");
277 }
278}
279
280ndk::ScopedAStatus EffectPreProcessing::getParameterAcousticEchoCanceler(
281 const AcousticEchoCanceler::Id& id, Parameter::Specific* specific) {
282 RETURN_IF(id.getTag() != AcousticEchoCanceler::Id::commonTag, EX_ILLEGAL_ARGUMENT,
283 "AcousticEchoCancelerTagNotSupported");
284 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
285 AcousticEchoCanceler param;
286 auto tag = id.get<AcousticEchoCanceler::Id::commonTag>();
287 switch (tag) {
288 case AcousticEchoCanceler::echoDelayUs: {
289 param.set<AcousticEchoCanceler::echoDelayUs>(
290 mContext->getAcousticEchoCancelerEchoDelay());
291 break;
292 }
293 case AcousticEchoCanceler::mobileMode: {
294 param.set<AcousticEchoCanceler::mobileMode>(
295 mContext->getAcousticEchoCancelerMobileMode());
296 break;
297 }
298 default: {
299 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
300 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
301 EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
302 }
303 }
304
305 specific->set<Parameter::Specific::acousticEchoCanceler>(param);
306 return ndk::ScopedAStatus::ok();
307}
308
309ndk::ScopedAStatus EffectPreProcessing::getParameterAutomaticGainControlV1(
310 const AutomaticGainControlV1::Id& id, Parameter::Specific* specific) {
311 RETURN_IF(id.getTag() != AutomaticGainControlV1::Id::commonTag, EX_ILLEGAL_ARGUMENT,
312 "AutomaticGainControlV1TagNotSupported");
313 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
314 AutomaticGainControlV1 param;
315
316 auto tag = id.get<AutomaticGainControlV1::Id::commonTag>();
317 switch (tag) {
318 case AutomaticGainControlV1::targetPeakLevelDbFs: {
319 param.set<AutomaticGainControlV1::targetPeakLevelDbFs>(
320 mContext->getAutomaticGainControlV1TargetPeakLevel());
321 break;
322 }
323 case AutomaticGainControlV1::maxCompressionGainDb: {
324 param.set<AutomaticGainControlV1::maxCompressionGainDb>(
325 mContext->getAutomaticGainControlV1MaxCompressionGain());
326 break;
327 }
328 case AutomaticGainControlV1::enableLimiter: {
329 param.set<AutomaticGainControlV1::enableLimiter>(
330 mContext->getAutomaticGainControlV1EnableLimiter());
331 break;
332 }
333 default: {
334 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
335 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
336 EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV1TagNotSupported");
337 }
338 }
339
340 specific->set<Parameter::Specific::automaticGainControlV1>(param);
341 return ndk::ScopedAStatus::ok();
342}
343
344ndk::ScopedAStatus EffectPreProcessing::getParameterAutomaticGainControlV2(
345 const AutomaticGainControlV2::Id& id, Parameter::Specific* specific) {
346 RETURN_IF(id.getTag() != AutomaticGainControlV2::Id::commonTag, EX_ILLEGAL_ARGUMENT,
347 "AutomaticGainControlV2TagNotSupported");
348 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
349 AutomaticGainControlV2 param;
350
351 auto tag = id.get<AutomaticGainControlV2::Id::commonTag>();
352 switch (tag) {
353 case AutomaticGainControlV2::fixedDigitalGainMb: {
354 param.set<AutomaticGainControlV2::fixedDigitalGainMb>(
355 mContext->getAutomaticGainControlV2DigitalGain());
356 break;
357 }
358 case AutomaticGainControlV2::levelEstimator: {
359 param.set<AutomaticGainControlV2::levelEstimator>(
360 mContext->getAutomaticGainControlV2LevelEstimator());
361 break;
362 }
363 case AutomaticGainControlV2::saturationMarginMb: {
364 param.set<AutomaticGainControlV2::saturationMarginMb>(
365 mContext->getAutomaticGainControlV2SaturationMargin());
366 break;
367 }
368 default: {
369 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
370 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
371 EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV2TagNotSupported");
372 }
373 }
374
375 specific->set<Parameter::Specific::automaticGainControlV2>(param);
376 return ndk::ScopedAStatus::ok();
377}
378
379ndk::ScopedAStatus EffectPreProcessing::getParameterNoiseSuppression(
380 const NoiseSuppression::Id& id, Parameter::Specific* specific) {
381 RETURN_IF(id.getTag() != NoiseSuppression::Id::commonTag, EX_ILLEGAL_ARGUMENT,
382 "NoiseSuppressionTagNotSupported");
383 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
384 NoiseSuppression param;
385
386 auto tag = id.get<NoiseSuppression::Id::commonTag>();
387 switch (tag) {
388 case NoiseSuppression::level: {
389 param.set<NoiseSuppression::level>(mContext->getNoiseSuppressionLevel());
390 break;
391 }
392 default: {
393 LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
394 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
395 EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
396 }
397 }
398
399 specific->set<Parameter::Specific::noiseSuppression>(param);
400 return ndk::ScopedAStatus::ok();
401}
402
403std::shared_ptr<EffectContext> EffectPreProcessing::createContext(const Parameter::Common& common) {
404 if (mContext) {
405 LOG(DEBUG) << __func__ << " context already exist";
406 } else {
407 // PreProcessingSession is a singleton
408 mContext = PreProcessingSession::getPreProcessingSession().createSession(
409 mType, 1 /* statusFmqDepth */, common);
410 }
411
412 return mContext;
413}
414
415std::shared_ptr<EffectContext> EffectPreProcessing::getContext() {
416 return mContext;
417}
418
419RetCode EffectPreProcessing::releaseContext() {
420 if (mContext) {
421 PreProcessingSession::getPreProcessingSession().releaseSession(mType,
422 mContext->getSessionId());
423 mContext.reset();
424 }
425 return RetCode::SUCCESS;
426}
427
428ndk::ScopedAStatus EffectPreProcessing::commandImpl(CommandId command) {
429 RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
430 switch (command) {
431 case CommandId::START:
432 mContext->enable();
433 break;
434 case CommandId::STOP:
435 mContext->disable();
436 break;
437 case CommandId::RESET:
438 mContext->disable();
439 mContext->resetBuffer();
440 break;
441 default:
442 LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
443 return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
444 "commandIdNotSupported");
445 }
446 return ndk::ScopedAStatus::ok();
447}
448
449// Processing method running in EffectWorker thread.
450IEffect::Status EffectPreProcessing::effectProcessImpl(float* in, float* out, int sampleToProcess) {
451 IEffect::Status status = {EX_NULL_POINTER, 0, 0};
452 RETURN_VALUE_IF(!mContext, status, "nullContext");
453 return mContext->lvmProcess(in, out, sampleToProcess);
454}
455
456} // namespace aidl::android::hardware::audio::effect