• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         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 
queryEffect(const AudioUuid * in_impl_uuid,Descriptor * _aidl_return)61 extern "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     }
66     if (*in_impl_uuid == getEffectImplUuidAcousticEchoCancelerSw()) {
67         *_aidl_return = aidl::android::hardware::audio::effect::kAcousticEchoCancelerDesc;
68     } else if (*in_impl_uuid == getEffectImplUuidAutomaticGainControlV1Sw()) {
69         *_aidl_return = aidl::android::hardware::audio::effect::kAutomaticGainControlV1Desc;
70     } else if (*in_impl_uuid == getEffectImplUuidAutomaticGainControlV2Sw()) {
71         *_aidl_return = aidl::android::hardware::audio::effect::kAutomaticGainControlV2Desc;
72     } else if (*in_impl_uuid == getEffectImplUuidNoiseSuppressionSw()) {
73         *_aidl_return = aidl::android::hardware::audio::effect::kNoiseSuppressionDesc;
74     }
75     return EX_NONE;
76 }
77 
78 namespace aidl::android::hardware::audio::effect {
79 
EffectPreProcessing(const AudioUuid & uuid)80 EffectPreProcessing::EffectPreProcessing(const AudioUuid& uuid) {
81     LOG(DEBUG) << __func__ << uuid.toString();
82     if (uuid == getEffectImplUuidAcousticEchoCancelerSw()) {
83         mType = PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION;
84         mDescriptor = &kAcousticEchoCancelerDesc;
85         mEffectName = &kAcousticEchoCancelerEffectName;
86     } else if (uuid == getEffectImplUuidAutomaticGainControlV1Sw()) {
87         mType = PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1;
88         mDescriptor = &kAutomaticGainControlV1Desc;
89         mEffectName = &kAutomaticGainControlV1EffectName;
90     } else if (uuid == getEffectImplUuidAutomaticGainControlV2Sw()) {
91         mType = PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2;
92         mDescriptor = &kAutomaticGainControlV2Desc;
93         mEffectName = &kAutomaticGainControlV2EffectName;
94     } else if (uuid == getEffectImplUuidNoiseSuppressionSw()) {
95         mType = PreProcessingEffectType::NOISE_SUPPRESSION;
96         mDescriptor = &kNoiseSuppressionDesc;
97         mEffectName = &kNoiseSuppressionEffectName;
98     } else {
99         LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
100     }
101 }
102 
~EffectPreProcessing()103 EffectPreProcessing::~EffectPreProcessing() {
104     cleanUp();
105     LOG(DEBUG) << __func__;
106 }
107 
getDescriptor(Descriptor * _aidl_return)108 ndk::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 
setParameterSpecific(const Parameter::Specific & specific)115 ndk::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 
setParameterAcousticEchoCanceler(const Parameter::Specific & specific)136 ndk::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 
setParameterAutomaticGainControlV1(const Parameter::Specific & specific)163 ndk::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 
setParameterAutomaticGainControlV2(const Parameter::Specific & specific)199 ndk::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 
setParameterNoiseSuppression(const Parameter::Specific & specific)235 ndk::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 
getParameterSpecific(const Parameter::Id & id,Parameter::Specific * specific)255 ndk::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 
getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Id & id,Parameter::Specific * specific)280 ndk::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 
getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Id & id,Parameter::Specific * specific)309 ndk::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 
getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Id & id,Parameter::Specific * specific)344 ndk::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 
getParameterNoiseSuppression(const NoiseSuppression::Id & id,Parameter::Specific * specific)379 ndk::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 
createContext(const Parameter::Common & common)403 std::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 
getContext()415 std::shared_ptr<EffectContext> EffectPreProcessing::getContext() {
416     return mContext;
417 }
418 
releaseContext()419 RetCode EffectPreProcessing::releaseContext() {
420     if (mContext) {
421         PreProcessingSession::getPreProcessingSession().releaseSession(mType,
422                                                                        mContext->getSessionId());
423         mContext.reset();
424     }
425     return RetCode::SUCCESS;
426 }
427 
commandImpl(CommandId command)428 ndk::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.
effectProcessImpl(float * in,float * out,int sampleToProcess)450 IEffect::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
457