AEC3: Added parametrization of the comfort noise floor

Bug: webrtc:8671
Change-Id: I2431b1dd8dbe35fc8742c0640c3b35166e8ef6b7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/171480
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30876}
This commit is contained in:
Per Åhgren
2020-03-25 07:31:47 +01:00
committed by Commit Bot
parent f5bbd1f068
commit a388b75223
8 changed files with 37 additions and 10 deletions

View File

@ -226,6 +226,8 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
res = res & Limit(&c->echo_model.render_pre_window_size, 0, 100);
res = res & Limit(&c->echo_model.render_post_window_size, 0, 100);
res = res & Limit(&c->comfort_noise.noise_floor_dbfs, -200.f, 0.f);
res = res & Limit(&c->suppressor.nearend_average_blocks, 1, 5000);
res = res &

View File

@ -154,6 +154,10 @@ struct RTC_EXPORT EchoCanceller3Config {
size_t render_post_window_size = 1;
} echo_model;
struct ComfortNoise {
float noise_floor_dbfs = -96.03406f;
} comfort_noise;
struct Suppressor {
Suppressor();
Suppressor(const Suppressor& e);

View File

@ -312,6 +312,10 @@ void Aec3ConfigFromJsonString(absl::string_view json_string,
&cfg.echo_model.render_post_window_size);
}
if (rtc::GetValueFromJsonObject(aec3_root, "comfort_noise", &section)) {
ReadParam(section, "noise_floor_dbfs", &cfg.comfort_noise.noise_floor_dbfs);
}
Json::Value subsection;
if (rtc::GetValueFromJsonObject(aec3_root, "suppressor", &section)) {
ReadParam(section, "nearend_average_blocks",
@ -626,6 +630,10 @@ std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) {
<< config.echo_model.render_post_window_size;
ost << "},";
ost << "\"comfort_noise\": {";
ost << "\"noise_floor_dbfs\": " << config.comfort_noise.noise_floor_dbfs;
ost << "},";
ost << "\"suppressor\": {";
ost << "\"nearend_average_blocks\": "
<< config.suppressor.nearend_average_blocks << ",";

View File

@ -23,6 +23,7 @@ TEST(EchoCanceller3JsonHelpers, ToStringAndParseJson) {
cfg.filter.refined.error_floor = 2.f;
cfg.filter.shadow_initial.length_blocks = 7u;
cfg.filter.coarse_initial.length_blocks = 3u;
cfg.comfort_noise.noise_floor_dbfs = 100.f;
cfg.suppressor.normal_tuning.mask_hf.enr_suppress = .5f;
cfg.suppressor.subband_nearend_detection.nearend_average_blocks = 3;
cfg.suppressor.subband_nearend_detection.subband1 = {1, 3};
@ -51,6 +52,8 @@ TEST(EchoCanceller3JsonHelpers, ToStringAndParseJson) {
cfg_transformed.filter.main.error_floor);
EXPECT_EQ(cfg.filter.refined.error_floor,
cfg_transformed.filter.refined.error_floor);
EXPECT_EQ(cfg.comfort_noise.noise_floor_dbfs,
cfg_transformed.comfort_noise.noise_floor_dbfs);
EXPECT_EQ(cfg.suppressor.normal_tuning.mask_hf.enr_suppress,
cfg_transformed.suppressor.normal_tuning.mask_hf.enr_suppress);
EXPECT_EQ(cfg.suppressor.subband_nearend_detection.nearend_average_blocks,

View File

@ -31,6 +31,13 @@ namespace webrtc {
namespace {
// Computes the noise floor value that matches a WGN input of noise_floor_dbfs.
float GetNoiseFloorFactor(float noise_floor_dbfs) {
// kdBfsNormalization = 20.f*log10(32768.f).
constexpr float kdBfsNormalization = 90.30899869919436f;
return 64.f * powf(10.f, (kdBfsNormalization + noise_floor_dbfs) * 0.1f);
}
// Table of sqrt(2) * sin(2*pi*i/32).
constexpr float kSqrt2Sin[32] = {
+0.0000000f, +0.2758994f, +0.5411961f, +0.7856950f, +1.0000000f,
@ -92,11 +99,13 @@ void GenerateComfortNoise(Aec3Optimization optimization,
} // namespace
ComfortNoiseGenerator::ComfortNoiseGenerator(Aec3Optimization optimization,
ComfortNoiseGenerator::ComfortNoiseGenerator(const EchoCanceller3Config& config,
Aec3Optimization optimization,
size_t num_capture_channels)
: optimization_(optimization),
seed_(42),
num_capture_channels_(num_capture_channels),
noise_floor_(GetNoiseFloorFactor(config.comfort_noise.noise_floor_dbfs)),
N2_initial_(
std::make_unique<std::vector<std::array<float, kFftLengthBy2Plus1>>>(
num_capture_channels_)),
@ -153,16 +162,13 @@ void ComfortNoiseGenerator::Compute(
}
}
// Limit the noise to a floor matching a WGN input of -96 dBFS.
constexpr float kNoiseFloor = 17.1267f;
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
for (auto& n : N2_[ch]) {
n = std::max(n, kNoiseFloor);
n = std::max(n, noise_floor_);
}
if (N2_initial_) {
for (auto& n : (*N2_initial_)[ch]) {
n = std::max(n, kNoiseFloor);
n = std::max(n, noise_floor_);
}
}
}

View File

@ -41,7 +41,8 @@ void EstimateComfortNoise(const std::array<float, kFftLengthBy2Plus1>& N2,
// Generates the comfort noise.
class ComfortNoiseGenerator {
public:
ComfortNoiseGenerator(Aec3Optimization optimization,
ComfortNoiseGenerator(const EchoCanceller3Config& config,
Aec3Optimization optimization,
size_t num_capture_channels);
ComfortNoiseGenerator() = delete;
~ComfortNoiseGenerator();
@ -64,6 +65,7 @@ class ComfortNoiseGenerator {
const Aec3Optimization optimization_;
uint32_t seed_;
const size_t num_capture_channels_;
const float noise_floor_;
std::unique_ptr<std::vector<std::array<float, kFftLengthBy2Plus1>>>
N2_initial_;
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2_smoothed_;

View File

@ -13,6 +13,7 @@
#include <algorithm>
#include <numeric>
#include "api/audio/echo_canceller3_config.h"
#include "modules/audio_processing/aec3/aec_state.h"
#include "rtc_base/random.h"
#include "rtc_base/system/arch.h"
@ -33,8 +34,9 @@ float Power(const FftData& N) {
TEST(ComfortNoiseGenerator, CorrectLevel) {
constexpr size_t kNumChannels = 5;
ComfortNoiseGenerator cng(DetectOptimization(), kNumChannels);
AecState aec_state(EchoCanceller3Config{}, kNumChannels);
EchoCanceller3Config config;
ComfortNoiseGenerator cng(config, DetectOptimization(), kNumChannels);
AecState aec_state(config, kNumChannels);
std::vector<std::array<float, kFftLengthBy2Plus1>> N2(kNumChannels);
std::vector<FftData> n_lower(kNumChannels);

View File

@ -200,7 +200,7 @@ EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config,
optimization_,
sample_rate_hz,
num_capture_channels),
cng_(optimization_, num_capture_channels_),
cng_(config_, optimization_, num_capture_channels_),
suppression_filter_(optimization_,
sample_rate_hz_,
num_capture_channels_),