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