312 lines
11 KiB
C++
312 lines
11 KiB
C++
/*
|
|
* 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 <cstddef>
|
|
#define LOG_TAG "PreProcessingContext"
|
|
#include <Utils.h>
|
|
|
|
#include "PreProcessingContext.h"
|
|
|
|
namespace aidl::android::hardware::audio::effect {
|
|
|
|
using aidl::android::media::audio::common::AudioDeviceDescription;
|
|
using aidl::android::media::audio::common::AudioDeviceType;
|
|
|
|
RetCode PreProcessingContext::init(const Parameter::Common& common) {
|
|
std::lock_guard lg(mMutex);
|
|
webrtc::AudioProcessingBuilder apBuilder;
|
|
mAudioProcessingModule = apBuilder.Create();
|
|
if (mAudioProcessingModule == nullptr) {
|
|
LOG(ERROR) << "init could not get apm engine";
|
|
return RetCode::ERROR_EFFECT_LIB_ERROR;
|
|
}
|
|
|
|
updateConfigs(common);
|
|
|
|
mEnabledMsk = 0;
|
|
mProcessedMsk = 0;
|
|
mRevEnabledMsk = 0;
|
|
mRevProcessedMsk = 0;
|
|
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
switch (mType) {
|
|
case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
|
|
config.echo_canceller.mobile_mode = true;
|
|
break;
|
|
case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
|
|
config.gain_controller1.target_level_dbfs = kAgcDefaultTargetLevel;
|
|
config.gain_controller1.compression_gain_db = kAgcDefaultCompGain;
|
|
config.gain_controller1.enable_limiter = kAgcDefaultLimiter;
|
|
break;
|
|
case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
|
|
config.gain_controller2.fixed_digital.gain_db = 0.f;
|
|
break;
|
|
case PreProcessingEffectType::NOISE_SUPPRESSION:
|
|
config.noise_suppression.level = kNsDefaultLevel;
|
|
break;
|
|
}
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
mState = PRE_PROC_STATE_INITIALIZED;
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
RetCode PreProcessingContext::deInit() {
|
|
std::lock_guard lg(mMutex);
|
|
mAudioProcessingModule = nullptr;
|
|
mState = PRE_PROC_STATE_UNINITIALIZED;
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
RetCode PreProcessingContext::enable() {
|
|
if (mState != PRE_PROC_STATE_INITIALIZED) {
|
|
return RetCode::ERROR_EFFECT_LIB_ERROR;
|
|
}
|
|
int typeMsk = (1 << int(mType));
|
|
std::lock_guard lg(mMutex);
|
|
// Check if effect is already enabled.
|
|
if ((mEnabledMsk & typeMsk) == typeMsk) {
|
|
return RetCode::ERROR_ILLEGAL_PARAMETER;
|
|
}
|
|
mEnabledMsk |= typeMsk;
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
switch (mType) {
|
|
case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
|
|
config.echo_canceller.enabled = true;
|
|
// AEC has reverse stream
|
|
mRevEnabledMsk |= typeMsk;
|
|
mRevProcessedMsk = 0;
|
|
break;
|
|
case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
|
|
config.gain_controller1.enabled = true;
|
|
break;
|
|
case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
|
|
config.gain_controller2.enabled = true;
|
|
break;
|
|
case PreProcessingEffectType::NOISE_SUPPRESSION:
|
|
config.noise_suppression.enabled = true;
|
|
break;
|
|
}
|
|
mProcessedMsk = 0;
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
mState = PRE_PROC_STATE_ACTIVE;
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
RetCode PreProcessingContext::disable() {
|
|
if (mState != PRE_PROC_STATE_ACTIVE) {
|
|
return RetCode::ERROR_EFFECT_LIB_ERROR;
|
|
}
|
|
int typeMsk = (1 << int(mType));
|
|
std::lock_guard lg(mMutex);
|
|
// Check if effect is already disabled.
|
|
if ((mEnabledMsk & typeMsk) != typeMsk) {
|
|
return RetCode::ERROR_ILLEGAL_PARAMETER;
|
|
}
|
|
mEnabledMsk &= ~typeMsk;
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
switch (mType) {
|
|
case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
|
|
config.echo_canceller.enabled = false;
|
|
// AEC has reverse stream
|
|
mRevEnabledMsk &= ~typeMsk;
|
|
mRevProcessedMsk = 0;
|
|
break;
|
|
case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
|
|
config.gain_controller1.enabled = false;
|
|
break;
|
|
case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
|
|
config.gain_controller2.enabled = false;
|
|
break;
|
|
case PreProcessingEffectType::NOISE_SUPPRESSION:
|
|
config.noise_suppression.enabled = false;
|
|
break;
|
|
}
|
|
mProcessedMsk = 0;
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
mState = PRE_PROC_STATE_INITIALIZED;
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setCommon(const Parameter::Common& common) {
|
|
mCommon = common;
|
|
updateConfigs(common);
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
void PreProcessingContext::updateConfigs(const Parameter::Common& common) {
|
|
mInputConfig.set_sample_rate_hz(common.input.base.sampleRate);
|
|
mInputConfig.set_num_channels(::aidl::android::hardware::audio::common::getChannelCount(
|
|
common.input.base.channelMask));
|
|
mOutputConfig.set_sample_rate_hz(common.input.base.sampleRate);
|
|
mOutputConfig.set_num_channels(::aidl::android::hardware::audio::common::getChannelCount(
|
|
common.output.base.channelMask));
|
|
}
|
|
|
|
RetCode PreProcessingContext::setAcousticEchoCancelerEchoDelay(int echoDelayUs) {
|
|
mEchoDelayUs = echoDelayUs;
|
|
std::lock_guard lg(mMutex);
|
|
mAudioProcessingModule->set_stream_delay_ms(mEchoDelayUs / 1000);
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
int PreProcessingContext::getAcousticEchoCancelerEchoDelay() const {
|
|
return mEchoDelayUs;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setAcousticEchoCancelerMobileMode(bool mobileMode) {
|
|
mMobileMode = mobileMode;
|
|
std::lock_guard lg(mMutex);
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
config.echo_canceller.mobile_mode = mobileMode;
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
bool PreProcessingContext::getAcousticEchoCancelerMobileMode() const {
|
|
return mMobileMode;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setAutomaticGainControlV1TargetPeakLevel(int targetPeakLevel) {
|
|
mTargetPeakLevel = targetPeakLevel;
|
|
std::lock_guard lg(mMutex);
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
config.gain_controller1.target_level_dbfs = -(mTargetPeakLevel / 100);
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
int PreProcessingContext::getAutomaticGainControlV1TargetPeakLevel() const {
|
|
return mTargetPeakLevel;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setAutomaticGainControlV1MaxCompressionGain(int maxCompressionGain) {
|
|
mMaxCompressionGain = maxCompressionGain;
|
|
std::lock_guard lg(mMutex);
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
config.gain_controller1.compression_gain_db = mMaxCompressionGain / 100;
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
int PreProcessingContext::getAutomaticGainControlV1MaxCompressionGain() const {
|
|
return mMaxCompressionGain;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setAutomaticGainControlV1EnableLimiter(bool enableLimiter) {
|
|
mEnableLimiter = enableLimiter;
|
|
std::lock_guard lg(mMutex);
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
config.gain_controller1.enable_limiter = mEnableLimiter;
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
bool PreProcessingContext::getAutomaticGainControlV1EnableLimiter() const {
|
|
return mEnableLimiter;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setAutomaticGainControlV2DigitalGain(int gain) {
|
|
mDigitalGain = gain;
|
|
std::lock_guard lg(mMutex);
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
config.gain_controller2.fixed_digital.gain_db = mDigitalGain;
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
int PreProcessingContext::getAutomaticGainControlV2DigitalGain() const {
|
|
return mDigitalGain;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setAutomaticGainControlV2LevelEstimator(
|
|
AutomaticGainControlV2::LevelEstimator levelEstimator) {
|
|
mLevelEstimator = levelEstimator;
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
AutomaticGainControlV2::LevelEstimator
|
|
PreProcessingContext::getAutomaticGainControlV2LevelEstimator() const {
|
|
return mLevelEstimator;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setAutomaticGainControlV2SaturationMargin(int saturationMargin) {
|
|
mSaturationMargin = saturationMargin;
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
int PreProcessingContext::getAutomaticGainControlV2SaturationMargin() const {
|
|
return mSaturationMargin;
|
|
}
|
|
|
|
RetCode PreProcessingContext::setNoiseSuppressionLevel(NoiseSuppression::Level level) {
|
|
mLevel = level;
|
|
std::lock_guard lg(mMutex);
|
|
auto config = mAudioProcessingModule->GetConfig();
|
|
config.noise_suppression.level =
|
|
(webrtc::AudioProcessing::Config::NoiseSuppression::Level)level;
|
|
mAudioProcessingModule->ApplyConfig(config);
|
|
return RetCode::SUCCESS;
|
|
}
|
|
|
|
NoiseSuppression::Level PreProcessingContext::getNoiseSuppressionLevel() const {
|
|
return mLevel;
|
|
}
|
|
|
|
IEffect::Status PreProcessingContext::lvmProcess(float* in, float* out, int samples) {
|
|
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
|
|
RETURN_VALUE_IF(!in, status, "nullInput");
|
|
RETURN_VALUE_IF(!out, status, "nullOutput");
|
|
status = {EX_ILLEGAL_STATE, 0, 0};
|
|
int64_t inputFrameCount = getCommon().input.frameCount;
|
|
int64_t outputFrameCount = getCommon().output.frameCount;
|
|
RETURN_VALUE_IF(inputFrameCount != outputFrameCount, status, "FrameCountMismatch");
|
|
RETURN_VALUE_IF(0 == getInputFrameSize(), status, "zeroFrameSize");
|
|
|
|
LOG(DEBUG) << __func__ << " start processing";
|
|
std::lock_guard lg(mMutex);
|
|
|
|
mProcessedMsk |= (1 << int(mType));
|
|
|
|
// webrtc implementation clear out was_stream_delay_set every time after ProcessStream() call
|
|
mAudioProcessingModule->set_stream_delay_ms(mEchoDelayUs / 1000);
|
|
|
|
if ((mProcessedMsk & mEnabledMsk) == mEnabledMsk) {
|
|
mProcessedMsk = 0;
|
|
int processStatus = mAudioProcessingModule->ProcessStream(
|
|
(const int16_t* const)in, mInputConfig, mOutputConfig, (int16_t* const)out);
|
|
if (processStatus != 0) {
|
|
LOG(ERROR) << "Process stream failed with error " << processStatus;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
mRevProcessedMsk |= (1 << int(mType));
|
|
|
|
if ((mRevProcessedMsk & mRevEnabledMsk) == mRevEnabledMsk) {
|
|
mRevProcessedMsk = 0;
|
|
int revProcessStatus = mAudioProcessingModule->ProcessReverseStream(
|
|
(const int16_t* const)in, mInputConfig, mInputConfig, (int16_t* const)out);
|
|
if (revProcessStatus != 0) {
|
|
LOG(ERROR) << "Process reverse stream failed with error " << revProcessStatus;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
return {STATUS_OK, samples, samples};
|
|
}
|
|
|
|
} // namespace aidl::android::hardware::audio::effect
|