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