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