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 <cstddef>
19 #include <set>
20 #include <unordered_set>
21 
22 #define LOG_TAG "AHAL_DynamicsProcessingSw"
23 #include <android-base/logging.h>
24 #include <fmq/AidlMessageQueue.h>
25 #include <system/audio_effects/effect_uuid.h>
26 
27 #include "DynamicsProcessingSw.h"
28 
29 using aidl::android::hardware::audio::effect::Descriptor;
30 using aidl::android::hardware::audio::effect::DynamicsProcessingSw;
31 using aidl::android::hardware::audio::effect::getEffectImplUuidDynamicsProcessingSw;
32 using aidl::android::hardware::audio::effect::getEffectTypeUuidDynamicsProcessing;
33 using aidl::android::hardware::audio::effect::IEffect;
34 using aidl::android::hardware::audio::effect::State;
35 using aidl::android::media::audio::common::AudioUuid;
36 
createEffect(const AudioUuid * in_impl_uuid,std::shared_ptr<IEffect> * instanceSpp)37 extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
38                                            std::shared_ptr<IEffect>* instanceSpp) {
39     if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidDynamicsProcessingSw()) {
40         LOG(ERROR) << __func__ << "uuid not supported";
41         return EX_ILLEGAL_ARGUMENT;
42     }
43     if (instanceSpp) {
44         *instanceSpp = ndk::SharedRefBase::make<DynamicsProcessingSw>();
45         LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
46         return EX_NONE;
47     } else {
48         LOG(ERROR) << __func__ << " invalid input parameter!";
49         return EX_ILLEGAL_ARGUMENT;
50     }
51 }
52 
queryEffect(const AudioUuid * in_impl_uuid,Descriptor * _aidl_return)53 extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
54     if (!in_impl_uuid || *in_impl_uuid != getEffectImplUuidDynamicsProcessingSw()) {
55         LOG(ERROR) << __func__ << "uuid not supported";
56         return EX_ILLEGAL_ARGUMENT;
57     }
58     *_aidl_return = DynamicsProcessingSw::kDescriptor;
59     return EX_NONE;
60 }
61 
62 namespace aidl::android::hardware::audio::effect {
63 
64 const std::string DynamicsProcessingSw::kEffectName = "DynamicsProcessingSw";
65 const DynamicsProcessing::EqBandConfig DynamicsProcessingSw::kEqBandConfigMin =
66         DynamicsProcessing::EqBandConfig({.channel = 0,
67                                           .band = 0,
68                                           .enable = false,
69                                           .cutoffFrequencyHz = 220,
70                                           .gainDb = std::numeric_limits<float>::min()});
71 const DynamicsProcessing::EqBandConfig DynamicsProcessingSw::kEqBandConfigMax =
72         DynamicsProcessing::EqBandConfig({.channel = std::numeric_limits<int>::max(),
73                                           .band = std::numeric_limits<int>::max(),
74                                           .enable = true,
75                                           .cutoffFrequencyHz = 20000,
76                                           .gainDb = std::numeric_limits<float>::max()});
77 const Range::DynamicsProcessingRange DynamicsProcessingSw::kPreEqBandRange = {
78         .min = DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
79                 {DynamicsProcessingSw::kEqBandConfigMin}),
80         .max = DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
81                 {DynamicsProcessingSw::kEqBandConfigMax})};
82 const Range::DynamicsProcessingRange DynamicsProcessingSw::kPostEqBandRange = {
83         .min = DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
84                 {DynamicsProcessingSw::kEqBandConfigMin}),
85         .max = DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
86                 {DynamicsProcessingSw::kEqBandConfigMax})};
87 
88 const std::vector<Range::DynamicsProcessingRange> DynamicsProcessingSw::kRanges = {
89         DynamicsProcessingSw::kPreEqBandRange, DynamicsProcessingSw::kPostEqBandRange};
90 const Capability DynamicsProcessingSw::kCapability = {.range = DynamicsProcessingSw::kRanges};
91 
92 const Descriptor DynamicsProcessingSw::kDescriptor = {
93         .common = {.id = {.type = getEffectTypeUuidDynamicsProcessing(),
94                           .uuid = getEffectImplUuidDynamicsProcessingSw(),
95                           .proxy = std::nullopt},
96                    .flags = {.type = Flags::Type::POST_PROC,
97                              .insert = Flags::Insert::FIRST,
98                              .volume = Flags::Volume::CTRL},
99                    .name = DynamicsProcessingSw::kEffectName,
100                    .implementor = "The Android Open Source Project"},
101         .capability = DynamicsProcessingSw::kCapability};
102 
getDescriptor(Descriptor * _aidl_return)103 ndk::ScopedAStatus DynamicsProcessingSw::getDescriptor(Descriptor* _aidl_return) {
104     LOG(DEBUG) << __func__ << kDescriptor.toString();
105     *_aidl_return = kDescriptor;
106     return ndk::ScopedAStatus::ok();
107 }
108 
setParameterSpecific(const Parameter::Specific & specific)109 ndk::ScopedAStatus DynamicsProcessingSw::setParameterSpecific(const Parameter::Specific& specific) {
110     RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
111               "EffectNotSupported");
112 
113     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
114 
115     LOG(INFO) << __func__ << specific.toString();
116     auto& dpParam = specific.get<Parameter::Specific::dynamicsProcessing>();
117     auto tag = dpParam.getTag();
118     switch (tag) {
119         case DynamicsProcessing::engineArchitecture: {
120             RETURN_IF(mContext->setEngineArchitecture(
121                               dpParam.get<DynamicsProcessing::engineArchitecture>()) !=
122                               RetCode::SUCCESS,
123                       EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
124             return ndk::ScopedAStatus::ok();
125         }
126         case DynamicsProcessing::preEq: {
127             RETURN_IF(mContext->setPreEqChannelCfgs(dpParam.get<DynamicsProcessing::preEq>()) !=
128                               RetCode::SUCCESS,
129                       EX_ILLEGAL_ARGUMENT, "setPreEqChannelCfgsFailed");
130             return ndk::ScopedAStatus::ok();
131         }
132         case DynamicsProcessing::postEq: {
133             RETURN_IF(mContext->setPostEqChannelCfgs(dpParam.get<DynamicsProcessing::postEq>()) !=
134                               RetCode::SUCCESS,
135                       EX_ILLEGAL_ARGUMENT, "setPostEqChannelCfgsFailed");
136             return ndk::ScopedAStatus::ok();
137         }
138         case DynamicsProcessing::mbc: {
139             RETURN_IF(mContext->setMbcChannelCfgs(dpParam.get<DynamicsProcessing::mbc>()) !=
140                               RetCode::SUCCESS,
141                       EX_ILLEGAL_ARGUMENT, "setMbcChannelCfgsFailed");
142             return ndk::ScopedAStatus::ok();
143         }
144         case DynamicsProcessing::preEqBand: {
145             RETURN_IF(mContext->setPreEqBandCfgs(dpParam.get<DynamicsProcessing::preEqBand>()) !=
146                               RetCode::SUCCESS,
147                       EX_ILLEGAL_ARGUMENT, "setPreEqBandCfgsFailed");
148             return ndk::ScopedAStatus::ok();
149         }
150         case DynamicsProcessing::postEqBand: {
151             RETURN_IF(mContext->setPostEqBandCfgs(dpParam.get<DynamicsProcessing::postEqBand>()) !=
152                               RetCode::SUCCESS,
153                       EX_ILLEGAL_ARGUMENT, "setPostEqBandCfgsFailed");
154             return ndk::ScopedAStatus::ok();
155         }
156         case DynamicsProcessing::mbcBand: {
157             RETURN_IF(mContext->setMbcBandCfgs(dpParam.get<DynamicsProcessing::mbcBand>()) !=
158                               RetCode::SUCCESS,
159                       EX_ILLEGAL_ARGUMENT, "setMbcBandCfgsFailed");
160             return ndk::ScopedAStatus::ok();
161         }
162         case DynamicsProcessing::limiter: {
163             RETURN_IF(mContext->setLimiterCfgs(dpParam.get<DynamicsProcessing::limiter>()) !=
164                               RetCode::SUCCESS,
165                       EX_ILLEGAL_ARGUMENT, "limiterCfgsFailed");
166             return ndk::ScopedAStatus::ok();
167         }
168         case DynamicsProcessing::inputGain: {
169             RETURN_IF(mContext->setInputGainCfgs(dpParam.get<DynamicsProcessing::inputGain>()) !=
170                               RetCode::SUCCESS,
171                       EX_ILLEGAL_ARGUMENT, "inputGainCfgFailed");
172             return ndk::ScopedAStatus::ok();
173         }
174         case DynamicsProcessing::vendor: {
175             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
176             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
177                     EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
178         }
179     }
180 }
181 
getParameterSpecific(const Parameter::Id & id,Parameter::Specific * specific)182 ndk::ScopedAStatus DynamicsProcessingSw::getParameterSpecific(const Parameter::Id& id,
183                                                               Parameter::Specific* specific) {
184     auto tag = id.getTag();
185     RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
186     auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
187     auto dpIdTag = dpId.getTag();
188     switch (dpIdTag) {
189         case DynamicsProcessing::Id::commonTag:
190             return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
191                                                   specific);
192         case DynamicsProcessing::Id::vendorExtensionTag:
193             LOG(ERROR) << __func__ << " unsupported tag: " << toString(dpIdTag);
194             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
195                     EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
196     }
197 }
198 
getParameterDynamicsProcessing(const DynamicsProcessing::Tag & tag,Parameter::Specific * specific)199 ndk::ScopedAStatus DynamicsProcessingSw::getParameterDynamicsProcessing(
200         const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
201     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
202 
203     DynamicsProcessing dpParam;
204     switch (tag) {
205         case DynamicsProcessing::Tag::engineArchitecture: {
206             dpParam.set<DynamicsProcessing::engineArchitecture>(mContext->getEngineArchitecture());
207             break;
208         }
209         case DynamicsProcessing::Tag::preEq: {
210             dpParam.set<DynamicsProcessing::preEq>(mContext->getPreEqChannelCfgs());
211             break;
212         }
213         case DynamicsProcessing::Tag::postEq: {
214             dpParam.set<DynamicsProcessing::postEq>(mContext->getPostEqChannelCfgs());
215             break;
216         }
217         case DynamicsProcessing::Tag::mbc: {
218             dpParam.set<DynamicsProcessing::mbc>(mContext->getMbcChannelCfgs());
219             break;
220         }
221         case DynamicsProcessing::Tag::preEqBand: {
222             dpParam.set<DynamicsProcessing::preEqBand>(mContext->getPreEqBandCfgs());
223             break;
224         }
225         case DynamicsProcessing::Tag::postEqBand: {
226             dpParam.set<DynamicsProcessing::postEqBand>(mContext->getPostEqBandCfgs());
227             break;
228         }
229         case DynamicsProcessing::Tag::mbcBand: {
230             dpParam.set<DynamicsProcessing::mbcBand>(mContext->getMbcBandCfgs());
231             break;
232         }
233         case DynamicsProcessing::Tag::limiter: {
234             dpParam.set<DynamicsProcessing::limiter>(mContext->getLimiterCfgs());
235             break;
236         }
237         case DynamicsProcessing::Tag::inputGain: {
238             dpParam.set<DynamicsProcessing::inputGain>(mContext->getInputGainCfgs());
239             break;
240         }
241         case DynamicsProcessing::vendor: {
242             LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
243             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
244                     EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
245         }
246     }
247 
248     specific->set<Parameter::Specific::dynamicsProcessing>(dpParam);
249     LOG(INFO) << __func__ << specific->toString();
250     return ndk::ScopedAStatus::ok();
251 }
252 
createContext(const Parameter::Common & common)253 std::shared_ptr<EffectContext> DynamicsProcessingSw::createContext(
254         const Parameter::Common& common) {
255     if (mContext) {
256         LOG(DEBUG) << __func__ << " context already exist";
257     } else {
258         mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
259     }
260     return mContext;
261 }
262 
releaseContext()263 RetCode DynamicsProcessingSw::releaseContext() {
264     if (mContext) {
265         mContext.reset();
266     }
267     return RetCode::SUCCESS;
268 }
269 
270 // Processing method running in EffectWorker thread.
effectProcessImpl(float * in,float * out,int samples)271 IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int samples) {
272     // TODO: get data buffer and process.
273     LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
274     for (int i = 0; i < samples; i++) {
275         *out++ = *in++;
276     }
277     return {STATUS_OK, samples, samples};
278 }
279 
setCommon(const Parameter::Common & common)280 RetCode DynamicsProcessingSwContext::setCommon(const Parameter::Common& common) {
281     if (auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
282         return ret;
283     }
284     mCommon = common;
285     mChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
286             common.input.base.channelMask);
287     resizeChannels();
288     resizeBands();
289     LOG(INFO) << __func__ << mCommon.toString();
290     return RetCode::SUCCESS;
291 }
292 
setEngineArchitecture(const DynamicsProcessing::EngineArchitecture & cfg)293 RetCode DynamicsProcessingSwContext::setEngineArchitecture(
294         const DynamicsProcessing::EngineArchitecture& cfg) {
295     RETURN_VALUE_IF(!validateEngineConfig(cfg), RetCode::ERROR_ILLEGAL_PARAMETER,
296                     "illegalEngineConfig");
297 
298     if (mEngineSettings == cfg) {
299         LOG(INFO) << __func__ << " not change in engine, do nothing";
300         return RetCode::SUCCESS;
301     }
302     mEngineSettings = cfg;
303     resizeBands();
304     return RetCode::SUCCESS;
305 }
306 
setChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig> & cfgs,std::vector<DynamicsProcessing::ChannelConfig> & targetCfgs,const DynamicsProcessing::StageEnablement & stage)307 RetCode DynamicsProcessingSwContext::setChannelCfgs(
308         const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
309         std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
310         const DynamicsProcessing::StageEnablement& stage) {
311     RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "stageNotInUse");
312 
313     RetCode ret = RetCode::SUCCESS;
314     std::unordered_set<int> channelSet;
315     for (auto& cfg : cfgs) {
316         if (cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount) {
317             LOG(ERROR) << __func__ << " skip illegal channel config " << cfg.toString();
318             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
319             continue;
320         }
321         if (0 != channelSet.count(cfg.channel)) {
322             LOG(WARNING) << __func__ << " duplicated channel " << cfg.channel;
323             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
324         } else {
325             channelSet.insert(cfg.channel);
326         }
327         targetCfgs[cfg.channel] = cfg;
328     }
329     return ret;
330 }
331 
setPreEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig> & cfgs)332 RetCode DynamicsProcessingSwContext::setPreEqChannelCfgs(
333         const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
334     return setChannelCfgs(cfgs, mPreEqChCfgs, mEngineSettings.preEqStage);
335 }
336 
setPostEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig> & cfgs)337 RetCode DynamicsProcessingSwContext::setPostEqChannelCfgs(
338         const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
339     return setChannelCfgs(cfgs, mPostEqChCfgs, mEngineSettings.postEqStage);
340 }
341 
setMbcChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig> & cfgs)342 RetCode DynamicsProcessingSwContext::setMbcChannelCfgs(
343         const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
344     return setChannelCfgs(cfgs, mMbcChCfgs, mEngineSettings.mbcStage);
345 }
346 
setEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig> & cfgs,std::vector<DynamicsProcessing::EqBandConfig> & targetCfgs,const DynamicsProcessing::StageEnablement & stage,const std::vector<DynamicsProcessing::ChannelConfig> & channelConfig)347 RetCode DynamicsProcessingSwContext::setEqBandCfgs(
348         const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
349         std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
350         const DynamicsProcessing::StageEnablement& stage,
351         const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
352     RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "eqStageNotInUse");
353 
354     RetCode ret = RetCode::SUCCESS;
355     std::set<std::pair<int /* channel */, int /* band */>> bandSet;
356 
357     for (auto& cfg : cfgs) {
358         if (0 != bandSet.count({cfg.channel, cfg.band})) {
359             LOG(WARNING) << __func__ << " duplicated band " << cfg.toString();
360             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
361         } else {
362             bandSet.insert({cfg.channel, cfg.band});
363         }
364         if (!validateEqBandConfig(cfg, mChannelCount, stage.bandCount, channelConfig)) {
365             LOG(WARNING) << __func__ << " skip invalid band " << cfg.toString();
366             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
367             continue;
368         }
369         targetCfgs[cfg.channel * stage.bandCount + cfg.band] = cfg;
370     }
371     return ret;
372 }
373 
setPreEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig> & cfgs)374 RetCode DynamicsProcessingSwContext::setPreEqBandCfgs(
375         const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
376     return setEqBandCfgs(cfgs, mPreEqChBands, mEngineSettings.preEqStage, mPreEqChCfgs);
377 }
378 
setPostEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig> & cfgs)379 RetCode DynamicsProcessingSwContext::setPostEqBandCfgs(
380         const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
381     return setEqBandCfgs(cfgs, mPostEqChBands, mEngineSettings.postEqStage, mPostEqChCfgs);
382 }
383 
setMbcBandCfgs(const std::vector<DynamicsProcessing::MbcBandConfig> & cfgs)384 RetCode DynamicsProcessingSwContext::setMbcBandCfgs(
385         const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
386     RETURN_VALUE_IF(!mEngineSettings.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
387                     "mbcNotInUse");
388 
389     RetCode ret = RetCode::SUCCESS;
390     std::set<std::pair<int /* channel */, int /* band */>> bandSet;
391 
392     int bandCount = mEngineSettings.mbcStage.bandCount;
393     std::vector<bool> filled(mChannelCount * bandCount, false);
394     for (auto& it : cfgs) {
395         if (0 != bandSet.count({it.channel, it.band})) {
396             LOG(WARNING) << __func__ << " duplicated band " << it.toString();
397             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
398         } else {
399             bandSet.insert({it.channel, it.band});
400         }
401         if (!validateMbcBandConfig(it, mChannelCount, mEngineSettings.mbcStage.bandCount,
402                                    mMbcChCfgs)) {
403             LOG(WARNING) << __func__ << " skip invalid band " << it.toString();
404             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
405             continue;
406         }
407         mMbcChBands[it.channel * bandCount + it.band] = it;
408     }
409     return ret;
410 }
411 
setLimiterCfgs(const std::vector<DynamicsProcessing::LimiterConfig> & cfgs)412 RetCode DynamicsProcessingSwContext::setLimiterCfgs(
413         const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
414     RETURN_VALUE_IF(!mEngineSettings.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
415                     "limiterNotInUse");
416 
417     RetCode ret = RetCode::SUCCESS;
418     std::unordered_set<int> channelSet;
419 
420     for (auto& it : cfgs) {
421         if (0 != channelSet.count(it.channel)) {
422             LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
423             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
424         } else {
425             channelSet.insert(it.channel);
426         }
427         if (!validateLimiterConfig(it, mChannelCount)) {
428             LOG(WARNING) << __func__ << " skip invalid limiter " << it.toString();
429             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
430             continue;
431         }
432         mLimiterCfgs[it.channel] = it;
433     }
434     return ret;
435 }
436 
resizeChannels()437 void DynamicsProcessingSwContext::resizeChannels() {
438     if (mPreEqChCfgs.size() != mChannelCount) {
439         mPreEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
440     }
441     if (mPostEqChCfgs.size() != mChannelCount) {
442         mPostEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
443     }
444     if (mMbcChCfgs.size() != mChannelCount) {
445         mMbcChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
446     }
447     if (mLimiterCfgs.size() != mChannelCount) {
448         mLimiterCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
449     }
450     if (mInputGainCfgs.size() != mChannelCount) {
451         mInputGainCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
452     }
453 }
454 
resizeBands()455 void DynamicsProcessingSwContext::resizeBands() {
456     if (mPreEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.preEqStage.bandCount)) {
457         mPreEqChBands.resize(mChannelCount * mEngineSettings.preEqStage.bandCount,
458                              {.channel = kInvalidChannelId});
459     }
460     if (mPostEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.postEqStage.bandCount)) {
461         mPostEqChBands.resize(mChannelCount * mEngineSettings.postEqStage.bandCount,
462                               {.channel = kInvalidChannelId});
463     }
464     if (mMbcChBands.size() != (size_t)(mChannelCount * mEngineSettings.mbcStage.bandCount)) {
465         mMbcChBands.resize(mChannelCount * mEngineSettings.mbcStage.bandCount,
466                            {.channel = kInvalidChannelId});
467     }
468 }
469 
setInputGainCfgs(const std::vector<DynamicsProcessing::InputGain> & cfgs)470 RetCode DynamicsProcessingSwContext::setInputGainCfgs(
471         const std::vector<DynamicsProcessing::InputGain>& cfgs) {
472     for (const auto& cfg : cfgs) {
473         RETURN_VALUE_IF(cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount,
474                         RetCode::ERROR_ILLEGAL_PARAMETER, "invalidChannel");
475         mInputGainCfgs[cfg.channel] = cfg;
476     }
477     return RetCode::SUCCESS;
478 }
479 
getInputGainCfgs()480 std::vector<DynamicsProcessing::InputGain> DynamicsProcessingSwContext::getInputGainCfgs() {
481     std::vector<DynamicsProcessing::InputGain> ret;
482     std::copy_if(mInputGainCfgs.begin(), mInputGainCfgs.end(), std::back_inserter(ret),
483                  [&](const auto& gain) { return gain.channel != kInvalidChannelId; });
484     return ret;
485 }
486 
validateStageEnablement(const DynamicsProcessing::StageEnablement & enablement)487 bool DynamicsProcessingSwContext::validateStageEnablement(
488         const DynamicsProcessing::StageEnablement& enablement) {
489     return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
490 }
491 
validateEngineConfig(const DynamicsProcessing::EngineArchitecture & engine)492 bool DynamicsProcessingSwContext::validateEngineConfig(
493         const DynamicsProcessing::EngineArchitecture& engine) {
494     return engine.preferredProcessingDurationMs >= 0 &&
495            validateStageEnablement(engine.preEqStage) &&
496            validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
497 }
498 
validateEqBandConfig(const DynamicsProcessing::EqBandConfig & band,int maxChannel,int maxBand,const std::vector<DynamicsProcessing::ChannelConfig> & channelConfig)499 bool DynamicsProcessingSwContext::validateEqBandConfig(
500         const DynamicsProcessing::EqBandConfig& band, int maxChannel, int maxBand,
501         const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
502     return band.channel >= 0 && band.channel < maxChannel &&
503            (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
504            band.band >= 0 && band.band < maxBand;
505 }
506 
validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig & band,int maxChannel,int maxBand,const std::vector<DynamicsProcessing::ChannelConfig> & channelConfig)507 bool DynamicsProcessingSwContext::validateMbcBandConfig(
508         const DynamicsProcessing::MbcBandConfig& band, int maxChannel, int maxBand,
509         const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
510     return band.channel >= 0 && band.channel < maxChannel &&
511            (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
512            band.band >= 0 && band.band < maxBand && band.attackTimeMs >= 0 &&
513            band.releaseTimeMs >= 0 && band.ratio >= 0 && band.thresholdDb <= 0 &&
514            band.kneeWidthDb <= 0 && band.noiseGateThresholdDb <= 0 && band.expanderRatio >= 0;
515 }
516 
validateLimiterConfig(const DynamicsProcessing::LimiterConfig & limiter,int maxChannel)517 bool DynamicsProcessingSwContext::validateLimiterConfig(
518         const DynamicsProcessing::LimiterConfig& limiter, int maxChannel) {
519     return limiter.channel >= 0 && limiter.channel < maxChannel && limiter.attackTimeMs >= 0 &&
520            limiter.releaseTimeMs >= 0 && limiter.ratio >= 0 && limiter.thresholdDb <= 0;
521 }
522 
523 }  // namespace aidl::android::hardware::audio::effect
524