From 8271d04009bbddbda35e12c7645185cea50a6312 Mon Sep 17 00:00:00 2001 From: peah Date: Tue, 22 Nov 2016 07:24:52 -0800 Subject: [PATCH] This CL introduces the new functionality for setting the APM parameters to the high-pass filter. The introduction will be done in three steps: 1) This CL which introduces the new scheme and changes the code in webrtcvoiceengine.cc to use it. 2) Introduce the scheme into upstream code. 3) Remove the HighPassFilter interface in APM. BUG=webrtc::6220, webrtc::6296, webrtc::6297, webrtc::6181, webrtc::5298 Review-Url: https://codereview.webrtc.org/2415403002 Cr-Commit-Position: refs/heads/master@{#15197} --- webrtc/media/engine/webrtcvoiceengine.cc | 12 +-- webrtc/media/engine/webrtcvoiceengine.h | 4 + .../engine/webrtcvoiceengine_unittest.cc | 21 +++-- webrtc/modules/BUILD.gn | 2 +- webrtc/modules/audio_processing/BUILD.gn | 4 +- .../audio_processing/audio_processing_impl.cc | 81 +++++++++++++++---- .../audio_processing/audio_processing_impl.h | 14 +++- .../audio_processing_unittest.cc | 14 ++-- .../audio_processing/high_pass_filter_impl.h | 47 ----------- .../include/audio_processing.h | 11 ++- .../level_controller_complexity_unittest.cc | 3 +- ..._pass_filter_impl.cc => low_cut_filter.cc} | 66 ++++----------- .../modules/audio_processing/low_cut_filter.h | 36 +++++++++ ...unittest.cc => low_cut_filter_unittest.cc} | 30 +++---- .../test/aec_dump_based_simulator.cc | 3 +- .../test/audio_processing_simulator.cc | 8 +- .../test/debug_dump_replayer.cc | 7 +- 17 files changed, 191 insertions(+), 172 deletions(-) delete mode 100644 webrtc/modules/audio_processing/high_pass_filter_impl.h rename webrtc/modules/audio_processing/{high_pass_filter_impl.cc => low_cut_filter.cc} (63%) create mode 100644 webrtc/modules/audio_processing/low_cut_filter.h rename webrtc/modules/audio_processing/{high_pass_filter_unittest.cc => low_cut_filter_unittest.cc} (98%) diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc index 1f88cb7245..96f9ed70d4 100644 --- a/webrtc/media/engine/webrtcvoiceengine.cc +++ b/webrtc/media/engine/webrtcvoiceengine.cc @@ -825,14 +825,6 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { } } - if (options.highpass_filter) { - LOG(LS_INFO) << "High pass filter enabled? " << *options.highpass_filter; - if (voep->EnableHighPassFilter(*options.highpass_filter) == -1) { - LOG_RTCERR1(SetHighpassFilterStatus, *options.highpass_filter); - return false; - } - } - if (options.stereo_swapping) { LOG(LS_INFO) << "Stereo swapping enabled? " << *options.stereo_swapping; voep->EnableStereoChannelSwapping(*options.stereo_swapping); @@ -920,6 +912,10 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) { } } + if (options.highpass_filter) { + apm_config_.high_pass_filter.enabled = *options.highpass_filter; + } + apm()->SetExtraOptions(config); apm()->ApplyConfig(apm_config_); diff --git a/webrtc/media/engine/webrtcvoiceengine.h b/webrtc/media/engine/webrtcvoiceengine.h index efb7120201..03b493744b 100644 --- a/webrtc/media/engine/webrtcvoiceengine.h +++ b/webrtc/media/engine/webrtcvoiceengine.h @@ -89,6 +89,10 @@ class WebRtcVoiceEngine final : public webrtc::TraceCallback { // Stops AEC dump. void StopAecDump(); + const webrtc::AudioProcessing::Config& GetApmConfigForTest() const { + return apm_config_; + } + private: // Every option that is "set" will be applied. Every option not "set" will be // ignored. This allows us to selectively turn on and off different options diff --git a/webrtc/media/engine/webrtcvoiceengine_unittest.cc b/webrtc/media/engine/webrtcvoiceengine_unittest.cc index e4e4cf1b12..674924eda8 100644 --- a/webrtc/media/engine/webrtcvoiceengine_unittest.cc +++ b/webrtc/media/engine/webrtcvoiceengine_unittest.cc @@ -571,6 +571,10 @@ class WebRtcVoiceEngineTestFake : public testing::Test { } } + bool IsHighPassFilterEnabled() { + return engine_->GetApmConfigForTest().high_pass_filter.enabled; + } + protected: StrictMock adm_; StrictMock apm_; @@ -2793,7 +2797,6 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) { webrtc::AgcConfig agc_config; bool ns_enabled; webrtc::NsModes ns_mode; - bool highpass_filter_enabled; bool stereo_swapping_enabled; bool typing_detection_enabled; voe_.GetEcStatus(ec_enabled, ec_mode); @@ -2801,7 +2804,6 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) { voe_.GetAgcStatus(agc_enabled, agc_mode); voe_.GetAgcConfig(agc_config); voe_.GetNsStatus(ns_enabled, ns_mode); - highpass_filter_enabled = voe_.IsHighPassFilterEnabled(); stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled(); voe_.GetTypingDetectionStatus(typing_detection_enabled); EXPECT_TRUE(ec_enabled); @@ -2810,7 +2812,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) { EXPECT_TRUE(agc_enabled); EXPECT_EQ(0, agc_config.targetLeveldBOv); EXPECT_TRUE(ns_enabled); - EXPECT_TRUE(highpass_filter_enabled); + EXPECT_TRUE(IsHighPassFilterEnabled()); EXPECT_FALSE(stereo_swapping_enabled); EXPECT_TRUE(typing_detection_enabled); EXPECT_EQ(ec_mode, webrtc::kEcConference); @@ -2826,7 +2828,6 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) { voe_.GetAgcStatus(agc_enabled, agc_mode); voe_.GetAgcConfig(agc_config); voe_.GetNsStatus(ns_enabled, ns_mode); - highpass_filter_enabled = voe_.IsHighPassFilterEnabled(); stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled(); voe_.GetTypingDetectionStatus(typing_detection_enabled); EXPECT_TRUE(ec_enabled); @@ -2835,7 +2836,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) { EXPECT_TRUE(agc_enabled); EXPECT_EQ(0, agc_config.targetLeveldBOv); EXPECT_TRUE(ns_enabled); - EXPECT_TRUE(highpass_filter_enabled); + EXPECT_TRUE(IsHighPassFilterEnabled()); EXPECT_FALSE(stereo_swapping_enabled); EXPECT_TRUE(typing_detection_enabled); EXPECT_EQ(ec_mode, webrtc::kEcConference); @@ -2858,7 +2859,6 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) { voe_.GetAgcStatus(agc_enabled, agc_mode); voe_.GetAgcConfig(agc_config); voe_.GetNsStatus(ns_enabled, ns_mode); - highpass_filter_enabled = voe_.IsHighPassFilterEnabled(); stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled(); voe_.GetTypingDetectionStatus(typing_detection_enabled); EXPECT_TRUE(ec_enabled); @@ -2866,7 +2866,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) { EXPECT_TRUE(agc_enabled); EXPECT_EQ(0, agc_config.targetLeveldBOv); EXPECT_TRUE(ns_enabled); - EXPECT_TRUE(highpass_filter_enabled); + EXPECT_TRUE(IsHighPassFilterEnabled()); EXPECT_FALSE(stereo_swapping_enabled); EXPECT_TRUE(typing_detection_enabled); EXPECT_EQ(ec_mode, webrtc::kEcConference); @@ -2919,11 +2919,10 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) { send_parameters_.options.stereo_swapping = rtc::Optional(true); SetSendParameters(send_parameters_); voe_.GetNsStatus(ns_enabled, ns_mode); - highpass_filter_enabled = voe_.IsHighPassFilterEnabled(); stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled(); voe_.GetTypingDetectionStatus(typing_detection_enabled); EXPECT_FALSE(ns_enabled); - EXPECT_FALSE(highpass_filter_enabled); + EXPECT_FALSE(IsHighPassFilterEnabled()); EXPECT_FALSE(typing_detection_enabled); EXPECT_TRUE(stereo_swapping_enabled); @@ -2946,20 +2945,18 @@ TEST_F(WebRtcVoiceEngineTestFake, DefaultOptions) { webrtc::AgcModes agc_mode; bool ns_enabled; webrtc::NsModes ns_mode; - bool highpass_filter_enabled; bool stereo_swapping_enabled; bool typing_detection_enabled; voe_.GetEcStatus(ec_enabled, ec_mode); voe_.GetAgcStatus(agc_enabled, agc_mode); voe_.GetNsStatus(ns_enabled, ns_mode); - highpass_filter_enabled = voe_.IsHighPassFilterEnabled(); stereo_swapping_enabled = voe_.IsStereoChannelSwappingEnabled(); voe_.GetTypingDetectionStatus(typing_detection_enabled); EXPECT_TRUE(ec_enabled); EXPECT_TRUE(agc_enabled); EXPECT_TRUE(ns_enabled); - EXPECT_TRUE(highpass_filter_enabled); + EXPECT_TRUE(IsHighPassFilterEnabled()); EXPECT_TRUE(typing_detection_enabled); EXPECT_FALSE(stereo_swapping_enabled); } diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index 042b38e4bd..a2861dd0ee 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -600,9 +600,9 @@ if (rtc_include_tests) { "audio_processing/echo_detector/mean_variance_estimator_unittest.cc", "audio_processing/echo_detector/normalized_covariance_estimator_unittest.cc", "audio_processing/gain_control_unittest.cc", - "audio_processing/high_pass_filter_unittest.cc", "audio_processing/level_controller/level_controller_unittest.cc", "audio_processing/level_estimator_unittest.cc", + "audio_processing/low_cut_filter_unittest.cc", "audio_processing/noise_suppression_unittest.cc", "audio_processing/residual_echo_detector_unittest.cc", "audio_processing/test/bitexactness_tools.cc", diff --git a/webrtc/modules/audio_processing/BUILD.gn b/webrtc/modules/audio_processing/BUILD.gn index b187db2ecd..f810d47583 100644 --- a/webrtc/modules/audio_processing/BUILD.gn +++ b/webrtc/modules/audio_processing/BUILD.gn @@ -71,8 +71,6 @@ rtc_static_library("audio_processing") { "gain_control_for_experimental_agc.h", "gain_control_impl.cc", "gain_control_impl.h", - "high_pass_filter_impl.cc", - "high_pass_filter_impl.h", "include/audio_processing.cc", "include/audio_processing.h", "include/config.cc", @@ -102,6 +100,8 @@ rtc_static_library("audio_processing") { "level_estimator_impl.h", "logging/apm_data_dumper.cc", "logging/apm_data_dumper.h", + "low_cut_filter.cc", + "low_cut_filter.h", "noise_suppression_impl.cc", "noise_suppression_impl.h", "render_queue_item_verifier.h", diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc index 80787794fd..39c79cdf5c 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.cc +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc @@ -28,12 +28,12 @@ #include "webrtc/modules/audio_processing/echo_control_mobile_impl.h" #include "webrtc/modules/audio_processing/gain_control_for_experimental_agc.h" #include "webrtc/modules/audio_processing/gain_control_impl.h" -#include "webrtc/modules/audio_processing/high_pass_filter_impl.h" #if WEBRTC_INTELLIGIBILITY_ENHANCER #include "webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h" #endif #include "webrtc/modules/audio_processing/level_controller/level_controller.h" #include "webrtc/modules/audio_processing/level_estimator_impl.h" +#include "webrtc/modules/audio_processing/low_cut_filter.h" #include "webrtc/modules/audio_processing/noise_suppression_impl.h" #include "webrtc/modules/audio_processing/residual_echo_detector.h" #include "webrtc/modules/audio_processing/transient/transient_suppressor.h" @@ -127,6 +127,29 @@ static const size_t kMaxAllowedValuesOfSamplesPerFrame = 160; // reverse and forward call numbers. static const size_t kMaxNumFramesToBuffer = 100; +class HighPassFilterImpl : public HighPassFilter { + public: + explicit HighPassFilterImpl(AudioProcessingImpl* apm) : apm_(apm) {} + ~HighPassFilterImpl() override = default; + + // HighPassFilter implementation. + int Enable(bool enable) override { + apm_->MutateConfig([enable](AudioProcessing::Config* config) { + config->high_pass_filter.enabled = enable; + }); + + return AudioProcessing::kNoError; + } + + bool is_enabled() const override { + return apm_->GetConfig().high_pass_filter.enabled; + } + + private: + AudioProcessingImpl* apm_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(HighPassFilterImpl); +}; + } // namespace // Throughout webrtc, it's assumed that success is represented by zero. @@ -135,7 +158,7 @@ static_assert(AudioProcessing::kNoError == 0, "kNoError must be zero"); AudioProcessingImpl::ApmSubmoduleStates::ApmSubmoduleStates() {} bool AudioProcessingImpl::ApmSubmoduleStates::Update( - bool high_pass_filter_enabled, + bool low_cut_filter_enabled, bool echo_canceller_enabled, bool mobile_echo_controller_enabled, bool residual_echo_detector_enabled, @@ -148,7 +171,7 @@ bool AudioProcessingImpl::ApmSubmoduleStates::Update( bool level_estimator_enabled, bool transient_suppressor_enabled) { bool changed = false; - changed |= (high_pass_filter_enabled != high_pass_filter_enabled_); + changed |= (low_cut_filter_enabled != low_cut_filter_enabled_); changed |= (echo_canceller_enabled != echo_canceller_enabled_); changed |= (mobile_echo_controller_enabled != mobile_echo_controller_enabled_); @@ -166,7 +189,7 @@ bool AudioProcessingImpl::ApmSubmoduleStates::Update( (voice_activity_detector_enabled != voice_activity_detector_enabled_); changed |= (transient_suppressor_enabled != transient_suppressor_enabled_); if (changed) { - high_pass_filter_enabled_ = high_pass_filter_enabled; + low_cut_filter_enabled_ = low_cut_filter_enabled; echo_canceller_enabled_ = echo_canceller_enabled; mobile_echo_controller_enabled_ = mobile_echo_controller_enabled; residual_echo_detector_enabled_ = residual_echo_detector_enabled; @@ -199,7 +222,7 @@ bool AudioProcessingImpl::ApmSubmoduleStates::CaptureMultiBandSubModulesActive() bool AudioProcessingImpl::ApmSubmoduleStates::CaptureMultiBandProcessingActive() const { - return high_pass_filter_enabled_ || echo_canceller_enabled_ || + return low_cut_filter_enabled_ || echo_canceller_enabled_ || mobile_echo_controller_enabled_ || noise_suppressor_enabled_ || beamformer_enabled_ || adaptive_gain_controller_enabled_; } @@ -226,7 +249,6 @@ struct AudioProcessingImpl::ApmPublicSubmodules { std::unique_ptr echo_cancellation; std::unique_ptr echo_control_mobile; std::unique_ptr gain_control; - std::unique_ptr high_pass_filter; std::unique_ptr level_estimator; std::unique_ptr noise_suppression; std::unique_ptr voice_detection; @@ -246,6 +268,7 @@ struct AudioProcessingImpl::ApmPrivateSubmodules { // Accessed internally from capture or during initialization std::unique_ptr beamformer; std::unique_ptr agc_manager; + std::unique_ptr low_cut_filter; std::unique_ptr level_controller; std::unique_ptr residual_echo_detector; }; @@ -275,7 +298,8 @@ AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config) AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config, NonlinearBeamformer* beamformer) - : public_submodules_(new ApmPublicSubmodules()), + : high_pass_filter_impl_(new HighPassFilterImpl(this)), + public_submodules_(new ApmPublicSubmodules()), private_submodules_(new ApmPrivateSubmodules(beamformer)), constants_(config.Get().startup_min_volume, #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) @@ -302,8 +326,6 @@ AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config, new EchoControlMobileImpl(&crit_render_, &crit_capture_)); public_submodules_->gain_control.reset( new GainControlImpl(&crit_capture_, &crit_capture_)); - public_submodules_->high_pass_filter.reset( - new HighPassFilterImpl(&crit_capture_)); public_submodules_->level_estimator.reset( new LevelEstimatorImpl(&crit_capture_)); public_submodules_->noise_suppression.reset( @@ -478,8 +500,7 @@ int AudioProcessingImpl::InitializeLocked() { #if WEBRTC_INTELLIGIBILITY_ENHANCER InitializeIntelligibility(); #endif - public_submodules_->high_pass_filter->Initialize(num_proc_channels(), - proc_sample_rate_hz()); + InitializeLowCutFilter(); public_submodules_->noise_suppression->Initialize(num_proc_channels(), proc_sample_rate_hz()); public_submodules_->voice_detection->Initialize(proc_split_sample_rate_hz()); @@ -602,6 +623,11 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) { << capture_nonlocked_.level_controller_enabled; private_submodules_->level_controller->ApplyConfig(config_.level_controller); + + InitializeLowCutFilter(); + + LOG(LS_INFO) << "Highpass filter activated: " + << config_.high_pass_filter.enabled; } void AudioProcessingImpl::SetExtraOptions(const webrtc::Config& config) { @@ -1089,7 +1115,9 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() { capture_buffer->set_num_channels(1); } - public_submodules_->high_pass_filter->ProcessCaptureAudio(capture_buffer); + if (private_submodules_->low_cut_filter) { + private_submodules_->low_cut_filter->Process(capture_buffer); + } RETURN_ON_ERR( public_submodules_->gain_control->AnalyzeCaptureAudio(capture_buffer)); public_submodules_->noise_suppression->AnalyzeCaptureAudio(capture_buffer); @@ -1523,7 +1551,7 @@ GainControl* AudioProcessingImpl::gain_control() const { } HighPassFilter* AudioProcessingImpl::high_pass_filter() const { - return public_submodules_->high_pass_filter.get(); + return high_pass_filter_impl_.get(); } LevelEstimator* AudioProcessingImpl::level_estimator() const { @@ -1538,9 +1566,23 @@ VoiceDetection* AudioProcessingImpl::voice_detection() const { return public_submodules_->voice_detection.get(); } +void AudioProcessingImpl::MutateConfig( + rtc::FunctionView mutator) { + rtc::CritScope cs_render(&crit_render_); + rtc::CritScope cs_capture(&crit_capture_); + mutator(&config_); + ApplyConfig(config_); +} + +AudioProcessing::Config AudioProcessingImpl::GetConfig() const { + rtc::CritScope cs_render(&crit_render_); + rtc::CritScope cs_capture(&crit_capture_); + return config_; +} + bool AudioProcessingImpl::UpdateActiveSubmoduleStates() { return submodule_states_.Update( - public_submodules_->high_pass_filter->is_enabled(), + config_.high_pass_filter.enabled, public_submodules_->echo_cancellation->is_enabled(), public_submodules_->echo_control_mobile->is_enabled(), config_.residual_echo_detector.enabled, @@ -1589,6 +1631,15 @@ void AudioProcessingImpl::InitializeIntelligibility() { #endif } +void AudioProcessingImpl::InitializeLowCutFilter() { + if (config_.high_pass_filter.enabled) { + private_submodules_->low_cut_filter.reset( + new LowCutFilter(num_proc_channels(), proc_sample_rate_hz())); + } else { + private_submodules_->low_cut_filter.reset(); + } +} + void AudioProcessingImpl::InitializeLevelController() { private_submodules_->level_controller->Initialize(proc_sample_rate_hz()); } @@ -1772,7 +1823,7 @@ int AudioProcessingImpl::WriteConfigMessage(bool forced) { public_submodules_->gain_control->is_limiter_enabled()); config.set_noise_robust_agc_enabled(constants_.use_experimental_agc); - config.set_hpf_enabled(public_submodules_->high_pass_filter->is_enabled()); + config.set_hpf_enabled(config_.high_pass_filter.enabled); config.set_ns_enabled(public_submodules_->noise_suppression->is_enabled()); config.set_ns_level( diff --git a/webrtc/modules/audio_processing/audio_processing_impl.h b/webrtc/modules/audio_processing/audio_processing_impl.h index 5ab32ec8d1..d171715a96 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.h +++ b/webrtc/modules/audio_processing/audio_processing_impl.h @@ -17,6 +17,7 @@ #include #include "webrtc/base/criticalsection.h" +#include "webrtc/base/function_view.h" #include "webrtc/base/gtest_prod_util.h" #include "webrtc/base/ignore_wundef.h" #include "webrtc/base/swap_queue.h" @@ -126,11 +127,16 @@ class AudioProcessingImpl : public AudioProcessing { EchoCancellation* echo_cancellation() const override; EchoControlMobile* echo_control_mobile() const override; GainControl* gain_control() const override; + // TODO(peah): Deprecate this API call. HighPassFilter* high_pass_filter() const override; LevelEstimator* level_estimator() const override; NoiseSuppression* noise_suppression() const override; VoiceDetection* voice_detection() const override; + // TODO(peah): Remove these two methods once the new API allows that. + void MutateConfig(rtc::FunctionView mutator); + AudioProcessing::Config GetConfig() const; + protected: // Overridden in a mock. virtual int InitializeLocked() @@ -145,11 +151,14 @@ class AudioProcessingImpl : public AudioProcessing { struct ApmPublicSubmodules; struct ApmPrivateSubmodules; + // Submodule interface implementations. + std::unique_ptr high_pass_filter_impl_; + class ApmSubmoduleStates { public: ApmSubmoduleStates(); // Updates the submodule state and returns true if it has changed. - bool Update(bool high_pass_filter_enabled, + bool Update(bool low_cut_filter_enabled, bool echo_canceller_enabled, bool mobile_echo_controller_enabled, bool residual_echo_detector_enabled, @@ -167,7 +176,7 @@ class AudioProcessingImpl : public AudioProcessing { bool RenderMultiBandProcessingActive() const; private: - bool high_pass_filter_enabled_ = false; + bool low_cut_filter_enabled_ = false; bool echo_canceller_enabled_ = false; bool mobile_echo_controller_enabled_ = false; bool residual_echo_detector_enabled_ = false; @@ -240,6 +249,7 @@ class AudioProcessingImpl : public AudioProcessing { void InitializeLevelController() EXCLUSIVE_LOCKS_REQUIRED(crit_capture_); void InitializeResidualEchoDetector() EXCLUSIVE_LOCKS_REQUIRED(crit_render_, crit_capture_); + void InitializeLowCutFilter() EXCLUSIVE_LOCKS_REQUIRED(crit_capture_); void EmptyQueuedRenderAudio(); void AllocateRenderQueue() diff --git a/webrtc/modules/audio_processing/audio_processing_unittest.cc b/webrtc/modules/audio_processing/audio_processing_unittest.cc index 139aa9daaf..c5f01f96fb 100644 --- a/webrtc/modules/audio_processing/audio_processing_unittest.cc +++ b/webrtc/modules/audio_processing/audio_processing_unittest.cc @@ -185,7 +185,10 @@ void EnableAllAPComponents(AudioProcessing* ap) { EXPECT_NOERR(ap->gain_control()->Enable(true)); #endif - EXPECT_NOERR(ap->high_pass_filter()->Enable(true)); + AudioProcessing::Config apm_config; + apm_config.high_pass_filter.enabled = true; + ap->ApplyConfig(apm_config); + EXPECT_NOERR(ap->level_estimator()->Enable(true)); EXPECT_NOERR(ap->noise_suppression()->Enable(true)); @@ -1391,10 +1394,11 @@ TEST_F(ApmTest, NoiseSuppression) { TEST_F(ApmTest, HighPassFilter) { // Turn HP filter on/off - EXPECT_EQ(apm_->kNoError, apm_->high_pass_filter()->Enable(true)); - EXPECT_TRUE(apm_->high_pass_filter()->is_enabled()); - EXPECT_EQ(apm_->kNoError, apm_->high_pass_filter()->Enable(false)); - EXPECT_FALSE(apm_->high_pass_filter()->is_enabled()); + AudioProcessing::Config apm_config; + apm_config.high_pass_filter.enabled = true; + apm_->ApplyConfig(apm_config); + apm_config.high_pass_filter.enabled = false; + apm_->ApplyConfig(apm_config); } TEST_F(ApmTest, LevelEstimator) { diff --git a/webrtc/modules/audio_processing/high_pass_filter_impl.h b/webrtc/modules/audio_processing/high_pass_filter_impl.h deleted file mode 100644 index 5cb18f12d0..0000000000 --- a/webrtc/modules/audio_processing/high_pass_filter_impl.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_IMPL_H_ -#define WEBRTC_MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_IMPL_H_ - -#include -#include - -#include "webrtc/base/constructormagic.h" -#include "webrtc/base/criticalsection.h" -#include "webrtc/modules/audio_processing/include/audio_processing.h" - -namespace webrtc { - -class AudioBuffer; - -class HighPassFilterImpl : public HighPassFilter { - public: - explicit HighPassFilterImpl(rtc::CriticalSection* crit); - ~HighPassFilterImpl() override; - - // TODO(peah): Fold into ctor, once public API is removed. - void Initialize(size_t channels, int sample_rate_hz); - void ProcessCaptureAudio(AudioBuffer* audio); - - // HighPassFilter implementation. - int Enable(bool enable) override; - bool is_enabled() const override; - - private: - class BiquadFilter; - rtc::CriticalSection* const crit_ = nullptr; - bool enabled_ GUARDED_BY(crit_) = false; - std::vector> filters_ GUARDED_BY(crit_); - RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(HighPassFilterImpl); -}; -} // namespace webrtc - -#endif // WEBRTC_MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_IMPL_H_ diff --git a/webrtc/modules/audio_processing/include/audio_processing.h b/webrtc/modules/audio_processing/include/audio_processing.h index 2c0f554607..d3ae3e8a6a 100644 --- a/webrtc/modules/audio_processing/include/audio_processing.h +++ b/webrtc/modules/audio_processing/include/audio_processing.h @@ -199,10 +199,9 @@ struct Intelligibility { // // AudioProcessing::Config config; // config.level_controller.enabled = true; +// config.high_pass_filter.enabled = true; // apm->ApplyConfig(config) // -// apm->high_pass_filter()->Enable(true); -// // apm->echo_cancellation()->enable_drift_compensation(false); // apm->echo_cancellation()->Enable(true); // @@ -265,6 +264,10 @@ class AudioProcessing { bool enabled = true; #endif } residual_echo_detector; + + struct HighPassFilter { + bool enabled = false; + } high_pass_filter; }; // TODO(mgraczyk): Remove once all methods that use ChannelLayout are gone. @@ -554,6 +557,7 @@ class AudioProcessing { virtual EchoCancellation* echo_cancellation() const = 0; virtual EchoControlMobile* echo_control_mobile() const = 0; virtual GainControl* gain_control() const = 0; + // TODO(peah): Deprecate this API call. virtual HighPassFilter* high_pass_filter() const = 0; virtual LevelEstimator* level_estimator() const = 0; virtual NoiseSuppression* noise_suppression() const = 0; @@ -960,7 +964,7 @@ class GainControl { protected: virtual ~GainControl() {} }; - +// TODO(peah): Remove this interface. // A filtering component which removes DC offset and low-frequency noise. // Recommended to be enabled on the client-side. class HighPassFilter { @@ -968,7 +972,6 @@ class HighPassFilter { virtual int Enable(bool enable) = 0; virtual bool is_enabled() const = 0; - protected: virtual ~HighPassFilter() {} }; diff --git a/webrtc/modules/audio_processing/level_controller/level_controller_complexity_unittest.cc b/webrtc/modules/audio_processing/level_controller/level_controller_complexity_unittest.cc index 5f321cee8a..49e7568418 100644 --- a/webrtc/modules/audio_processing/level_controller/level_controller_complexity_unittest.cc +++ b/webrtc/modules/audio_processing/level_controller/level_controller_complexity_unittest.cc @@ -225,8 +225,7 @@ void RunTogetherWithApm(std::string test_description, ASSERT_EQ(AudioProcessing::kNoError, apm->echo_control_mobile()->Enable(false)); } - ASSERT_EQ(AudioProcessing::kNoError, - apm->high_pass_filter()->Enable(include_default_apm_processing)); + apm_config.high_pass_filter.enabled = include_default_apm_processing; ASSERT_EQ(AudioProcessing::kNoError, apm->noise_suppression()->Enable(include_default_apm_processing)); ASSERT_EQ(AudioProcessing::kNoError, diff --git a/webrtc/modules/audio_processing/high_pass_filter_impl.cc b/webrtc/modules/audio_processing/low_cut_filter.cc similarity index 63% rename from webrtc/modules/audio_processing/high_pass_filter_impl.cc rename to webrtc/modules/audio_processing/low_cut_filter.cc index d33ec78dcb..77dab9af43 100644 --- a/webrtc/modules/audio_processing/high_pass_filter_impl.cc +++ b/webrtc/modules/audio_processing/low_cut_filter.cc @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/modules/audio_processing/high_pass_filter_impl.h" +#include "webrtc/modules/audio_processing/low_cut_filter.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_processing/audio_buffer.h" @@ -20,16 +20,12 @@ const int16_t kFilterCoefficients8kHz[5] = {3798, -7596, 3798, 7807, -3733}; const int16_t kFilterCoefficients[5] = {4012, -8024, 4012, 8002, -3913}; } // namespace -class HighPassFilterImpl::BiquadFilter { +class LowCutFilter::BiquadFilter { public: - explicit BiquadFilter(int sample_rate_hz) : - ba_(sample_rate_hz == AudioProcessing::kSampleRate8kHz ? - kFilterCoefficients8kHz : kFilterCoefficients) - { - Reset(); - } - - void Reset() { + explicit BiquadFilter(int sample_rate_hz) + : ba_(sample_rate_hz == AudioProcessing::kSampleRate8kHz + ? kFilterCoefficients8kHz + : kFilterCoefficients) { std::memset(x_, 0, sizeof(x_)); std::memset(y_, 0, sizeof(y_)); } @@ -44,11 +40,11 @@ class HighPassFilterImpl::BiquadFilter { // y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2] // + -a[1] * y[i-1] + -a[2] * y[i-2]; - tmp_int32 = y[1] * ba[3]; // -a[1] * y[i-1] (low part) - tmp_int32 += y[3] * ba[4]; // -a[2] * y[i-2] (low part) + tmp_int32 = y[1] * ba[3]; // -a[1] * y[i-1] (low part) + tmp_int32 += y[3] * ba[4]; // -a[2] * y[i-2] (low part) tmp_int32 = (tmp_int32 >> 15); - tmp_int32 += y[0] * ba[3]; // -a[1] * y[i-1] (high part) - tmp_int32 += y[2] * ba[4]; // -a[2] * y[i-2] (high part) + tmp_int32 += y[0] * ba[3]; // -a[1] * y[i-1] (high part) + tmp_int32 += y[2] * ba[4]; // -a[2] * y[i-2] (high part) tmp_int32 = (tmp_int32 << 1); tmp_int32 += data[i] * ba[0]; // b[0] * x[0] @@ -70,8 +66,7 @@ class HighPassFilterImpl::BiquadFilter { tmp_int32 += 2048; // Saturate (to 2^27) so that the HP filtered signal does not overflow. - tmp_int32 = WEBRTC_SPL_SAT(static_cast(134217727), - tmp_int32, + tmp_int32 = WEBRTC_SPL_SAT(static_cast(134217727), tmp_int32, static_cast(-134217728)); // Convert back to Q0 and use rounding. @@ -85,29 +80,17 @@ class HighPassFilterImpl::BiquadFilter { int16_t y_[4]; }; -HighPassFilterImpl::HighPassFilterImpl(rtc::CriticalSection* crit) - : crit_(crit) { - RTC_DCHECK(crit_); -} - -HighPassFilterImpl::~HighPassFilterImpl() {} - -void HighPassFilterImpl::Initialize(size_t channels, int sample_rate_hz) { - std::vector> new_filters(channels); +LowCutFilter::LowCutFilter(size_t channels, int sample_rate_hz) { + filters_.resize(channels); for (size_t i = 0; i < channels; i++) { - new_filters[i].reset(new BiquadFilter(sample_rate_hz)); + filters_[i].reset(new BiquadFilter(sample_rate_hz)); } - rtc::CritScope cs(crit_); - filters_.swap(new_filters); } -void HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) { - RTC_DCHECK(audio); - rtc::CritScope cs(crit_); - if (!enabled_) { - return; - } +LowCutFilter::~LowCutFilter() {} +void LowCutFilter::Process(AudioBuffer* audio) { + RTC_DCHECK(audio); RTC_DCHECK_GE(160u, audio->num_frames_per_band()); RTC_DCHECK_EQ(filters_.size(), audio->num_channels()); for (size_t i = 0; i < filters_.size(); i++) { @@ -116,19 +99,4 @@ void HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) { } } -int HighPassFilterImpl::Enable(bool enable) { - rtc::CritScope cs(crit_); - if (!enabled_ && enable) { - for (auto& filter : filters_) { - filter->Reset(); - } - } - enabled_ = enable; - return AudioProcessing::kNoError; -} - -bool HighPassFilterImpl::is_enabled() const { - rtc::CritScope cs(crit_); - return enabled_; -} } // namespace webrtc diff --git a/webrtc/modules/audio_processing/low_cut_filter.h b/webrtc/modules/audio_processing/low_cut_filter.h new file mode 100644 index 0000000000..3a4da71d8b --- /dev/null +++ b/webrtc/modules/audio_processing/low_cut_filter.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_LOW_CUT_FILTER_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_LOW_CUT_FILTER_H_ + +#include +#include + +#include "webrtc/base/constructormagic.h" + +namespace webrtc { + +class AudioBuffer; + +class LowCutFilter { + public: + LowCutFilter(size_t channels, int sample_rate_hz); + ~LowCutFilter(); + void Process(AudioBuffer* audio); + + private: + class BiquadFilter; + std::vector> filters_; + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(LowCutFilter); +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_LOW_CUT_FILTER_H_ diff --git a/webrtc/modules/audio_processing/high_pass_filter_unittest.cc b/webrtc/modules/audio_processing/low_cut_filter_unittest.cc similarity index 98% rename from webrtc/modules/audio_processing/high_pass_filter_unittest.cc rename to webrtc/modules/audio_processing/low_cut_filter_unittest.cc index 932b5c3762..0273472c03 100644 --- a/webrtc/modules/audio_processing/high_pass_filter_unittest.cc +++ b/webrtc/modules/audio_processing/low_cut_filter_unittest.cc @@ -11,7 +11,7 @@ #include "webrtc/base/array_view.h" #include "webrtc/modules/audio_processing/audio_buffer.h" -#include "webrtc/modules/audio_processing/high_pass_filter_impl.h" +#include "webrtc/modules/audio_processing/low_cut_filter.h" #include "webrtc/modules/audio_processing/test/audio_buffer_tools.h" #include "webrtc/modules/audio_processing/test/bitexactness_tools.h" #include "webrtc/test/gtest.h" @@ -22,14 +22,14 @@ namespace { // Process one frame of data and produce the output. std::vector ProcessOneFrame(const std::vector& frame_input, const StreamConfig& stream_config, - HighPassFilterImpl* high_pass_filter) { + LowCutFilter* low_cut_filter) { AudioBuffer audio_buffer( stream_config.num_frames(), stream_config.num_channels(), stream_config.num_frames(), stream_config.num_channels(), stream_config.num_frames()); test::CopyVectorToAudioBuffer(stream_config, frame_input, &audio_buffer); - high_pass_filter->ProcessCaptureAudio(&audio_buffer); + low_cut_filter->Process(&audio_buffer); std::vector frame_output; test::ExtractVectorFromAudioBuffer(stream_config, &audio_buffer, &frame_output); @@ -43,11 +43,7 @@ void RunBitexactnessTest(int sample_rate, const std::vector& input, const std::vector& reference) { const StreamConfig stream_config(sample_rate, num_channels, false); - rtc::CriticalSection crit; - HighPassFilterImpl high_pass_filter(&crit); - - high_pass_filter.Initialize(num_channels, sample_rate); - high_pass_filter.Enable(true); + LowCutFilter low_cut_filter(num_channels, sample_rate); std::vector output; const size_t num_frames_to_process = @@ -62,7 +58,7 @@ void RunBitexactnessTest(int sample_rate, stream_config.num_frames() * stream_config.num_channels() * (frame_no + 1)); - output = ProcessOneFrame(frame_input, stream_config, &high_pass_filter); + output = ProcessOneFrame(frame_input, stream_config, &low_cut_filter); } // Form vector to compare the reference to. Only the last frame processed @@ -98,7 +94,7 @@ std::vector CreateVector(const rtc::ArrayView& array_view) { } } // namespace -TEST(HighPassFilterBitExactnessTest, Mono8kHzInitial) { +TEST(LowCutFilterBitExactnessTest, Mono8kHzInitial) { const float kReferenceInput[] = { 0.153442f, -0.436920f, -0.057602f, -0.141767f, 0.108608f, 0.116834f, 0.114979f, -0.103151f, -0.169925f, -0.167180f, 0.242024f, -0.525426f, @@ -124,7 +120,7 @@ TEST(HighPassFilterBitExactnessTest, Mono8kHzInitial) { CreateVector(rtc::ArrayView(kReference))); } -TEST(HighPassFilterBitExactnessTest, Mono8kHzConverged) { +TEST(LowCutFilterBitExactnessTest, Mono8kHzConverged) { const float kReferenceInput[] = { 0.153442f, -0.436920f, -0.057602f, -0.141767f, 0.108608f, 0.116834f, 0.114979f, -0.103151f, -0.169925f, -0.167180f, 0.242024f, -0.525426f, @@ -176,7 +172,7 @@ TEST(HighPassFilterBitExactnessTest, Mono8kHzConverged) { CreateVector(rtc::ArrayView(kReference))); } -TEST(HighPassFilterBitExactnessTest, Stereo8kHzInitial) { +TEST(LowCutFilterBitExactnessTest, Stereo8kHzInitial) { const float kReferenceInput[] = { 0.790847f, 0.165037f, 0.165494f, 0.709852f, -0.930269f, 0.770840f, -0.184538f, -0.927236f, 0.492296f, -0.690342f, -0.712183f, 0.211918f, @@ -217,7 +213,7 @@ TEST(HighPassFilterBitExactnessTest, Stereo8kHzInitial) { CreateVector(rtc::ArrayView(kReference))); } -TEST(HighPassFilterBitExactnessTest, Stereo8kHzConverged) { +TEST(LowCutFilterBitExactnessTest, Stereo8kHzConverged) { const float kReferenceInput[] = { -0.502095f, -0.227154f, -0.137133f, 0.661773f, 0.649294f, -0.094003f, -0.238880f, 0.851737f, 0.481687f, 0.475266f, 0.893832f, 0.020199f, @@ -311,7 +307,7 @@ TEST(HighPassFilterBitExactnessTest, Stereo8kHzConverged) { CreateVector(rtc::ArrayView(kReference))); } -TEST(HighPassFilterBitExactnessTest, Mono16kHzInitial) { +TEST(LowCutFilterBitExactnessTest, Mono16kHzInitial) { const float kReferenceInput[] = { 0.150254f, 0.512488f, -0.631245f, 0.240938f, 0.089080f, -0.365440f, -0.121169f, 0.095748f, 1.000000f, 0.773932f, -0.377232f, 0.848124f, @@ -350,7 +346,7 @@ TEST(HighPassFilterBitExactnessTest, Mono16kHzInitial) { CreateVector(rtc::ArrayView(kReference))); } -TEST(HighPassFilterBitExactnessTest, Mono16kHzConverged) { +TEST(LowCutFilterBitExactnessTest, Mono16kHzConverged) { const float kReferenceInput[] = { 0.150254f, 0.512488f, -0.631245f, 0.240938f, 0.089080f, -0.365440f, -0.121169f, 0.095748f, 1.000000f, 0.773932f, -0.377232f, 0.848124f, @@ -442,7 +438,7 @@ TEST(HighPassFilterBitExactnessTest, Mono16kHzConverged) { CreateVector(rtc::ArrayView(kReference))); } -TEST(HighPassFilterBitExactnessTest, Stereo16kHzInitial) { +TEST(LowCutFilterBitExactnessTest, Stereo16kHzInitial) { const float kReferenceInput[] = { 0.087390f, -0.370759f, -0.235918f, 0.583079f, 0.678359f, 0.360473f, -0.166156f, 0.285780f, -0.571837f, 0.234542f, 0.350382f, 0.202047f, @@ -510,7 +506,7 @@ TEST(HighPassFilterBitExactnessTest, Stereo16kHzInitial) { CreateVector(rtc::ArrayView(kReference))); } -TEST(HighPassFilterBitExactnessTest, Stereo16kHzConverged) { +TEST(LowCutFilterBitExactnessTest, Stereo16kHzConverged) { const float kReferenceInput[] = { -0.145875f, 0.910744f, 0.448494f, 0.161783f, 0.080516f, 0.410882f, -0.989942f, 0.565032f, 0.853719f, -0.983409f, 0.649257f, 0.534672f, diff --git a/webrtc/modules/audio_processing/test/aec_dump_based_simulator.cc b/webrtc/modules/audio_processing/test/aec_dump_based_simulator.cc index 8580f159c2..694f2cd90c 100644 --- a/webrtc/modules/audio_processing/test/aec_dump_based_simulator.cc +++ b/webrtc/modules/audio_processing/test/aec_dump_based_simulator.cc @@ -403,8 +403,7 @@ void AecDumpBasedSimulator::HandleMessage( if (msg.has_hpf_enabled() || settings_.use_hpf) { bool enable = settings_.use_hpf ? *settings_.use_hpf : msg.hpf_enabled(); - RTC_CHECK_EQ(AudioProcessing::kNoError, - ap_->high_pass_filter()->Enable(enable)); + apm_config.high_pass_filter.enabled = enable; if (settings_.use_verbose_logging) { std::cout << " hpf_enabled: " << (enable ? "true" : "false") << std::endl; diff --git a/webrtc/modules/audio_processing/test/audio_processing_simulator.cc b/webrtc/modules/audio_processing/test/audio_processing_simulator.cc index a341a579c9..ddfc562aaf 100644 --- a/webrtc/modules/audio_processing/test/audio_processing_simulator.cc +++ b/webrtc/modules/audio_processing/test/audio_processing_simulator.cc @@ -273,6 +273,10 @@ void AudioProcessingSimulator::CreateAudioProcessor() { if (settings_.use_lc) { apm_config.level_controller.enabled = *settings_.use_lc; } + if (settings_.use_hpf) { + apm_config.high_pass_filter.enabled = *settings_.use_hpf; + } + if (settings_.use_refined_adaptive_filter) { config.Set( new RefinedAdaptiveFilter(*settings_.use_refined_adaptive_filter)); @@ -302,10 +306,6 @@ void AudioProcessingSimulator::CreateAudioProcessor() { RTC_CHECK_EQ(AudioProcessing::kNoError, ap_->gain_control()->Enable(*settings_.use_agc)); } - if (settings_.use_hpf) { - RTC_CHECK_EQ(AudioProcessing::kNoError, - ap_->high_pass_filter()->Enable(*settings_.use_hpf)); - } if (settings_.use_ns) { RTC_CHECK_EQ(AudioProcessing::kNoError, ap_->noise_suppression()->Enable(*settings_.use_ns)); diff --git a/webrtc/modules/audio_processing/test/debug_dump_replayer.cc b/webrtc/modules/audio_processing/test/debug_dump_replayer.cc index fa76747c2b..c34a14ef73 100644 --- a/webrtc/modules/audio_processing/test/debug_dump_replayer.cc +++ b/webrtc/modules/audio_processing/test/debug_dump_replayer.cc @@ -199,6 +199,8 @@ void DebugDumpReplayer::MaybeRecreateApm(const audioproc::Config& msg) { } void DebugDumpReplayer::ConfigureApm(const audioproc::Config& msg) { + AudioProcessing::Config apm_config; + // AEC configs. RTC_CHECK(msg.has_aec_enabled()); RTC_CHECK_EQ(AudioProcessing::kNoError, @@ -247,8 +249,7 @@ void DebugDumpReplayer::ConfigureApm(const audioproc::Config& msg) { // HPF configs. RTC_CHECK(msg.has_hpf_enabled()); - RTC_CHECK_EQ(AudioProcessing::kNoError, - apm_->high_pass_filter()->Enable(msg.hpf_enabled())); + apm_config.high_pass_filter.enabled = msg.hpf_enabled(); // NS configs. RTC_CHECK(msg.has_ns_enabled()); @@ -259,6 +260,8 @@ void DebugDumpReplayer::ConfigureApm(const audioproc::Config& msg) { RTC_CHECK_EQ(AudioProcessing::kNoError, apm_->noise_suppression()->set_level( static_cast(msg.ns_level()))); + + apm_->ApplyConfig(apm_config); } void DebugDumpReplayer::LoadNextMessage() {