xref: /aosp_15_r20/frameworks/av/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 "AHAL_DPLibEffectsContext"
18 
19 #include "DynamicsProcessingContext.h"
20 #include "DynamicsProcessing.h"
21 
22 #include <audio_utils/power.h>
23 #include <sys/param.h>
24 #include <functional>
25 #include <unordered_set>
26 
27 namespace aidl::android::hardware::audio::effect {
28 
DynamicsProcessingContext(int statusDepth,const Parameter::Common & common)29 DynamicsProcessingContext::DynamicsProcessingContext(int statusDepth,
30                                                      const Parameter::Common& common)
31     : EffectContext(statusDepth, common) {
32     init();
33 }
34 
enable()35 RetCode DynamicsProcessingContext::enable() {
36     if (mState != DYNAMICS_PROCESSING_STATE_INITIALIZED) {
37         return RetCode::ERROR_EFFECT_LIB_ERROR;
38     }
39     mState = DYNAMICS_PROCESSING_STATE_ACTIVE;
40     return RetCode::SUCCESS;
41 }
42 
disable()43 RetCode DynamicsProcessingContext::disable() {
44     if (mState != DYNAMICS_PROCESSING_STATE_ACTIVE) {
45         return RetCode::ERROR_EFFECT_LIB_ERROR;
46     }
47     mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
48     return RetCode::SUCCESS;
49 }
50 
reset()51 RetCode DynamicsProcessingContext::reset() {
52     if (mDpFreq != nullptr) {
53         mDpFreq->reset();
54     }
55     mEngineInited = false;
56     return RetCode::SUCCESS;
57 }
58 
setCommon(const Parameter::Common & common)59 RetCode DynamicsProcessingContext::setCommon(const Parameter::Common& common) {
60     if(auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
61         return ret;
62     }
63     mCommon = common;
64     init();
65     return RetCode::SUCCESS;
66 }
67 
setVolumeStereo(const Parameter::VolumeStereo & volumeStereo)68 RetCode DynamicsProcessingContext::setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
69     dp_fx::DPChannel* leftChannel = mDpFreq->getChannel(0);
70     dp_fx::DPChannel* rightChannel = mDpFreq->getChannel(1);
71     if (leftChannel != nullptr) {
72         leftChannel->setOutputGain(audio_utils_power_from_amplitude(volumeStereo.left));
73     }
74     if (rightChannel != nullptr) {
75         rightChannel->setOutputGain(audio_utils_power_from_amplitude(volumeStereo.right));
76     }
77     return RetCode::SUCCESS;
78 }
79 
getVolumeStereo()80 Parameter::VolumeStereo DynamicsProcessingContext::getVolumeStereo() {
81     return {1.0f, 1.0f};
82 }
83 
dpSetFreqDomainVariant_l(const DynamicsProcessing::EngineArchitecture & engine)84 void DynamicsProcessingContext::dpSetFreqDomainVariant_l(
85         const DynamicsProcessing::EngineArchitecture& engine) {
86     mDpFreq.reset(new dp_fx::DPFrequency());
87     mDpFreq->init(mChannelCount, engine.preEqStage.inUse, engine.preEqStage.bandCount,
88                   engine.mbcStage.inUse, engine.mbcStage.bandCount, engine.postEqStage.inUse,
89                   engine.postEqStage.bandCount, engine.limiterInUse);
90 
91     int32_t sampleRate = mCommon.input.base.sampleRate;
92     int32_t minBlockSize = (int32_t)dp_fx::DPFrequency::getMinBockSize();
93     int32_t block = engine.preferredProcessingDurationMs * sampleRate / 1000.0f;
94     LOG(VERBOSE) << __func__ << " sampleRate " << sampleRate << " block length "
95                  << engine.preferredProcessingDurationMs << " ms (" << block << "samples)";
96     if (block < minBlockSize) {
97         block = minBlockSize;
98     } else if (!powerof2(block)) {
99         // find next highest power of 2.
100         block = 1 << (32 - __builtin_clz(block));
101     }
102     mDpFreq->configure(block, block >> 1, sampleRate);
103 }
104 
setEngineArchitecture(const DynamicsProcessing::EngineArchitecture & engineArchitecture)105 RetCode DynamicsProcessingContext::setEngineArchitecture(
106         const DynamicsProcessing::EngineArchitecture& engineArchitecture) {
107     if (!mEngineInited || mEngineArchitecture != engineArchitecture) {
108         if (engineArchitecture.resolutionPreference ==
109             DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION) {
110             dpSetFreqDomainVariant_l(engineArchitecture);
111         } else {
112             LOG(WARNING) << __func__ << toString(engineArchitecture.resolutionPreference)
113                          << " not available now";
114         }
115         mEngineInited = true;
116         mEngineArchitecture = engineArchitecture;
117     }
118     return RetCode::SUCCESS;
119 }
120 
setPreEq(const std::vector<DynamicsProcessing::ChannelConfig> & channels)121 RetCode DynamicsProcessingContext::setPreEq(
122         const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
123     return setDpChannels_l<dp_fx::DPEq>(channels, StageType::PREEQ);
124 }
125 
setPostEq(const std::vector<DynamicsProcessing::ChannelConfig> & channels)126 RetCode DynamicsProcessingContext::setPostEq(
127         const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
128     return setDpChannels_l<dp_fx::DPEq>(channels, StageType::POSTEQ);
129 }
130 
setMbc(const std::vector<DynamicsProcessing::ChannelConfig> & channels)131 RetCode DynamicsProcessingContext::setMbc(
132         const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
133     return setDpChannels_l<dp_fx::DPMbc>(channels, StageType::MBC);
134 }
135 
setPreEqBand(const std::vector<DynamicsProcessing::EqBandConfig> & bands)136 RetCode DynamicsProcessingContext::setPreEqBand(
137         const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
138     RETURN_VALUE_IF(
139             !validateBandConfig(bands, mChannelCount, mEngineArchitecture.preEqStage.bandCount),
140             RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
141     return setBands_l<DynamicsProcessing::EqBandConfig>(bands, StageType::PREEQ);
142 }
143 
setPostEqBand(const std::vector<DynamicsProcessing::EqBandConfig> & bands)144 RetCode DynamicsProcessingContext::setPostEqBand(
145         const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
146     RETURN_VALUE_IF(
147             !validateBandConfig(bands, mChannelCount, mEngineArchitecture.postEqStage.bandCount),
148             RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
149     return setBands_l<DynamicsProcessing::EqBandConfig>(bands, StageType::POSTEQ);
150 }
151 
setMbcBand(const std::vector<DynamicsProcessing::MbcBandConfig> & bands)152 RetCode DynamicsProcessingContext::setMbcBand(
153         const std::vector<DynamicsProcessing::MbcBandConfig>& bands) {
154     RETURN_VALUE_IF(
155             !validateBandConfig(bands, mChannelCount, mEngineArchitecture.mbcStage.bandCount),
156             RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
157     return setBands_l<DynamicsProcessing::MbcBandConfig>(bands, StageType::MBC);
158 }
159 
setLimiter(const std::vector<DynamicsProcessing::LimiterConfig> & limiters)160 RetCode DynamicsProcessingContext::setLimiter(
161         const std::vector<DynamicsProcessing::LimiterConfig>& limiters) {
162     RETURN_VALUE_IF(!validateLimiterConfig(limiters, mChannelCount),
163                     RetCode::ERROR_ILLEGAL_PARAMETER, "limiterConfigNotValid");
164     return setBands_l<DynamicsProcessing::LimiterConfig>(limiters, StageType::LIMITER);
165 }
166 
setInputGain(const std::vector<DynamicsProcessing::InputGain> & inputGains)167 RetCode DynamicsProcessingContext::setInputGain(
168         const std::vector<DynamicsProcessing::InputGain>& inputGains) {
169     RETURN_VALUE_IF(!validateInputGainConfig(inputGains, mChannelCount),
170                     RetCode::ERROR_ILLEGAL_PARAMETER, "inputGainNotValid");
171     return setBands_l<DynamicsProcessing::InputGain>(inputGains, StageType::INPUTGAIN);
172 }
173 
getEngineArchitecture()174 DynamicsProcessing::EngineArchitecture DynamicsProcessingContext::getEngineArchitecture() {
175     return mEngineArchitecture;
176 }
177 
getPreEq()178 std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getPreEq() {
179     return getChannelConfig(StageType::PREEQ);
180 }
181 
getPostEq()182 std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getPostEq() {
183     return getChannelConfig(StageType::POSTEQ);
184 }
185 
getPreEqBand()186 std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getPreEqBand() {
187     return getEqBandConfigs(StageType::PREEQ);
188 }
189 
getPostEqBand()190 std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getPostEqBand() {
191     return getEqBandConfigs(StageType::POSTEQ);
192 }
193 
getMbc()194 std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getMbc() {
195     return getChannelConfig(StageType::MBC);
196 }
197 
getMbcBand()198 std::vector<DynamicsProcessing::MbcBandConfig> DynamicsProcessingContext::getMbcBand() {
199     std::vector<DynamicsProcessing::MbcBandConfig> bands;
200     auto maxBand = mEngineArchitecture.mbcStage.bandCount;
201     for (int32_t ch = 0; ch < mChannelCount; ch++) {
202         auto mbc = getMbc_l(ch);
203         if (!mbc) {
204             continue;
205         }
206         for (int32_t bandId = 0; bandId < maxBand; bandId++) {
207             auto band = mbc->getBand(bandId);
208             if (!band) {
209                 continue;
210             }
211             bands.push_back({.channel = ch,
212                              .band = bandId,
213                              .enable = band->isEnabled(),
214                              .cutoffFrequencyHz = band->getCutoffFrequency(),
215                              .attackTimeMs = band->getAttackTime(),
216                              .releaseTimeMs = band->getReleaseTime(),
217                              .ratio = band->getRatio(),
218                              .thresholdDb = band->getThreshold(),
219                              .kneeWidthDb = band->getKneeWidth(),
220                              .noiseGateThresholdDb = band->getNoiseGateThreshold(),
221                              .expanderRatio = band->getExpanderRatio(),
222                              .preGainDb = band->getPreGain(),
223                              .postGainDb = band->getPostGain()});
224         }
225     }
226     return bands;
227 }
228 
getLimiter()229 std::vector<DynamicsProcessing::LimiterConfig> DynamicsProcessingContext::getLimiter() {
230     std::vector<DynamicsProcessing::LimiterConfig> ret;
231     for (int32_t ch = 0; ch < mChannelCount; ch++) {
232         auto limiter = getLimiter_l(ch);
233         if (!limiter) {
234             continue;
235         }
236         ret.push_back({.channel = ch,
237                        .enable = limiter->isEnabled(),
238                        .linkGroup = static_cast<int32_t>(limiter->getLinkGroup()),
239                        .attackTimeMs = limiter->getAttackTime(),
240                        .releaseTimeMs = limiter->getReleaseTime(),
241                        .ratio = limiter->getRatio(),
242                        .thresholdDb = limiter->getThreshold(),
243                        .postGainDb = limiter->getPostGain()});
244     }
245     return ret;
246 }
247 
getInputGain()248 std::vector<DynamicsProcessing::InputGain> DynamicsProcessingContext::getInputGain() {
249     std::vector<DynamicsProcessing::InputGain> ret;
250     for (int32_t ch = 0; ch < mChannelCount; ch++) {
251         auto channel = getChannel_l(ch);
252         if (!channel) {
253             continue;
254         }
255         ret.push_back({.channel = ch, .gainDb = channel->getInputGain()});
256     }
257     return ret;
258 }
259 
dpeProcess(float * in,float * out,int samples)260 IEffect::Status DynamicsProcessingContext::dpeProcess(float* in, float* out, int samples) {
261 
262     IEffect::Status status = {EX_NULL_POINTER, 0, 0};
263     RETURN_VALUE_IF(!in, status, "nullInput");
264     RETURN_VALUE_IF(!out, status, "nullOutput");
265     status = {EX_ILLEGAL_STATE, 0, 0};
266 
267     RETURN_VALUE_IF(mState != DynamicsProcessingState::DYNAMICS_PROCESSING_STATE_ACTIVE, status,
268                     "notInActiveState");
269     RETURN_VALUE_IF(!mDpFreq, status, "engineNotInited");
270     mDpFreq->processSamples(in, out, samples);
271     return {STATUS_OK, samples, samples};
272 }
273 
init()274 void DynamicsProcessingContext::init() {
275     if (mState == DYNAMICS_PROCESSING_STATE_UNINITIALIZED) {
276         mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
277     }
278     mChannelCount = static_cast<int>(::aidl::android::hardware::audio::common::getChannelCount(
279             mCommon.input.base.channelMask));
280 }
281 
getChannel_l(int channel)282 dp_fx::DPChannel* DynamicsProcessingContext::getChannel_l(int channel) {
283     RETURN_VALUE_IF(mDpFreq == nullptr, nullptr, "DPFreqNotInited");
284 
285     return mDpFreq->getChannel(channel);
286 }
287 
getPreEq_l(int ch)288 dp_fx::DPEq* DynamicsProcessingContext::getPreEq_l(int ch) {
289     auto channel = getChannel_l(ch);
290     RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
291 
292     return channel->getPreEq();
293 }
294 
getPostEq_l(int ch)295 dp_fx::DPEq* DynamicsProcessingContext::getPostEq_l(int ch) {
296     auto channel = getChannel_l(ch);
297     RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
298 
299     return channel->getPostEq();
300 }
301 
getMbc_l(int ch)302 dp_fx::DPMbc* DynamicsProcessingContext::getMbc_l(int ch) {
303     auto channel = getChannel_l(ch);
304     RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
305 
306     return channel->getMbc();
307 }
308 
getLimiter_l(int ch)309 dp_fx::DPLimiter* DynamicsProcessingContext::getLimiter_l(int ch) {
310     auto channel = getChannel_l(ch);
311     RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
312 
313     return channel->getLimiter();
314 }
315 
getStageWithType_l(DynamicsProcessingContext::StageType type,int ch)316 dp_fx::DPBandStage* DynamicsProcessingContext::getStageWithType_l(
317         DynamicsProcessingContext::StageType type, int ch) {
318     switch (type) {
319         case StageType::PREEQ: {
320             return getEqWithType_l(type, ch);
321         }
322         case StageType::POSTEQ: {
323             return getEqWithType_l(type, ch);
324         }
325         case StageType::MBC: {
326             return getMbc_l(ch);
327         }
328         case StageType::LIMITER:
329             FALLTHROUGH_INTENDED;
330         case StageType::INPUTGAIN: {
331             return nullptr;
332         }
333     }
334 }
335 
getEqWithType_l(DynamicsProcessingContext::StageType type,int ch)336 dp_fx::DPEq* DynamicsProcessingContext::getEqWithType_l(DynamicsProcessingContext::StageType type,
337                                                         int ch) {
338     switch (type) {
339         case StageType::PREEQ: {
340             return getPreEq_l(ch);
341         }
342         case StageType::POSTEQ: {
343             return getPostEq_l(ch);
344         }
345         case StageType::MBC:
346             FALLTHROUGH_INTENDED;
347         case StageType::LIMITER:
348             FALLTHROUGH_INTENDED;
349         case StageType::INPUTGAIN: {
350             return nullptr;
351         }
352     }
353 }
354 
getChannelConfig(StageType type)355 std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getChannelConfig(
356         StageType type) {
357     std::vector<DynamicsProcessing::ChannelConfig> ret;
358 
359     for (int32_t ch = 0; ch < mChannelCount; ch++) {
360         auto stage = getStageWithType_l(type, ch);
361         if (!stage) {
362             continue;
363         }
364         ret.push_back({.channel = ch, .enable = stage->isEnabled()});
365     }
366     return ret;
367 }
368 
getEqBandConfigs(StageType type)369 std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getEqBandConfigs(
370         StageType type) {
371     std::vector<DynamicsProcessing::EqBandConfig> eqBands;
372 
373     auto maxBand = mEngineArchitecture.preEqStage.bandCount;
374     for (int32_t ch = 0; ch < mChannelCount; ch++) {
375         auto eq = getEqWithType_l(type, ch);
376         if (!eq) {
377             continue;
378         }
379         for (int32_t bandId = 0; bandId < maxBand; bandId++) {
380             auto band = eq->getBand(bandId);
381             if (!band) {
382                 continue;
383             }
384             eqBands.push_back({.channel = ch,
385                                .band = bandId,
386                                .enable = band->isEnabled(),
387                                .cutoffFrequencyHz = band->getCutoffFrequency(),
388                                .gainDb = band->getGain()});
389         }
390     }
391     return eqBands;
392 }
393 
394 template <typename T>
validateBandConfig(const std::vector<T> & bands,int maxChannel,int maxBand)395 bool DynamicsProcessingContext::validateBandConfig(const std::vector<T>& bands, int maxChannel,
396                                                    int maxBand) {
397     std::map<int, float> freqs;
398     for (auto band : bands) {
399         if (!validateChannel(band.channel, maxChannel)) {
400             LOG(ERROR) << __func__ << " " << band.toString() << " invalid, maxCh " << maxChannel;
401             return false;
402         }
403         if (!validateBand(band.band, maxBand)) {
404             LOG(ERROR) << __func__ << " " << band.toString() << " invalid, maxBand " << maxBand;
405             return false;
406         }
407         if (freqs.find(band.band) != freqs.end()) {
408             LOG(ERROR) << __func__ << " " << band.toString() << " found duplicate";
409             return false;
410         }
411         freqs[band.band] = band.cutoffFrequencyHz;
412     }
413     return true;
414 }
415 
validateLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig> & cfgs,int maxChannel)416 bool DynamicsProcessingContext::validateLimiterConfig(
417         const std::vector<DynamicsProcessing::LimiterConfig>& cfgs, int maxChannel) {
418     for (auto cfg : cfgs) {
419         if (!validateChannel(cfg.channel, maxChannel)) return false;
420     }
421     return true;
422 }
423 
validateInputGainConfig(const std::vector<DynamicsProcessing::InputGain> & cfgs,int maxChannel)424 bool DynamicsProcessingContext::validateInputGainConfig(
425         const std::vector<DynamicsProcessing::InputGain>& cfgs, int maxChannel) {
426     for (auto cfg : cfgs) {
427         if (!validateChannel(cfg.channel, maxChannel)) return false;
428     }
429     return true;
430 }
431 
432 template <typename D>
setDpChannels_l(const std::vector<DynamicsProcessing::ChannelConfig> & channels,StageType type)433 RetCode DynamicsProcessingContext::setDpChannels_l(
434         const std::vector<DynamicsProcessing::ChannelConfig>& channels, StageType type) {
435     RetCode ret = RetCode::SUCCESS;
436     std::unordered_set<int> channelSet;
437 
438     for (auto& it : channels) {
439         if (0 != channelSet.count(it.channel)) {
440             LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
441             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
442         } else {
443             channelSet.insert(it.channel);
444         }
445         if (it.channel < 0 || it.channel >= mChannelCount) {
446             LOG(WARNING) << __func__ << " skip illegal ChannelConfig " << it.toString() << " max "
447                          << mChannelCount;
448             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
449             continue;
450         }
451         auto dp = getStageWithType_l(type, it.channel);
452         if (!dp) {
453             LOG(WARNING) << __func__ << " channel " << it.channel << " not exist";
454             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
455             continue;
456         }
457         if (dp->isEnabled() != it.enable) {
458             dp->setEnabled(it.enable);
459         }
460     }
461     return ret;
462 }
463 
setDpChannelBand_l(const std::any & anyConfig,StageType type,std::set<std::pair<int,int>> & chBandSet)464 RetCode DynamicsProcessingContext::setDpChannelBand_l(const std::any& anyConfig, StageType type,
465                                                       std::set<std::pair<int, int>>& chBandSet) {
466     RETURN_VALUE_IF(!anyConfig.has_value(), RetCode::ERROR_ILLEGAL_PARAMETER, "bandInvalid");
467     RetCode ret = RetCode::SUCCESS;
468     std::pair<int, int> chBandKey;
469     switch (type) {
470         case StageType::PREEQ:
471             FALLTHROUGH_INTENDED;
472         case StageType::POSTEQ: {
473             dp_fx::DPEq* dp;
474             const auto& config = std::any_cast<DynamicsProcessing::EqBandConfig>(anyConfig);
475             RETURN_VALUE_IF(
476                     nullptr == (dp = getEqWithType_l(type, config.channel)) || !dp->isEnabled(),
477                     RetCode::ERROR_ILLEGAL_PARAMETER, "dpEqNotExist");
478             dp_fx::DPEqBand band;
479             band.init(config.enable, config.cutoffFrequencyHz, config.gainDb);
480             dp->setBand(config.band, band);
481             chBandKey = {config.channel, config.band};
482             break;
483         }
484         case StageType::MBC: {
485             dp_fx::DPMbc* dp;
486             const auto& config = std::any_cast<DynamicsProcessing::MbcBandConfig>(anyConfig);
487             RETURN_VALUE_IF(nullptr == (dp = getMbc_l(config.channel)) || !dp->isEnabled(),
488                             RetCode::ERROR_ILLEGAL_PARAMETER, "dpMbcNotExist");
489             dp_fx::DPMbcBand band;
490             band.init(config.enable, config.cutoffFrequencyHz, config.attackTimeMs,
491                       config.releaseTimeMs, config.ratio, config.thresholdDb, config.kneeWidthDb,
492                       config.noiseGateThresholdDb, config.expanderRatio, config.preGainDb,
493                       config.postGainDb);
494             dp->setBand(config.band, band);
495             chBandKey = {config.channel, config.band};
496             break;
497         }
498         case StageType::LIMITER: {
499             dp_fx::DPChannel* dp;
500             const auto& config = std::any_cast<DynamicsProcessing::LimiterConfig>(anyConfig);
501             RETURN_VALUE_IF(nullptr == (dp = getChannel_l(config.channel)),
502                             RetCode::ERROR_ILLEGAL_PARAMETER, "dpChNotExist");
503             dp_fx::DPLimiter limiter;
504             limiter.init(mEngineArchitecture.limiterInUse, config.enable, config.linkGroup,
505                          config.attackTimeMs, config.releaseTimeMs, config.ratio,
506                          config.thresholdDb, config.postGainDb);
507             dp->setLimiter(limiter);
508             chBandKey = {config.channel, 0};
509             break;
510         }
511         case StageType::INPUTGAIN: {
512             dp_fx::DPChannel* dp;
513             const auto& config = std::any_cast<DynamicsProcessing::InputGain>(anyConfig);
514             RETURN_VALUE_IF(nullptr == (dp = getChannel_l(config.channel)),
515                             RetCode::ERROR_ILLEGAL_PARAMETER, "dpChNotExist");
516             dp->setInputGain(config.gainDb);
517             chBandKey = {config.channel, 0};
518             break;
519         }
520     }
521     RETURN_VALUE_IF(0 != chBandSet.count(chBandKey), RetCode::ERROR_ILLEGAL_PARAMETER,
522                     "duplicatedBand");
523     chBandSet.insert(chBandKey);
524     return ret;
525 }
526 
527 template <typename T /* BandConfig */>
setBands_l(const std::vector<T> & bands,StageType type)528 RetCode DynamicsProcessingContext::setBands_l(const std::vector<T>& bands, StageType type) {
529     RetCode ret = RetCode::SUCCESS;
530     std::set<std::pair<int /* channel */, int /* band */>> bandSet;
531 
532     for (const auto& it : bands) {
533         if (RetCode::SUCCESS != setDpChannelBand_l(std::make_any<T>(it), type, bandSet)) {
534             LOG(WARNING) << __func__ << " skipping band " << it.toString();
535             ret = RetCode::ERROR_ILLEGAL_PARAMETER;
536             continue;
537         }
538     }
539     return ret;
540 }
541 
542 }  // namespace aidl::android::hardware::audio::effect
543