blob: f77c0938dcc7e7858c402707352c0f8467f4b87e [file] [log] [blame]
/*
* 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 <cstdint>
#include <cstring>
#include <optional>
#define LOG_TAG "AidlConversionDp"
//#define LOG_NDEBUG 0
#include <error/expected_utils.h>
#include <media/AidlConversionCppNdk.h>
#include <media/AidlConversionNdk.h>
#include <media/AidlConversionEffect.h>
#include <system/audio_effect.h>
#include <system/audio_effects/effect_dynamicsprocessing.h>
#include <Utils.h>
#include <utils/Log.h>
#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<DynamicsProcessing::InputGain> gains =
VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
aidlParam, DynamicsProcessing, dynamicsProcessing,
DynamicsProcessing::inputGain,
std::vector<DynamicsProcessing::InputGain>));
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<int32_t>(engine.preEqStage.inUse));
int32_t mbcInUse =
VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(engine.mbcStage.inUse));
int32_t postEqInUse =
VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(engine.postEqStage.inUse));
int32_t limiterInUse =
VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(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<DynamicsProcessing::ChannelConfig>
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<bool>(enable))});
}
ConversionResult<DynamicsProcessing::EqBandConfig>
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<bool>(enable));
return config;
}
ConversionResult<DynamicsProcessing::MbcBandConfig>
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<bool>(enable));
return config;
}
ConversionResult<DynamicsProcessing::LimiterConfig>
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<bool>(enable));
return config;
}
ConversionResult<DynamicsProcessing::EngineArchitecture>
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<bool>(preEqInUse));
engine.mbcStage.inUse = VALUE_OR_RETURN(convertIntegral<bool>(mbcInUse));
engine.postEqStage.inUse = VALUE_OR_RETURN(convertIntegral<bool>(postEqInUse));
engine.limiterInUse = VALUE_OR_RETURN(convertIntegral<bool>(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<DynamicsProcessing::ChannelConfig> 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<DynamicsProcessing::ChannelConfig>));
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<DynamicsProcessing::ChannelConfig>));
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<DynamicsProcessing::ChannelConfig>));
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<DynamicsProcessing::EqBandConfig> bands;
if (tag == DynamicsProcessing::preEqBand) {
bands = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
aidlParam, DynamicsProcessing, dynamicsProcessing, preEqBand,
std::vector<DynamicsProcessing::EqBandConfig>));
} else if (tag == DynamicsProcessing::postEqBand) {
bands = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
aidlParam, DynamicsProcessing, dynamicsProcessing, postEqBand,
std::vector<DynamicsProcessing::EqBandConfig>));
} 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<DynamicsProcessing::MbcBandConfig> bands =
VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
aidlParam, DynamicsProcessing, dynamicsProcessing, mbcBand,
std::vector<DynamicsProcessing::MbcBandConfig>));
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<DynamicsProcessing::LimiterConfig> configs =
VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
aidlParam, DynamicsProcessing, dynamicsProcessing, limiter,
std::vector<DynamicsProcessing::LimiterConfig>));
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