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