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() {