diff --git a/modules/audio_processing/aec3/echo_canceller3.cc b/modules/audio_processing/aec3/echo_canceller3.cc index 632b91bac5..dafb14f544 100644 --- a/modules/audio_processing/aec3/echo_canceller3.cc +++ b/modules/audio_processing/aec3/echo_canceller3.cc @@ -248,7 +248,7 @@ EchoCanceller3::RenderWriter::RenderWriter( : data_dumper_(data_dumper), num_bands_(num_bands), num_channels_(num_channels), - high_pass_filter_(num_channels), + high_pass_filter_(16000, num_channels), render_queue_input_frame_( num_bands_, std::vector>( diff --git a/modules/audio_processing/aec3/echo_canceller3_unittest.cc b/modules/audio_processing/aec3/echo_canceller3_unittest.cc index 8d9199c830..4fc68ff0d9 100644 --- a/modules/audio_processing/aec3/echo_canceller3_unittest.cc +++ b/modules/audio_processing/aec3/echo_canceller3_unittest.cc @@ -237,7 +237,7 @@ class EchoCanceller3Tester { capture_output.push_back(capture_buffer_.split_bands(0)[0][k]); } } - HighPassFilter hp_filter(1); + HighPassFilter hp_filter(16000, 1); hp_filter.Process(&render_input); EXPECT_TRUE( @@ -530,7 +530,7 @@ class EchoCanceller3Tester { capture_output.push_back(capture_buffer_.split_bands(0)[0][k]); } } - HighPassFilter hp_filter(1); + HighPassFilter hp_filter(16000, 1); hp_filter.Process(&render_input); EXPECT_TRUE( diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc index d544304070..6d8b209740 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -75,6 +75,11 @@ bool DetectLegacyNsEnforcement() { return field_trial::IsEnabled("WebRTC-NewNoiseSuppressionKillSwitch"); } +// Checks whether the high-pass filter should be done in the full-band. +bool EnforceSplitBandHpf() { + return field_trial::IsEnabled("WebRTC-FullBandHpfKillSwitch"); +} + // Checks whether AEC3 should be allowed to decide what the default // configuration should be based on the render and capture channel configuration // at hand. @@ -343,7 +348,8 @@ AudioProcessingImpl::AudioProcessingImpl( !field_trial::IsEnabled( "WebRTC-ApmExperimentalMultiChannelRenderKillSwitch"), !field_trial::IsEnabled( - "WebRTC-ApmExperimentalMultiChannelCaptureKillSwitch")), + "WebRTC-ApmExperimentalMultiChannelCaptureKillSwitch"), + EnforceSplitBandHpf()), #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) capture_(false), #else @@ -629,7 +635,9 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) { config_.pipeline.multi_channel_render != config.pipeline.multi_channel_render || config_.pipeline.multi_channel_capture != - config.pipeline.multi_channel_capture; + config.pipeline.multi_channel_capture || + config_.pipeline.maximum_internal_processing_rate != + config.pipeline.maximum_internal_processing_rate; const bool aec_config_changed = config_.echo_canceller.enabled != config.echo_canceller.enabled || @@ -1199,6 +1207,13 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() { AudioBuffer* capture_buffer = capture_.capture_audio.get(); // For brevity. + if (submodules_.high_pass_filter && + config_.high_pass_filter.apply_in_full_band && + !constants_.enforce_split_band_hpf) { + submodules_.high_pass_filter->Process(capture_buffer, + /*use_split_band_data=*/false); + } + if (submodules_.pre_amplifier) { submodules_.pre_amplifier->ApplyGain(AudioFrameView( capture_buffer->channels(), capture_buffer->num_channels(), @@ -1267,8 +1282,11 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() { capture_buffer->set_num_channels(1); } - if (submodules_.high_pass_filter) { - submodules_.high_pass_filter->Process(capture_buffer); + if (submodules_.high_pass_filter && + (!config_.high_pass_filter.apply_in_full_band || + constants_.enforce_split_band_hpf)) { + submodules_.high_pass_filter->Process(capture_buffer, + /*use_split_band_data=*/true); } RETURN_ON_ERR(submodules_.gain_control->AnalyzeCaptureAudio(*capture_buffer)); @@ -1760,7 +1778,14 @@ void AudioProcessingImpl::InitializeHighPassFilter() { !config_.echo_canceller.mobile_mode; if (submodule_states_.HighPassFilteringRequired() || high_pass_filter_needed_by_aec) { - submodules_.high_pass_filter.reset(new HighPassFilter(num_proc_channels())); + bool use_full_band = config_.high_pass_filter.apply_in_full_band && + !constants_.enforce_split_band_hpf; + int rate = use_full_band ? proc_fullband_sample_rate_hz() + : proc_split_sample_rate_hz(); + size_t num_channels = + use_full_band ? num_output_channels() : num_proc_channels(); + + submodules_.high_pass_filter.reset(new HighPassFilter(rate, num_channels)); } else { submodules_.high_pass_filter.reset(); } diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h index 08379ad0a3..29a3c8df4f 100644 --- a/modules/audio_processing/audio_processing_impl.h +++ b/modules/audio_processing/audio_processing_impl.h @@ -372,7 +372,8 @@ class AudioProcessingImpl : public AudioProcessing { bool use_experimental_agc_agc2_level_estimation, bool use_experimental_agc_agc2_digital_adaptive, bool multi_channel_render_support, - bool multi_channel_capture_support) + bool multi_channel_capture_support, + bool enforce_split_band_hpf) : agc_startup_min_volume(agc_startup_min_volume), agc_clipped_level_min(agc_clipped_level_min), use_experimental_agc(use_experimental_agc), @@ -381,7 +382,8 @@ class AudioProcessingImpl : public AudioProcessing { use_experimental_agc_agc2_digital_adaptive( use_experimental_agc_agc2_digital_adaptive), multi_channel_render_support(multi_channel_render_support), - multi_channel_capture_support(multi_channel_capture_support) {} + multi_channel_capture_support(multi_channel_capture_support), + enforce_split_band_hpf(enforce_split_band_hpf) {} int agc_startup_min_volume; int agc_clipped_level_min; bool use_experimental_agc; @@ -389,6 +391,7 @@ class AudioProcessingImpl : public AudioProcessing { bool use_experimental_agc_agc2_digital_adaptive; bool multi_channel_render_support; bool multi_channel_capture_support; + bool enforce_split_band_hpf; } constants_; struct ApmCaptureState { diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc index 0fd07bf3f6..9355c11de1 100644 --- a/modules/audio_processing/audio_processing_unittest.cc +++ b/modules/audio_processing/audio_processing_unittest.cc @@ -209,6 +209,7 @@ void EnableAllAPComponents(AudioProcessing* ap) { apm_config.high_pass_filter.enabled = true; apm_config.level_estimation.enabled = true; apm_config.voice_detection.enabled = true; + apm_config.pipeline.maximum_internal_processing_rate = 48000; ap->ApplyConfig(apm_config); } @@ -432,6 +433,9 @@ ApmTest::ApmTest() Config config; config.Set(new ExperimentalAgc(false)); apm_.reset(AudioProcessingBuilder().Create(config)); + AudioProcessing::Config apm_config = apm_->GetConfig(); + apm_config.pipeline.maximum_internal_processing_rate = 48000; + apm_->ApplyConfig(apm_config); } void ApmTest::SetUp() { @@ -1961,11 +1965,7 @@ TEST_P(AudioProcessingTest, Formats) { } else { ref_rate = 8000; } -#ifdef WEBRTC_ARCH_ARM_FAMILY - if (file_direction == kForward) { - ref_rate = std::min(ref_rate, 32000); - } -#endif + FILE* out_file = fopen( OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_, reverse_output_rate_, cf[i].num_input, @@ -2087,9 +2087,9 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple(44100, 16000, 32000, 16000, 25, 20), std::make_tuple(44100, 16000, 16000, 16000, 25, 0), - std::make_tuple(32000, 48000, 48000, 48000, 30, 0), - std::make_tuple(32000, 48000, 32000, 48000, 32, 30), - std::make_tuple(32000, 48000, 16000, 48000, 30, 20), + std::make_tuple(32000, 48000, 48000, 48000, 15, 0), + std::make_tuple(32000, 48000, 32000, 48000, 15, 30), + std::make_tuple(32000, 48000, 16000, 48000, 15, 20), std::make_tuple(32000, 44100, 48000, 44100, 19, 20), std::make_tuple(32000, 44100, 32000, 44100, 19, 15), std::make_tuple(32000, 44100, 16000, 44100, 19, 15), @@ -2100,9 +2100,9 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple(32000, 16000, 32000, 16000, 25, 20), std::make_tuple(32000, 16000, 16000, 16000, 25, 0), - std::make_tuple(16000, 48000, 48000, 48000, 23, 0), - std::make_tuple(16000, 48000, 32000, 48000, 24, 30), - std::make_tuple(16000, 48000, 16000, 48000, 24, 20), + std::make_tuple(16000, 48000, 48000, 48000, 9, 0), + std::make_tuple(16000, 48000, 32000, 48000, 9, 30), + std::make_tuple(16000, 48000, 16000, 48000, 9, 20), std::make_tuple(16000, 44100, 48000, 44100, 15, 20), std::make_tuple(16000, 44100, 32000, 44100, 15, 15), std::make_tuple(16000, 44100, 16000, 44100, 15, 15), @@ -2143,9 +2143,9 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple(44100, 16000, 32000, 16000, 19, 20), std::make_tuple(44100, 16000, 16000, 16000, 19, 0), - std::make_tuple(32000, 48000, 48000, 48000, 27, 0), - std::make_tuple(32000, 48000, 32000, 48000, 65, 30), - std::make_tuple(32000, 48000, 16000, 48000, 30, 20), + std::make_tuple(32000, 48000, 48000, 48000, 17, 0), + std::make_tuple(32000, 48000, 32000, 48000, 17, 30), + std::make_tuple(32000, 48000, 16000, 48000, 17, 20), std::make_tuple(32000, 44100, 48000, 44100, 20, 20), std::make_tuple(32000, 44100, 32000, 44100, 20, 15), std::make_tuple(32000, 44100, 16000, 44100, 20, 15), @@ -2156,9 +2156,9 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple(32000, 16000, 32000, 16000, 20, 20), std::make_tuple(32000, 16000, 16000, 16000, 20, 0), - std::make_tuple(16000, 48000, 48000, 48000, 23, 0), - std::make_tuple(16000, 48000, 32000, 48000, 24, 30), - std::make_tuple(16000, 48000, 16000, 48000, 25, 20), + std::make_tuple(16000, 48000, 48000, 48000, 11, 0), + std::make_tuple(16000, 48000, 32000, 48000, 11, 30), + std::make_tuple(16000, 48000, 16000, 48000, 11, 20), std::make_tuple(16000, 44100, 48000, 44100, 15, 20), std::make_tuple(16000, 44100, 32000, 44100, 15, 15), std::make_tuple(16000, 44100, 16000, 44100, 15, 15), diff --git a/modules/audio_processing/high_pass_filter.cc b/modules/audio_processing/high_pass_filter.cc index bd953e319d..bff7209e96 100644 --- a/modules/audio_processing/high_pass_filter.cc +++ b/modules/audio_processing/high_pass_filter.cc @@ -18,30 +18,67 @@ namespace webrtc { namespace { // [B,A] = butter(2,100/8000,'high') -constexpr CascadedBiQuadFilter::BiQuadCoefficients kHighPassFilterCoefficients = - {{0.97261f, -1.94523f, 0.97261f}, {-1.94448f, 0.94598f}}; +constexpr CascadedBiQuadFilter::BiQuadCoefficients + kHighPassFilterCoefficients16kHz = {{0.97261f, -1.94523f, 0.97261f}, + {-1.94448f, 0.94598f}}; + +// [B,A] = butter(2,100/16000,'high') +constexpr CascadedBiQuadFilter::BiQuadCoefficients + kHighPassFilterCoefficients32kHz = {{0.98621f, -1.97242f, 0.98621f}, + {-1.97223f, 0.97261f}}; + +// [B,A] = butter(2,100/24000,'high') +constexpr CascadedBiQuadFilter::BiQuadCoefficients + kHighPassFilterCoefficients48kHz = {{0.99079f, -1.98157f, 0.99079f}, + {-1.98149f, 0.98166f}}; constexpr size_t kNumberOfHighPassBiQuads = 1; +const CascadedBiQuadFilter::BiQuadCoefficients& ChooseCoefficients( + int sample_rate_hz) { + switch (sample_rate_hz) { + case 16000: + return kHighPassFilterCoefficients16kHz; + case 32000: + return kHighPassFilterCoefficients32kHz; + case 48000: + return kHighPassFilterCoefficients48kHz; + default: + RTC_NOTREACHED(); + } + RTC_NOTREACHED(); + return kHighPassFilterCoefficients16kHz; +} + } // namespace -HighPassFilter::HighPassFilter(size_t num_channels) { +HighPassFilter::HighPassFilter(int sample_rate_hz, size_t num_channels) + : sample_rate_hz_(sample_rate_hz) { filters_.resize(num_channels); + const auto& coefficients = ChooseCoefficients(sample_rate_hz_); for (size_t k = 0; k < filters_.size(); ++k) { - filters_[k].reset(new CascadedBiQuadFilter(kHighPassFilterCoefficients, - kNumberOfHighPassBiQuads)); + filters_[k].reset( + new CascadedBiQuadFilter(coefficients, kNumberOfHighPassBiQuads)); } } HighPassFilter::~HighPassFilter() = default; -void HighPassFilter::Process(AudioBuffer* audio) { +void HighPassFilter::Process(AudioBuffer* audio, bool use_split_band_data) { RTC_DCHECK(audio); RTC_DCHECK_EQ(filters_.size(), audio->num_channels()); - for (size_t k = 0; k < audio->num_channels(); ++k) { - rtc::ArrayView channel_data = rtc::ArrayView( - audio->split_bands(k)[0], audio->num_frames_per_band()); - filters_[k]->Process(channel_data); + if (use_split_band_data) { + for (size_t k = 0; k < audio->num_channels(); ++k) { + rtc::ArrayView channel_data = rtc::ArrayView( + audio->split_bands(k)[0], audio->num_frames_per_band()); + filters_[k]->Process(channel_data); + } + } else { + for (size_t k = 0; k < audio->num_channels(); ++k) { + rtc::ArrayView channel_data = + rtc::ArrayView(&audio->channels()[k][0], audio->num_frames()); + filters_[k]->Process(channel_data); + } } } @@ -67,9 +104,10 @@ void HighPassFilter::Reset(size_t num_channels) { for (size_t k = 0; k < old_num_channels; ++k) { filters_[k]->Reset(); } + const auto& coefficients = ChooseCoefficients(sample_rate_hz_); for (size_t k = old_num_channels; k < filters_.size(); ++k) { - filters_[k].reset(new CascadedBiQuadFilter(kHighPassFilterCoefficients, - kNumberOfHighPassBiQuads)); + filters_[k].reset( + new CascadedBiQuadFilter(coefficients, kNumberOfHighPassBiQuads)); } } } diff --git a/modules/audio_processing/high_pass_filter.h b/modules/audio_processing/high_pass_filter.h index 87105cebaf..d396383b0c 100644 --- a/modules/audio_processing/high_pass_filter.h +++ b/modules/audio_processing/high_pass_filter.h @@ -21,20 +21,20 @@ namespace webrtc { class AudioBuffer; -// Filters that high class HighPassFilter { public: - explicit HighPassFilter(size_t num_channels); + HighPassFilter(int sample_rate_hz, size_t num_channels); ~HighPassFilter(); HighPassFilter(const HighPassFilter&) = delete; HighPassFilter& operator=(const HighPassFilter&) = delete; - void Process(AudioBuffer* audio); + void Process(AudioBuffer* audio, bool use_split_band_data); void Process(std::vector>* audio); void Reset(); void Reset(size_t num_channels); private: + const int sample_rate_hz_; std::vector> filters_; }; } // namespace webrtc diff --git a/modules/audio_processing/high_pass_filter_unittest.cc b/modules/audio_processing/high_pass_filter_unittest.cc index 56ccb950b2..f8e7226b6c 100644 --- a/modules/audio_processing/high_pass_filter_unittest.cc +++ b/modules/audio_processing/high_pass_filter_unittest.cc @@ -32,7 +32,7 @@ std::vector ProcessOneFrameAsAudioBuffer( stream_config.sample_rate_hz(), stream_config.num_channels()); test::CopyVectorToAudioBuffer(stream_config, frame_input, &audio_buffer); - high_pass_filter->Process(&audio_buffer); + high_pass_filter->Process(&audio_buffer, /*use_split_band_data=*/false); std::vector frame_output; test::ExtractVectorFromAudioBuffer(stream_config, &audio_buffer, &frame_output); @@ -76,7 +76,7 @@ void RunBitexactnessTest(int num_channels, const std::vector& input, const std::vector& reference) { const StreamConfig stream_config(16000, num_channels, false); - HighPassFilter high_pass_filter(num_channels); + HighPassFilter high_pass_filter(16000, num_channels); std::vector output; const size_t num_frames_to_process = @@ -135,7 +135,7 @@ TEST(HighPassFilterAccuracyTest, ResetWithAudioBufferInterface) { const StreamConfig stream_config_mono(16000, 1, false); std::vector x_mono(160, 1.f); std::vector x_stereo(320, 1.f); - HighPassFilter hpf(1); + HighPassFilter hpf(16000, 1); std::vector y = ProcessOneFrameAsAudioBuffer(x_mono, stream_config_mono, &hpf); hpf.Reset(2); @@ -151,7 +151,7 @@ TEST(HighPassFilterAccuracyTest, ResetWithVectorInterface) { const StreamConfig stream_config_mono(16000, 1, false); std::vector x_mono(160, 1.f); std::vector x_stereo(320, 1.f); - HighPassFilter hpf(1); + HighPassFilter hpf(16000, 1); std::vector y = ProcessOneFrameAsVector(x_mono, stream_config_mono, &hpf); hpf.Reset(2); diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h index 2f679196b0..5ab591bc7f 100644 --- a/modules/audio_processing/include/audio_processing.h +++ b/modules/audio_processing/include/audio_processing.h @@ -224,6 +224,7 @@ class RTC_EXPORT AudioProcessing : public rtc::RefCountInterface { struct HighPassFilter { bool enabled = false; + bool apply_in_full_band = true; } high_pass_filter; struct EchoCanceller { diff --git a/resources/audio_processing/output_data_float.pb.sha1 b/resources/audio_processing/output_data_float.pb.sha1 index 38c5251104..b8312fc58f 100644 --- a/resources/audio_processing/output_data_float.pb.sha1 +++ b/resources/audio_processing/output_data_float.pb.sha1 @@ -1 +1 @@ -8d368435bbc80edab08205c6f21db1416e119119 \ No newline at end of file +d22d4b0bc8f59aa27da61e158b9d35596f3844f5 \ No newline at end of file