mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 22:00:47 +01:00

This CL centralizes the render buffering in AEC3 so that all render buffers are updated and synchronized/aligned with the render alignment buffer. Bug: webrtc:8597, chromium:790905 Change-Id: I8a94e5c1f27316b6100b420eec9652ea31c1a91d Reviewed-on: https://webrtc-review.googlesource.com/25680 Commit-Queue: Per Åhgren <peah@webrtc.org> Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20989}
240 lines
8.1 KiB
C++
240 lines
8.1 KiB
C++
/*
|
|
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/audio_processing/aec3/render_delay_buffer.h"
|
|
|
|
#include <string.h>
|
|
#include <algorithm>
|
|
|
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
|
#include "modules/audio_processing/aec3/aec3_fft.h"
|
|
#include "modules/audio_processing/aec3/block_processor.h"
|
|
#include "modules/audio_processing/aec3/decimator.h"
|
|
#include "modules/audio_processing/aec3/fft_buffer.h"
|
|
#include "modules/audio_processing/aec3/fft_data.h"
|
|
#include "modules/audio_processing/aec3/matrix_buffer.h"
|
|
#include "rtc_base/atomicops.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/constructormagic.h"
|
|
#include "rtc_base/logging.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
constexpr int kBufferHeadroom = kAdaptiveFilterLength;
|
|
|
|
class RenderDelayBufferImpl final : public RenderDelayBuffer {
|
|
public:
|
|
RenderDelayBufferImpl(const EchoCanceller3Config& config, size_t num_bands);
|
|
~RenderDelayBufferImpl() override;
|
|
|
|
void Reset() override;
|
|
BufferingEvent Insert(const std::vector<std::vector<float>>& block) override;
|
|
BufferingEvent PrepareCaptureCall() override;
|
|
void SetDelay(size_t delay) override;
|
|
size_t Delay() const override { return delay_; }
|
|
size_t MaxDelay() const override {
|
|
return blocks_.buffer.size() - 1 - kBufferHeadroom;
|
|
}
|
|
size_t MaxApiJitter() const override { return max_api_jitter_; }
|
|
const RenderBuffer& GetRenderBuffer() const override {
|
|
return echo_remover_buffer_;
|
|
}
|
|
|
|
const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const override {
|
|
return low_rate_;
|
|
}
|
|
|
|
private:
|
|
static int instance_count_;
|
|
std::unique_ptr<ApmDataDumper> data_dumper_;
|
|
const Aec3Optimization optimization_;
|
|
const size_t api_call_jitter_blocks_;
|
|
const size_t min_echo_path_delay_blocks_;
|
|
const int sub_block_size_;
|
|
MatrixBuffer blocks_;
|
|
VectorBuffer spectra_;
|
|
FftBuffer ffts_;
|
|
size_t delay_;
|
|
int max_api_jitter_ = 0;
|
|
int render_surplus_ = 0;
|
|
bool first_reset_occurred_ = false;
|
|
RenderBuffer echo_remover_buffer_;
|
|
DownsampledRenderBuffer low_rate_;
|
|
Decimator render_decimator_;
|
|
const std::vector<std::vector<float>> zero_block_;
|
|
const Aec3Fft fft_;
|
|
size_t capture_call_counter_ = 0;
|
|
std::vector<float> render_ds_;
|
|
int render_calls_in_a_row_ = 0;
|
|
|
|
void UpdateBuffersWithLatestBlock(size_t previous_write);
|
|
void IncreaseRead();
|
|
void IncreaseInsert();
|
|
|
|
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderDelayBufferImpl);
|
|
};
|
|
|
|
int RenderDelayBufferImpl::instance_count_ = 0;
|
|
|
|
RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
|
|
size_t num_bands)
|
|
: data_dumper_(
|
|
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
|
optimization_(DetectOptimization()),
|
|
api_call_jitter_blocks_(config.delay.api_call_jitter_blocks),
|
|
min_echo_path_delay_blocks_(config.delay.min_echo_path_delay_blocks),
|
|
sub_block_size_(
|
|
static_cast<int>(config.delay.down_sampling_factor > 0
|
|
? kBlockSize / config.delay.down_sampling_factor
|
|
: kBlockSize)),
|
|
blocks_(GetRenderDelayBufferSize(config.delay.down_sampling_factor,
|
|
config.delay.num_filters),
|
|
num_bands,
|
|
kBlockSize),
|
|
spectra_(blocks_.buffer.size(), kFftLengthBy2Plus1),
|
|
ffts_(blocks_.buffer.size()),
|
|
delay_(min_echo_path_delay_blocks_),
|
|
echo_remover_buffer_(kAdaptiveFilterLength, &blocks_, &spectra_, &ffts_),
|
|
low_rate_(GetDownSampledBufferSize(config.delay.down_sampling_factor,
|
|
config.delay.num_filters)),
|
|
render_decimator_(config.delay.down_sampling_factor),
|
|
zero_block_(num_bands, std::vector<float>(kBlockSize, 0.f)),
|
|
fft_(),
|
|
render_ds_(sub_block_size_, 0.f) {
|
|
RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size());
|
|
RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size());
|
|
Reset();
|
|
first_reset_occurred_ = false;
|
|
}
|
|
|
|
RenderDelayBufferImpl::~RenderDelayBufferImpl() = default;
|
|
|
|
void RenderDelayBufferImpl::Reset() {
|
|
delay_ = min_echo_path_delay_blocks_;
|
|
const int offset1 = std::max<int>(
|
|
std::min(api_call_jitter_blocks_, min_echo_path_delay_blocks_), 1);
|
|
const int offset2 = static_cast<int>(delay_ + offset1);
|
|
const int offset3 = offset1 * sub_block_size_;
|
|
low_rate_.read = low_rate_.OffsetIndex(low_rate_.write, offset3);
|
|
blocks_.read = blocks_.OffsetIndex(blocks_.write, -offset2);
|
|
spectra_.read = spectra_.OffsetIndex(spectra_.write, offset2);
|
|
ffts_.read = ffts_.OffsetIndex(ffts_.write, offset2);
|
|
render_surplus_ = 0;
|
|
first_reset_occurred_ = true;
|
|
}
|
|
|
|
RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert(
|
|
const std::vector<std::vector<float>>& block) {
|
|
RTC_DCHECK_EQ(block.size(), blocks_.buffer[0].size());
|
|
RTC_DCHECK_EQ(block[0].size(), blocks_.buffer[0][0].size());
|
|
BufferingEvent event = BufferingEvent::kNone;
|
|
|
|
++render_surplus_;
|
|
if (first_reset_occurred_) {
|
|
++render_calls_in_a_row_;
|
|
max_api_jitter_ = std::max(max_api_jitter_, render_calls_in_a_row_);
|
|
}
|
|
|
|
const size_t previous_write = blocks_.write;
|
|
IncreaseInsert();
|
|
|
|
if (low_rate_.read == low_rate_.write || blocks_.read == blocks_.write) {
|
|
// Render overrun due to more render data being inserted than read. Discard
|
|
// the oldest render data.
|
|
event = BufferingEvent::kRenderOverrun;
|
|
IncreaseRead();
|
|
}
|
|
|
|
for (size_t k = 0; k < block.size(); ++k) {
|
|
std::copy(block[k].begin(), block[k].end(),
|
|
blocks_.buffer[blocks_.write][k].begin());
|
|
}
|
|
|
|
UpdateBuffersWithLatestBlock(previous_write);
|
|
return event;
|
|
}
|
|
|
|
RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::PrepareCaptureCall() {
|
|
BufferingEvent event = BufferingEvent::kNone;
|
|
render_calls_in_a_row_ = 0;
|
|
|
|
if (low_rate_.read == low_rate_.write || blocks_.read == blocks_.write) {
|
|
event = BufferingEvent::kRenderUnderrun;
|
|
} else {
|
|
IncreaseRead();
|
|
}
|
|
--render_surplus_;
|
|
|
|
echo_remover_buffer_.UpdateSpectralSum();
|
|
|
|
if (render_surplus_ >= static_cast<int>(api_call_jitter_blocks_)) {
|
|
event = BufferingEvent::kApiCallSkew;
|
|
RTC_LOG(LS_WARNING) << "Api call skew detected at " << capture_call_counter_
|
|
<< ".";
|
|
}
|
|
|
|
++capture_call_counter_;
|
|
return event;
|
|
}
|
|
|
|
void RenderDelayBufferImpl::SetDelay(size_t delay) {
|
|
if (delay_ == delay) {
|
|
return;
|
|
}
|
|
|
|
const int delta_delay = static_cast<int>(delay_) - static_cast<int>(delay);
|
|
delay_ = delay;
|
|
if (delay_ > MaxDelay()) {
|
|
delay_ = std::min(MaxDelay(), delay);
|
|
RTC_NOTREACHED();
|
|
}
|
|
|
|
// Recompute the read indices according to the set delay.
|
|
blocks_.UpdateReadIndex(delta_delay);
|
|
spectra_.UpdateReadIndex(-delta_delay);
|
|
ffts_.UpdateReadIndex(-delta_delay);
|
|
}
|
|
|
|
void RenderDelayBufferImpl::UpdateBuffersWithLatestBlock(
|
|
size_t previous_write) {
|
|
render_decimator_.Decimate(blocks_.buffer[blocks_.write][0], render_ds_);
|
|
std::copy(render_ds_.rbegin(), render_ds_.rend(),
|
|
low_rate_.buffer.begin() + low_rate_.write);
|
|
|
|
fft_.PaddedFft(blocks_.buffer[blocks_.write][0],
|
|
blocks_.buffer[previous_write][0], &ffts_.buffer[ffts_.write]);
|
|
|
|
ffts_.buffer[ffts_.write].Spectrum(optimization_,
|
|
spectra_.buffer[spectra_.write]);
|
|
};
|
|
|
|
void RenderDelayBufferImpl::IncreaseRead() {
|
|
low_rate_.UpdateReadIndex(-sub_block_size_);
|
|
blocks_.IncReadIndex();
|
|
spectra_.DecReadIndex();
|
|
ffts_.DecReadIndex();
|
|
};
|
|
|
|
void RenderDelayBufferImpl::IncreaseInsert() {
|
|
low_rate_.UpdateWriteIndex(-sub_block_size_);
|
|
blocks_.IncWriteIndex();
|
|
spectra_.DecWriteIndex();
|
|
ffts_.DecWriteIndex();
|
|
};
|
|
|
|
} // namespace
|
|
|
|
RenderDelayBuffer* RenderDelayBuffer::Create(const EchoCanceller3Config& config,
|
|
size_t num_bands) {
|
|
return new RenderDelayBufferImpl(config, num_bands);
|
|
}
|
|
|
|
} // namespace webrtc
|