blob: 4c0d55d2af2acd86b7ec1edfe6a2d3847a9a35f2 [file] [log] [blame]
Gustaf Ullberg11539f02018-10-15 13:40:29 +02001/*
2 * Copyright (c) 2018 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
Gustaf Ullberg11539f02018-10-15 13:40:29 +020011#include <string.h>
12#include <algorithm>
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <memory>
Gustaf Ullberg11539f02018-10-15 13:40:29 +020014#include <numeric>
Yves Gerey988cc082018-10-23 12:03:01 +020015#include <vector>
Gustaf Ullberg11539f02018-10-15 13:40:29 +020016
Yves Gerey988cc082018-10-23 12:03:01 +020017#include "absl/types/optional.h"
18#include "api/array_view.h"
19#include "api/audio/echo_canceller3_config.h"
Gustaf Ullberg11539f02018-10-15 13:40:29 +020020#include "modules/audio_processing/aec3/aec3_common.h"
21#include "modules/audio_processing/aec3/aec3_fft.h"
Gustaf Ullberg11539f02018-10-15 13:40:29 +020022#include "modules/audio_processing/aec3/decimator.h"
Yves Gerey988cc082018-10-23 12:03:01 +020023#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
Gustaf Ullberg11539f02018-10-15 13:40:29 +020024#include "modules/audio_processing/aec3/fft_buffer.h"
25#include "modules/audio_processing/aec3/fft_data.h"
26#include "modules/audio_processing/aec3/matrix_buffer.h"
Yves Gerey988cc082018-10-23 12:03:01 +020027#include "modules/audio_processing/aec3/render_buffer.h"
28#include "modules/audio_processing/aec3/render_delay_buffer.h"
29#include "modules/audio_processing/aec3/vector_buffer.h"
30#include "modules/audio_processing/logging/apm_data_dumper.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/atomic_ops.h"
Gustaf Ullberg11539f02018-10-15 13:40:29 +020032#include "rtc_base/checks.h"
33#include "rtc_base/logging.h"
Gustaf Ullberg11539f02018-10-15 13:40:29 +020034
35namespace webrtc {
36namespace {
37
38class RenderDelayBufferImpl2 final : public RenderDelayBuffer {
39 public:
40 RenderDelayBufferImpl2(const EchoCanceller3Config& config, size_t num_bands);
41 RenderDelayBufferImpl2() = delete;
42 ~RenderDelayBufferImpl2() override;
43
44 void Reset() override;
45 BufferingEvent Insert(const std::vector<std::vector<float>>& block) override;
46 BufferingEvent PrepareCaptureProcessing() override;
47 bool SetDelay(size_t delay) override;
48 size_t Delay() const override { return ComputeDelay(); }
49 size_t MaxDelay() const override {
50 return blocks_.buffer.size() - 1 - buffer_headroom_;
51 }
52 RenderBuffer* GetRenderBuffer() override { return &echo_remover_buffer_; }
53
54 const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const override {
55 return low_rate_;
56 }
57
58 int BufferLatency() const;
59 bool CausalDelay(size_t delay) const override;
60 void SetAudioBufferDelay(size_t delay_ms) override;
61
62 private:
63 static int instance_count_;
64 std::unique_ptr<ApmDataDumper> data_dumper_;
65 const Aec3Optimization optimization_;
66 const EchoCanceller3Config config_;
67 size_t down_sampling_factor_;
68 const int sub_block_size_;
69 MatrixBuffer blocks_;
70 VectorBuffer spectra_;
71 FftBuffer ffts_;
72 absl::optional<size_t> delay_;
73 RenderBuffer echo_remover_buffer_;
74 DownsampledRenderBuffer low_rate_;
75 Decimator render_decimator_;
76 const Aec3Fft fft_;
77 std::vector<float> render_ds_;
78 const int buffer_headroom_;
79 bool last_call_was_render_ = false;
80 int num_api_calls_in_a_row_ = 0;
81 int max_observed_jitter_ = 1;
82 size_t capture_call_counter_ = 0;
83 size_t render_call_counter_ = 0;
84 bool render_activity_ = false;
85 size_t render_activity_counter_ = 0;
86 absl::optional<size_t> external_audio_buffer_delay_;
87 bool external_audio_buffer_delay_verified_after_reset_ = false;
88 size_t min_latency_blocks_ = 0;
89 size_t excess_render_detection_counter_ = 0;
90 size_t num_bands_;
91
92 int MapDelayToTotalDelay(size_t delay) const;
93 int ComputeDelay() const;
94 void ApplyTotalDelay(int delay);
95 void InsertBlock(const std::vector<std::vector<float>>& block,
96 int previous_write);
97 bool DetectActiveRender(rtc::ArrayView<const float> x) const;
98 bool DetectExcessRenderBlocks();
99 void IncrementWriteIndices();
100 void IncrementLowRateReadIndices();
101 void IncrementReadIndices();
102 bool RenderOverrun();
103 bool RenderUnderrun();
104};
105
106int RenderDelayBufferImpl2::instance_count_ = 0;
107
108RenderDelayBufferImpl2::RenderDelayBufferImpl2(
109 const EchoCanceller3Config& config,
110 size_t num_bands)
111 : data_dumper_(
112 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
113 optimization_(DetectOptimization()),
114 config_(config),
115 down_sampling_factor_(config.delay.down_sampling_factor),
116 sub_block_size_(static_cast<int>(down_sampling_factor_ > 0
117 ? kBlockSize / down_sampling_factor_
118 : kBlockSize)),
119 blocks_(GetRenderDelayBufferSize(down_sampling_factor_,
120 config.delay.num_filters,
121 config.filter.main.length_blocks),
122 num_bands,
123 kBlockSize),
124 spectra_(blocks_.buffer.size(), kFftLengthBy2Plus1),
125 ffts_(blocks_.buffer.size()),
126 delay_(config_.delay.default_delay),
127 echo_remover_buffer_(&blocks_, &spectra_, &ffts_),
128 low_rate_(GetDownSampledBufferSize(down_sampling_factor_,
129 config.delay.num_filters)),
130 render_decimator_(down_sampling_factor_),
131 fft_(),
132 render_ds_(sub_block_size_, 0.f),
133 buffer_headroom_(config.filter.main.length_blocks),
134 num_bands_(num_bands) {
135 RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size());
136 RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size());
137
138 Reset();
139}
140
141RenderDelayBufferImpl2::~RenderDelayBufferImpl2() = default;
142
143// Resets the buffer delays and clears the reported delays.
144void RenderDelayBufferImpl2::Reset() {
145 last_call_was_render_ = false;
146 num_api_calls_in_a_row_ = 1;
147 min_latency_blocks_ = 0;
148 excess_render_detection_counter_ = 0;
149
150 // Initialize the read index to one sub-block before the write index.
151 low_rate_.read = low_rate_.OffsetIndex(low_rate_.write, sub_block_size_);
152
153 // Check for any external audio buffer delay and whether it is feasible.
154 if (external_audio_buffer_delay_) {
155 const size_t headroom = 2;
156 size_t audio_buffer_delay_to_set;
157 // Minimum delay is 1 (like the low-rate render buffer).
158 if (*external_audio_buffer_delay_ <= headroom) {
159 audio_buffer_delay_to_set = 1;
160 } else {
161 audio_buffer_delay_to_set = *external_audio_buffer_delay_ - headroom;
162 }
163
164 audio_buffer_delay_to_set = std::min(audio_buffer_delay_to_set, MaxDelay());
165
166 // When an external delay estimate is available, use that delay as the
167 // initial render buffer delay.
168 ApplyTotalDelay(audio_buffer_delay_to_set);
169 delay_ = ComputeDelay();
170
171 external_audio_buffer_delay_verified_after_reset_ = false;
172 } else {
173 // If an external delay estimate is not available, use that delay as the
174 // initial delay. Set the render buffer delays to the default delay.
175 ApplyTotalDelay(config_.delay.default_delay);
176
177 // Unset the delays which are set by SetDelay.
178 delay_ = absl::nullopt;
179 }
180}
181
182// Inserts a new block into the render buffers.
183RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl2::Insert(
184 const std::vector<std::vector<float>>& block) {
185 ++render_call_counter_;
186 if (delay_) {
187 if (!last_call_was_render_) {
188 last_call_was_render_ = true;
189 num_api_calls_in_a_row_ = 1;
190 } else {
191 if (++num_api_calls_in_a_row_ > max_observed_jitter_) {
192 max_observed_jitter_ = num_api_calls_in_a_row_;
193 RTC_LOG(LS_WARNING)
194 << "New max number api jitter observed at render block "
195 << render_call_counter_ << ": " << num_api_calls_in_a_row_
196 << " blocks";
197 }
198 }
199 }
200
201 // Increase the write indices to where the new blocks should be written.
202 const int previous_write = blocks_.write;
203 IncrementWriteIndices();
204
205 // Allow overrun and do a reset when render overrun occurrs due to more render
206 // data being inserted than capture data is received.
207 BufferingEvent event =
208 RenderOverrun() ? BufferingEvent::kRenderOverrun : BufferingEvent::kNone;
209
210 // Detect and update render activity.
211 if (!render_activity_) {
212 render_activity_counter_ += DetectActiveRender(block[0]) ? 1 : 0;
213 render_activity_ = render_activity_counter_ >= 20;
214 }
215
216 // Insert the new render block into the specified position.
217 InsertBlock(block, previous_write);
218
219 if (event != BufferingEvent::kNone) {
220 Reset();
221 }
222
223 return event;
224}
225
226// Prepares the render buffers for processing another capture block.
227RenderDelayBuffer::BufferingEvent
228RenderDelayBufferImpl2::PrepareCaptureProcessing() {
229 RenderDelayBuffer::BufferingEvent event = BufferingEvent::kNone;
230 ++capture_call_counter_;
231
232 if (delay_) {
233 if (last_call_was_render_) {
234 last_call_was_render_ = false;
235 num_api_calls_in_a_row_ = 1;
236 } else {
237 if (++num_api_calls_in_a_row_ > max_observed_jitter_) {
238 max_observed_jitter_ = num_api_calls_in_a_row_;
239 RTC_LOG(LS_WARNING)
240 << "New max number api jitter observed at capture block "
241 << capture_call_counter_ << ": " << num_api_calls_in_a_row_
242 << " blocks";
243 }
244 }
245 }
246
247 if (DetectExcessRenderBlocks()) {
248 // Too many render blocks compared to capture blocks. Risk of delay ending
249 // up before the filter used by the delay estimator.
250 RTC_LOG(LS_WARNING) << "Excess render blocks detected at block "
251 << capture_call_counter_;
252 Reset();
253 event = BufferingEvent::kRenderOverrun;
254 } else if (RenderUnderrun()) {
255 // Don't increment the read indices of the low rate buffer if there is a
256 // render underrun.
257 RTC_LOG(LS_WARNING) << "Render buffer underrun detected at block "
258 << capture_call_counter_;
259 IncrementReadIndices();
260 // Incrementing the buffer index without increasing the low rate buffer
261 // index means that the delay is reduced by one.
262 if (delay_ && *delay_ > 0)
263 delay_ = *delay_ - 1;
264 event = BufferingEvent::kRenderUnderrun;
265 } else {
266 // Increment the read indices in the render buffers to point to the most
267 // recent block to use in the capture processing.
268 IncrementLowRateReadIndices();
269 IncrementReadIndices();
270 }
271
272 echo_remover_buffer_.SetRenderActivity(render_activity_);
273 if (render_activity_) {
274 render_activity_counter_ = 0;
275 render_activity_ = false;
276 }
277
278 return event;
279}
280
281// Sets the delay and returns a bool indicating whether the delay was changed.
282bool RenderDelayBufferImpl2::SetDelay(size_t delay) {
283 if (!external_audio_buffer_delay_verified_after_reset_ &&
284 external_audio_buffer_delay_ && delay_) {
285 int difference = static_cast<int>(delay) - static_cast<int>(*delay_);
286 RTC_LOG(LS_WARNING) << "Mismatch between first estimated delay after reset "
287 "and externally reported audio buffer delay: "
288 << difference << " blocks";
289 external_audio_buffer_delay_verified_after_reset_ = true;
290 }
291 if (delay_ && *delay_ == delay) {
292 return false;
293 }
294 delay_ = delay;
295
296 // Compute the total delay and limit the delay to the allowed range.
297 int total_delay = MapDelayToTotalDelay(*delay_);
298 total_delay =
299 std::min(MaxDelay(), static_cast<size_t>(std::max(total_delay, 0)));
300
301 // Apply the delay to the buffers.
302 ApplyTotalDelay(total_delay);
303 return true;
304}
305
306// Returns whether the specified delay is causal.
307bool RenderDelayBufferImpl2::CausalDelay(size_t delay) const {
308 // TODO(gustaf): Remove this from RenderDelayBuffer.
309 return true;
310}
311
312void RenderDelayBufferImpl2::SetAudioBufferDelay(size_t delay_ms) {
313 if (!external_audio_buffer_delay_) {
314 RTC_LOG(LS_WARNING)
315 << "Receiving a first externally reported audio buffer delay of "
316 << delay_ms << " ms.";
317 }
318
319 // Convert delay from milliseconds to blocks (rounded down).
320 external_audio_buffer_delay_ = delay_ms >> ((num_bands_ == 1) ? 1 : 2);
321}
322
323// Maps the externally computed delay to the delay used internally.
324int RenderDelayBufferImpl2::MapDelayToTotalDelay(
325 size_t external_delay_blocks) const {
326 const int latency_blocks = BufferLatency();
327 return latency_blocks + static_cast<int>(external_delay_blocks);
328}
329
330// Returns the delay (not including call jitter).
331int RenderDelayBufferImpl2::ComputeDelay() const {
332 const int latency_blocks = BufferLatency();
333 int internal_delay = spectra_.read >= spectra_.write
334 ? spectra_.read - spectra_.write
335 : spectra_.size + spectra_.read - spectra_.write;
336
337 return internal_delay - latency_blocks;
338}
339
340// Set the read indices according to the delay.
341void RenderDelayBufferImpl2::ApplyTotalDelay(int delay) {
342 RTC_LOG(LS_WARNING) << "Applying total delay of " << delay << " blocks.";
343 blocks_.read = blocks_.OffsetIndex(blocks_.write, -delay);
344 spectra_.read = spectra_.OffsetIndex(spectra_.write, delay);
345 ffts_.read = ffts_.OffsetIndex(ffts_.write, delay);
346}
347
348// Inserts a block into the render buffers.
349void RenderDelayBufferImpl2::InsertBlock(
350 const std::vector<std::vector<float>>& block,
351 int previous_write) {
352 auto& b = blocks_;
353 auto& lr = low_rate_;
354 auto& ds = render_ds_;
355 auto& f = ffts_;
356 auto& s = spectra_;
357 RTC_DCHECK_EQ(block.size(), b.buffer[b.write].size());
358 for (size_t k = 0; k < block.size(); ++k) {
359 RTC_DCHECK_EQ(block[k].size(), b.buffer[b.write][k].size());
360 std::copy(block[k].begin(), block[k].end(), b.buffer[b.write][k].begin());
361 }
362
363 data_dumper_->DumpWav("aec3_render_decimator_input", block[0].size(),
364 block[0].data(), 16000, 1);
365 render_decimator_.Decimate(block[0], ds);
366 data_dumper_->DumpWav("aec3_render_decimator_output", ds.size(), ds.data(),
367 16000 / down_sampling_factor_, 1);
368 std::copy(ds.rbegin(), ds.rend(), lr.buffer.begin() + lr.write);
369 fft_.PaddedFft(block[0], b.buffer[previous_write][0], &f.buffer[f.write]);
370 f.buffer[f.write].Spectrum(optimization_, s.buffer[s.write]);
371}
372
373bool RenderDelayBufferImpl2::DetectActiveRender(
374 rtc::ArrayView<const float> x) const {
375 const float x_energy = std::inner_product(x.begin(), x.end(), x.begin(), 0.f);
376 return x_energy > (config_.render_levels.active_render_limit *
377 config_.render_levels.active_render_limit) *
378 kFftLengthBy2;
379}
380
381bool RenderDelayBufferImpl2::DetectExcessRenderBlocks() {
382 bool excess_render_detected = false;
383 const size_t latency_blocks = static_cast<size_t>(BufferLatency());
384 // The recently seen minimum latency in blocks. Should be close to 0.
385 min_latency_blocks_ = std::min(min_latency_blocks_, latency_blocks);
386 // After processing a configurable number of blocks the minimum latency is
387 // checked.
388 if (++excess_render_detection_counter_ >=
389 config_.buffering.excess_render_detection_interval_blocks) {
390 // If the minimum latency is not lower than the threshold there have been
391 // more render than capture frames.
392 excess_render_detected = min_latency_blocks_ >
393 config_.buffering.max_allowed_excess_render_blocks;
394 // Reset the counter and let the minimum latency be the current latency.
395 min_latency_blocks_ = latency_blocks;
396 excess_render_detection_counter_ = 0;
397 }
398
399 data_dumper_->DumpRaw("aec3_latency_blocks", latency_blocks);
400 data_dumper_->DumpRaw("aec3_min_latency_blocks", min_latency_blocks_);
401 data_dumper_->DumpRaw("aec3_excess_render_detected", excess_render_detected);
402 return excess_render_detected;
403}
404
405// Computes the latency in the buffer (the number of unread sub-blocks).
406int RenderDelayBufferImpl2::BufferLatency() const {
407 const DownsampledRenderBuffer& l = low_rate_;
408 int latency_samples = (l.buffer.size() + l.read - l.write) % l.buffer.size();
409 int latency_blocks = latency_samples / sub_block_size_;
410 return latency_blocks;
411}
412
413// Increments the write indices for the render buffers.
414void RenderDelayBufferImpl2::IncrementWriteIndices() {
415 low_rate_.UpdateWriteIndex(-sub_block_size_);
416 blocks_.IncWriteIndex();
417 spectra_.DecWriteIndex();
418 ffts_.DecWriteIndex();
419}
420
421// Increments the read indices of the low rate render buffers.
422void RenderDelayBufferImpl2::IncrementLowRateReadIndices() {
423 low_rate_.UpdateReadIndex(-sub_block_size_);
424}
425
426// Increments the read indices for the render buffers.
427void RenderDelayBufferImpl2::IncrementReadIndices() {
428 if (blocks_.read != blocks_.write) {
429 blocks_.IncReadIndex();
430 spectra_.DecReadIndex();
431 ffts_.DecReadIndex();
432 }
433}
434
435// Checks for a render buffer overrun.
436bool RenderDelayBufferImpl2::RenderOverrun() {
437 return low_rate_.read == low_rate_.write || blocks_.read == blocks_.write;
438}
439
440// Checks for a render buffer underrun.
441bool RenderDelayBufferImpl2::RenderUnderrun() {
442 return low_rate_.read == low_rate_.write;
443}
444
445} // namespace
446
447RenderDelayBuffer* RenderDelayBuffer::Create2(
448 const EchoCanceller3Config& config,
449 size_t num_bands) {
450 return new RenderDelayBufferImpl2(config, num_bands);
451}
452
453} // namespace webrtc