Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da3c7768 authored by Shunkai Yao's avatar Shunkai Yao Committed by Automerger Merge Worker
Browse files

Merge "DynamicsProcessing: Add libeffects DynamicsProcessing AIDL implementation" am: 4dc86526

parents a1eac76f 4dc86526
Loading
Loading
Loading
Loading
+46 −12
Original line number Diff line number Diff line
@@ -32,34 +32,68 @@ license {
    ],
}

cc_defaults {
    name : "dynamicsprocessingdefaults",
    srcs: [
        "dsp/DPBase.cpp",
        "dsp/DPFrequency.cpp",
    ],

    shared_libs: [
        "libaudioutils",
        "libbase",
        "liblog",
        "libutils",
    ],
    header_libs: [
        "libaudioeffects",
        "libeigen",
    ],
    cflags: [
        "-Wthread-safety",
        "-Wall",
        "-Werror",
    ],
}

cc_library_shared {
    name: "libdynproc",

    vendor: true,

    defaults: [
        "dynamicsprocessingdefaults",
    ],

    srcs: [
        "EffectDynamicsProcessing.cpp",
        "dsp/DPBase.cpp",
        "dsp/DPFrequency.cpp",
    ],

    cflags: [
        "-O2",
        "-fvisibility=hidden",

        "-Wall",
        "-Werror",
    ],

    shared_libs: [
        "libcutils",
        "liblog",
    relative_install_path: "soundfx",
}

cc_library_shared {
    name: "libdynamicsprocessingaidl",

    srcs: [
        "aidl/DynamicsProcessing.cpp",
        "aidl/DynamicsProcessingContext.cpp",
        ":effectCommonFile",
    ],

    relative_install_path: "soundfx",
    defaults: [
        "aidlaudioservice_defaults",
        "latest_android_hardware_audio_effect_ndk_shared",
        "latest_android_media_audio_common_types_ndk_shared",
        "dynamicsprocessingdefaults",
    ],

    header_libs: [
        "libaudioeffects",
        "libeigen",
    visibility: [
        "//hardware/interfaces/audio/aidl/default",
    ],
}
+313 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "AHAL_DynamicsProcessingLibEffects"

#include <android-base/logging.h>

#include "DynamicsProcessing.h"

#include <dsp/DPBase.h>
#include <dsp/DPFrequency.h>

using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::DynamicsProcessingImpl;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kDynamicsProcessingImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
using aidl::android::media::audio::common::PcmType;

extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
                                           std::shared_ptr<IEffect>* instanceSpp) {
    if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingImplUUID) {
        LOG(ERROR) << __func__ << "uuid not supported";
        return EX_ILLEGAL_ARGUMENT;
    }
    if (instanceSpp) {
        *instanceSpp = ndk::SharedRefBase::make<DynamicsProcessingImpl>();
        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
        return EX_NONE;
    } else {
        LOG(ERROR) << __func__ << " invalid input parameter!";
        return EX_ILLEGAL_ARGUMENT;
    }
}

extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
    if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingImplUUID) {
        LOG(ERROR) << __func__ << "uuid not supported";
        return EX_ILLEGAL_ARGUMENT;
    }
    *_aidl_return = DynamicsProcessingImpl::kDescriptor;
    return EX_NONE;
}

namespace aidl::android::hardware::audio::effect {

const std::string DynamicsProcessingImpl::kEffectName = "DynamicsProcessing";
const DynamicsProcessing::Capability DynamicsProcessingImpl::kCapability = {.minCutOffFreq = 220,
                                                                            .maxCutOffFreq = 20000};
const Descriptor DynamicsProcessingImpl::kDescriptor = {
        .common = {.id = {.type = kDynamicsProcessingTypeUUID,
                          .uuid = kDynamicsProcessingImplUUID,
                          .proxy = std::nullopt},
                   .flags = {.type = Flags::Type::INSERT,
                             .insert = Flags::Insert::LAST,
                             .volume = Flags::Volume::CTRL},
                   .name = DynamicsProcessingImpl::kEffectName,
                   .implementor = "The Android Open Source Project"},
        .capability = Capability::make<Capability::dynamicsProcessing>(
                DynamicsProcessingImpl::kCapability)};

ndk::ScopedAStatus DynamicsProcessingImpl::open(const Parameter::Common& common,
                                                const std::optional<Parameter::Specific>& specific,
                                                OpenEffectReturn* ret) {
    LOG(DEBUG) << __func__;
    // effect only support 32bits float
    RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
                      common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
              EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
    RETURN_OK_IF(mState != State::INIT);
    auto context = createContext(common);
    RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");

    RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
    if (specific.has_value()) {
        RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
    } else {
        Parameter::Specific defaultSpecific =
                Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(
                        DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
                                mContext->getEngineArchitecture()));
        RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(defaultSpecific), "setDefaultEngineErr");
    }

    mState = State::IDLE;
    context->dupeFmq(ret);
    RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
              "FailedToCreateWorker");
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus DynamicsProcessingImpl::getDescriptor(Descriptor* _aidl_return) {
    RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
    LOG(DEBUG) << __func__ << kDescriptor.toString();
    *_aidl_return = kDescriptor;
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus DynamicsProcessingImpl::commandImpl(CommandId command) {
    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
    switch (command) {
        case CommandId::START:
            mContext->enable();
            return ndk::ScopedAStatus::ok();
        case CommandId::STOP:
            mContext->disable();
            return ndk::ScopedAStatus::ok();
        case CommandId::RESET:
            mContext->disable();
            mContext->resetBuffer();
            return ndk::ScopedAStatus::ok();
        default:
            // Need this default handling for vendor extendable CommandId::VENDOR_COMMAND_*
            LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
                                                                    "commandIdNotSupported");
    }
}

