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