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