ndk::ScopedAStatus DynamicsProcessingImpl::setParameterSpecific(
        const Parameter::Specific& specific) {
    RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
              "EffectNotSupported");
    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");

    auto& param = specific.get<Parameter::Specific::dynamicsProcessing>();
    auto tag = param.getTag();

    switch (tag) {
        case DynamicsProcessing::engineArchitecture: {
            RETURN_IF(mContext->setEngineArchitecture(
                              param.get<DynamicsProcessing::engineArchitecture>()) !=
                              RetCode::SUCCESS,
                      EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::preEq: {
            RETURN_IF(
                    mContext->setPreEq(param.get<DynamicsProcessing::preEq>()) != RetCode::SUCCESS,
                    EX_ILLEGAL_ARGUMENT, "setPreEqFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::postEq: {
            RETURN_IF(mContext->setPostEq(param.get<DynamicsProcessing::postEq>()) !=
                              RetCode::SUCCESS,
                      EX_ILLEGAL_ARGUMENT, "setPostEqFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::preEqBand: {
            RETURN_IF(mContext->setPreEqBand(param.get<DynamicsProcessing::preEqBand>()) !=
                              RetCode::SUCCESS,
                      EX_ILLEGAL_ARGUMENT, "setPreEqBandFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::postEqBand: {
            RETURN_IF(mContext->setPostEqBand(param.get<DynamicsProcessing::postEqBand>()) !=
                              RetCode::SUCCESS,
                      EX_ILLEGAL_ARGUMENT, "setPostEqBandFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::mbc: {
            RETURN_IF(mContext->setMbc(param.get<DynamicsProcessing::mbc>()) != RetCode::SUCCESS,
                      EX_ILLEGAL_ARGUMENT, "setMbcFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::mbcBand: {
            RETURN_IF(mContext->setMbcBand(param.get<DynamicsProcessing::mbcBand>()) !=
                              RetCode::SUCCESS,
                      EX_ILLEGAL_ARGUMENT, "setMbcBandFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::limiter: {
            RETURN_IF(mContext->setLimiter(param.get<DynamicsProcessing::limiter>()) !=
                              RetCode::SUCCESS,
                      EX_ILLEGAL_ARGUMENT, "setLimiterFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::inputGain: {
            RETURN_IF(mContext->setInputGain(param.get<DynamicsProcessing::inputGain>()) !=
                              RetCode::SUCCESS,
                      EX_ILLEGAL_ARGUMENT, "setInputGainFailed");
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::vendorExtension: {
            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
                    EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagNotSupported");
        }
    }
}

ndk::ScopedAStatus DynamicsProcessingImpl::getParameterSpecific(const Parameter::Id& id,
                                                                Parameter::Specific* specific) {
    RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
    auto tag = id.getTag();
    RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
    auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
    auto dpIdTag = dpId.getTag();
    switch (dpIdTag) {
        case DynamicsProcessing::Id::commonTag:
            return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
                                                  specific);
        case DynamicsProcessing::Id::vendorExtensionTag:
            LOG(ERROR) << __func__ << " unsupported ID: " << toString(dpIdTag);
            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
                    EX_ILLEGAL_ARGUMENT, "DPVendorExtensionIdNotSupported");
    }
}

ndk::ScopedAStatus DynamicsProcessingImpl::getParameterDynamicsProcessing(
        const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");

    switch (tag) {
        case DynamicsProcessing::engineArchitecture: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
                            mContext->getEngineArchitecture()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::preEq: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::preEq>(mContext->getPreEq()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::postEq: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::postEq>(mContext->getPostEq()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::preEqBand: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
                            mContext->getPreEqBand()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::postEqBand: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
                            mContext->getPostEqBand()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::mbc: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::mbc>(mContext->getMbc()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::mbcBand: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::mbcBand>(mContext->getMbcBand()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::limiter: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::limiter>(mContext->getLimiter()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::inputGain: {
            specific->set<Parameter::Specific::dynamicsProcessing>(
                    DynamicsProcessing::make<DynamicsProcessing::inputGain>(
                            mContext->getInputGain()));
            return ndk::ScopedAStatus::ok();
        }
        case DynamicsProcessing::vendorExtension: {
            LOG(ERROR) << __func__ << " wrong vendor tag in CommonTag: " << toString(tag);
            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
                    EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagInWrongId");
        }
    }
}

std::shared_ptr<EffectContext> DynamicsProcessingImpl::createContext(
        const Parameter::Common& common) {
    if (mContext) {
        LOG(DEBUG) << __func__ << " context already exist";
        return mContext;
    }

    mContext = std::make_shared<DynamicsProcessingContext>(1 /* statusFmqDepth */, common);
    return mContext;
}

RetCode DynamicsProcessingImpl::releaseContext() {
    if (mContext) {
        mContext->disable();
        mContext->resetBuffer();
        mContext.reset();
    }
    return RetCode::SUCCESS;
}

// Processing method running in EffectWorker thread.
IEffect::Status DynamicsProcessingImpl::effectProcessImpl(float* in, float* out, int samples) {
    IEffect::Status status = {EX_NULL_POINTER, 0, 0};
    RETURN_VALUE_IF(!mContext, status, "nullContext");
    return mContext->lvmProcess(in, out, samples);
}

}  // namespace aidl::android::hardware::audio::effect
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <aidl/android/hardware/audio/effect/BnEffect.h>

#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
#include "DynamicsProcessingContext.h"

namespace aidl::android::hardware::audio::effect {

class DynamicsProcessingImpl final : public EffectImpl {
  public:
    static const std::string kEffectName;
    static const Descriptor kDescriptor;
    static const DynamicsProcessing::Capability kCapability;

    DynamicsProcessingImpl() { LOG(DEBUG) << __func__; }
    ~DynamicsProcessingImpl() {
        cleanUp();
        LOG(DEBUG) << __func__;
    }

    ndk::ScopedAStatus open(const Parameter::Common& common,
                            const std::optional<Parameter::Specific>& specific,
                            OpenEffectReturn* ret) override;
    ndk::ScopedAStatus commandImpl(CommandId command) override;
    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                            Parameter::Specific* specific) override;
    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
    RetCode releaseContext() override;

    std::shared_ptr<EffectContext> getContext() override { return mContext; }
    std::string getEffectName() override { return kEffectName; }

  private:
    std::shared_ptr<DynamicsProcessingContext> mContext;
    ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
                                                      Parameter::Specific* specific);
};

}  // namespace aidl::android::hardware::audio::effect
+580 −0

File added.

Preview size limit exceeded, changes collapsed.

+130 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <android-base/thread_annotations.h>
#include <audio_effects/effect_dynamicsprocessing.h>

#include "effect-impl/EffectContext.h"

#include <any>
#include <cstddef>
#include <dsp/DPBase.h>
#include <dsp/DPFrequency.h>

namespace aidl::android::hardware::audio::effect {

enum DynamicsProcessingState {
    DYNAMICS_PROCESSING_STATE_UNINITIALIZED,
    DYNAMICS_PROCESSING_STATE_INITIALIZED,
    DYNAMICS_PROCESSING_STATE_ACTIVE,
};

class DynamicsProcessingContext final : public EffectContext {
  public:
    DynamicsProcessingContext(int statusDepth, const Parameter::Common& common);
    ~DynamicsProcessingContext();

    RetCode enable();
    RetCode disable();
    void reset();

    // override EffectContext::setCommon to update mChannelCount
    RetCode setCommon(const Parameter::Common& common) override;

    RetCode setEngineArchitecture(const DynamicsProcessing::EngineArchitecture& engineArchitecture);
    RetCode setPreEq(const std::vector<DynamicsProcessing::ChannelConfig>& eqChannels);
    RetCode setPostEq(const std::vector<DynamicsProcessing::ChannelConfig>& eqChannels);
    RetCode setPreEqBand(const std::vector<DynamicsProcessing::EqBandConfig>& eqBands);
    RetCode setPostEqBand(const std::vector<DynamicsProcessing::EqBandConfig>& eqBands);
    RetCode setMbc(const std::vector<DynamicsProcessing::ChannelConfig>& mbcChannels);
    RetCode setMbcBand(const std::vector<DynamicsProcessing::MbcBandConfig>& eqBands);
    RetCode setLimiter(const std::vector<DynamicsProcessing::LimiterConfig>& limiters);
    RetCode setInputGain(const std::vector<DynamicsProcessing::InputGain>& gain);

    DynamicsProcessing::EngineArchitecture getEngineArchitecture();
    std::vector<DynamicsProcessing::ChannelConfig> getPreEq();
    std::vector<DynamicsProcessing::ChannelConfig> getPostEq();
    std::vector<DynamicsProcessing::EqBandConfig> getPreEqBand();
    std::vector<DynamicsProcessing::EqBandConfig> getPostEqBand();
    std::vector<DynamicsProcessing::ChannelConfig> getMbc();
    std::vector<DynamicsProcessing::MbcBandConfig> getMbcBand();
    std::vector<DynamicsProcessing::LimiterConfig> getLimiter();
    std::vector<DynamicsProcessing::InputGain> getInputGain();

    IEffect::Status lvmProcess(float* in, float* out, int samples);

  private:
    static constexpr float kPreferredProcessingDurationMs = 10.0f;
    static constexpr int kBandCount = 5;
    std::mutex mMutex;
    size_t mChannelCount GUARDED_BY(mMutex) = 0;
    DynamicsProcessingState mState GUARDED_BY(mMutex) = DYNAMICS_PROCESSING_STATE_UNINITIALIZED;
    std::unique_ptr<dp_fx::DPFrequency> mDpFreq GUARDED_BY(mMutex) = nullptr;
    bool mEngineInited GUARDED_BY(mMutex) = false;
    DynamicsProcessing::EngineArchitecture mEngineArchitecture GUARDED_BY(mMutex) = {
            .resolutionPreference =
                    DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
            .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
            .preEqStage = {.inUse = true, .bandCount = kBandCount},
            .postEqStage = {.inUse = true, .bandCount = kBandCount},
            .mbcStage = {.inUse = true, .bandCount = kBandCount},
            .limiterInUse = true,
    };

    enum class StageType { PREEQ, POSTEQ, MBC, LIMITER, INPUTGAIN };

    void init();

    void dpSetFreqDomainVariant_l(const DynamicsProcessing::EngineArchitecture& engine)
            REQUIRES(mMutex);
    dp_fx::DPChannel* getChannel_l(int ch) REQUIRES(mMutex);
    dp_fx::DPEq* getPreEq_l(int ch) REQUIRES(mMutex);
    dp_fx::DPEq* getPostEq_l(int ch) REQUIRES(mMutex);
    dp_fx::DPMbc* getMbc_l(int ch) REQUIRES(mMutex);
    dp_fx::DPLimiter* getLimiter_l(int ch) REQUIRES(mMutex);
    dp_fx::DPBandStage* getStageWithType_l(StageType type, int ch) REQUIRES(mMutex);
    dp_fx::DPEq* getEqWithType_l(StageType type, int ch) REQUIRES(mMutex);
    template <typename D>
    RetCode setDpChannels_l(const std::vector<DynamicsProcessing::ChannelConfig>& channels,
                            bool stageInUse, StageType type) REQUIRES(mMutex);
    template <typename T /* BandConfig */>
    RetCode setBands_l(const std::vector<T>& bands, int maxBand, StageType type) REQUIRES(mMutex);
    RetCode setDpChannelBand_l(const std::any& anyConfig, StageType type, int maxCh, int maxBand,
                               std::set<std::pair<int, int>>& chBandSet) REQUIRES(mMutex);

    std::vector<DynamicsProcessing::EqBandConfig> getEqBandConfigs(StageType type);
    std::vector<DynamicsProcessing::ChannelConfig> getChannelConfig(StageType type);

    bool validateStageEnablement(const DynamicsProcessing::StageEnablement& enablement);
    bool validateEngineConfig(const DynamicsProcessing::EngineArchitecture& engine);
    bool validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band, int maxChannel,
                              int maxBand);
    bool validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band, int maxChannel,
                               int maxBand);
    bool validateLimiterConfig(const DynamicsProcessing::LimiterConfig& limiter, int maxChannel);
    bool validateInputGainConfig(const DynamicsProcessing::InputGain& gain, int maxChannel);

    inline bool validateCutoffFrequency(float freq);
    inline bool validateChannel(int ch, int maxCh) { return ch >= 0 && ch < maxCh; }
    inline bool validateBand(int band, int maxBand) { return band >= 0 && band < maxBand; }
    inline bool validateTime(int time) { return time >= 0; }
    inline bool validateRatio(int ratio) { return ratio >= 0; }
    inline bool validateBandDb(int db) { return db <= 0; }
};

}  // namespace aidl::android::hardware::audio::effect
 No newline at end of file