peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 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 |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 11 | #include "modules/audio_processing/aec3/render_delay_buffer.h" |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 12 | |
| 13 | #include <string.h> |
| 14 | #include <algorithm> |
| 15 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 16 | #include "modules/audio_processing/aec3/aec3_common.h" |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 17 | #include "modules/audio_processing/aec3/aec3_fft.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 18 | #include "modules/audio_processing/aec3/block_processor.h" |
Per Åhgren | 38e2d95 | 2017-11-17 14:54:28 +0100 | [diff] [blame] | 19 | #include "modules/audio_processing/aec3/decimator.h" |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 20 | #include "modules/audio_processing/aec3/fft_buffer.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 21 | #include "modules/audio_processing/aec3/fft_data.h" |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 22 | #include "modules/audio_processing/aec3/matrix_buffer.h" |
Per Åhgren | 38e2d95 | 2017-11-17 14:54:28 +0100 | [diff] [blame] | 23 | #include "rtc_base/atomicops.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 24 | #include "rtc_base/checks.h" |
| 25 | #include "rtc_base/constructormagic.h" |
| 26 | #include "rtc_base/logging.h" |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 27 | |
| 28 | namespace webrtc { |
| 29 | namespace { |
| 30 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 31 | constexpr int kBufferHeadroom = kAdaptiveFilterLength; |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 32 | |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 33 | class RenderDelayBufferImpl final : public RenderDelayBuffer { |
| 34 | public: |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 35 | RenderDelayBufferImpl(const EchoCanceller3Config& config, size_t num_bands); |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 36 | ~RenderDelayBufferImpl() override; |
| 37 | |
| 38 | void Reset() override; |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 39 | BufferingEvent Insert(const std::vector<std::vector<float>>& block) override; |
| 40 | BufferingEvent PrepareCaptureCall() override; |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 41 | void SetDelay(size_t delay) override; |
| 42 | size_t Delay() const override { return delay_; } |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 43 | size_t MaxDelay() const override { |
| 44 | return blocks_.buffer.size() - 1 - kBufferHeadroom; |
| 45 | } |
| 46 | size_t MaxApiJitter() const override { return max_api_jitter_; } |
| 47 | const RenderBuffer& GetRenderBuffer() const override { |
| 48 | return echo_remover_buffer_; |
| 49 | } |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 50 | |
| 51 | const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const override { |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 52 | return low_rate_; |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | private: |
Per Åhgren | 38e2d95 | 2017-11-17 14:54:28 +0100 | [diff] [blame] | 56 | static int instance_count_; |
| 57 | std::unique_ptr<ApmDataDumper> data_dumper_; |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 58 | const Aec3Optimization optimization_; |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 59 | const size_t api_call_jitter_blocks_; |
| 60 | const size_t min_echo_path_delay_blocks_; |
| 61 | const int sub_block_size_; |
| 62 | MatrixBuffer blocks_; |
| 63 | VectorBuffer spectra_; |
| 64 | FftBuffer ffts_; |
| 65 | size_t delay_; |
| 66 | int max_api_jitter_ = 0; |
| 67 | int render_surplus_ = 0; |
| 68 | bool first_reset_occurred_ = false; |
| 69 | RenderBuffer echo_remover_buffer_; |
| 70 | DownsampledRenderBuffer low_rate_; |
Per Åhgren | 38e2d95 | 2017-11-17 14:54:28 +0100 | [diff] [blame] | 71 | Decimator render_decimator_; |
peah | debaa44 | 2017-05-03 05:39:09 -0700 | [diff] [blame] | 72 | const std::vector<std::vector<float>> zero_block_; |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 73 | const Aec3Fft fft_; |
| 74 | size_t capture_call_counter_ = 0; |
| 75 | std::vector<float> render_ds_; |
| 76 | int render_calls_in_a_row_ = 0; |
| 77 | |
| 78 | void UpdateBuffersWithLatestBlock(size_t previous_write); |
| 79 | void IncreaseRead(); |
| 80 | void IncreaseInsert(); |
| 81 | |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 82 | RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderDelayBufferImpl); |
| 83 | }; |
| 84 | |
Per Åhgren | 38e2d95 | 2017-11-17 14:54:28 +0100 | [diff] [blame] | 85 | int RenderDelayBufferImpl::instance_count_ = 0; |
| 86 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 87 | RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config, |
| 88 | size_t num_bands) |
Per Åhgren | 38e2d95 | 2017-11-17 14:54:28 +0100 | [diff] [blame] | 89 | : data_dumper_( |
| 90 | new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), |
| 91 | optimization_(DetectOptimization()), |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 92 | api_call_jitter_blocks_(config.delay.api_call_jitter_blocks), |
| 93 | min_echo_path_delay_blocks_(config.delay.min_echo_path_delay_blocks), |
| 94 | sub_block_size_( |
| 95 | static_cast<int>(config.delay.down_sampling_factor > 0 |
| 96 | ? kBlockSize / config.delay.down_sampling_factor |
| 97 | : kBlockSize)), |
| 98 | blocks_(GetRenderDelayBufferSize(config.delay.down_sampling_factor, |
| 99 | config.delay.num_filters), |
| 100 | num_bands, |
| 101 | kBlockSize), |
| 102 | spectra_(blocks_.buffer.size(), kFftLengthBy2Plus1), |
| 103 | ffts_(blocks_.buffer.size()), |
| 104 | delay_(min_echo_path_delay_blocks_), |
| 105 | echo_remover_buffer_(kAdaptiveFilterLength, &blocks_, &spectra_, &ffts_), |
| 106 | low_rate_(GetDownSampledBufferSize(config.delay.down_sampling_factor, |
| 107 | config.delay.num_filters)), |
| 108 | render_decimator_(config.delay.down_sampling_factor), |
| 109 | zero_block_(num_bands, std::vector<float>(kBlockSize, 0.f)), |
| 110 | fft_(), |
| 111 | render_ds_(sub_block_size_, 0.f) { |
| 112 | RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size()); |
| 113 | RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size()); |
| 114 | Reset(); |
| 115 | first_reset_occurred_ = false; |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 116 | } |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 117 | |
| 118 | RenderDelayBufferImpl::~RenderDelayBufferImpl() = default; |
| 119 | |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 120 | void RenderDelayBufferImpl::Reset() { |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 121 | delay_ = min_echo_path_delay_blocks_; |
| 122 | const int offset1 = std::max<int>( |
| 123 | std::min(api_call_jitter_blocks_, min_echo_path_delay_blocks_), 1); |
| 124 | const int offset2 = static_cast<int>(delay_ + offset1); |
| 125 | const int offset3 = offset1 * sub_block_size_; |
| 126 | low_rate_.read = low_rate_.OffsetIndex(low_rate_.write, offset3); |
| 127 | blocks_.read = blocks_.OffsetIndex(blocks_.write, -offset2); |
| 128 | spectra_.read = spectra_.OffsetIndex(spectra_.write, offset2); |
| 129 | ffts_.read = ffts_.OffsetIndex(ffts_.write, offset2); |
| 130 | render_surplus_ = 0; |
| 131 | first_reset_occurred_ = true; |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 132 | } |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 133 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 134 | RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert( |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 135 | const std::vector<std::vector<float>>& block) { |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 136 | RTC_DCHECK_EQ(block.size(), blocks_.buffer[0].size()); |
| 137 | RTC_DCHECK_EQ(block[0].size(), blocks_.buffer[0][0].size()); |
| 138 | BufferingEvent event = BufferingEvent::kNone; |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 139 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 140 | ++render_surplus_; |
| 141 | if (first_reset_occurred_) { |
| 142 | ++render_calls_in_a_row_; |
| 143 | max_api_jitter_ = std::max(max_api_jitter_, render_calls_in_a_row_); |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 144 | } |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 145 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 146 | const size_t previous_write = blocks_.write; |
| 147 | IncreaseInsert(); |
| 148 | |
| 149 | if (low_rate_.read == low_rate_.write || blocks_.read == blocks_.write) { |
| 150 | // Render overrun due to more render data being inserted than read. Discard |
| 151 | // the oldest render data. |
| 152 | event = BufferingEvent::kRenderOverrun; |
| 153 | IncreaseRead(); |
| 154 | } |
| 155 | |
| 156 | for (size_t k = 0; k < block.size(); ++k) { |
| 157 | std::copy(block[k].begin(), block[k].end(), |
| 158 | blocks_.buffer[blocks_.write][k].begin()); |
| 159 | } |
| 160 | |
| 161 | UpdateBuffersWithLatestBlock(previous_write); |
| 162 | return event; |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 163 | } |
| 164 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 165 | RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::PrepareCaptureCall() { |
| 166 | BufferingEvent event = BufferingEvent::kNone; |
| 167 | render_calls_in_a_row_ = 0; |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 168 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 169 | if (low_rate_.read == low_rate_.write || blocks_.read == blocks_.write) { |
| 170 | event = BufferingEvent::kRenderUnderrun; |
peah | debaa44 | 2017-05-03 05:39:09 -0700 | [diff] [blame] | 171 | } else { |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 172 | IncreaseRead(); |
peah | debaa44 | 2017-05-03 05:39:09 -0700 | [diff] [blame] | 173 | } |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 174 | --render_surplus_; |
| 175 | |
| 176 | echo_remover_buffer_.UpdateSpectralSum(); |
| 177 | |
| 178 | if (render_surplus_ >= static_cast<int>(api_call_jitter_blocks_)) { |
| 179 | event = BufferingEvent::kApiCallSkew; |
| 180 | RTC_LOG(LS_WARNING) << "Api call skew detected at " << capture_call_counter_ |
| 181 | << "."; |
| 182 | } |
| 183 | |
| 184 | ++capture_call_counter_; |
| 185 | return event; |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 186 | } |
| 187 | |
| 188 | void RenderDelayBufferImpl::SetDelay(size_t delay) { |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 189 | if (delay_ == delay) { |
| 190 | return; |
| 191 | } |
| 192 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 193 | const int delta_delay = static_cast<int>(delay_) - static_cast<int>(delay); |
| 194 | delay_ = delay; |
| 195 | if (delay_ > MaxDelay()) { |
| 196 | delay_ = std::min(MaxDelay(), delay); |
| 197 | RTC_NOTREACHED(); |
peah | cf02cf1 | 2017-04-05 14:18:07 -0700 | [diff] [blame] | 198 | } |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 199 | |
| 200 | // Recompute the read indices according to the set delay. |
| 201 | blocks_.UpdateReadIndex(delta_delay); |
| 202 | spectra_.UpdateReadIndex(-delta_delay); |
| 203 | ffts_.UpdateReadIndex(-delta_delay); |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 204 | } |
| 205 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 206 | void RenderDelayBufferImpl::UpdateBuffersWithLatestBlock( |
| 207 | size_t previous_write) { |
| 208 | render_decimator_.Decimate(blocks_.buffer[blocks_.write][0], render_ds_); |
| 209 | std::copy(render_ds_.rbegin(), render_ds_.rend(), |
| 210 | low_rate_.buffer.begin() + low_rate_.write); |
| 211 | |
| 212 | fft_.PaddedFft(blocks_.buffer[blocks_.write][0], |
| 213 | blocks_.buffer[previous_write][0], &ffts_.buffer[ffts_.write]); |
| 214 | |
| 215 | ffts_.buffer[ffts_.write].Spectrum(optimization_, |
| 216 | spectra_.buffer[spectra_.write]); |
| 217 | }; |
| 218 | |
| 219 | void RenderDelayBufferImpl::IncreaseRead() { |
| 220 | low_rate_.UpdateReadIndex(-sub_block_size_); |
| 221 | blocks_.IncReadIndex(); |
| 222 | spectra_.DecReadIndex(); |
| 223 | ffts_.DecReadIndex(); |
| 224 | }; |
| 225 | |
| 226 | void RenderDelayBufferImpl::IncreaseInsert() { |
| 227 | low_rate_.UpdateWriteIndex(-sub_block_size_); |
| 228 | blocks_.IncWriteIndex(); |
| 229 | spectra_.DecWriteIndex(); |
| 230 | ffts_.DecWriteIndex(); |
| 231 | }; |
| 232 | |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 233 | } // namespace |
| 234 | |
Per Åhgren | 8ba5861 | 2017-12-01 23:01:44 +0100 | [diff] [blame^] | 235 | RenderDelayBuffer* RenderDelayBuffer::Create(const EchoCanceller3Config& config, |
| 236 | size_t num_bands) { |
| 237 | return new RenderDelayBufferImpl(config, num_bands); |
peah | 69221db | 2017-01-27 03:28:19 -0800 | [diff] [blame] | 238 | } |
| 239 | |
| 240 | } // namespace webrtc |