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