/* * 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. */ #include #include #include #define LOG_TAG "AidlConversionDp" //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include #include #include "AidlConversionDynamicsProcessing.h" namespace android { namespace effect { using ::aidl::android::convertIntegral; using ::aidl::android::getParameterSpecificField; using ::aidl::android::aidl_utils::statusTFromBinderStatus; using ::aidl::android::hardware::audio::effect::Capability; using ::aidl::android::hardware::audio::effect::DynamicsProcessing; using ::aidl::android::hardware::audio::effect::Parameter; using ::aidl::android::hardware::audio::effect::toString; using ::aidl::android::hardware::audio::effect::VendorExtension; using ::android::status_t; using utils::EffectParamReader; using utils::EffectParamWriter; status_t AidlConversionDp::setParameter(EffectParamReader& param) { uint32_t type = 0; RETURN_STATUS_IF_ERROR(param.readFromParameter(&type)); Parameter aidlParam; switch (type) { case DP_PARAM_INPUT_GAIN: { DynamicsProcessing::InputGain inputGainAidl; RETURN_STATUS_IF_ERROR(param.readFromParameter(&inputGainAidl.channel)); RETURN_STATUS_IF_ERROR(param.readFromValue(&inputGainAidl.gainDb)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, inputGain, {inputGainAidl}); break; } case DP_PARAM_ENGINE_ARCHITECTURE: { DynamicsProcessing::EngineArchitecture engine = VALUE_OR_RETURN_STATUS(readEngineArchitectureFromParam(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, engineArchitecture, engine); mEngine = engine; break; } case DP_PARAM_PRE_EQ: { DynamicsProcessing::ChannelConfig chConfig = VALUE_OR_RETURN_STATUS(readChannelConfigFromParam(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, preEq, {chConfig}); break; } case DP_PARAM_POST_EQ: { DynamicsProcessing::ChannelConfig chConfig = VALUE_OR_RETURN_STATUS(readChannelConfigFromParam(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, postEq, {chConfig}); break; } case DP_PARAM_MBC: { DynamicsProcessing::ChannelConfig chConfig = VALUE_OR_RETURN_STATUS(readChannelConfigFromParam(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, mbc, {chConfig}); break; } case DP_PARAM_PRE_EQ_BAND: { DynamicsProcessing::EqBandConfig bandConfig = VALUE_OR_RETURN_STATUS(readEqBandConfigFromParam(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, preEqBand, {bandConfig}); break; } case DP_PARAM_POST_EQ_BAND: { DynamicsProcessing::EqBandConfig bandConfig = VALUE_OR_RETURN_STATUS(readEqBandConfigFromParam(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, postEqBand, {bandConfig}); break; } case DP_PARAM_MBC_BAND: { DynamicsProcessing::MbcBandConfig bandConfig = VALUE_OR_RETURN_STATUS(readMbcBandConfigFromParam(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, mbcBand, {bandConfig}); break; } case DP_PARAM_LIMITER: { DynamicsProcessing::LimiterConfig config = VALUE_OR_RETURN_STATUS(readLimiterConfigFromParam(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, limiter, {config}); break; } default: { // for vendor extension, copy data area to the DefaultExtension, parameter ignored VendorExtension ext = VALUE_OR_RETURN_STATUS( aidl::android::legacy2aidl_EffectParameterReader_VendorExtension(param)); aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, vendor, ext); break; } } return statusTFromBinderStatus(mEffect->setParameter(aidlParam)); } status_t AidlConversionDp::getParameter(EffectParamWriter& param) { uint32_t type = 0; RETURN_STATUS_IF_ERROR(param.readFromParameter(&type)); Parameter aidlParam; switch (type) { case DP_PARAM_INPUT_GAIN: { int32_t channel; RETURN_STATUS_IF_ERROR(param.readFromParameter(&channel)); Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag, DynamicsProcessing::inputGain); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam))); std::vector gains = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, DynamicsProcessing::inputGain, std::vector)); for (const auto& gain : gains) { if (gain.channel == channel) { return param.writeToValue(&gain.gainDb); } } ALOGE("%s not able to find channel %d", __func__, channel); return BAD_VALUE; } case DP_PARAM_ENGINE_ARCHITECTURE: { Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag, DynamicsProcessing::engineArchitecture); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam))); DynamicsProcessing::EngineArchitecture engine = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, DynamicsProcessing::engineArchitecture, DynamicsProcessing::EngineArchitecture)); int32_t resolution = VALUE_OR_RETURN_STATUS( aidl::android::aidl2legacy_DynamicsProcessing_ResolutionPreference_int32( engine.resolutionPreference)); int32_t preEqInUse = VALUE_OR_RETURN_STATUS(convertIntegral(engine.preEqStage.inUse)); int32_t mbcInUse = VALUE_OR_RETURN_STATUS(convertIntegral(engine.mbcStage.inUse)); int32_t postEqInUse = VALUE_OR_RETURN_STATUS(convertIntegral(engine.postEqStage.inUse)); int32_t limiterInUse = VALUE_OR_RETURN_STATUS(convertIntegral(engine.limiterInUse)); RETURN_STATUS_IF_ERROR(param.writeToValue(&resolution)); RETURN_STATUS_IF_ERROR(param.writeToValue(&engine.preferredProcessingDurationMs)); RETURN_STATUS_IF_ERROR(param.writeToValue(&preEqInUse)); RETURN_STATUS_IF_ERROR(param.writeToValue(&engine.preEqStage.bandCount)); RETURN_STATUS_IF_ERROR(param.writeToValue(&mbcInUse)); RETURN_STATUS_IF_ERROR(param.writeToValue(&engine.mbcStage.bandCount)); RETURN_STATUS_IF_ERROR(param.writeToValue(&postEqInUse)); RETURN_STATUS_IF_ERROR(param.writeToValue(&engine.postEqStage.bandCount)); RETURN_STATUS_IF_ERROR(param.writeToValue(&limiterInUse)); mEngine = engine; return OK; } case DP_PARAM_PRE_EQ: { return getChannelConfig(DynamicsProcessing::preEq, param); } case DP_PARAM_POST_EQ: { return getChannelConfig(DynamicsProcessing::postEq, param); } case DP_PARAM_MBC: { return getChannelConfig(DynamicsProcessing::mbc, param); } case DP_PARAM_PRE_EQ_BAND: { return getEqBandConfig(DynamicsProcessing::preEqBand, param); } case DP_PARAM_POST_EQ_BAND: { return getEqBandConfig(DynamicsProcessing::postEqBand, param); } case DP_PARAM_MBC_BAND: { return getMbcBandConfig(param); } case DP_PARAM_LIMITER: { return getLimiterConfig(param); } case DP_PARAM_GET_CHANNEL_COUNT: { uint32_t channel = ::aidl::android::hardware::audio::common::getChannelCount( mCommon.input.base.channelMask); RETURN_STATUS_IF_ERROR(param.writeToValue(&channel)); return OK; } default: { VENDOR_EXTENSION_GET_AND_RETURN(DynamicsProcessing, dynamicsProcessing, param); } } } ConversionResult AidlConversionDp::readChannelConfigFromParam(EffectParamReader& param) { int32_t enable, channel; RETURN_IF_ERROR(param.readFromParameter(&channel)); RETURN_IF_ERROR(param.readFromValue(&enable)); return DynamicsProcessing::ChannelConfig( {.channel = channel, .enable = VALUE_OR_RETURN(convertIntegral(enable))}); } ConversionResult AidlConversionDp::readEqBandConfigFromParam(EffectParamReader& param) { DynamicsProcessing::EqBandConfig config; int32_t enable; RETURN_IF_ERROR(param.readFromParameter(&config.channel)); RETURN_IF_ERROR(param.readFromParameter(&config.band)); RETURN_IF_ERROR(param.readFromValue(&enable)); RETURN_IF_ERROR(param.readFromValue(&config.cutoffFrequencyHz)); RETURN_IF_ERROR(param.readFromValue(&config.gainDb)); config.enable = VALUE_OR_RETURN(convertIntegral(enable)); return config; } ConversionResult AidlConversionDp::readMbcBandConfigFromParam(EffectParamReader& param) { DynamicsProcessing::MbcBandConfig config; int32_t enable; RETURN_IF_ERROR(param.readFromParameter(&config.channel)); RETURN_IF_ERROR(param.readFromParameter(&config.band)); RETURN_IF_ERROR(param.readFromValue(&enable)); RETURN_IF_ERROR(param.readFromValue(&config.cutoffFrequencyHz)); RETURN_IF_ERROR(param.readFromValue(&config.attackTimeMs)); RETURN_IF_ERROR(param.readFromValue(&config.releaseTimeMs)); RETURN_IF_ERROR(param.readFromValue(&config.ratio)); RETURN_IF_ERROR(param.readFromValue(&config.thresholdDb)); RETURN_IF_ERROR(param.readFromValue(&config.kneeWidthDb)); RETURN_IF_ERROR(param.readFromValue(&config.noiseGateThresholdDb)); RETURN_IF_ERROR(param.readFromValue(&config.expanderRatio)); RETURN_IF_ERROR(param.readFromValue(&config.preGainDb)); RETURN_IF_ERROR(param.readFromValue(&config.postGainDb)); config.enable = VALUE_OR_RETURN(convertIntegral(enable)); return config; } ConversionResult AidlConversionDp::readLimiterConfigFromParam(EffectParamReader& param) { DynamicsProcessing::LimiterConfig config; int32_t enable, inUse; RETURN_IF_ERROR(param.readFromParameter(&config.channel)); RETURN_IF_ERROR(param.readFromValue(&inUse)); RETURN_IF_ERROR(param.readFromValue(&enable)); RETURN_IF_ERROR(param.readFromValue(&config.linkGroup)); RETURN_IF_ERROR(param.readFromValue(&config.attackTimeMs)); RETURN_IF_ERROR(param.readFromValue(&config.releaseTimeMs)); RETURN_IF_ERROR(param.readFromValue(&config.ratio)); RETURN_IF_ERROR(param.readFromValue(&config.thresholdDb)); RETURN_IF_ERROR(param.readFromValue(&config.postGainDb)); config.enable = VALUE_OR_RETURN(convertIntegral(enable)); return config; } ConversionResult AidlConversionDp::readEngineArchitectureFromParam(EffectParamReader& param) { DynamicsProcessing::EngineArchitecture engine; int32_t variant, preEqInUse, mbcInUse, postEqInUse, limiterInUse; RETURN_IF_ERROR(param.readFromValue(&variant)); RETURN_IF_ERROR(param.readFromValue(&engine.preferredProcessingDurationMs)); RETURN_IF_ERROR(param.readFromValue(&preEqInUse)); RETURN_IF_ERROR(param.readFromValue(&engine.preEqStage.bandCount)); RETURN_IF_ERROR(param.readFromValue(&mbcInUse)); RETURN_IF_ERROR(param.readFromValue(&engine.mbcStage.bandCount)); RETURN_IF_ERROR(param.readFromValue(&postEqInUse)); RETURN_IF_ERROR(param.readFromValue(&engine.postEqStage.bandCount)); RETURN_IF_ERROR(param.readFromValue(&limiterInUse)); engine.resolutionPreference = VALUE_OR_RETURN( aidl::android::legacy2aidl_int32_DynamicsProcessing_ResolutionPreference(variant)); engine.preEqStage.inUse = VALUE_OR_RETURN(convertIntegral(preEqInUse)); engine.mbcStage.inUse = VALUE_OR_RETURN(convertIntegral(mbcInUse)); engine.postEqStage.inUse = VALUE_OR_RETURN(convertIntegral(postEqInUse)); engine.limiterInUse = VALUE_OR_RETURN(convertIntegral(limiterInUse)); return engine; } status_t AidlConversionDp::getChannelConfig(DynamicsProcessing::Tag tag, EffectParamWriter& param) { int32_t channel; RETURN_STATUS_IF_ERROR(param.readFromParameter(&channel)); Parameter aidlParam; Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag, tag); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam))); std::vector channels; int32_t inUse, bandCount; switch (tag) { case DynamicsProcessing::preEq: { inUse = mEngine.preEqStage.inUse; bandCount = mEngine.preEqStage.bandCount; channels = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, DynamicsProcessing::preEq, std::vector)); break; } case DynamicsProcessing::postEq: { inUse = mEngine.postEqStage.inUse; bandCount = mEngine.postEqStage.bandCount; channels = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, DynamicsProcessing::postEq, std::vector)); break; } case DynamicsProcessing::mbc: { inUse = mEngine.mbcStage.inUse; bandCount = mEngine.mbcStage.bandCount; channels = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, DynamicsProcessing::mbc, std::vector)); break; } default: { ALOGE("%s unsupported tag %s", __func__, toString(tag).c_str()); return BAD_VALUE; } } for (const auto& ch : channels) { if (ch.channel == channel) { int32_t enable = ch.enable; RETURN_STATUS_IF_ERROR(param.writeToValue(&inUse)); RETURN_STATUS_IF_ERROR(param.writeToValue(&enable)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandCount)); return OK; } } ALOGE("%s not able to find channel %d", __func__, channel); return BAD_VALUE; } status_t AidlConversionDp::getEqBandConfig(DynamicsProcessing::Tag tag, EffectParamWriter& param) { int32_t channel, band; RETURN_STATUS_IF_ERROR(param.readFromParameter(&channel)); RETURN_STATUS_IF_ERROR(param.readFromParameter(&band)); Parameter aidlParam; Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag, tag); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam))); std::vector bands; if (tag == DynamicsProcessing::preEqBand) { bands = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, preEqBand, std::vector)); } else if (tag == DynamicsProcessing::postEqBand) { bands = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, postEqBand, std::vector)); } else { return BAD_VALUE; } for (const auto& bandIt : bands) { if (bandIt.channel == channel && bandIt.band == band) { int32_t enable = bandIt.enable; RETURN_STATUS_IF_ERROR(param.writeToValue(&enable)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.cutoffFrequencyHz)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.gainDb)); return OK; } } ALOGE("%s not able to find channel %d band %d", __func__, channel, band); return BAD_VALUE; } status_t AidlConversionDp::getMbcBandConfig(EffectParamWriter& param) { int32_t channel, band; RETURN_STATUS_IF_ERROR(param.readFromParameter(&channel)); RETURN_STATUS_IF_ERROR(param.readFromParameter(&band)); Parameter aidlParam; Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag, DynamicsProcessing::mbcBand); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam))); std::vector bands = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, mbcBand, std::vector)); for (const auto& bandIt : bands) { if (bandIt.channel == channel && bandIt.band == band) { int32_t enable = bandIt.enable; RETURN_STATUS_IF_ERROR(param.writeToValue(&enable)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.cutoffFrequencyHz)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.attackTimeMs)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.releaseTimeMs)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.ratio)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.thresholdDb)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.kneeWidthDb)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.noiseGateThresholdDb)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.expanderRatio)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.preGainDb)); RETURN_STATUS_IF_ERROR(param.writeToValue(&bandIt.postGainDb)); return OK; } } ALOGE("%s not able to find channel %d band %d", __func__, channel, band); return BAD_VALUE; } status_t AidlConversionDp::getLimiterConfig(EffectParamWriter& param) { int32_t channel; RETURN_STATUS_IF_ERROR(param.readFromParameter(&channel)); Parameter aidlParam; Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag, DynamicsProcessing::limiter); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam))); std::vector configs = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD( aidlParam, DynamicsProcessing, dynamicsProcessing, limiter, std::vector)); for (const auto& config : configs) { if (config.channel == channel) { int32_t inUse = mEngine.limiterInUse; int32_t enable = config.enable; RETURN_STATUS_IF_ERROR(param.writeToValue(&inUse)); RETURN_STATUS_IF_ERROR(param.writeToValue(&enable)); RETURN_STATUS_IF_ERROR(param.writeToValue(&config.linkGroup)); RETURN_STATUS_IF_ERROR(param.writeToValue(&config.attackTimeMs)); RETURN_STATUS_IF_ERROR(param.writeToValue(&config.releaseTimeMs)); RETURN_STATUS_IF_ERROR(param.writeToValue(&config.ratio)); RETURN_STATUS_IF_ERROR(param.writeToValue(&config.thresholdDb)); RETURN_STATUS_IF_ERROR(param.writeToValue(&config.postGainDb)); return OK; } } ALOGE("%s not able to find channel %d", __func__, channel); return BAD_VALUE; } } // namespace effect } // namespace android