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 #include <algorithm>
18 #include <limits.h>
19 #include <unordered_set>
20 
21 #define LOG_TAG "EffectReverb"
22 
23 #include <audio_effects/effect_bassboost.h>
24 #include <audio_effects/effect_equalizer.h>
25 #include <audio_effects/effect_virtualizer.h>
26 #include <android-base/logging.h>
27 #include <fmq/AidlMessageQueue.h>
28 #include <Utils.h>
29 
30 #include "EffectReverb.h"
31 #include "ReverbTypes.h"
32 
33 using aidl::android::hardware::audio::effect::Descriptor;
34 using aidl::android::hardware::audio::effect::EffectReverb;
35 using aidl::android::hardware::audio::effect::getEffectImplUuidAuxEnvReverb;
36 using aidl::android::hardware::audio::effect::getEffectImplUuidAuxPresetReverb;
37 using aidl::android::hardware::audio::effect::getEffectImplUuidInsertEnvReverb;
38 using aidl::android::hardware::audio::effect::getEffectImplUuidInsertPresetReverb;
39 using aidl::android::hardware::audio::effect::IEffect;
40 using aidl::android::hardware::audio::effect::State;
41 using aidl::android::media::audio::common::AudioUuid;
42 
isReverbUuidSupported(const AudioUuid * uuid)43 bool isReverbUuidSupported(const AudioUuid* uuid) {
44     return (*uuid == getEffectImplUuidAuxEnvReverb() ||
45             *uuid == getEffectImplUuidAuxPresetReverb() ||
46             *uuid == getEffectImplUuidInsertEnvReverb() ||
47             *uuid == getEffectImplUuidInsertPresetReverb());
48 }
49 
createEffect(const AudioUuid * uuid,std::shared_ptr<IEffect> * instanceSpp)50 extern "C" binder_exception_t createEffect(const AudioUuid* uuid,
51                                            std::shared_ptr<IEffect>* instanceSpp) {
52     if (uuid == nullptr || !isReverbUuidSupported(uuid)) {
53         LOG(ERROR) << __func__ << "uuid not supported";
54         return EX_ILLEGAL_ARGUMENT;
55     }
56     if (instanceSpp) {
57         *instanceSpp = ndk::SharedRefBase::make<EffectReverb>(*uuid);
58         return EX_NONE;
59     } else {
60         LOG(ERROR) << __func__ << " invalid input parameter!";
61         return EX_ILLEGAL_ARGUMENT;
62     }
63 }
64 
queryEffect(const AudioUuid * in_impl_uuid,Descriptor * _aidl_return)65 extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
66     if (*in_impl_uuid == getEffectImplUuidAuxEnvReverb()) {
67         *_aidl_return = aidl::android::hardware::audio::effect::lvm::kAuxEnvReverbDesc;
68     } else if (*in_impl_uuid == getEffectImplUuidInsertEnvReverb()) {
69         *_aidl_return = aidl::android::hardware::audio::effect::lvm::kInsertEnvReverbDesc;
70     } else if (*in_impl_uuid == getEffectImplUuidAuxPresetReverb()) {
71         *_aidl_return = aidl::android::hardware::audio::effect::lvm::kAuxPresetReverbDesc;
72     } else if (*in_impl_uuid == getEffectImplUuidInsertPresetReverb()) {
73         *_aidl_return = aidl::android::hardware::audio::effect::lvm::kInsertPresetReverbDesc;
74     } else {
75         LOG(ERROR) << __func__ << "uuid not supported";
76         return EX_ILLEGAL_ARGUMENT;
77     }
78     return EX_NONE;
79 }
80 
81 namespace aidl::android::hardware::audio::effect {
82 
EffectReverb(const AudioUuid & uuid)83 EffectReverb::EffectReverb(const AudioUuid& uuid) {
84     if (uuid == getEffectImplUuidAuxEnvReverb()) {
85         mType = lvm::ReverbEffectType::AUX_ENV;
86         mDescriptor = &lvm::kAuxEnvReverbDesc;
87         mEffectName = &lvm::kAuxEnvReverbEffectName;
88     } else if (uuid == getEffectImplUuidInsertEnvReverb()) {
89         mType = lvm::ReverbEffectType::INSERT_ENV;
90         mDescriptor = &lvm::kInsertEnvReverbDesc;
91         mEffectName = &lvm::kInsertEnvReverbEffectName;
92     } else if (uuid == getEffectImplUuidAuxPresetReverb()) {
93         mType = lvm::ReverbEffectType::AUX_PRESET;
94         mDescriptor = &lvm::kAuxPresetReverbDesc;
95         mEffectName = &lvm::kAuxPresetReverbEffectName;
96     } else if (uuid == getEffectImplUuidInsertPresetReverb()) {
97         mType = lvm::ReverbEffectType::INSERT_PRESET;
98         mDescriptor = &lvm::kInsertPresetReverbDesc;
99         mEffectName = &lvm::kInsertPresetReverbEffectName;
100     } else {
101         LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
102     }
103 }
104 
~EffectReverb()105 EffectReverb::~EffectReverb() {
106     cleanUp();
107 }
108 
getDescriptor(Descriptor * _aidl_return)109 ndk::ScopedAStatus EffectReverb::getDescriptor(Descriptor* _aidl_return) {
110     RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
111     *_aidl_return = *mDescriptor;
112     return ndk::ScopedAStatus::ok();
113 }
114 
setParameterSpecific(const Parameter::Specific & specific)115 ndk::ScopedAStatus EffectReverb::setParameterSpecific(const Parameter::Specific& specific) {
116     LOG(VERBOSE) << __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::presetReverb:
122             return setParameterPresetReverb(specific);
123         case Parameter::Specific::environmentalReverb:
124             return setParameterEnvironmentalReverb(specific);
125         default:
126             LOG(ERROR) << __func__ << " unsupported tag " << toString(tag);
127             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
128                                                                     "specificParamNotSupported");
129     }
130 }
131 
setParameterPresetReverb(const Parameter::Specific & specific)132 ndk::ScopedAStatus EffectReverb::setParameterPresetReverb(const Parameter::Specific& specific) {
133     auto& prParam = specific.get<Parameter::Specific::presetReverb>();
134     RETURN_IF(!inRange(prParam, lvm::kPresetReverbRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
135     auto tag = prParam.getTag();
136 
137     switch (tag) {
138         case PresetReverb::preset: {
139             RETURN_IF(mContext->setPresetReverbPreset(prParam.get<PresetReverb::preset>()) !=
140                               RetCode::SUCCESS,
141                       EX_ILLEGAL_ARGUMENT, "setPresetFailed");
142             return ndk::ScopedAStatus::ok();
143         }
144         default: {
145             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
146             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
147                                                                     "PresetReverbTagNotSupported");
148         }
149     }
150 }
151 
setParameterEnvironmentalReverb(const Parameter::Specific & specific)152 ndk::ScopedAStatus EffectReverb::setParameterEnvironmentalReverb(
153         const Parameter::Specific& specific) {
154     auto& erParam = specific.get<Parameter::Specific::environmentalReverb>();
155     RETURN_IF(!inRange(erParam, lvm::kEnvReverbRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
156     auto tag = erParam.getTag();
157 
158     switch (tag) {
159         case EnvironmentalReverb::roomLevelMb: {
160             RETURN_IF(mContext->setEnvironmentalReverbRoomLevel(
161                               erParam.get<EnvironmentalReverb::roomLevelMb>()) != RetCode::SUCCESS,
162                       EX_ILLEGAL_ARGUMENT, "setRoomLevelFailed");
163             return ndk::ScopedAStatus::ok();
164         }
165         case EnvironmentalReverb::roomHfLevelMb: {
166             RETURN_IF(
167                     mContext->setEnvironmentalReverbRoomHfLevel(
168                             erParam.get<EnvironmentalReverb::roomHfLevelMb>()) != RetCode::SUCCESS,
169                     EX_ILLEGAL_ARGUMENT, "setRoomHfLevelFailed");
170             return ndk::ScopedAStatus::ok();
171         }
172         case EnvironmentalReverb::decayTimeMs: {
173             RETURN_IF(mContext->setEnvironmentalReverbDecayTime(
174                               erParam.get<EnvironmentalReverb::decayTimeMs>()) != RetCode::SUCCESS,
175                       EX_ILLEGAL_ARGUMENT, "setDecayTimeFailed");
176             return ndk::ScopedAStatus::ok();
177         }
178         case EnvironmentalReverb::decayHfRatioPm: {
179             RETURN_IF(
180                     mContext->setEnvironmentalReverbDecayHfRatio(
181                             erParam.get<EnvironmentalReverb::decayHfRatioPm>()) != RetCode::SUCCESS,
182                     EX_ILLEGAL_ARGUMENT, "setDecayHfRatioFailed");
183             return ndk::ScopedAStatus::ok();
184         }
185         case EnvironmentalReverb::reflectionsLevelMb: {
186             RETURN_IF(mContext->setReflectionsLevel(
187                               erParam.get<EnvironmentalReverb::reflectionsLevelMb>()) !=
188                               RetCode::SUCCESS,
189                       EX_ILLEGAL_ARGUMENT, "setReflectionsLevelFailed");
190             return ndk::ScopedAStatus::ok();
191         }
192         case EnvironmentalReverb::reflectionsDelayMs: {
193             RETURN_IF(mContext->setReflectionsDelay(
194                               erParam.get<EnvironmentalReverb::reflectionsDelayMs>()) !=
195                               RetCode::SUCCESS,
196                       EX_ILLEGAL_ARGUMENT, "setReflectionsDelayFailed");
197             return ndk::ScopedAStatus::ok();
198         }
199         case EnvironmentalReverb::levelMb: {
200             RETURN_IF(mContext->setEnvironmentalReverbLevel(
201                               erParam.get<EnvironmentalReverb::levelMb>()) != RetCode::SUCCESS,
202                       EX_ILLEGAL_ARGUMENT, "setLevelFailed");
203             return ndk::ScopedAStatus::ok();
204         }
205         case EnvironmentalReverb::delayMs: {
206             RETURN_IF(mContext->setEnvironmentalReverbDelay(
207                               erParam.get<EnvironmentalReverb::delayMs>()) != RetCode::SUCCESS,
208                       EX_ILLEGAL_ARGUMENT, "setDelayFailed");
209             return ndk::ScopedAStatus::ok();
210         }
211         case EnvironmentalReverb::diffusionPm: {
212             RETURN_IF(mContext->setEnvironmentalReverbDiffusion(
213                               erParam.get<EnvironmentalReverb::diffusionPm>()) != RetCode::SUCCESS,
214                       EX_ILLEGAL_ARGUMENT, "setDiffusionFailed");
215             return ndk::ScopedAStatus::ok();
216         }
217         case EnvironmentalReverb::densityPm: {
218             RETURN_IF(mContext->setEnvironmentalReverbDensity(
219                               erParam.get<EnvironmentalReverb::densityPm>()) != RetCode::SUCCESS,
220                       EX_ILLEGAL_ARGUMENT, "setDensityFailed");
221             return ndk::ScopedAStatus::ok();
222         }
223         case EnvironmentalReverb::bypass: {
224             RETURN_IF(mContext->setEnvironmentalReverbBypass(
225                               erParam.get<EnvironmentalReverb::bypass>()) != RetCode::SUCCESS,
226                       EX_ILLEGAL_ARGUMENT, "setBypassFailed");
227             return ndk::ScopedAStatus::ok();
228         }
229         default: {
230             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
231             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
232                     EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
233         }
234     }
235 }
236 
getParameterSpecific(const Parameter::Id & id,Parameter::Specific * specific)237 ndk::ScopedAStatus EffectReverb::getParameterSpecific(const Parameter::Id& id,
238                                                       Parameter::Specific* specific) {
239     RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
240     auto tag = id.getTag();
241 
242     switch (tag) {
243         case Parameter::Id::presetReverbTag:
244             return getParameterPresetReverb(id.get<Parameter::Id::presetReverbTag>(), specific);
245         case Parameter::Id::environmentalReverbTag:
246             return getParameterEnvironmentalReverb(id.get<Parameter::Id::environmentalReverbTag>(),
247                                                    specific);
248         default:
249             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
250             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
251                                                                     "wrongIdTag");
252     }
253 }
254 
getParameterPresetReverb(const PresetReverb::Id & id,Parameter::Specific * specific)255 ndk::ScopedAStatus EffectReverb::getParameterPresetReverb(const PresetReverb::Id& id,
256                                                           Parameter::Specific* specific) {
257     RETURN_IF(id.getTag() != PresetReverb::Id::commonTag, EX_ILLEGAL_ARGUMENT,
258               "PresetReverbTagNotSupported");
259     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
260     PresetReverb prParam;
261     auto tag = id.get<PresetReverb::Id::commonTag>();
262     switch (tag) {
263         case PresetReverb::preset: {
264             prParam.set<PresetReverb::preset>(mContext->getPresetReverbPreset());
265             break;
266         }
267         default: {
268             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
269             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
270                                                                     "PresetReverbTagNotSupported");
271         }
272     }
273 
274     specific->set<Parameter::Specific::presetReverb>(prParam);
275     return ndk::ScopedAStatus::ok();
276 }
277 
getParameterEnvironmentalReverb(const EnvironmentalReverb::Id & id,Parameter::Specific * specific)278 ndk::ScopedAStatus EffectReverb::getParameterEnvironmentalReverb(const EnvironmentalReverb::Id& id,
279                                                                  Parameter::Specific* specific) {
280     RETURN_IF(id.getTag() != EnvironmentalReverb::Id::commonTag, EX_ILLEGAL_ARGUMENT,
281               "EnvironmentalReverbTagNotSupported");
282     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
283     EnvironmentalReverb erParam;
284 
285     auto tag = id.get<EnvironmentalReverb::Id::commonTag>();
286     switch (tag) {
287         case EnvironmentalReverb::roomLevelMb: {
288             erParam.set<EnvironmentalReverb::roomLevelMb>(
289                     mContext->getEnvironmentalReverbRoomLevel());
290             break;
291         }
292         case EnvironmentalReverb::roomHfLevelMb: {
293             erParam.set<EnvironmentalReverb::roomHfLevelMb>(
294                     mContext->getEnvironmentalReverbRoomHfLevel());
295             break;
296         }
297         case EnvironmentalReverb::decayTimeMs: {
298             erParam.set<EnvironmentalReverb::decayTimeMs>(
299                     mContext->getEnvironmentalReverbDecayTime());
300             break;
301         }
302         case EnvironmentalReverb::decayHfRatioPm: {
303             erParam.set<EnvironmentalReverb::decayHfRatioPm>(
304                     mContext->getEnvironmentalReverbDecayHfRatio());
305             break;
306         }
307         case EnvironmentalReverb::reflectionsLevelMb: {
308             erParam.set<EnvironmentalReverb::reflectionsLevelMb>(mContext->getReflectionsLevel());
309             break;
310         }
311         case EnvironmentalReverb::reflectionsDelayMs: {
312             erParam.set<EnvironmentalReverb::reflectionsDelayMs>(mContext->getReflectionsDelay());
313             break;
314         }
315         case EnvironmentalReverb::levelMb: {
316             erParam.set<EnvironmentalReverb::levelMb>(mContext->getEnvironmentalReverbLevel());
317             break;
318         }
319         case EnvironmentalReverb::delayMs: {
320             erParam.set<EnvironmentalReverb::delayMs>(mContext->getEnvironmentalReverbDelay());
321             break;
322         }
323         case EnvironmentalReverb::diffusionPm: {
324             erParam.set<EnvironmentalReverb::diffusionPm>(
325                     mContext->getEnvironmentalReverbDiffusion());
326             break;
327         }
328         case EnvironmentalReverb::densityPm: {
329             erParam.set<EnvironmentalReverb::densityPm>(mContext->getEnvironmentalReverbDensity());
330             break;
331         }
332         case EnvironmentalReverb::bypass: {
333             erParam.set<EnvironmentalReverb::bypass>(mContext->getEnvironmentalReverbBypass());
334             break;
335         }
336         default: {
337             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
338             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
339                     EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
340         }
341     }
342 
343     specific->set<Parameter::Specific::environmentalReverb>(erParam);
344     return ndk::ScopedAStatus::ok();
345 }
346 
createContext(const Parameter::Common & common)347 std::shared_ptr<EffectContext> EffectReverb::createContext(const Parameter::Common& common) {
348     if (mContext) {
349         LOG(DEBUG) << __func__ << " context already exist";
350     } else {
351         mContext = std::make_shared<ReverbContext>(1 /* statusFmqDepth */, common, mType);
352     }
353 
354     return mContext;
355 }
356 
releaseContext()357 RetCode EffectReverb::releaseContext() {
358     if (mContext) {
359         mContext.reset();
360     }
361     return RetCode::SUCCESS;
362 }
363 
commandImpl(CommandId command)364 ndk::ScopedAStatus EffectReverb::commandImpl(CommandId command) {
365     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
366     switch (command) {
367         case CommandId::START:
368             mContext->enable();
369             break;
370         case CommandId::STOP:
371             mContext->disable();
372             break;
373         case CommandId::RESET:
374             mContext->disable();
375             mContext->resetBuffer();
376             break;
377         default:
378             LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
379             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
380                                                                     "commandIdNotSupported");
381     }
382     return ndk::ScopedAStatus::ok();
383 }
384 
385 // Processing method running in EffectWorker thread.
effectProcessImpl(float * in,float * out,int sampleToProcess)386 IEffect::Status EffectReverb::effectProcessImpl(float* in, float* out, int sampleToProcess) {
387     IEffect::Status status = {EX_NULL_POINTER, 0, 0};
388     RETURN_VALUE_IF(!mContext, status, "nullContext");
389     return mContext->process(in, out, sampleToProcess);
390 }
391 
392 }  // namespace aidl::android::hardware::audio::effect
393