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