1 /*
2  * Copyright (C) 2022 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 #define LOG_TAG "EffectBundleAidl"
21 
22 #include <audio_effects/effect_bassboost.h>
23 #include <audio_effects/effect_equalizer.h>
24 #include <audio_effects/effect_virtualizer.h>
25 #include <android-base/logging.h>
26 #include <fmq/AidlMessageQueue.h>
27 #include <LVM.h>
28 #include <Utils.h>
29 
30 #include "BundleTypes.h"
31 #include "EffectBundleAidl.h"
32 
33 using aidl::android::hardware::audio::effect::getEffectImplUuidBassBoostBundle;
34 using aidl::android::hardware::audio::effect::Descriptor;
35 using aidl::android::hardware::audio::effect::EffectBundleAidl;
36 using aidl::android::hardware::audio::effect::getEffectImplUuidEqualizerBundle;
37 using aidl::android::hardware::audio::effect::IEffect;
38 using aidl::android::hardware::audio::effect::State;
39 using aidl::android::hardware::audio::effect::getEffectImplUuidVirtualizerBundle;
40 using aidl::android::hardware::audio::effect::getEffectImplUuidVolumeBundle;
41 using aidl::android::media::audio::common::AudioUuid;
42 
isUuidSupported(const AudioUuid * uuid)43 bool isUuidSupported(const AudioUuid* uuid) {
44     return (*uuid == getEffectImplUuidBassBoostBundle() ||
45             *uuid == getEffectImplUuidEqualizerBundle() ||
46             *uuid == getEffectImplUuidVirtualizerBundle() ||
47             *uuid == getEffectImplUuidVolumeBundle());
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 || !isUuidSupported(uuid)) {
53         LOG(ERROR) << __func__ << "uuid not supported";
54         return EX_ILLEGAL_ARGUMENT;
55     }
56     if (instanceSpp) {
57         *instanceSpp = ndk::SharedRefBase::make<EffectBundleAidl>(*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 || !isUuidSupported(in_impl_uuid)) {
67         LOG(ERROR) << __func__ << "uuid not supported";
68         return EX_ILLEGAL_ARGUMENT;
69     }
70     if (*in_impl_uuid == getEffectImplUuidEqualizerBundle()) {
71         *_aidl_return = aidl::android::hardware::audio::effect::lvm::kEqualizerDesc;
72     } else if (*in_impl_uuid == getEffectImplUuidBassBoostBundle()) {
73         *_aidl_return = aidl::android::hardware::audio::effect::lvm:: kBassBoostDesc;
74     } else if (*in_impl_uuid == getEffectImplUuidVirtualizerBundle()) {
75         *_aidl_return = aidl::android::hardware::audio::effect::lvm::kVirtualizerDesc;
76     } else if (*in_impl_uuid == getEffectImplUuidVolumeBundle()) {
77         *_aidl_return = aidl::android::hardware::audio::effect::lvm::kVolumeDesc;
78     }
79     return EX_NONE;
80 }
81 
82 namespace aidl::android::hardware::audio::effect {
83 
EffectBundleAidl(const AudioUuid & uuid)84 EffectBundleAidl::EffectBundleAidl(const AudioUuid& uuid) {
85     if (uuid == getEffectImplUuidEqualizerBundle()) {
86         mType = lvm::BundleEffectType::EQUALIZER;
87         mDescriptor = &lvm::kEqualizerDesc;
88         mEffectName = &lvm::kEqualizerEffectName;
89     } else if (uuid == getEffectImplUuidBassBoostBundle()) {
90         mType = lvm::BundleEffectType::BASS_BOOST;
91         mDescriptor = &lvm::kBassBoostDesc;
92         mEffectName = &lvm::kBassBoostEffectName;
93     } else if (uuid == getEffectImplUuidVirtualizerBundle()) {
94         mType = lvm::BundleEffectType::VIRTUALIZER;
95         mDescriptor = &lvm::kVirtualizerDesc;
96         mEffectName = &lvm::kVirtualizerEffectName;
97     } else if (uuid == getEffectImplUuidVolumeBundle()) {
98         mType = lvm::BundleEffectType::VOLUME;
99         mDescriptor = &lvm::kVolumeDesc;
100         mEffectName = &lvm::kVolumeEffectName;
101     } else {
102         LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
103     }
104 }
105 
~EffectBundleAidl()106 EffectBundleAidl::~EffectBundleAidl() {
107     cleanUp();
108 }
109 
getDescriptor(Descriptor * _aidl_return)110 ndk::ScopedAStatus EffectBundleAidl::getDescriptor(Descriptor* _aidl_return) {
111     RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
112     *_aidl_return = *mDescriptor;
113     return ndk::ScopedAStatus::ok();
114 }
115 
setParameterCommon(const Parameter & param)116 ndk::ScopedAStatus EffectBundleAidl::setParameterCommon(const Parameter& param) {
117     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
118 
119     auto tag = param.getTag();
120     switch (tag) {
121         case Parameter::common:
122             RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
123                       EX_ILLEGAL_ARGUMENT, "setCommFailed");
124             break;
125         case Parameter::deviceDescription:
126             RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
127                               RetCode::SUCCESS,
128                       EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
129             break;
130         case Parameter::mode:
131             RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
132                       EX_ILLEGAL_ARGUMENT, "setModeFailed");
133             break;
134         case Parameter::source:
135             RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
136                       EX_ILLEGAL_ARGUMENT, "setSourceFailed");
137             break;
138         case Parameter::volumeStereo:
139             RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
140                               RetCode::SUCCESS,
141                       EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
142             break;
143         default: {
144             LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
145             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
146                                                                     "commonParamNotSupported");
147         }
148     }
149     return ndk::ScopedAStatus::ok();
150 }
151 
setParameterSpecific(const Parameter::Specific & specific)152 ndk::ScopedAStatus EffectBundleAidl::setParameterSpecific(const Parameter::Specific& specific) {
153     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
154 
155     auto tag = specific.getTag();
156     switch (tag) {
157         case Parameter::Specific::equalizer:
158             return setParameterEqualizer(specific);
159         case Parameter::Specific::bassBoost:
160             return setParameterBassBoost(specific);
161         case Parameter::Specific::virtualizer:
162             return setParameterVirtualizer(specific);
163         case Parameter::Specific::volume:
164             return setParameterVolume(specific);
165         default:
166             LOG(ERROR) << __func__ << " unsupported tag " << toString(tag);
167             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
168                                                                     "specificParamNotSupported");
169     }
170 }
171 
setParameterEqualizer(const Parameter::Specific & specific)172 ndk::ScopedAStatus EffectBundleAidl::setParameterEqualizer(const Parameter::Specific& specific) {
173     auto& eq = specific.get<Parameter::Specific::equalizer>();
174     RETURN_IF(!inRange(eq, lvm::kEqRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
175     auto eqTag = eq.getTag();
176     switch (eqTag) {
177         case Equalizer::preset:
178             RETURN_IF(mContext->setEqualizerPreset(eq.get<Equalizer::preset>()) != RetCode::SUCCESS,
179                       EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
180             return ndk::ScopedAStatus::ok();
181         case Equalizer::bandLevels:
182             RETURN_IF(mContext->setEqualizerBandLevels(eq.get<Equalizer::bandLevels>()) !=
183                               RetCode::SUCCESS,
184                       EX_ILLEGAL_ARGUMENT, "setBandLevelsFailed");
185             return ndk::ScopedAStatus::ok();
186         default:
187             LOG(ERROR) << __func__ << " unsupported parameter " << specific.toString();
188             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
189                                                                     "eqTagNotSupported");
190     }
191 }
192 
setParameterBassBoost(const Parameter::Specific & specific)193 ndk::ScopedAStatus EffectBundleAidl::setParameterBassBoost(const Parameter::Specific& specific) {
194     auto& bb = specific.get<Parameter::Specific::bassBoost>();
195     RETURN_IF(!inRange(bb, lvm::kBassBoostRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
196     auto bbTag = bb.getTag();
197     switch (bbTag) {
198         case BassBoost::strengthPm: {
199             RETURN_IF(mContext->setBassBoostStrength(bb.get<BassBoost::strengthPm>()) !=
200                               RetCode::SUCCESS,
201                       EX_ILLEGAL_ARGUMENT, "setStrengthFailed");
202             return ndk::ScopedAStatus::ok();
203         }
204         default:
205             LOG(ERROR) << __func__ << " unsupported parameter " << specific.toString();
206             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
207                                                                     "bbTagNotSupported");
208     }
209 }
210 
setParameterVirtualizer(const Parameter::Specific & specific)211 ndk::ScopedAStatus EffectBundleAidl::setParameterVirtualizer(const Parameter::Specific& specific) {
212     auto& vr = specific.get<Parameter::Specific::virtualizer>();
213     RETURN_IF(!inRange(vr, lvm::kVirtualizerRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
214     auto vrTag = vr.getTag();
215     switch (vrTag) {
216         case Virtualizer::strengthPm: {
217             RETURN_IF(mContext->setVirtualizerStrength(vr.get<Virtualizer::strengthPm>()) !=
218                               RetCode::SUCCESS,
219                       EX_ILLEGAL_ARGUMENT, "setStrengthFailed");
220             return ndk::ScopedAStatus::ok();
221         }
222         case Virtualizer::device: {
223             RETURN_IF(mContext->setForcedDevice(vr.get<Virtualizer::device>()) != RetCode::SUCCESS,
224                       EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
225             return ndk::ScopedAStatus::ok();
226         }
227         case Virtualizer::speakerAngles:
228             FALLTHROUGH_INTENDED;
229         case Virtualizer::vendor: {
230             LOG(ERROR) << __func__ << " unsupported tag: " << toString(vrTag);
231             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
232                                                                     "VirtualizerTagNotSupported");
233         }
234     }
235 }
236 
setParameterVolume(const Parameter::Specific & specific)237 ndk::ScopedAStatus EffectBundleAidl::setParameterVolume(const Parameter::Specific& specific) {
238     auto& vol = specific.get<Parameter::Specific::volume>();
239     RETURN_IF(!inRange(vol, lvm::kVolumeRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
240     auto volTag = vol.getTag();
241     switch (volTag) {
242         case Volume::levelDb: {
243             RETURN_IF(mContext->setVolumeLevel(vol.get<Volume::levelDb>()) != RetCode::SUCCESS,
244                       EX_ILLEGAL_ARGUMENT, "setLevelFailed");
245             return ndk::ScopedAStatus::ok();
246         }
247         case Volume::mute:
248             RETURN_IF(mContext->setVolumeMute(vol.get<Volume::mute>()) != RetCode::SUCCESS,
249                       EX_ILLEGAL_ARGUMENT, "setMuteFailed");
250             return ndk::ScopedAStatus::ok();
251         default:
252             LOG(ERROR) << __func__ << " unsupported parameter " << specific.toString();
253             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
254                                                                     "volTagNotSupported");
255     }
256 }
257 
getParameterSpecific(const Parameter::Id & id,Parameter::Specific * specific)258 ndk::ScopedAStatus EffectBundleAidl::getParameterSpecific(const Parameter::Id& id,
259                                                           Parameter::Specific* specific) {
260     RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
261     auto tag = id.getTag();
262 
263     switch (tag) {
264         case Parameter::Id::equalizerTag:
265             return getParameterEqualizer(id.get<Parameter::Id::equalizerTag>(), specific);
266         case Parameter::Id::bassBoostTag:
267             return getParameterBassBoost(id.get<Parameter::Id::bassBoostTag>(), specific);
268         case Parameter::Id::virtualizerTag:
269             return getParameterVirtualizer(id.get<Parameter::Id::virtualizerTag>(), specific);
270         case Parameter::Id::volumeTag:
271             return getParameterVolume(id.get<Parameter::Id::volumeTag>(), specific);
272         default:
273             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
274             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
275                                                                     "wrongIdTag");
276     }
277 }
278 
getParameterEqualizer(const Equalizer::Id & id,Parameter::Specific * specific)279 ndk::ScopedAStatus EffectBundleAidl::getParameterEqualizer(const Equalizer::Id& id,
280                                                            Parameter::Specific* specific) {
281     RETURN_IF(id.getTag() != Equalizer::Id::commonTag, EX_ILLEGAL_ARGUMENT,
282               "EqualizerTagNotSupported");
283     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
284     Equalizer eqParam;
285 
286     auto tag = id.get<Equalizer::Id::commonTag>();
287     switch (tag) {
288         case Equalizer::bandLevels: {
289             eqParam.set<Equalizer::bandLevels>(mContext->getEqualizerBandLevels());
290             break;
291         }
292         case Equalizer::preset: {
293             eqParam.set<Equalizer::preset>(mContext->getEqualizerPreset());
294             break;
295         }
296         case Equalizer::bandFrequencies: {
297             eqParam.set<Equalizer::bandFrequencies>(lvm::kEqBandFrequency);
298             break;
299         }
300         case Equalizer::presets: {
301             eqParam.set<Equalizer::presets>(lvm::kEqPresets);
302             break;
303         }
304         case Equalizer::centerFreqMh: {
305             eqParam.set<Equalizer::centerFreqMh>(mContext->getEqualizerCenterFreqs());
306             break;
307         }
308         case Equalizer::vendor: {
309             LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
310             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
311                     EX_ILLEGAL_ARGUMENT, "unsupportedTag");
312         }
313     }
314 
315     specific->set<Parameter::Specific::equalizer>(eqParam);
316     return ndk::ScopedAStatus::ok();
317 }
318 
getParameterBassBoost(const BassBoost::Id & id,Parameter::Specific * specific)319 ndk::ScopedAStatus EffectBundleAidl::getParameterBassBoost(const BassBoost::Id& id,
320                                                            Parameter::Specific* specific) {
321     RETURN_IF(id.getTag() != BassBoost::Id::commonTag, EX_ILLEGAL_ARGUMENT,
322               "BassBoostTagNotSupported");
323     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
324     BassBoost bbParam;
325 
326     auto tag = id.get<BassBoost::Id::commonTag>();
327     switch (tag) {
328         case BassBoost::strengthPm: {
329             bbParam.set<BassBoost::strengthPm>(mContext->getBassBoostStrength());
330             break;
331         }
332         default: {
333             LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
334             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
335                                                                     "BassBoostTagNotSupported");
336         }
337     }
338 
339     specific->set<Parameter::Specific::bassBoost>(bbParam);
340     return ndk::ScopedAStatus::ok();
341 }
342 
getParameterVolume(const Volume::Id & id,Parameter::Specific * specific)343 ndk::ScopedAStatus EffectBundleAidl::getParameterVolume(const Volume::Id& id,
344                                                         Parameter::Specific* specific) {
345     RETURN_IF(id.getTag() != Volume::Id::commonTag, EX_ILLEGAL_ARGUMENT, "VolumeTagNotSupported");
346 
347     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
348     Volume volParam;
349 
350     auto tag = id.get<Volume::Id::commonTag>();
351     switch (tag) {
352         case Volume::levelDb: {
353             volParam.set<Volume::levelDb>(static_cast<int>(mContext->getVolumeLevel()));
354             break;
355         }
356         case Volume::mute: {
357             volParam.set<Volume::mute>(mContext->getVolumeMute());
358             break;
359         }
360         default: {
361             LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
362             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
363                                                                     "VolumeTagNotSupported");
364         }
365     }
366 
367     specific->set<Parameter::Specific::volume>(volParam);
368     return ndk::ScopedAStatus::ok();
369 }
370 
getParameterVirtualizer(const Virtualizer::Id & id,Parameter::Specific * specific)371 ndk::ScopedAStatus EffectBundleAidl::getParameterVirtualizer(const Virtualizer::Id& id,
372                                                              Parameter::Specific* specific) {
373     RETURN_IF((id.getTag() != Virtualizer::Id::commonTag) &&
374                       (id.getTag() != Virtualizer::Id::speakerAnglesPayload),
375               EX_ILLEGAL_ARGUMENT, "VirtualizerTagNotSupported");
376 
377     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
378     Virtualizer vrParam;
379 
380     if (id.getTag() == Virtualizer::Id::speakerAnglesPayload) {
381         auto angles = mContext->getSpeakerAngles(id.get<Virtualizer::Id::speakerAnglesPayload>());
382         RETURN_IF(angles.size() == 0, EX_ILLEGAL_ARGUMENT, "getSpeakerAnglesFailed");
383         Virtualizer param = Virtualizer::make<Virtualizer::speakerAngles>(angles);
384         specific->set<Parameter::Specific::virtualizer>(param);
385         return ndk::ScopedAStatus::ok();
386     }
387 
388     auto tag = id.get<Virtualizer::Id::commonTag>();
389     switch (tag) {
390         case Virtualizer::strengthPm: {
391             vrParam.set<Virtualizer::strengthPm>(mContext->getVirtualizerStrength());
392             break;
393         }
394         case Virtualizer::device: {
395             vrParam.set<Virtualizer::device>(mContext->getForcedDevice());
396             break;
397         }
398         case Virtualizer::speakerAngles:
399             FALLTHROUGH_INTENDED;
400         case Virtualizer::vendor: {
401             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
402             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
403                                                                     "VirtualizerTagNotSupported");
404         }
405     }
406 
407     specific->set<Parameter::Specific::virtualizer>(vrParam);
408     return ndk::ScopedAStatus::ok();
409 }
410 
createContext(const Parameter::Common & common)411 std::shared_ptr<EffectContext> EffectBundleAidl::createContext(const Parameter::Common& common) {
412     if (mContext) {
413         LOG(DEBUG) << __func__ << " context already exist";
414     } else {
415         // GlobalSession is a singleton
416         mContext = GlobalSession::getGlobalSession().createSession(mType, 1 /* statusFmqDepth */,
417                                                                    common);
418     }
419 
420     return mContext;
421 }
422 
releaseContext()423 RetCode EffectBundleAidl::releaseContext() {
424     if (mContext) {
425         GlobalSession::getGlobalSession().releaseSession(mType, mContext->getSessionId());
426         mContext.reset();
427     }
428     return RetCode::SUCCESS;
429 }
430 
commandImpl(CommandId command)431 ndk::ScopedAStatus EffectBundleAidl::commandImpl(CommandId command) {
432     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
433     switch (command) {
434         case CommandId::START:
435             mContext->enable();
436             break;
437         case CommandId::STOP:
438             mContext->disable();
439             break;
440         case CommandId::RESET:
441             mContext->disable();
442             mContext->resetBuffer();
443             break;
444         default:
445             LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
446             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
447                                                                     "commandIdNotSupported");
448     }
449     return ndk::ScopedAStatus::ok();
450 }
451 
452 // Processing method running in EffectWorker thread.
effectProcessImpl(float * in,float * out,int sampleToProcess)453 IEffect::Status EffectBundleAidl::effectProcessImpl(float* in, float* out, int sampleToProcess) {
454     IEffect::Status status = {EX_NULL_POINTER, 0, 0};
455     RETURN_VALUE_IF(!mContext, status, "nullContext");
456     return mContext->process(in, out, sampleToProcess);
457 }
458 
459 }  // namespace aidl::android::hardware::audio::effect
460