Utilizing the AEC3 config struct for constants.
This CL replaces inline constants with config struct constants. BUG=webrtc:5298 Review-Url: https://codereview.webrtc.org/3003733002 Cr-Commit-Position: refs/heads/master@{#19507}
This commit is contained in:
parent
2dbc69fa64
commit
8cee56f254
@ -305,7 +305,7 @@ TEST(AdaptiveFirFilter, FilterAndAdapt) {
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> n(kBlockSize, 0.f);
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
AecState aec_state(0.f);
|
||||
AecState aec_state(AudioProcessing::Config::EchoCanceller3{});
|
||||
RenderSignalAnalyzer render_signal_analyzer;
|
||||
std::vector<float> e(kBlockSize, 0.f);
|
||||
std::array<float, kFftLength> s_scratch;
|
||||
|
||||
@ -75,11 +75,15 @@ constexpr int kEchoPathChangeCounterMax = 2 * kNumBlocksPerSecond;
|
||||
|
||||
int AecState::instance_count_ = 0;
|
||||
|
||||
AecState::AecState(float reverb_decay)
|
||||
AecState::AecState(const AudioProcessing::Config::EchoCanceller3& config)
|
||||
: data_dumper_(
|
||||
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
||||
erle_estimator_(config.param.erle.min,
|
||||
config.param.erle.max_l,
|
||||
config.param.erle.max_h),
|
||||
echo_path_change_counter_(kEchoPathChangeCounterInitial),
|
||||
reverb_decay_(reverb_decay) {}
|
||||
config_(config),
|
||||
reverb_decay_(config_.param.ep_strength.default_len) {}
|
||||
|
||||
AecState::~AecState() = default;
|
||||
|
||||
@ -252,7 +256,8 @@ void AecState::UpdateReverb(
|
||||
|
||||
// Limit the estimated reverb_decay_ to the maximum one needed in practice
|
||||
// to minimize the impact of incorrect estimates.
|
||||
reverb_decay_ = std::min(0.8f, reverb_decay_);
|
||||
reverb_decay_ =
|
||||
std::min(config_.param.ep_strength.default_len, reverb_decay_);
|
||||
}
|
||||
reverb_decay_to_test_ = 0.9f;
|
||||
reverb_decay_candidate_residual_ = -1.f;
|
||||
@ -260,7 +265,7 @@ void AecState::UpdateReverb(
|
||||
|
||||
// For noisy impulse responses, assume a fixed tail length.
|
||||
if (tail_power > 0.0005f) {
|
||||
reverb_decay_ = 0.7f;
|
||||
reverb_decay_ = config_.param.ep_strength.default_len;
|
||||
}
|
||||
data_dumper_->DumpRaw("aec3_reverb_decay", reverb_decay_);
|
||||
data_dumper_->DumpRaw("aec3_tail_power", tail_power);
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "webrtc/modules/audio_processing/aec3/erl_estimator.h"
|
||||
#include "webrtc/modules/audio_processing/aec3/erle_estimator.h"
|
||||
#include "webrtc/modules/audio_processing/aec3/render_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/rtc_base/array_view.h"
|
||||
#include "webrtc/rtc_base/constructormagic.h"
|
||||
#include "webrtc/rtc_base/optional.h"
|
||||
@ -31,7 +32,7 @@ class ApmDataDumper;
|
||||
// Handles the state and the conditions for the echo removal functionality.
|
||||
class AecState {
|
||||
public:
|
||||
explicit AecState(float reverb_decay);
|
||||
explicit AecState(const AudioProcessing::Config::EchoCanceller3& config);
|
||||
~AecState();
|
||||
|
||||
// Returns whether the linear filter estimate is usable.
|
||||
@ -140,13 +141,14 @@ class AecState {
|
||||
rtc::Optional<size_t> filter_delay_;
|
||||
rtc::Optional<size_t> external_delay_;
|
||||
size_t blocks_since_last_saturation_ = 1000;
|
||||
float reverb_decay_;
|
||||
float reverb_decay_to_test_ = 0.9f;
|
||||
float reverb_decay_candidate_ = 0.f;
|
||||
float reverb_decay_candidate_residual_ = -1.f;
|
||||
EchoAudibility echo_audibility_;
|
||||
const AudioProcessing::Config::EchoCanceller3 config_;
|
||||
float reverb_decay_;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AecState);
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AecState);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -18,7 +18,7 @@ namespace webrtc {
|
||||
// Verify the general functionality of AecState
|
||||
TEST(AecState, NormalUsage) {
|
||||
ApmDataDumper data_dumper(42);
|
||||
AecState state(0.f);
|
||||
AecState state(AudioProcessing::Config::EchoCanceller3{});
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 30,
|
||||
std::vector<size_t>(1, 30));
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main = {};
|
||||
@ -163,7 +163,7 @@ TEST(AecState, NormalUsage) {
|
||||
|
||||
// Verifies the a non-significant delay is correctly identified.
|
||||
TEST(AecState, NonSignificantDelay) {
|
||||
AecState state(0.f);
|
||||
AecState state(AudioProcessing::Config::EchoCanceller3{});
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 30,
|
||||
std::vector<size_t>(1, 30));
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
@ -192,7 +192,7 @@ TEST(AecState, NonSignificantDelay) {
|
||||
// Verifies the delay for a converged filter is correctly identified.
|
||||
TEST(AecState, ConvergedFilterDelay) {
|
||||
constexpr int kFilterLength = 10;
|
||||
AecState state(0.f);
|
||||
AecState state(AudioProcessing::Config::EchoCanceller3{});
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 30,
|
||||
std::vector<size_t>(1, 30));
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
@ -228,7 +228,7 @@ TEST(AecState, ConvergedFilterDelay) {
|
||||
|
||||
// Verify that the externally reported delay is properly reported and converted.
|
||||
TEST(AecState, ExternalDelay) {
|
||||
AecState state(0.f);
|
||||
AecState state(AudioProcessing::Config::EchoCanceller3{});
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
std::array<float, kFftLengthBy2Plus1> E2_shadow;
|
||||
std::array<float, kFftLengthBy2Plus1> Y2;
|
||||
|
||||
@ -36,7 +36,8 @@ TEST(ComfortNoiseGenerator, NullLowerBandNoise) {
|
||||
std::array<float, kFftLengthBy2Plus1> N2;
|
||||
FftData noise;
|
||||
EXPECT_DEATH(ComfortNoiseGenerator(DetectOptimization())
|
||||
.Compute(AecState(0.f), N2, nullptr, &noise),
|
||||
.Compute(AecState(AudioProcessing::Config::EchoCanceller3{}),
|
||||
N2, nullptr, &noise),
|
||||
"");
|
||||
}
|
||||
|
||||
@ -44,7 +45,8 @@ TEST(ComfortNoiseGenerator, NullUpperBandNoise) {
|
||||
std::array<float, kFftLengthBy2Plus1> N2;
|
||||
FftData noise;
|
||||
EXPECT_DEATH(ComfortNoiseGenerator(DetectOptimization())
|
||||
.Compute(AecState(0.f), N2, &noise, nullptr),
|
||||
.Compute(AecState(AudioProcessing::Config::EchoCanceller3{}),
|
||||
N2, &noise, nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
@ -91,7 +93,7 @@ TEST(ComfortNoiseGenerator, TestOptimizations) {
|
||||
|
||||
TEST(ComfortNoiseGenerator, CorrectLevel) {
|
||||
ComfortNoiseGenerator cng(DetectOptimization());
|
||||
AecState aec_state(0.f);
|
||||
AecState aec_state(AudioProcessing::Config::EchoCanceller3{});
|
||||
|
||||
std::array<float, kFftLengthBy2Plus1> N2;
|
||||
N2.fill(1000.f * 1000.f);
|
||||
|
||||
@ -72,6 +72,7 @@ class EchoRemoverImpl final : public EchoRemover {
|
||||
|
||||
private:
|
||||
static int instance_count_;
|
||||
const AudioProcessing::Config::EchoCanceller3 config_;
|
||||
const Aec3Fft fft_;
|
||||
std::unique_ptr<ApmDataDumper> data_dumper_;
|
||||
const Aec3Optimization optimization_;
|
||||
@ -95,16 +96,18 @@ int EchoRemoverImpl::instance_count_ = 0;
|
||||
EchoRemoverImpl::EchoRemoverImpl(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
int sample_rate_hz)
|
||||
: fft_(),
|
||||
: config_(config),
|
||||
fft_(),
|
||||
data_dumper_(
|
||||
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
||||
optimization_(DetectOptimization()),
|
||||
sample_rate_hz_(sample_rate_hz),
|
||||
subtractor_(data_dumper_.get(), optimization_),
|
||||
suppression_gain_(optimization_),
|
||||
suppression_gain_(config_, optimization_),
|
||||
cng_(optimization_),
|
||||
suppression_filter_(sample_rate_hz_),
|
||||
aec_state_(0.8f) {
|
||||
residual_echo_estimator_(config_),
|
||||
aec_state_(config_) {
|
||||
RTC_DCHECK(ValidFullBandRate(sample_rate_hz));
|
||||
}
|
||||
|
||||
|
||||
@ -126,7 +126,7 @@ TEST(DbMetric, Constructor) {
|
||||
// Verify the general functionality of EchoRemoverMetrics.
|
||||
TEST(EchoRemoverMetrics, NormalUsage) {
|
||||
EchoRemoverMetrics metrics;
|
||||
AecState aec_state(0.f);
|
||||
AecState aec_state(AudioProcessing::Config::EchoCanceller3{});
|
||||
std::array<float, kFftLengthBy2Plus1> comfort_noise_spectrum;
|
||||
std::array<float, kFftLengthBy2Plus1> suppressor_gain;
|
||||
comfort_noise_spectrum.fill(10.f);
|
||||
|
||||
@ -16,16 +16,13 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float kMinErle = 1.f;
|
||||
constexpr float kMaxLfErle = 8.f;
|
||||
constexpr float kMaxHfErle = 1.5f;
|
||||
|
||||
} // namespace
|
||||
|
||||
ErleEstimator::ErleEstimator() {
|
||||
erle_.fill(kMinErle);
|
||||
ErleEstimator::ErleEstimator(float min_erle,
|
||||
float max_erle_lf,
|
||||
float max_erle_hf)
|
||||
: min_erle_(min_erle),
|
||||
max_erle_lf_(max_erle_lf),
|
||||
max_erle_hf_(max_erle_hf) {
|
||||
erle_.fill(min_erle_);
|
||||
hold_counters_.fill(0);
|
||||
}
|
||||
|
||||
@ -50,19 +47,19 @@ void ErleEstimator::Update(
|
||||
if (new_erle > erle_[k]) {
|
||||
hold_counters_[k - 1] = 100;
|
||||
erle_[k] += 0.1f * (new_erle - erle_[k]);
|
||||
erle_[k] = rtc::SafeClamp(erle_[k], kMinErle, max_erle);
|
||||
erle_[k] = rtc::SafeClamp(erle_[k], min_erle_, max_erle);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
erle_update(1, kFftLengthBy2 / 2, kMaxLfErle);
|
||||
erle_update(kFftLengthBy2 / 2, kFftLengthBy2, kMaxHfErle);
|
||||
erle_update(1, kFftLengthBy2 / 2, max_erle_lf_);
|
||||
erle_update(kFftLengthBy2 / 2, kFftLengthBy2, max_erle_hf_);
|
||||
|
||||
std::for_each(hold_counters_.begin(), hold_counters_.end(),
|
||||
[](int& a) { --a; });
|
||||
std::transform(hold_counters_.begin(), hold_counters_.end(),
|
||||
erle_.begin() + 1, erle_.begin() + 1, [](int a, float b) {
|
||||
return a > 0 ? b : std::max(kMinErle, 0.97f * b);
|
||||
erle_.begin() + 1, erle_.begin() + 1, [&](int a, float b) {
|
||||
return a > 0 ? b : std::max(min_erle_, 0.97f * b);
|
||||
});
|
||||
|
||||
erle_[0] = erle_[1];
|
||||
|
||||
@ -21,7 +21,7 @@ namespace webrtc {
|
||||
// Estimates the echo return loss enhancement based on the signal spectra.
|
||||
class ErleEstimator {
|
||||
public:
|
||||
ErleEstimator();
|
||||
ErleEstimator(float min_erle, float max_erle_lf, float max_erle_hf);
|
||||
~ErleEstimator();
|
||||
|
||||
// Updates the ERLE estimate.
|
||||
@ -35,6 +35,9 @@ class ErleEstimator {
|
||||
private:
|
||||
std::array<float, kFftLengthBy2Plus1> erle_;
|
||||
std::array<int, kFftLengthBy2Minus1> hold_counters_;
|
||||
const float min_erle_;
|
||||
const float max_erle_lf_;
|
||||
const float max_erle_hf_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(ErleEstimator);
|
||||
};
|
||||
|
||||
@ -36,7 +36,7 @@ TEST(ErleEstimator, Estimates) {
|
||||
std::array<float, kFftLengthBy2Plus1> E2;
|
||||
std::array<float, kFftLengthBy2Plus1> Y2;
|
||||
|
||||
ErleEstimator estimator;
|
||||
ErleEstimator estimator(1.f, 8.f, 1.5f);
|
||||
|
||||
// Verifies that the ERLE estimate is properley increased to higher values.
|
||||
X2.fill(500 * 1000.f * 1000.f);
|
||||
|
||||
@ -53,7 +53,7 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
||||
Random random_generator(42U);
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
AecState aec_state(0.f);
|
||||
AecState aec_state(AudioProcessing::Config::EchoCanceller3{});
|
||||
RenderSignalAnalyzer render_signal_analyzer;
|
||||
std::array<float, kFftLength> s_scratch;
|
||||
std::array<float, kBlockSize> s;
|
||||
|
||||
@ -79,7 +79,9 @@ constexpr float kHeadsetEchoPathGain = 0.0005f;
|
||||
|
||||
} // namespace
|
||||
|
||||
ResidualEchoEstimator::ResidualEchoEstimator() {
|
||||
ResidualEchoEstimator::ResidualEchoEstimator(
|
||||
const AudioProcessing::Config::EchoCanceller3& config)
|
||||
: config_(config) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
@ -188,11 +190,12 @@ void ResidualEchoEstimator::NonLinearEstimate(
|
||||
const std::array<float, kFftLengthBy2Plus1>& Y2,
|
||||
std::array<float, kFftLengthBy2Plus1>* R2) {
|
||||
// Choose gains.
|
||||
const float echo_path_gain_lf = headset_detected ? kHeadsetEchoPathGain : 100;
|
||||
const float echo_path_gain_lf =
|
||||
headset_detected ? kHeadsetEchoPathGain : config_.param.ep_strength.lf;
|
||||
const float echo_path_gain_mf =
|
||||
headset_detected ? kHeadsetEchoPathGain : 1000;
|
||||
headset_detected ? kHeadsetEchoPathGain : config_.param.ep_strength.mf;
|
||||
const float echo_path_gain_hf =
|
||||
headset_detected ? kHeadsetEchoPathGain : 5000;
|
||||
headset_detected ? kHeadsetEchoPathGain : config_.param.ep_strength.hf;
|
||||
|
||||
// Compute preliminary residual echo.
|
||||
std::transform(
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "webrtc/modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "webrtc/modules/audio_processing/aec3/aec_state.h"
|
||||
#include "webrtc/modules/audio_processing/aec3/render_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/rtc_base/array_view.h"
|
||||
#include "webrtc/rtc_base/constructormagic.h"
|
||||
|
||||
@ -25,7 +26,8 @@ namespace webrtc {
|
||||
|
||||
class ResidualEchoEstimator {
|
||||
public:
|
||||
ResidualEchoEstimator();
|
||||
explicit ResidualEchoEstimator(
|
||||
const AudioProcessing::Config::EchoCanceller3& config);
|
||||
~ResidualEchoEstimator();
|
||||
|
||||
void Estimate(bool using_subtractor_output,
|
||||
@ -69,8 +71,9 @@ class ResidualEchoEstimator {
|
||||
S2_old_;
|
||||
std::array<float, kFftLengthBy2Plus1> X2_noise_floor_;
|
||||
std::array<int, kFftLengthBy2Plus1> X2_noise_floor_counter_;
|
||||
const AudioProcessing::Config::EchoCanceller3 config_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(ResidualEchoEstimator);
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ResidualEchoEstimator);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec3/aec3_fft.h"
|
||||
#include "webrtc/modules/audio_processing/aec3/aec_state.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/modules/audio_processing/test/echo_canceller_test_tools.h"
|
||||
#include "webrtc/rtc_base/random.h"
|
||||
#include "webrtc/test/gtest.h"
|
||||
@ -22,22 +23,25 @@ namespace webrtc {
|
||||
|
||||
// Verifies that the check for non-null output residual echo power works.
|
||||
TEST(ResidualEchoEstimator, NullResidualEchoPowerOutput) {
|
||||
AecState aec_state(0.f);
|
||||
AecState aec_state(AudioProcessing::Config::EchoCanceller3{});
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 10,
|
||||
std::vector<size_t>(1, 10));
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>> H2;
|
||||
std::array<float, kFftLengthBy2Plus1> S2_linear;
|
||||
std::array<float, kFftLengthBy2Plus1> Y2;
|
||||
EXPECT_DEATH(ResidualEchoEstimator().Estimate(true, aec_state, render_buffer,
|
||||
S2_linear, Y2, nullptr),
|
||||
"");
|
||||
EXPECT_DEATH(
|
||||
ResidualEchoEstimator(AudioProcessing::Config::EchoCanceller3{})
|
||||
.Estimate(true, aec_state, render_buffer, S2_linear, Y2, nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST(ResidualEchoEstimator, BasicTest) {
|
||||
ResidualEchoEstimator estimator;
|
||||
AecState aec_state(0.f);
|
||||
ResidualEchoEstimator estimator(AudioProcessing::Config::EchoCanceller3{});
|
||||
AudioProcessing::Config::EchoCanceller3 config;
|
||||
config.param.ep_strength.default_len = 0.f;
|
||||
AecState aec_state(config);
|
||||
RenderBuffer render_buffer(Aec3Optimization::kNone, 3, 10,
|
||||
std::vector<size_t>(1, 10));
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
|
||||
@ -47,7 +47,7 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
||||
Random random_generator(42U);
|
||||
std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
AecState aec_state(0.f);
|
||||
AecState aec_state(AudioProcessing::Config::EchoCanceller3{});
|
||||
RenderSignalAnalyzer render_signal_analyzer;
|
||||
std::array<float, kFftLength> s;
|
||||
FftData S;
|
||||
|
||||
@ -40,7 +40,7 @@ float RunSubtractorTest(int num_blocks_to_process,
|
||||
std::array<float, kFftLengthBy2Plus1> Y2;
|
||||
std::array<float, kFftLengthBy2Plus1> E2_main;
|
||||
std::array<float, kFftLengthBy2Plus1> E2_shadow;
|
||||
AecState aec_state(0.f);
|
||||
AecState aec_state(AudioProcessing::Config::EchoCanceller3{});
|
||||
x_old.fill(0.f);
|
||||
Y2.fill(0.f);
|
||||
E2_main.fill(0.f);
|
||||
@ -109,9 +109,11 @@ TEST(Subtractor, DISABLED_NullOutput) {
|
||||
RenderSignalAnalyzer render_signal_analyzer;
|
||||
std::vector<float> y(kBlockSize, 0.f);
|
||||
|
||||
EXPECT_DEATH(subtractor.Process(render_buffer, y, render_signal_analyzer,
|
||||
AecState(0.f), nullptr),
|
||||
"");
|
||||
EXPECT_DEATH(
|
||||
subtractor.Process(render_buffer, y, render_signal_analyzer,
|
||||
AecState(AudioProcessing::Config::EchoCanceller3{}),
|
||||
nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
// Verifies the check for the capture signal size.
|
||||
@ -124,9 +126,11 @@ TEST(Subtractor, WrongCaptureSize) {
|
||||
std::vector<float> y(kBlockSize - 1, 0.f);
|
||||
SubtractorOutput output;
|
||||
|
||||
EXPECT_DEATH(subtractor.Process(render_buffer, y, render_signal_analyzer,
|
||||
AecState(0.f), &output),
|
||||
"");
|
||||
EXPECT_DEATH(
|
||||
subtractor.Process(render_buffer, y, render_signal_analyzer,
|
||||
AecState(AudioProcessing::Config::EchoCanceller3{}),
|
||||
&output),
|
||||
"");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -109,6 +109,7 @@ float UpperBandsGain(
|
||||
|
||||
// Limits the gain increase.
|
||||
void UpdateMaxGainIncrease(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
size_t no_saturation_counter,
|
||||
bool low_noise_render,
|
||||
const std::array<float, kFftLengthBy2Plus1>& last_echo,
|
||||
@ -123,27 +124,28 @@ void UpdateMaxGainIncrease(
|
||||
float min_increasing;
|
||||
float min_decreasing;
|
||||
|
||||
auto& param = config.param.gain_updates;
|
||||
if (low_noise_render) {
|
||||
max_increasing = 8.f;
|
||||
max_decreasing = 8.f;
|
||||
rate_increasing = 2.f;
|
||||
rate_decreasing = 2.f;
|
||||
min_increasing = 4.f;
|
||||
min_decreasing = 4.f;
|
||||
max_increasing = param.low_noise.max_inc;
|
||||
max_decreasing = param.low_noise.max_dec;
|
||||
rate_increasing = param.low_noise.rate_inc;
|
||||
rate_decreasing = param.low_noise.rate_dec;
|
||||
min_increasing = param.low_noise.min_inc;
|
||||
min_decreasing = param.low_noise.min_dec;
|
||||
} else if (no_saturation_counter > 10) {
|
||||
max_increasing = 4.f;
|
||||
max_decreasing = 4.f;
|
||||
rate_increasing = 2.f;
|
||||
rate_decreasing = 2.f;
|
||||
min_increasing = 1.2f;
|
||||
min_decreasing = 2.f;
|
||||
max_increasing = param.normal.max_inc;
|
||||
max_decreasing = param.normal.max_dec;
|
||||
rate_increasing = param.normal.rate_inc;
|
||||
rate_decreasing = param.normal.rate_dec;
|
||||
min_increasing = param.normal.min_inc;
|
||||
min_decreasing = param.normal.min_dec;
|
||||
} else {
|
||||
max_increasing = 1.2f;
|
||||
max_decreasing = 1.2f;
|
||||
rate_increasing = 1.5f;
|
||||
rate_decreasing = 1.5f;
|
||||
min_increasing = 1.f;
|
||||
min_decreasing = 1.f;
|
||||
max_increasing = param.saturation.max_inc;
|
||||
max_decreasing = param.saturation.max_dec;
|
||||
rate_increasing = param.saturation.rate_inc;
|
||||
rate_decreasing = param.saturation.rate_dec;
|
||||
min_increasing = param.saturation.min_inc;
|
||||
min_decreasing = param.saturation.min_dec;
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < new_gain.size(); ++k) {
|
||||
@ -163,6 +165,7 @@ void UpdateMaxGainIncrease(
|
||||
|
||||
// Computes the gain to reduce the echo to a non audible level.
|
||||
void GainToNoAudibleEcho(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
bool low_noise_render,
|
||||
bool saturated_echo,
|
||||
const std::array<float, kFftLengthBy2Plus1>& nearend,
|
||||
@ -172,16 +175,17 @@ void GainToNoAudibleEcho(
|
||||
const std::array<float, kFftLengthBy2Plus1>& max_gain,
|
||||
const std::array<float, kFftLengthBy2Plus1>& one_by_echo,
|
||||
std::array<float, kFftLengthBy2Plus1>* gain) {
|
||||
constexpr float kEchoMaskingMargin = 1.f / 100.f;
|
||||
const float nearend_masking_margin =
|
||||
low_noise_render ? 0.1f : (saturated_echo ? 0.001f : 0.01f);
|
||||
low_noise_render ? 0.1f
|
||||
: (saturated_echo ? config.param.gain_mask.m2
|
||||
: config.param.gain_mask.m3);
|
||||
|
||||
for (size_t k = 0; k < gain->size(); ++k) {
|
||||
RTC_DCHECK_LE(0.f, nearend_masking_margin * nearend[k]);
|
||||
if (echo[k] <= nearend_masking_margin * nearend[k]) {
|
||||
(*gain)[k] = 1.f;
|
||||
} else {
|
||||
(*gain)[k] = kEchoMaskingMargin * masker[k] * one_by_echo[k];
|
||||
(*gain)[k] = config.param.gain_mask.m1 * masker[k] * one_by_echo[k];
|
||||
}
|
||||
|
||||
(*gain)[k] = std::min(std::max((*gain)[k], min_gain[k]), max_gain[k]);
|
||||
@ -189,7 +193,8 @@ void GainToNoAudibleEcho(
|
||||
}
|
||||
|
||||
// Computes the signal output power that masks the echo signal.
|
||||
void MaskingPower(const std::array<float, kFftLengthBy2Plus1>& nearend,
|
||||
void MaskingPower(const AudioProcessing::Config::EchoCanceller3& config,
|
||||
const std::array<float, kFftLengthBy2Plus1>& nearend,
|
||||
const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
|
||||
const std::array<float, kFftLengthBy2Plus1>& last_masker,
|
||||
const std::array<float, kFftLengthBy2Plus1>& gain,
|
||||
@ -197,7 +202,8 @@ void MaskingPower(const std::array<float, kFftLengthBy2Plus1>& nearend,
|
||||
std::array<float, kFftLengthBy2Plus1> side_band_masker;
|
||||
for (size_t k = 0; k < gain.size(); ++k) {
|
||||
side_band_masker[k] = nearend[k] * gain[k] + comfort_noise[k];
|
||||
(*masker)[k] = comfort_noise[k] + 0.1f * last_masker[k];
|
||||
(*masker)[k] =
|
||||
comfort_noise[k] + config.param.gain_mask.m4 * last_masker[k];
|
||||
}
|
||||
for (size_t k = 1; k < gain.size() - 1; ++k) {
|
||||
(*masker)[k] += 0.1f * (side_band_masker[k - 1] + side_band_masker[k + 1]);
|
||||
@ -227,7 +233,9 @@ void SuppressionGain::LowerBandGain(
|
||||
// Compute the minimum gain as the attenuating gain to put the signal just
|
||||
// above the zero sample values.
|
||||
std::array<float, kFftLengthBy2Plus1> min_gain;
|
||||
const float min_echo_power = low_noise_render ? 192.f : 64.f;
|
||||
const float min_echo_power =
|
||||
low_noise_render ? config_.param.echo_audibility.low_render_limit
|
||||
: config_.param.echo_audibility.normal_render_limit;
|
||||
if (no_saturation_counter_ > 10) {
|
||||
for (size_t k = 0; k < nearend.size(); ++k) {
|
||||
const float denom = std::min(nearend[k], echo[k]);
|
||||
@ -243,7 +251,9 @@ void SuppressionGain::LowerBandGain(
|
||||
std::array<float, kFftLengthBy2Plus1> max_gain;
|
||||
for (size_t k = 0; k < gain->size(); ++k) {
|
||||
max_gain[k] =
|
||||
std::min(std::max(last_gain_[k] * gain_increase_[k], 0.001f), 1.f);
|
||||
std::min(std::max(last_gain_[k] * gain_increase_[k],
|
||||
config_.param.gain_updates.floor_first_increase),
|
||||
1.f);
|
||||
}
|
||||
|
||||
// Iteratively compute the gain required to attenuate the echo to a non
|
||||
@ -251,9 +261,9 @@ void SuppressionGain::LowerBandGain(
|
||||
gain->fill(0.f);
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
std::array<float, kFftLengthBy2Plus1> masker;
|
||||
MaskingPower(nearend, comfort_noise, last_masker_, *gain, &masker);
|
||||
GainToNoAudibleEcho(low_noise_render, saturated_echo, nearend, echo, masker,
|
||||
min_gain, max_gain, one_by_echo, gain);
|
||||
MaskingPower(config_, nearend, comfort_noise, last_masker_, *gain, &masker);
|
||||
GainToNoAudibleEcho(config_, low_noise_render, saturated_echo, nearend,
|
||||
echo, masker, min_gain, max_gain, one_by_echo, gain);
|
||||
AdjustForExternalFilters(gain);
|
||||
if (narrow_peak_band) {
|
||||
NarrowBandAttenuation(*narrow_peak_band, gain);
|
||||
@ -261,18 +271,21 @@ void SuppressionGain::LowerBandGain(
|
||||
}
|
||||
|
||||
// Update the allowed maximum gain increase.
|
||||
UpdateMaxGainIncrease(no_saturation_counter_, low_noise_render, last_echo_,
|
||||
echo, last_gain_, *gain, &gain_increase_);
|
||||
UpdateMaxGainIncrease(config_, no_saturation_counter_, low_noise_render,
|
||||
last_echo_, echo, last_gain_, *gain, &gain_increase_);
|
||||
|
||||
// Store data required for the gain computation of the next block.
|
||||
std::copy(echo.begin(), echo.end(), last_echo_.begin());
|
||||
std::copy(gain->begin(), gain->end(), last_gain_.begin());
|
||||
MaskingPower(nearend, comfort_noise, last_masker_, *gain, &last_masker_);
|
||||
MaskingPower(config_, nearend, comfort_noise, last_masker_, *gain,
|
||||
&last_masker_);
|
||||
aec3::VectorMath(optimization_).Sqrt(*gain);
|
||||
}
|
||||
|
||||
SuppressionGain::SuppressionGain(Aec3Optimization optimization)
|
||||
: optimization_(optimization) {
|
||||
SuppressionGain::SuppressionGain(
|
||||
const AudioProcessing::Config::EchoCanceller3& config,
|
||||
Aec3Optimization optimization)
|
||||
: optimization_(optimization), config_(config) {
|
||||
last_gain_.fill(1.f);
|
||||
last_masker_.fill(0.f);
|
||||
gain_increase_.fill(1.f);
|
||||
|
||||
@ -16,13 +16,15 @@
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "webrtc/modules/audio_processing/aec3/render_signal_analyzer.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/rtc_base/constructormagic.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class SuppressionGain {
|
||||
public:
|
||||
explicit SuppressionGain(Aec3Optimization optimization);
|
||||
SuppressionGain(const AudioProcessing::Config::EchoCanceller3& config,
|
||||
Aec3Optimization optimization);
|
||||
void GetGain(const std::array<float, kFftLengthBy2Plus1>& nearend,
|
||||
const std::array<float, kFftLengthBy2Plus1>& echo,
|
||||
const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
|
||||
@ -58,7 +60,8 @@ class SuppressionGain {
|
||||
|
||||
LowNoiseRenderDetector low_render_detector_;
|
||||
size_t no_saturation_counter_ = 0;
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SuppressionGain);
|
||||
const AudioProcessing::Config::EchoCanceller3 config_;
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(SuppressionGain);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -29,7 +29,8 @@ TEST(SuppressionGain, NullOutputGains) {
|
||||
R2.fill(0.f);
|
||||
N2.fill(0.f);
|
||||
float high_bands_gain;
|
||||
EXPECT_DEATH(SuppressionGain(DetectOptimization())
|
||||
EXPECT_DEATH(SuppressionGain(AudioProcessing::Config::EchoCanceller3{},
|
||||
DetectOptimization())
|
||||
.GetGain(E2, R2, N2, RenderSignalAnalyzer(), false,
|
||||
std::vector<std::vector<float>>(
|
||||
3, std::vector<float>(kBlockSize, 0.f)),
|
||||
@ -41,7 +42,8 @@ TEST(SuppressionGain, NullOutputGains) {
|
||||
|
||||
// Does a sanity check that the gains are correctly computed.
|
||||
TEST(SuppressionGain, BasicGainComputation) {
|
||||
SuppressionGain suppression_gain(DetectOptimization());
|
||||
SuppressionGain suppression_gain(AudioProcessing::Config::EchoCanceller3(),
|
||||
DetectOptimization());
|
||||
RenderSignalAnalyzer analyzer;
|
||||
float high_bands_gain;
|
||||
std::array<float, kFftLengthBy2Plus1> E2;
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#include <math.h>
|
||||
#include <stddef.h> // size_t
|
||||
#include <stdio.h> // FILE
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/modules/audio_processing/beamformer/array_util.h"
|
||||
@ -267,6 +268,49 @@ class AudioProcessing : public rtc::RefCountInterface {
|
||||
// The functionality is not yet activated in the code and turning this on
|
||||
// does not yet have the desired behavior.
|
||||
struct EchoCanceller3 {
|
||||
struct Param {
|
||||
struct Erle {
|
||||
float min = 1.f;
|
||||
float max_l = 8.f;
|
||||
float max_h = 1.5f;
|
||||
} erle;
|
||||
|
||||
struct EpStrength {
|
||||
float lf = 100.f;
|
||||
float mf = 1000.f;
|
||||
float hf = 5000.f;
|
||||
float default_len = 0.7f;
|
||||
} ep_strength;
|
||||
|
||||
struct Mask {
|
||||
float m1 = 0.01f;
|
||||
float m2 = 0.001f;
|
||||
float m3 = 0.01f;
|
||||
float m4 = 0.1f;
|
||||
} gain_mask;
|
||||
|
||||
struct EchoAudibility {
|
||||
float low_render_limit = 192.f;
|
||||
float normal_render_limit = 64.f;
|
||||
} echo_audibility;
|
||||
|
||||
struct GainUpdates {
|
||||
struct GainChanges {
|
||||
float max_inc;
|
||||
float max_dec;
|
||||
float rate_inc;
|
||||
float rate_dec;
|
||||
float min_inc;
|
||||
float min_dec;
|
||||
};
|
||||
|
||||
GainChanges low_noise = {8.f, 8.f, 2.f, 2.f, 4.f, 4.f};
|
||||
GainChanges normal = {4.f, 4.f, 2.f, 2.f, 1.2f, 2.f};
|
||||
GainChanges saturation = {1.2f, 1.2f, 1.5f, 1.5f, 1.f, 1.f};
|
||||
|
||||
float floor_first_increase = 0.001f;
|
||||
} gain_updates;
|
||||
} param;
|
||||
bool enabled = false;
|
||||
} echo_canceller3;
|
||||
|
||||
@ -277,6 +321,17 @@ class AudioProcessing : public rtc::RefCountInterface {
|
||||
struct GainController2 {
|
||||
bool enabled = false;
|
||||
} gain_controller2;
|
||||
|
||||
// Explicit copy assignment implementation to avoid issues with memory
|
||||
// sanitizer complaints in case of self-assignment.
|
||||
// TODO(peah): Add buildflag to ensure that this is only included for memory
|
||||
// sanitizer builds.
|
||||
Config& operator=(const Config& config) {
|
||||
if (this != &config) {
|
||||
memcpy(this, &config, sizeof(*this));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(mgraczyk): Remove once all methods that use ChannelLayout are gone.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user