Refactoring of the noise suppressor and adding true multichannel support
This CL adds proper multichannel support to the noise suppressor.
To accomplish that in a safe way, a full refactoring of the noise
suppressor code has been done.
Due to floating point precision, the changes made are not entirely
bitexact. They are, however, very close to being bitexact.
As a safety measure, the former noise suppressor code is preserved
and a kill-switch is added to allow revering to the legacy noise
suppressor in case issues arise.
Bug: webrtc:10895, b/143344262
Change-Id: I0b071011b23265ac12e6d4b3956499d122286657
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158407
Commit-Queue: Per Åhgren <peah@webrtc.org>
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29646}
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index f9e7bce..4573aed 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -70,6 +70,11 @@
sample_rate_hz == AudioProcessing::kSampleRate48kHz;
}
+// Checks whether the legacy ns functionality should be enforced.
+bool DetectLegacyNsEnforcement() {
+ return field_trial::IsEnabled("WebRTC-NewNoiseSuppressionKillSwitch");
+}
+
// Identify the native processing rate that best handles a sample rate.
int SuitableProcessRate(int minimum_rate,
int max_splitting_rate,
@@ -306,6 +311,7 @@
std::unique_ptr<CustomAudioAnalyzer> capture_analyzer)
: data_dumper_(
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+ enforced_usage_of_legacy_ns_(DetectLegacyNsEnforcement()),
capture_runtime_settings_(kRuntimeSettingQueueSize),
render_runtime_settings_(kRuntimeSettingQueueSize),
capture_runtime_settings_enqueuer_(&capture_runtime_settings_),
@@ -1303,9 +1309,14 @@
if (submodules_.high_pass_filter) {
submodules_.high_pass_filter->Process(capture_buffer);
}
+
RETURN_ON_ERR(submodules_.gain_control->AnalyzeCaptureAudio(capture_buffer));
+ RTC_DCHECK(
+ !(submodules_.legacy_noise_suppressor && submodules_.noise_suppressor));
if (submodules_.noise_suppressor) {
- submodules_.noise_suppressor->AnalyzeCaptureAudio(capture_buffer);
+ submodules_.noise_suppressor->Analyze(*capture_buffer);
+ } else if (submodules_.legacy_noise_suppressor) {
+ submodules_.legacy_noise_suppressor->AnalyzeCaptureAudio(capture_buffer);
}
if (submodules_.echo_control_mobile) {
@@ -1316,8 +1327,10 @@
}
if (submodules_.noise_suppressor) {
+ submodules_.noise_suppressor->Process(capture_buffer);
+ } else if (submodules_.legacy_noise_suppressor) {
submodules_.echo_control_mobile->CopyLowPassReference(capture_buffer);
- submodules_.noise_suppressor->ProcessCaptureAudio(capture_buffer);
+ submodules_.legacy_noise_suppressor->ProcessCaptureAudio(capture_buffer);
}
RETURN_ON_ERR(submodules_.echo_control_mobile->ProcessCaptureAudio(
@@ -1344,7 +1357,9 @@
}
if (submodules_.noise_suppressor) {
- submodules_.noise_suppressor->ProcessCaptureAudio(capture_buffer);
+ submodules_.noise_suppressor->Process(capture_buffer);
+ } else if (submodules_.legacy_noise_suppressor) {
+ submodules_.legacy_noise_suppressor->ProcessCaptureAudio(capture_buffer);
}
}
@@ -1726,9 +1741,9 @@
return submodule_states_.Update(
config_.high_pass_filter.enabled, !!submodules_.echo_cancellation,
!!submodules_.echo_control_mobile, config_.residual_echo_detector.enabled,
- !!submodules_.noise_suppressor, submodules_.gain_control->is_enabled(),
- config_.gain_controller2.enabled, config_.pre_amplifier.enabled,
- capture_nonlocked_.echo_controller_enabled,
+ !!submodules_.legacy_noise_suppressor || !!submodules_.noise_suppressor,
+ submodules_.gain_control->is_enabled(), config_.gain_controller2.enabled,
+ config_.pre_amplifier.enabled, capture_nonlocked_.echo_controller_enabled,
config_.voice_detection.enabled, capture_.transient_suppressor_enabled);
}
@@ -1868,13 +1883,42 @@
}
void AudioProcessingImpl::InitializeNoiseSuppressor() {
+ submodules_.legacy_noise_suppressor.reset();
+ submodules_.noise_suppressor.reset();
+
if (config_.noise_suppression.enabled) {
- auto ns_level =
- NsConfigLevelToInterfaceLevel(config_.noise_suppression.level);
- submodules_.noise_suppressor = std::make_unique<NoiseSuppression>(
- num_proc_channels(), proc_sample_rate_hz(), ns_level);
- } else {
- submodules_.noise_suppressor.reset();
+ const bool use_legacy_ns =
+ config_.noise_suppression.use_legacy_ns || enforced_usage_of_legacy_ns_;
+
+ if (!use_legacy_ns) {
+ auto map_level =
+ [](AudioProcessing::Config::NoiseSuppression::Level level) {
+ using NoiseSuppresionConfig =
+ AudioProcessing::Config::NoiseSuppression;
+ switch (level) {
+ case NoiseSuppresionConfig::kLow:
+ return NsConfig::SuppressionLevel::k6dB;
+ case NoiseSuppresionConfig::kModerate:
+ return NsConfig::SuppressionLevel::k12dB;
+ case NoiseSuppresionConfig::kHigh:
+ return NsConfig::SuppressionLevel::k18dB;
+ case NoiseSuppresionConfig::kVeryHigh:
+ return NsConfig::SuppressionLevel::k21dB;
+ default:
+ RTC_NOTREACHED();
+ }
+ };
+
+ NsConfig cfg;
+ cfg.target_level = map_level(config_.noise_suppression.level);
+ submodules_.noise_suppressor = std::make_unique<NoiseSuppressor>(
+ cfg, proc_sample_rate_hz(), num_proc_channels());
+ } else {
+ auto ns_level =
+ NsConfigLevelToInterfaceLevel(config_.noise_suppression.level);
+ submodules_.legacy_noise_suppressor = std::make_unique<NoiseSuppression>(
+ num_proc_channels(), proc_sample_rate_hz(), ns_level);
+ }
}
}