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