blob: 9640131885401a5ae8342e201e8ae84268fec1fb [file] [log] [blame]
/*
* 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