| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/audio_processing/aec3/aec_state.h" | 11 #include "webrtc/modules/audio_processing/aec3/aec_state.h" |
| 12 | 12 |
| 13 #include <math.h> | 13 #include <math.h> |
| 14 #include <numeric> | 14 #include <numeric> |
| 15 #include <vector> | 15 #include <vector> |
| 16 | 16 |
| 17 #include "webrtc/base/array_view.h" | 17 #include "webrtc/base/array_view.h" |
| 18 #include "webrtc/base/atomicops.h" | 18 #include "webrtc/base/atomicops.h" |
| 19 #include "webrtc/base/checks.h" | 19 #include "webrtc/base/checks.h" |
| 20 #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h" | 20 #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h" |
| 21 | 21 |
| 22 namespace webrtc { | 22 namespace webrtc { |
| 23 namespace { | 23 namespace { |
| 24 | 24 |
| 25 constexpr size_t kEchoPathChangeConvergenceBlocks = 4 * kNumBlocksPerSecond; | 25 constexpr size_t kEchoPathChangeConvergenceBlocks = 2 * kNumBlocksPerSecond; |
| 26 constexpr size_t kSaturationLeakageBlocks = 20; | 26 constexpr size_t kSaturationLeakageBlocks = 20; |
| 27 | 27 |
| 28 // Computes delay of the adaptive filter. | 28 // Computes delay of the adaptive filter. |
| 29 rtc::Optional<size_t> EstimateFilterDelay( | 29 rtc::Optional<size_t> EstimateFilterDelay( |
| 30 const std::vector<std::array<float, kFftLengthBy2Plus1>>& | 30 const std::vector<std::array<float, kFftLengthBy2Plus1>>& |
| 31 adaptive_filter_frequency_response) { | 31 adaptive_filter_frequency_response) { |
| 32 const auto& H2 = adaptive_filter_frequency_response; | 32 const auto& H2 = adaptive_filter_frequency_response; |
| 33 | 33 |
| 34 size_t reliable_delays_sum = 0; | 34 size_t reliable_delays_sum = 0; |
| 35 size_t num_reliable_delays = 0; | 35 size_t num_reliable_delays = 0; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 : data_dumper_( | 82 : data_dumper_( |
| 83 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), | 83 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), |
| 84 echo_path_change_counter_(kEchoPathChangeCounterInitial) {} | 84 echo_path_change_counter_(kEchoPathChangeCounterInitial) {} |
| 85 | 85 |
| 86 AecState::~AecState() = default; | 86 AecState::~AecState() = default; |
| 87 | 87 |
| 88 void AecState::HandleEchoPathChange( | 88 void AecState::HandleEchoPathChange( |
| 89 const EchoPathVariability& echo_path_variability) { | 89 const EchoPathVariability& echo_path_variability) { |
| 90 if (echo_path_variability.AudioPathChanged()) { | 90 if (echo_path_variability.AudioPathChanged()) { |
| 91 blocks_since_last_saturation_ = 0; | 91 blocks_since_last_saturation_ = 0; |
| 92 active_render_blocks_ = 0; | |
| 93 usable_linear_estimate_ = false; | 92 usable_linear_estimate_ = false; |
| 94 echo_leakage_detected_ = false; | 93 echo_leakage_detected_ = false; |
| 95 capture_signal_saturation_ = false; | 94 capture_signal_saturation_ = false; |
| 96 echo_saturation_ = false; | 95 echo_saturation_ = false; |
| 97 previous_max_sample_ = 0.f; | 96 previous_max_sample_ = 0.f; |
| 98 | 97 |
| 99 if (echo_path_variability.delay_change) { | 98 if (echo_path_variability.delay_change) { |
| 100 force_zero_gain_counter_ = 0; | 99 force_zero_gain_counter_ = 0; |
| 100 blocks_with_filter_adaptation_ = 0; |
| 101 render_received_ = false; |
| 101 force_zero_gain_ = true; | 102 force_zero_gain_ = true; |
| 102 echo_path_change_counter_ = kEchoPathChangeCounterMax; | 103 echo_path_change_counter_ = kEchoPathChangeCounterMax; |
| 103 } | 104 } |
| 104 if (echo_path_variability.gain_change) { | 105 if (echo_path_variability.gain_change) { |
| 105 echo_path_change_counter_ = kEchoPathChangeCounterInitial; | 106 echo_path_change_counter_ = kEchoPathChangeCounterInitial; |
| 106 } | 107 } |
| 107 } | 108 } |
| 108 } | 109 } |
| 109 | 110 |
| 110 void AecState::Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>& | 111 void AecState::Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>& |
| 111 adaptive_filter_frequency_response, | 112 adaptive_filter_frequency_response, |
| 112 const rtc::Optional<size_t>& external_delay_samples, | 113 const rtc::Optional<size_t>& external_delay_samples, |
| 113 const RenderBuffer& render_buffer, | 114 const RenderBuffer& render_buffer, |
| 114 const std::array<float, kFftLengthBy2Plus1>& E2_main, | 115 const std::array<float, kFftLengthBy2Plus1>& E2_main, |
| 115 const std::array<float, kFftLengthBy2Plus1>& Y2, | 116 const std::array<float, kFftLengthBy2Plus1>& Y2, |
| 116 rtc::ArrayView<const float> x, | 117 rtc::ArrayView<const float> x, |
| 117 bool echo_leakage_detected) { | 118 bool echo_leakage_detected) { |
| 118 // Store input parameters. | 119 // Store input parameters. |
| 119 echo_leakage_detected_ = echo_leakage_detected; | 120 echo_leakage_detected_ = echo_leakage_detected; |
| 120 | 121 |
| 121 // Update counters. | 122 // Update counters. |
| 122 const float x_energy = std::inner_product(x.begin(), x.end(), x.begin(), 0.f); | 123 const float x_energy = std::inner_product(x.begin(), x.end(), x.begin(), 0.f); |
| 123 const bool active_render_block = x_energy > 10000.f * kFftLengthBy2; | 124 const bool active_render_block = x_energy > 10000.f * kFftLengthBy2; |
| 124 active_render_blocks_ += active_render_block ? 1 : 0; | 125 if (active_render_block) { |
| 126 render_received_ = true; |
| 127 } |
| 128 blocks_with_filter_adaptation_ += |
| 129 (active_render_block && (!SaturatedCapture()) ? 1 : 0); |
| 125 --echo_path_change_counter_; | 130 --echo_path_change_counter_; |
| 126 | 131 |
| 127 // Force zero echo suppression gain after an echo path change to allow at | 132 // Force zero echo suppression gain after an echo path change to allow at |
| 128 // least some render data to be collected in order to avoid an initial echo | 133 // least some render data to be collected in order to avoid an initial echo |
| 129 // burst. | 134 // burst. |
| 130 constexpr size_t kZeroGainBlocksAfterChange = kNumBlocksPerSecond / 5; | 135 constexpr size_t kZeroGainBlocksAfterChange = kNumBlocksPerSecond / 5; |
| 131 force_zero_gain_ = (++force_zero_gain_counter_) < kZeroGainBlocksAfterChange; | 136 force_zero_gain_ = (++force_zero_gain_counter_) < kZeroGainBlocksAfterChange; |
| 132 | 137 |
| 133 // Estimate delays. | 138 // Estimate delays. |
| 134 filter_delay_ = EstimateFilterDelay(adaptive_filter_frequency_response); | 139 filter_delay_ = EstimateFilterDelay(adaptive_filter_frequency_response); |
| 135 external_delay_ = | 140 external_delay_ = |
| 136 external_delay_samples | 141 external_delay_samples |
| 137 ? rtc::Optional<size_t>(*external_delay_samples / kBlockSize) | 142 ? rtc::Optional<size_t>(*external_delay_samples / kBlockSize) |
| 138 : rtc::Optional<size_t>(); | 143 : rtc::Optional<size_t>(); |
| 139 | 144 |
| 140 // Update the ERL and ERLE measures. | 145 // Update the ERL and ERLE measures. |
| 141 if (filter_delay_ && echo_path_change_counter_ <= 0) { | 146 if (filter_delay_ && echo_path_change_counter_ <= 0) { |
| 142 const auto& X2 = render_buffer.Spectrum(*filter_delay_); | 147 const auto& X2 = render_buffer.Spectrum(*filter_delay_); |
| 143 erle_estimator_.Update(X2, Y2, E2_main); | 148 erle_estimator_.Update(X2, Y2, E2_main); |
| 144 erl_estimator_.Update(X2, Y2); | 149 erl_estimator_.Update(X2, Y2); |
| 145 } | 150 } |
| 146 | 151 |
| 147 // Detect and flag echo saturation. | 152 // Detect and flag echo saturation. |
| 153 // TODO(peah): Add the delay in this computation to ensure that the render and |
| 154 // capture signals are properly aligned. |
| 148 RTC_DCHECK_LT(0, x.size()); | 155 RTC_DCHECK_LT(0, x.size()); |
| 149 const float max_sample = fabs(*std::max_element( | 156 const float max_sample = fabs(*std::max_element( |
| 150 x.begin(), x.end(), [](float a, float b) { return a * a < b * b; })); | 157 x.begin(), x.end(), [](float a, float b) { return a * a < b * b; })); |
| 151 const bool saturated_echo = | 158 const bool saturated_echo = |
| 152 previous_max_sample_ * kFixedEchoPathGain > 1600 && SaturatedCapture(); | 159 previous_max_sample_ * kFixedEchoPathGain > 1600 && SaturatedCapture(); |
| 153 previous_max_sample_ = max_sample; | 160 previous_max_sample_ = max_sample; |
| 154 | 161 |
| 155 // Counts the blocks since saturation. | 162 // Counts the blocks since saturation. |
| 156 blocks_since_last_saturation_ = | 163 blocks_since_last_saturation_ = |
| 157 saturated_echo ? 0 : blocks_since_last_saturation_ + 1; | 164 saturated_echo ? 0 : blocks_since_last_saturation_ + 1; |
| 158 echo_saturation_ = blocks_since_last_saturation_ < kSaturationLeakageBlocks; | 165 echo_saturation_ = blocks_since_last_saturation_ < kSaturationLeakageBlocks; |
| 159 | 166 |
| 160 // Flag whether the linear filter estimate is usable. | 167 // Flag whether the linear filter estimate is usable. |
| 161 usable_linear_estimate_ = | 168 usable_linear_estimate_ = |
| 162 (!echo_saturation_) && | 169 (!echo_saturation_) && |
| 163 active_render_blocks_ > kEchoPathChangeConvergenceBlocks && | 170 (!render_received_ || |
| 171 blocks_with_filter_adaptation_ > kEchoPathChangeConvergenceBlocks) && |
| 164 filter_delay_ && echo_path_change_counter_ <= 0; | 172 filter_delay_ && echo_path_change_counter_ <= 0; |
| 165 | 173 |
| 166 // After an amount of active render samples for which an echo should have been | 174 // After an amount of active render samples for which an echo should have been |
| 167 // detected in the capture signal if the ERL was not infinite, flag that a | 175 // detected in the capture signal if the ERL was not infinite, flag that a |
| 168 // headset is used. | 176 // headset is used. |
| 169 headset_detected_ = !external_delay_ && !filter_delay_ && | 177 headset_detected_ = |
| 170 active_render_blocks_ >= kEchoPathChangeConvergenceBlocks; | 178 !external_delay_ && !filter_delay_ && |
| 179 (!render_received_ || |
| 180 blocks_with_filter_adaptation_ >= kEchoPathChangeConvergenceBlocks); |
| 171 } | 181 } |
| 172 | 182 |
| 173 } // namespace webrtc | 183 } // namespace webrtc |
| OLD | NEW |