AEC3: 'Block' class
This change adds a Block class to reduce the need for std::vector<std::vector<std::vector<float>>>. This make the code easier to read and less error prone. It also enables future changes to the underlying data structure of a block. For instance, the data of all bands and channels could be stored in a single vector. The change has been verified to be bit-exact. Bug: webrtc:14089 Change-Id: Ied9a78124c0bbafe0e912017aef91f7c311de2ae Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/262252 Reviewed-by: Per Åhgren <peah@webrtc.org> Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org> Cr-Commit-Position: refs/heads/main@{#36968}
This commit is contained in:
parent
742714870a
commit
d3ead1a942
@ -22,6 +22,7 @@ rtc_library("aec3") {
|
|||||||
"alignment_mixer.h",
|
"alignment_mixer.h",
|
||||||
"api_call_jitter_metrics.cc",
|
"api_call_jitter_metrics.cc",
|
||||||
"api_call_jitter_metrics.h",
|
"api_call_jitter_metrics.h",
|
||||||
|
"block.h",
|
||||||
"block_buffer.cc",
|
"block_buffer.cc",
|
||||||
"block_delay_buffer.cc",
|
"block_delay_buffer.cc",
|
||||||
"block_delay_buffer.h",
|
"block_delay_buffer.h",
|
||||||
@ -182,6 +183,7 @@ rtc_source_set("aec3_fft") {
|
|||||||
|
|
||||||
rtc_source_set("render_buffer") {
|
rtc_source_set("render_buffer") {
|
||||||
sources = [
|
sources = [
|
||||||
|
"block.h",
|
||||||
"block_buffer.h",
|
"block_buffer.h",
|
||||||
"fft_buffer.h",
|
"fft_buffer.h",
|
||||||
"render_buffer.h",
|
"render_buffer.h",
|
||||||
|
|||||||
@ -73,10 +73,7 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
|
|||||||
RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
|
RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
|
||||||
num_render_channels));
|
num_render_channels));
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_render_channels);
|
||||||
kNumBands,
|
|
||||||
std::vector<std::vector<float>>(num_render_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
FftData S_C;
|
FftData S_C;
|
||||||
FftData S_Neon;
|
FftData S_Neon;
|
||||||
FftData G;
|
FftData G;
|
||||||
@ -92,10 +89,10 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t k = 0; k < 30; ++k) {
|
for (int k = 0; k < 30; ++k) {
|
||||||
for (size_t band = 0; band < x.size(); ++band) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (size_t ch = 0; ch < x[band].size(); ++ch) {
|
for (int ch = 0; ch < x.NumChannels(); ++ch) {
|
||||||
RandomizeSampleVector(&random_generator, x[band][ch]);
|
RandomizeSampleVector(&random_generator, x.View(band, ch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render_delay_buffer->Insert(x);
|
render_delay_buffer->Insert(x);
|
||||||
@ -186,10 +183,7 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
|
|||||||
RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
|
RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
|
||||||
num_render_channels));
|
num_render_channels));
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_render_channels);
|
||||||
kNumBands,
|
|
||||||
std::vector<std::vector<float>>(num_render_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
FftData S_C;
|
FftData S_C;
|
||||||
FftData S_Sse2;
|
FftData S_Sse2;
|
||||||
FftData G;
|
FftData G;
|
||||||
@ -206,9 +200,9 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t k = 0; k < 500; ++k) {
|
for (size_t k = 0; k < 500; ++k) {
|
||||||
for (size_t band = 0; band < x.size(); ++band) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (size_t ch = 0; ch < x[band].size(); ++ch) {
|
for (int ch = 0; ch < x.NumChannels(); ++ch) {
|
||||||
RandomizeSampleVector(&random_generator, x[band][ch]);
|
RandomizeSampleVector(&random_generator, x.View(band, ch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render_delay_buffer->Insert(x);
|
render_delay_buffer->Insert(x);
|
||||||
@ -261,10 +255,7 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
|
|||||||
RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
|
RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
|
||||||
num_render_channels));
|
num_render_channels));
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_render_channels);
|
||||||
kNumBands,
|
|
||||||
std::vector<std::vector<float>>(num_render_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
FftData S_C;
|
FftData S_C;
|
||||||
FftData S_Avx2;
|
FftData S_Avx2;
|
||||||
FftData G;
|
FftData G;
|
||||||
@ -281,9 +272,9 @@ TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t k = 0; k < 500; ++k) {
|
for (size_t k = 0; k < 500; ++k) {
|
||||||
for (size_t band = 0; band < x.size(); ++band) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (size_t ch = 0; ch < x[band].size(); ++ch) {
|
for (int ch = 0; ch < x.NumChannels(); ++ch) {
|
||||||
RandomizeSampleVector(&random_generator, x[band][ch]);
|
RandomizeSampleVector(&random_generator, x.View(band, ch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render_delay_buffer->Insert(x);
|
render_delay_buffer->Insert(x);
|
||||||
@ -488,9 +479,7 @@ TEST_P(AdaptiveFirFilterMultiChannel, FilterAndAdapt) {
|
|||||||
CoarseFilterUpdateGain gain(config.filter.coarse,
|
CoarseFilterUpdateGain gain(config.filter.coarse,
|
||||||
config.filter.config_change_duration_blocks);
|
config.filter.config_change_duration_blocks);
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_render_channels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<float> n(kBlockSize, 0.f);
|
std::vector<float> n(kBlockSize, 0.f);
|
||||||
std::vector<float> y(kBlockSize, 0.f);
|
std::vector<float> y(kBlockSize, 0.f);
|
||||||
AecState aec_state(EchoCanceller3Config{}, num_capture_channels);
|
AecState aec_state(EchoCanceller3Config{}, num_capture_channels);
|
||||||
@ -540,9 +529,9 @@ TEST_P(AdaptiveFirFilterMultiChannel, FilterAndAdapt) {
|
|||||||
for (size_t j = 0; j < num_blocks_to_process; ++j) {
|
for (size_t j = 0; j < num_blocks_to_process; ++j) {
|
||||||
std::fill(y.begin(), y.end(), 0.f);
|
std::fill(y.begin(), y.end(), 0.f);
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||||
RandomizeSampleVector(&random_generator, x[0][ch]);
|
RandomizeSampleVector(&random_generator, x.View(/*band=*/0, ch));
|
||||||
std::array<float, kBlockSize> y_channel;
|
std::array<float, kBlockSize> y_channel;
|
||||||
delay_buffer[ch].Delay(x[0][ch], y_channel);
|
delay_buffer[ch].Delay(x.View(/*band=*/0, ch), y_channel);
|
||||||
for (size_t k = 0; k < y.size(); ++k) {
|
for (size_t k = 0; k < y.size(); ++k) {
|
||||||
y[k] += y_channel[k] / num_render_channels;
|
y[k] += y_channel[k] / num_render_channels;
|
||||||
}
|
}
|
||||||
@ -555,7 +544,7 @@ TEST_P(AdaptiveFirFilterMultiChannel, FilterAndAdapt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||||
x_hp_filter[ch]->Process(x[0][ch]);
|
x_hp_filter[ch]->Process(x.View(/*band=*/0, ch));
|
||||||
}
|
}
|
||||||
y_hp_filter.Process(y);
|
y_hp_filter.Process(y);
|
||||||
|
|
||||||
|
|||||||
@ -206,15 +206,16 @@ void AecState::Update(
|
|||||||
strong_not_saturated_render_blocks_);
|
strong_not_saturated_render_blocks_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::vector<float>>& aligned_render_block =
|
const Block& aligned_render_block =
|
||||||
render_buffer.Block(-delay_state_.MinDirectPathFilterDelay())[0];
|
render_buffer.Block(-delay_state_.MinDirectPathFilterDelay());
|
||||||
|
|
||||||
// Update render counters.
|
// Update render counters.
|
||||||
bool active_render = false;
|
bool active_render = false;
|
||||||
for (size_t ch = 0; ch < aligned_render_block.size(); ++ch) {
|
for (int ch = 0; ch < aligned_render_block.NumChannels(); ++ch) {
|
||||||
const float render_energy = std::inner_product(
|
const float render_energy =
|
||||||
aligned_render_block[ch].begin(), aligned_render_block[ch].end(),
|
std::inner_product(aligned_render_block.begin(/*block=*/0, ch),
|
||||||
aligned_render_block[ch].begin(), 0.f);
|
aligned_render_block.end(/*block=*/0, ch),
|
||||||
|
aligned_render_block.begin(/*block=*/0, ch), 0.f);
|
||||||
if (render_energy > (config_.render_levels.active_render_limit *
|
if (render_energy > (config_.render_levels.active_render_limit *
|
||||||
config_.render_levels.active_render_limit) *
|
config_.render_levels.active_render_limit) *
|
||||||
kFftLengthBy2) {
|
kFftLengthBy2) {
|
||||||
@ -446,7 +447,7 @@ void AecState::FilteringQualityAnalyzer::Update(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AecState::SaturationDetector::Update(
|
void AecState::SaturationDetector::Update(
|
||||||
rtc::ArrayView<const std::vector<float>> x,
|
const Block& x,
|
||||||
bool saturated_capture,
|
bool saturated_capture,
|
||||||
bool usable_linear_estimate,
|
bool usable_linear_estimate,
|
||||||
rtc::ArrayView<const SubtractorOutput> subtractor_output,
|
rtc::ArrayView<const SubtractorOutput> subtractor_output,
|
||||||
@ -466,8 +467,9 @@ void AecState::SaturationDetector::Update(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
float max_sample = 0.f;
|
float max_sample = 0.f;
|
||||||
for (auto& channel : x) {
|
for (int ch = 0; ch < x.NumChannels(); ++ch) {
|
||||||
for (float sample : channel) {
|
rtc::ArrayView<const float, kBlockSize> x_ch = x.View(/*band=*/0, ch);
|
||||||
|
for (float sample : x_ch) {
|
||||||
max_sample = std::max(max_sample, fabsf(sample));
|
max_sample = std::max(max_sample, fabsf(sample));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -272,7 +272,7 @@ class AecState {
|
|||||||
bool SaturatedEcho() const { return saturated_echo_; }
|
bool SaturatedEcho() const { return saturated_echo_; }
|
||||||
|
|
||||||
// Updates the detection decision based on new data.
|
// Updates the detection decision based on new data.
|
||||||
void Update(rtc::ArrayView<const std::vector<float>> x,
|
void Update(const Block& x,
|
||||||
bool saturated_capture,
|
bool saturated_capture,
|
||||||
bool usable_linear_estimate,
|
bool usable_linear_estimate,
|
||||||
rtc::ArrayView<const SubtractorOutput> subtractor_output,
|
rtc::ArrayView<const SubtractorOutput> subtractor_output,
|
||||||
|
|||||||
@ -35,9 +35,7 @@ void RunNormalUsageTest(size_t num_render_channels,
|
|||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> E2_refined(
|
std::vector<std::array<float, kFftLengthBy2Plus1>> E2_refined(
|
||||||
num_capture_channels);
|
num_capture_channels);
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2(num_capture_channels);
|
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2(num_capture_channels);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_render_channels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
EchoPathVariability echo_path_variability(
|
EchoPathVariability echo_path_variability(
|
||||||
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
||||||
std::vector<std::array<float, kBlockSize>> y(num_capture_channels);
|
std::vector<std::array<float, kBlockSize>> y(num_capture_channels);
|
||||||
@ -52,9 +50,9 @@ void RunNormalUsageTest(size_t num_render_channels,
|
|||||||
}
|
}
|
||||||
Aec3Fft fft;
|
Aec3Fft fft;
|
||||||
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
||||||
converged_filter_frequency_response(
|
converged_filter_frequency_response(
|
||||||
num_capture_channels,
|
num_capture_channels,
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>>(10));
|
std::vector<std::array<float, kFftLengthBy2Plus1>>(10));
|
||||||
for (auto& v_ch : converged_filter_frequency_response) {
|
for (auto& v_ch : converged_filter_frequency_response) {
|
||||||
for (auto& v : v_ch) {
|
for (auto& v : v_ch) {
|
||||||
v.fill(0.01f);
|
v.fill(0.01f);
|
||||||
@ -72,7 +70,7 @@ void RunNormalUsageTest(size_t num_render_channels,
|
|||||||
// Verify that linear AEC usability is true when the filter is converged
|
// Verify that linear AEC usability is true when the filter is converged
|
||||||
for (size_t band = 0; band < kNumBands; ++band) {
|
for (size_t band = 0; band < kNumBands; ++band) {
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||||
std::fill(x[band][ch].begin(), x[band][ch].end(), 101.f);
|
std::fill(x.begin(band, ch), x.end(band, ch), 101.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int k = 0; k < 3000; ++k) {
|
for (int k = 0; k < 3000; ++k) {
|
||||||
@ -100,7 +98,7 @@ void RunNormalUsageTest(size_t num_render_channels,
|
|||||||
|
|
||||||
// Verify that the active render detection works as intended.
|
// Verify that the active render detection works as intended.
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||||
std::fill(x[0][ch].begin(), x[0][ch].end(), 101.f);
|
std::fill(x.begin(0, ch), x.end(0, ch), 101.f);
|
||||||
}
|
}
|
||||||
render_delay_buffer->Insert(x);
|
render_delay_buffer->Insert(x);
|
||||||
for (size_t ch = 0; ch < num_capture_channels; ++ch) {
|
for (size_t ch = 0; ch < num_capture_channels; ++ch) {
|
||||||
@ -125,14 +123,14 @@ void RunNormalUsageTest(size_t num_render_channels,
|
|||||||
EXPECT_TRUE(state.ActiveRender());
|
EXPECT_TRUE(state.ActiveRender());
|
||||||
|
|
||||||
// Verify that the ERL is properly estimated
|
// Verify that the ERL is properly estimated
|
||||||
for (auto& band : x) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (auto& channel : band) {
|
for (int channel = 0; channel < x.NumChannels(); ++channel) {
|
||||||
channel = std::vector<float>(kBlockSize, 0.f);
|
std::fill(x.begin(band, channel), x.end(band, channel), 0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||||
x[0][ch][0] = 5000.f;
|
x.View(/*band=*/0, ch)[0] = 5000.f;
|
||||||
}
|
}
|
||||||
for (size_t k = 0;
|
for (size_t k = 0;
|
||||||
k < render_delay_buffer->GetRenderBuffer()->GetFftBuffer().size(); ++k) {
|
k < render_delay_buffer->GetRenderBuffer()->GetFftBuffer().size(); ++k) {
|
||||||
@ -266,9 +264,9 @@ TEST(AecState, ConvergedFilterDelay) {
|
|||||||
y.fill(0.f);
|
y.fill(0.f);
|
||||||
|
|
||||||
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
||||||
frequency_response(
|
frequency_response(kNumCaptureChannels,
|
||||||
kNumCaptureChannels,
|
std::vector<std::array<float, kFftLengthBy2Plus1>>(
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>>(kFilterLengthBlocks));
|
kFilterLengthBlocks));
|
||||||
for (auto& v_ch : frequency_response) {
|
for (auto& v_ch : frequency_response) {
|
||||||
for (auto& v : v_ch) {
|
for (auto& v : v_ch) {
|
||||||
v.fill(0.01f);
|
v.fill(0.01f);
|
||||||
|
|||||||
@ -63,9 +63,10 @@ AlignmentMixer::AlignmentMixer(size_t num_channels,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlignmentMixer::ProduceOutput(rtc::ArrayView<const std::vector<float>> x,
|
void AlignmentMixer::ProduceOutput(const Block& x,
|
||||||
rtc::ArrayView<float, kBlockSize> y) {
|
rtc::ArrayView<float, kBlockSize> y) {
|
||||||
RTC_DCHECK_EQ(x.size(), num_channels_);
|
RTC_DCHECK_EQ(x.NumChannels(), num_channels_);
|
||||||
|
|
||||||
if (selection_variant_ == MixingVariant::kDownmix) {
|
if (selection_variant_ == MixingVariant::kDownmix) {
|
||||||
Downmix(x, y);
|
Downmix(x, y);
|
||||||
return;
|
return;
|
||||||
@ -73,18 +74,20 @@ void AlignmentMixer::ProduceOutput(rtc::ArrayView<const std::vector<float>> x,
|
|||||||
|
|
||||||
int ch = selection_variant_ == MixingVariant::kFixed ? 0 : SelectChannel(x);
|
int ch = selection_variant_ == MixingVariant::kFixed ? 0 : SelectChannel(x);
|
||||||
|
|
||||||
RTC_DCHECK_GE(x.size(), ch);
|
RTC_DCHECK_GT(x.NumChannels(), ch);
|
||||||
std::copy(x[ch].begin(), x[ch].end(), y.begin());
|
std::copy(x.begin(/*band=*/0, ch), x.end(/*band=*/0, ch), y.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlignmentMixer::Downmix(rtc::ArrayView<const std::vector<float>> x,
|
void AlignmentMixer::Downmix(const Block& x,
|
||||||
rtc::ArrayView<float, kBlockSize> y) const {
|
rtc::ArrayView<float, kBlockSize> y) const {
|
||||||
RTC_DCHECK_EQ(x.size(), num_channels_);
|
RTC_DCHECK_EQ(x.NumChannels(), num_channels_);
|
||||||
RTC_DCHECK_GE(num_channels_, 2);
|
RTC_DCHECK_GE(num_channels_, 2);
|
||||||
std::copy(x[0].begin(), x[0].end(), y.begin());
|
std::memcpy(&y[0], x.View(/*band=*/0, /*channel=*/0).data(),
|
||||||
|
kBlockSize * sizeof(y[0]));
|
||||||
for (size_t ch = 1; ch < num_channels_; ++ch) {
|
for (size_t ch = 1; ch < num_channels_; ++ch) {
|
||||||
|
const auto x_ch = x.View(/*band=*/0, ch);
|
||||||
for (size_t i = 0; i < kBlockSize; ++i) {
|
for (size_t i = 0; i < kBlockSize; ++i) {
|
||||||
y[i] += x[ch][i];
|
y[i] += x_ch[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +96,8 @@ void AlignmentMixer::Downmix(rtc::ArrayView<const std::vector<float>> x,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AlignmentMixer::SelectChannel(rtc::ArrayView<const std::vector<float>> x) {
|
int AlignmentMixer::SelectChannel(const Block& x) {
|
||||||
RTC_DCHECK_EQ(x.size(), num_channels_);
|
RTC_DCHECK_EQ(x.NumChannels(), num_channels_);
|
||||||
RTC_DCHECK_GE(num_channels_, 2);
|
RTC_DCHECK_GE(num_channels_, 2);
|
||||||
RTC_DCHECK_EQ(cumulative_energies_.size(), num_channels_);
|
RTC_DCHECK_EQ(cumulative_energies_.size(), num_channels_);
|
||||||
|
|
||||||
@ -112,10 +115,10 @@ int AlignmentMixer::SelectChannel(rtc::ArrayView<const std::vector<float>> x) {
|
|||||||
++block_counter_;
|
++block_counter_;
|
||||||
|
|
||||||
for (int ch = 0; ch < num_ch_to_analyze; ++ch) {
|
for (int ch = 0; ch < num_ch_to_analyze; ++ch) {
|
||||||
RTC_DCHECK_EQ(x[ch].size(), kBlockSize);
|
|
||||||
float x2_sum = 0.f;
|
float x2_sum = 0.f;
|
||||||
|
rtc::ArrayView<const float, kBlockSize> x_ch = x.View(/*band=*/0, ch);
|
||||||
for (size_t i = 0; i < kBlockSize; ++i) {
|
for (size_t i = 0; i < kBlockSize; ++i) {
|
||||||
x2_sum += x[ch][i] * x[ch][i];
|
x2_sum += x_ch[i] * x_ch[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch < 2 && x2_sum > excitation_energy_threshold_) {
|
if (ch < 2 && x2_sum > excitation_energy_threshold_) {
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "api/audio/echo_canceller3_config.h"
|
#include "api/audio/echo_canceller3_config.h"
|
||||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -33,8 +34,7 @@ class AlignmentMixer {
|
|||||||
float excitation_limit,
|
float excitation_limit,
|
||||||
bool prefer_first_two_channels);
|
bool prefer_first_two_channels);
|
||||||
|
|
||||||
void ProduceOutput(rtc::ArrayView<const std::vector<float>> x,
|
void ProduceOutput(const Block& x, rtc::ArrayView<float, kBlockSize> y);
|
||||||
rtc::ArrayView<float, kBlockSize> y);
|
|
||||||
|
|
||||||
enum class MixingVariant { kDownmix, kAdaptive, kFixed };
|
enum class MixingVariant { kDownmix, kAdaptive, kFixed };
|
||||||
|
|
||||||
@ -49,9 +49,8 @@ class AlignmentMixer {
|
|||||||
int selected_channel_ = 0;
|
int selected_channel_ = 0;
|
||||||
size_t block_counter_ = 0;
|
size_t block_counter_ = 0;
|
||||||
|
|
||||||
void Downmix(rtc::ArrayView<const std::vector<float>> x,
|
void Downmix(const Block& x, rtc::ArrayView<float, kBlockSize> y) const;
|
||||||
rtc::ArrayView<float, kBlockSize> y) const;
|
int SelectChannel(const Block& x);
|
||||||
int SelectChannel(rtc::ArrayView<const std::vector<float>> x);
|
|
||||||
};
|
};
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
|
|||||||
@ -60,12 +60,9 @@ TEST(AlignmentMixer, GeneralAdaptiveMode) {
|
|||||||
/*adaptive_selection*/ true, excitation_limit,
|
/*adaptive_selection*/ true, excitation_limit,
|
||||||
prefer_first_two_channels);
|
prefer_first_two_channels);
|
||||||
|
|
||||||
std::vector<std::vector<float>> x(
|
Block x(
|
||||||
num_channels, std::vector<float>(kBlockSize, 0.f));
|
/*num_bands=*/1, num_channels);
|
||||||
if (initial_silence) {
|
if (initial_silence) {
|
||||||
for (int ch = 0; ch < num_channels; ++ch) {
|
|
||||||
std::fill(x[ch].begin(), x[ch].end(), 0.f);
|
|
||||||
}
|
|
||||||
std::array<float, kBlockSize> y;
|
std::array<float, kBlockSize> y;
|
||||||
for (int frame = 0; frame < 10 * kNumBlocksPerSecond; ++frame) {
|
for (int frame = 0; frame < 10 * kNumBlocksPerSecond; ++frame) {
|
||||||
am.ProduceOutput(x, y);
|
am.ProduceOutput(x, y);
|
||||||
@ -82,7 +79,8 @@ TEST(AlignmentMixer, GeneralAdaptiveMode) {
|
|||||||
for (int ch = 0; ch < num_channels; ++ch) {
|
for (int ch = 0; ch < num_channels; ++ch) {
|
||||||
float scaling =
|
float scaling =
|
||||||
ch == strongest_ch ? kStrongestSignalScaling : 1.f;
|
ch == strongest_ch ? kStrongestSignalScaling : 1.f;
|
||||||
std::fill(x[ch].begin(), x[ch].end(),
|
auto x_ch = x.View(/*band=*/0, ch);
|
||||||
|
std::fill(x_ch.begin(), x_ch.end(),
|
||||||
channel_value(frame, ch) * scaling);
|
channel_value(frame, ch) * scaling);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,13 +90,15 @@ TEST(AlignmentMixer, GeneralAdaptiveMode) {
|
|||||||
|
|
||||||
if (frame > 1 * kNumBlocksPerSecond) {
|
if (frame > 1 * kNumBlocksPerSecond) {
|
||||||
if (!prefer_first_two_channels || huge_activity_threshold) {
|
if (!prefer_first_two_channels || huge_activity_threshold) {
|
||||||
EXPECT_THAT(y, AllOf(Each(x[strongest_ch][0])));
|
EXPECT_THAT(y,
|
||||||
|
AllOf(Each(x.View(/*band=*/0, strongest_ch)[0])));
|
||||||
} else {
|
} else {
|
||||||
bool left_or_right_chosen;
|
bool left_or_right_chosen;
|
||||||
for (int ch = 0; ch < 2; ++ch) {
|
for (int ch = 0; ch < 2; ++ch) {
|
||||||
left_or_right_chosen = true;
|
left_or_right_chosen = true;
|
||||||
|
const auto x_ch = x.View(/*band=*/0, ch);
|
||||||
for (size_t k = 0; k < kBlockSize; ++k) {
|
for (size_t k = 0; k < kBlockSize; ++k) {
|
||||||
if (y[k] != x[ch][k]) {
|
if (y[k] != x_ch[k]) {
|
||||||
left_or_right_chosen = false;
|
left_or_right_chosen = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -124,14 +124,14 @@ TEST(AlignmentMixer, DownmixMode) {
|
|||||||
/*adaptive_selection*/ false, /*excitation_limit*/ 1.f,
|
/*adaptive_selection*/ false, /*excitation_limit*/ 1.f,
|
||||||
/*prefer_first_two_channels*/ false);
|
/*prefer_first_two_channels*/ false);
|
||||||
|
|
||||||
std::vector<std::vector<float>> x(num_channels,
|
Block x(/*num_bands=*/1, num_channels);
|
||||||
std::vector<float>(kBlockSize, 0.f));
|
|
||||||
const auto channel_value = [](int frame_index, int channel_index) {
|
const auto channel_value = [](int frame_index, int channel_index) {
|
||||||
return static_cast<float>(frame_index + channel_index);
|
return static_cast<float>(frame_index + channel_index);
|
||||||
};
|
};
|
||||||
for (int frame = 0; frame < 10; ++frame) {
|
for (int frame = 0; frame < 10; ++frame) {
|
||||||
for (int ch = 0; ch < num_channels; ++ch) {
|
for (int ch = 0; ch < num_channels; ++ch) {
|
||||||
std::fill(x[ch].begin(), x[ch].end(), channel_value(frame, ch));
|
auto x_ch = x.View(/*band=*/0, ch);
|
||||||
|
std::fill(x_ch.begin(), x_ch.end(), channel_value(frame, ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<float, kBlockSize> y;
|
std::array<float, kBlockSize> y;
|
||||||
@ -155,20 +155,20 @@ TEST(AlignmentMixer, FixedMode) {
|
|||||||
/*adaptive_selection*/ false, /*excitation_limit*/ 1.f,
|
/*adaptive_selection*/ false, /*excitation_limit*/ 1.f,
|
||||||
/*prefer_first_two_channels*/ false);
|
/*prefer_first_two_channels*/ false);
|
||||||
|
|
||||||
std::vector<std::vector<float>> x(num_channels,
|
Block x(/*num_band=*/1, num_channels);
|
||||||
std::vector<float>(kBlockSize, 0.f));
|
|
||||||
const auto channel_value = [](int frame_index, int channel_index) {
|
const auto channel_value = [](int frame_index, int channel_index) {
|
||||||
return static_cast<float>(frame_index + channel_index);
|
return static_cast<float>(frame_index + channel_index);
|
||||||
};
|
};
|
||||||
for (int frame = 0; frame < 10; ++frame) {
|
for (int frame = 0; frame < 10; ++frame) {
|
||||||
for (int ch = 0; ch < num_channels; ++ch) {
|
for (int ch = 0; ch < num_channels; ++ch) {
|
||||||
std::fill(x[ch].begin(), x[ch].end(), channel_value(frame, ch));
|
auto x_ch = x.View(/*band=*/0, ch);
|
||||||
|
std::fill(x_ch.begin(), x_ch.end(), channel_value(frame, ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<float, kBlockSize> y;
|
std::array<float, kBlockSize> y;
|
||||||
y.fill(-1.f);
|
y.fill(-1.f);
|
||||||
am.ProduceOutput(x, y);
|
am.ProduceOutput(x, y);
|
||||||
EXPECT_THAT(y, AllOf(Each(x[0][0])));
|
EXPECT_THAT(y, AllOf(Each(x.View(/*band=*/0, /*channel=*/0)[0])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
73
modules/audio_processing/aec3/block.h
Normal file
73
modules/audio_processing/aec3/block.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MODULES_AUDIO_PROCESSING_AEC3_BLOCK_H_
|
||||||
|
#define MODULES_AUDIO_PROCESSING_AEC3_BLOCK_H_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "api/array_view.h"
|
||||||
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class Block {
|
||||||
|
public:
|
||||||
|
Block(int num_bands, int num_channels, float default_value = 0.0f)
|
||||||
|
: data_(num_bands,
|
||||||
|
std::vector<std::array<float, kBlockSize>>(
|
||||||
|
num_channels,
|
||||||
|
std::array<float, kBlockSize>({default_value}))) {}
|
||||||
|
|
||||||
|
// Returns the number of bands.
|
||||||
|
int NumBands() const { return data_.size(); }
|
||||||
|
|
||||||
|
// Returns the number of channels.
|
||||||
|
int NumChannels() const { return data_[0].size(); }
|
||||||
|
|
||||||
|
// Modifies the number of channels.
|
||||||
|
void SetNumChannels(int num_channels) {
|
||||||
|
for (std::vector<std::array<float, kBlockSize>>& block_band : data_) {
|
||||||
|
block_band.resize(num_channels, std::array<float, kBlockSize>({0.0f}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterators for accessing the data.
|
||||||
|
auto begin(int band, int channel) { return data_[band][channel].begin(); }
|
||||||
|
|
||||||
|
auto begin(int band, int channel) const {
|
||||||
|
return data_[band][channel].begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end(int band, int channel) { return data_[band][channel].end(); }
|
||||||
|
|
||||||
|
auto end(int band, int channel) const { return data_[band][channel].end(); }
|
||||||
|
|
||||||
|
// Access data via ArrayView.
|
||||||
|
rtc::ArrayView<float, kBlockSize> View(int band, int channel) {
|
||||||
|
return rtc::ArrayView<float, kBlockSize>(data_[band][channel].data(),
|
||||||
|
kBlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::ArrayView<const float, kBlockSize> View(int band, int channel) const {
|
||||||
|
return rtc::ArrayView<const float, kBlockSize>(data_[band][channel].data(),
|
||||||
|
kBlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lets two Blocks swap audio data.
|
||||||
|
void Swap(Block& b) { data_.swap(b.data_); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::vector<std::array<float, kBlockSize>>> data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
#endif // MODULES_AUDIO_PROCESSING_AEC3_BLOCK_H_
|
||||||
@ -14,25 +14,9 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
BlockBuffer::BlockBuffer(size_t size,
|
BlockBuffer::BlockBuffer(size_t size, size_t num_bands, size_t num_channels)
|
||||||
size_t num_bands,
|
|
||||||
size_t num_channels,
|
|
||||||
size_t frame_length)
|
|
||||||
: size(static_cast<int>(size)),
|
: size(static_cast<int>(size)),
|
||||||
buffer(size,
|
buffer(size, Block(num_bands, num_channels)) {}
|
||||||
std::vector<std::vector<std::vector<float>>>(
|
|
||||||
num_bands,
|
|
||||||
std::vector<std::vector<float>>(
|
|
||||||
num_channels,
|
|
||||||
std::vector<float>(frame_length, 0.f)))) {
|
|
||||||
for (auto& block : buffer) {
|
|
||||||
for (auto& band : block) {
|
|
||||||
for (auto& channel : band) {
|
|
||||||
std::fill(channel.begin(), channel.end(), 0.f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockBuffer::~BlockBuffer() = default;
|
BlockBuffer::~BlockBuffer() = default;
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -22,10 +23,7 @@ namespace webrtc {
|
|||||||
// Struct for bundling a circular buffer of two dimensional vector objects
|
// Struct for bundling a circular buffer of two dimensional vector objects
|
||||||
// together with the read and write indices.
|
// together with the read and write indices.
|
||||||
struct BlockBuffer {
|
struct BlockBuffer {
|
||||||
BlockBuffer(size_t size,
|
BlockBuffer(size_t size, size_t num_bands, size_t num_channels);
|
||||||
size_t num_bands,
|
|
||||||
size_t num_channels,
|
|
||||||
size_t frame_length);
|
|
||||||
~BlockBuffer();
|
~BlockBuffer();
|
||||||
|
|
||||||
int IncIndex(int index) const {
|
int IncIndex(int index) const {
|
||||||
@ -52,7 +50,7 @@ struct BlockBuffer {
|
|||||||
void DecReadIndex() { read = DecIndex(read); }
|
void DecReadIndex() { read = DecIndex(read); }
|
||||||
|
|
||||||
const int size;
|
const int size;
|
||||||
std::vector<std::vector<std::vector<std::vector<float>>>> buffer;
|
std::vector<Block> buffer;
|
||||||
int write = 0;
|
int write = 0;
|
||||||
int read = 0;
|
int read = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -34,35 +34,32 @@ BlockFramer::~BlockFramer() = default;
|
|||||||
// samples for InsertBlockAndExtractSubFrame to produce a frame. In order to
|
// samples for InsertBlockAndExtractSubFrame to produce a frame. In order to
|
||||||
// achieve this, the InsertBlockAndExtractSubFrame and InsertBlock methods need
|
// achieve this, the InsertBlockAndExtractSubFrame and InsertBlock methods need
|
||||||
// to be called in the correct order.
|
// to be called in the correct order.
|
||||||
void BlockFramer::InsertBlock(
|
void BlockFramer::InsertBlock(const Block& block) {
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) {
|
RTC_DCHECK_EQ(num_bands_, block.NumBands());
|
||||||
RTC_DCHECK_EQ(num_bands_, block.size());
|
RTC_DCHECK_EQ(num_channels_, block.NumChannels());
|
||||||
for (size_t band = 0; band < num_bands_; ++band) {
|
for (size_t band = 0; band < num_bands_; ++band) {
|
||||||
RTC_DCHECK_EQ(num_channels_, block[band].size());
|
|
||||||
for (size_t channel = 0; channel < num_channels_; ++channel) {
|
for (size_t channel = 0; channel < num_channels_; ++channel) {
|
||||||
RTC_DCHECK_EQ(kBlockSize, block[band][channel].size());
|
|
||||||
RTC_DCHECK_EQ(0, buffer_[band][channel].size());
|
RTC_DCHECK_EQ(0, buffer_[band][channel].size());
|
||||||
|
|
||||||
buffer_[band][channel].insert(buffer_[band][channel].begin(),
|
buffer_[band][channel].insert(buffer_[band][channel].begin(),
|
||||||
block[band][channel].begin(),
|
block.begin(band, channel),
|
||||||
block[band][channel].end());
|
block.end(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockFramer::InsertBlockAndExtractSubFrame(
|
void BlockFramer::InsertBlockAndExtractSubFrame(
|
||||||
const std::vector<std::vector<std::vector<float>>>& block,
|
const Block& block,
|
||||||
std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame) {
|
std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame) {
|
||||||
RTC_DCHECK(sub_frame);
|
RTC_DCHECK(sub_frame);
|
||||||
RTC_DCHECK_EQ(num_bands_, block.size());
|
RTC_DCHECK_EQ(num_bands_, block.NumBands());
|
||||||
|
RTC_DCHECK_EQ(num_channels_, block.NumChannels());
|
||||||
RTC_DCHECK_EQ(num_bands_, sub_frame->size());
|
RTC_DCHECK_EQ(num_bands_, sub_frame->size());
|
||||||
for (size_t band = 0; band < num_bands_; ++band) {
|
for (size_t band = 0; band < num_bands_; ++band) {
|
||||||
RTC_DCHECK_EQ(num_channels_, block[band].size());
|
|
||||||
RTC_DCHECK_EQ(num_channels_, (*sub_frame)[0].size());
|
RTC_DCHECK_EQ(num_channels_, (*sub_frame)[0].size());
|
||||||
for (size_t channel = 0; channel < num_channels_; ++channel) {
|
for (size_t channel = 0; channel < num_channels_; ++channel) {
|
||||||
RTC_DCHECK_LE(kSubFrameLength,
|
RTC_DCHECK_LE(kSubFrameLength,
|
||||||
buffer_[band][channel].size() + kBlockSize);
|
buffer_[band][channel].size() + kBlockSize);
|
||||||
RTC_DCHECK_EQ(kBlockSize, block[band][channel].size());
|
|
||||||
RTC_DCHECK_GE(kBlockSize, buffer_[band][channel].size());
|
RTC_DCHECK_GE(kBlockSize, buffer_[band][channel].size());
|
||||||
RTC_DCHECK_EQ(kSubFrameLength, (*sub_frame)[band][channel].size());
|
RTC_DCHECK_EQ(kSubFrameLength, (*sub_frame)[band][channel].size());
|
||||||
|
|
||||||
@ -71,14 +68,14 @@ void BlockFramer::InsertBlockAndExtractSubFrame(
|
|||||||
std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(),
|
std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(),
|
||||||
(*sub_frame)[band][channel].begin());
|
(*sub_frame)[band][channel].begin());
|
||||||
std::copy(
|
std::copy(
|
||||||
block[band][channel].begin(),
|
block.begin(band, channel),
|
||||||
block[band][channel].begin() + samples_to_frame,
|
block.begin(band, channel) + samples_to_frame,
|
||||||
(*sub_frame)[band][channel].begin() + buffer_[band][channel].size());
|
(*sub_frame)[band][channel].begin() + buffer_[band][channel].size());
|
||||||
buffer_[band][channel].clear();
|
buffer_[band][channel].clear();
|
||||||
buffer_[band][channel].insert(
|
buffer_[band][channel].insert(
|
||||||
buffer_[band][channel].begin(),
|
buffer_[band][channel].begin(),
|
||||||
block[band][channel].begin() + samples_to_frame,
|
block.begin(band, channel) + samples_to_frame,
|
||||||
block[band][channel].end());
|
block.end(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -32,10 +33,10 @@ class BlockFramer {
|
|||||||
BlockFramer& operator=(const BlockFramer&) = delete;
|
BlockFramer& operator=(const BlockFramer&) = delete;
|
||||||
|
|
||||||
// Adds a 64 sample block into the data that will form the next output frame.
|
// Adds a 64 sample block into the data that will form the next output frame.
|
||||||
void InsertBlock(const std::vector<std::vector<std::vector<float>>>& block);
|
void InsertBlock(const Block& block);
|
||||||
// Adds a 64 sample block and extracts an 80 sample subframe.
|
// Adds a 64 sample block and extracts an 80 sample subframe.
|
||||||
void InsertBlockAndExtractSubFrame(
|
void InsertBlockAndExtractSubFrame(
|
||||||
const std::vector<std::vector<std::vector<float>>>& block,
|
const Block& block,
|
||||||
std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame);
|
std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -64,14 +64,13 @@ bool VerifySubFrame(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FillBlock(size_t block_counter,
|
void FillBlock(size_t block_counter, Block* block) {
|
||||||
std::vector<std::vector<std::vector<float>>>* block) {
|
for (int band = 0; band < block->NumBands(); ++band) {
|
||||||
for (size_t band = 0; band < block->size(); ++band) {
|
for (int channel = 0; channel < block->NumChannels(); ++channel) {
|
||||||
for (size_t channel = 0; channel < (*block)[band].size(); ++channel) {
|
auto b = block->View(band, channel);
|
||||||
for (size_t sample = 0; sample < (*block)[band][channel].size();
|
for (size_t sample = 0; sample < kBlockSize; ++sample) {
|
||||||
++sample) {
|
b[sample] = ComputeSampleValue(block_counter, kBlockSize, band, channel,
|
||||||
(*block)[band][channel][sample] = ComputeSampleValue(
|
sample, 0);
|
||||||
block_counter, kBlockSize, band, channel, sample, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,9 +81,7 @@ void RunFramerTest(int sample_rate_hz, size_t num_channels) {
|
|||||||
constexpr size_t kNumSubFramesToProcess = 10;
|
constexpr size_t kNumSubFramesToProcess = 10;
|
||||||
const size_t num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(num_bands, num_channels);
|
||||||
num_bands, std::vector<std::vector<float>>(
|
|
||||||
num_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> output_sub_frame(
|
std::vector<std::vector<std::vector<float>>> output_sub_frame(
|
||||||
num_bands, std::vector<std::vector<float>>(
|
num_bands, std::vector<std::vector<float>>(
|
||||||
num_channels, std::vector<float>(kSubFrameLength, 0.f)));
|
num_channels, std::vector<float>(kSubFrameLength, 0.f)));
|
||||||
@ -117,16 +114,12 @@ void RunWronglySizedInsertAndExtractParametersTest(
|
|||||||
size_t correct_num_channels,
|
size_t correct_num_channels,
|
||||||
size_t num_block_bands,
|
size_t num_block_bands,
|
||||||
size_t num_block_channels,
|
size_t num_block_channels,
|
||||||
size_t block_length,
|
|
||||||
size_t num_sub_frame_bands,
|
size_t num_sub_frame_bands,
|
||||||
size_t num_sub_frame_channels,
|
size_t num_sub_frame_channels,
|
||||||
size_t sub_frame_length) {
|
size_t sub_frame_length) {
|
||||||
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(num_block_bands, num_block_channels);
|
||||||
num_block_bands,
|
|
||||||
std::vector<std::vector<float>>(num_block_channels,
|
|
||||||
std::vector<float>(block_length, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> output_sub_frame(
|
std::vector<std::vector<std::vector<float>>> output_sub_frame(
|
||||||
num_sub_frame_bands,
|
num_sub_frame_bands,
|
||||||
std::vector<std::vector<float>>(
|
std::vector<std::vector<float>>(
|
||||||
@ -145,18 +138,11 @@ void RunWronglySizedInsertAndExtractParametersTest(
|
|||||||
void RunWronglySizedInsertParameterTest(int sample_rate_hz,
|
void RunWronglySizedInsertParameterTest(int sample_rate_hz,
|
||||||
size_t correct_num_channels,
|
size_t correct_num_channels,
|
||||||
size_t num_block_bands,
|
size_t num_block_bands,
|
||||||
size_t num_block_channels,
|
size_t num_block_channels) {
|
||||||
size_t block_length) {
|
|
||||||
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> correct_block(
|
Block correct_block(correct_num_bands, correct_num_channels);
|
||||||
correct_num_bands,
|
Block wrong_block(num_block_bands, num_block_channels);
|
||||||
std::vector<std::vector<float>>(correct_num_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> wrong_block(
|
|
||||||
num_block_bands,
|
|
||||||
std::vector<std::vector<float>>(num_block_channels,
|
|
||||||
std::vector<float>(block_length, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> output_sub_frame(
|
std::vector<std::vector<std::vector<float>>> output_sub_frame(
|
||||||
correct_num_bands,
|
correct_num_bands,
|
||||||
std::vector<std::vector<float>>(
|
std::vector<std::vector<float>>(
|
||||||
@ -183,10 +169,7 @@ void RunWronglyInsertOrderTest(int sample_rate_hz,
|
|||||||
size_t num_preceeding_api_calls) {
|
size_t num_preceeding_api_calls) {
|
||||||
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(correct_num_bands, num_channels);
|
||||||
correct_num_bands,
|
|
||||||
std::vector<std::vector<float>>(num_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> output_sub_frame(
|
std::vector<std::vector<std::vector<float>>> output_sub_frame(
|
||||||
correct_num_bands,
|
correct_num_bands,
|
||||||
std::vector<std::vector<float>>(
|
std::vector<std::vector<float>>(
|
||||||
@ -223,7 +206,7 @@ TEST(BlockFramerDeathTest,
|
|||||||
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, wrong_num_bands, correct_num_channels,
|
rate, correct_num_channels, wrong_num_bands, correct_num_channels,
|
||||||
kBlockSize, correct_num_bands, correct_num_channels, kSubFrameLength);
|
correct_num_bands, correct_num_channels, kSubFrameLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +220,7 @@ TEST(BlockFramerDeathTest,
|
|||||||
const size_t wrong_num_channels = correct_num_channels + 1;
|
const size_t wrong_num_channels = correct_num_channels + 1;
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, correct_num_bands, wrong_num_channels,
|
rate, correct_num_channels, correct_num_bands, wrong_num_channels,
|
||||||
kBlockSize, correct_num_bands, correct_num_channels, kSubFrameLength);
|
correct_num_bands, correct_num_channels, kSubFrameLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,7 +234,7 @@ TEST(BlockFramerDeathTest,
|
|||||||
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
||||||
kBlockSize, wrong_num_bands, correct_num_channels, kSubFrameLength);
|
wrong_num_bands, correct_num_channels, kSubFrameLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,21 +248,7 @@ TEST(BlockFramerDeathTest,
|
|||||||
const size_t wrong_num_channels = correct_num_channels + 1;
|
const size_t wrong_num_channels = correct_num_channels + 1;
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
||||||
kBlockSize, correct_num_bands, wrong_num_channels, kSubFrameLength);
|
correct_num_bands, wrong_num_channels, kSubFrameLength);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BlockFramerDeathTest,
|
|
||||||
WrongNumberOfSamplesInBlockForInsertBlockAndExtractSubFrame) {
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
|
||||||
for (auto correct_num_channels : {1, 2, 8}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
|
|
||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
|
||||||
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
|
||||||
kBlockSize - 1, correct_num_bands, correct_num_channels,
|
|
||||||
kSubFrameLength);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,8 +261,7 @@ TEST(BlockFramerDeathTest,
|
|||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
const size_t correct_num_bands = NumBandsForRate(rate);
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
||||||
kBlockSize, correct_num_bands, correct_num_channels,
|
correct_num_bands, correct_num_channels, kSubFrameLength - 1);
|
||||||
kSubFrameLength - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,8 +272,7 @@ TEST(BlockFramerDeathTest, WrongNumberOfBandsInBlockForInsertBlock) {
|
|||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
const size_t correct_num_bands = NumBandsForRate(rate);
|
||||||
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
||||||
RunWronglySizedInsertParameterTest(rate, correct_num_channels,
|
RunWronglySizedInsertParameterTest(rate, correct_num_channels,
|
||||||
wrong_num_bands, correct_num_channels,
|
wrong_num_bands, correct_num_channels);
|
||||||
kBlockSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,20 +284,7 @@ TEST(BlockFramerDeathTest, WrongNumberOfChannelsInBlockForInsertBlock) {
|
|||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
const size_t correct_num_bands = NumBandsForRate(rate);
|
||||||
const size_t wrong_num_channels = correct_num_channels + 1;
|
const size_t wrong_num_channels = correct_num_channels + 1;
|
||||||
RunWronglySizedInsertParameterTest(rate, correct_num_channels,
|
RunWronglySizedInsertParameterTest(rate, correct_num_channels,
|
||||||
correct_num_bands, wrong_num_channels,
|
correct_num_bands, wrong_num_channels);
|
||||||
kBlockSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BlockFramerDeathTest, WrongNumberOfSamplesInBlockForInsertBlock) {
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
|
||||||
for (auto correct_num_channels : {1, 2, 8}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
|
|
||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
|
||||||
RunWronglySizedInsertParameterTest(rate, correct_num_channels,
|
|
||||||
correct_num_bands,
|
|
||||||
correct_num_channels, kBlockSize - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,12 +318,9 @@ TEST(BlockFramerDeathTest, ZeroNumberOfBandsParameter) {
|
|||||||
|
|
||||||
// Verifies that the verification for null sub_frame pointer works.
|
// Verifies that the verification for null sub_frame pointer works.
|
||||||
TEST(BlockFramerDeathTest, NullSubFrameParameter) {
|
TEST(BlockFramerDeathTest, NullSubFrameParameter) {
|
||||||
EXPECT_DEATH(BlockFramer(1, 1).InsertBlockAndExtractSubFrame(
|
EXPECT_DEATH(
|
||||||
std::vector<std::vector<std::vector<float>>>(
|
BlockFramer(1, 1).InsertBlockAndExtractSubFrame(Block(1, 1), nullptr),
|
||||||
1, std::vector<std::vector<float>>(
|
"");
|
||||||
1, std::vector<float>(kBlockSize, 0.f))),
|
|
||||||
nullptr),
|
|
||||||
"");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -49,14 +49,12 @@ class BlockProcessorImpl final : public BlockProcessor {
|
|||||||
|
|
||||||
~BlockProcessorImpl() override;
|
~BlockProcessorImpl() override;
|
||||||
|
|
||||||
void ProcessCapture(
|
void ProcessCapture(bool echo_path_gain_change,
|
||||||
bool echo_path_gain_change,
|
bool capture_signal_saturation,
|
||||||
bool capture_signal_saturation,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* capture_block) override;
|
||||||
std::vector<std::vector<std::vector<float>>>* capture_block) override;
|
|
||||||
|
|
||||||
void BufferRender(
|
void BufferRender(const Block& block) override;
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) override;
|
|
||||||
|
|
||||||
void UpdateEchoLeakageStatus(bool leakage_detected) override;
|
void UpdateEchoLeakageStatus(bool leakage_detected) override;
|
||||||
|
|
||||||
@ -104,21 +102,20 @@ BlockProcessorImpl::BlockProcessorImpl(
|
|||||||
|
|
||||||
BlockProcessorImpl::~BlockProcessorImpl() = default;
|
BlockProcessorImpl::~BlockProcessorImpl() = default;
|
||||||
|
|
||||||
void BlockProcessorImpl::ProcessCapture(
|
void BlockProcessorImpl::ProcessCapture(bool echo_path_gain_change,
|
||||||
bool echo_path_gain_change,
|
bool capture_signal_saturation,
|
||||||
bool capture_signal_saturation,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* capture_block) {
|
||||||
std::vector<std::vector<std::vector<float>>>* capture_block) {
|
|
||||||
RTC_DCHECK(capture_block);
|
RTC_DCHECK(capture_block);
|
||||||
RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), capture_block->size());
|
RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), capture_block->NumBands());
|
||||||
RTC_DCHECK_EQ(kBlockSize, (*capture_block)[0][0].size());
|
|
||||||
|
|
||||||
capture_call_counter_++;
|
capture_call_counter_++;
|
||||||
|
|
||||||
data_dumper_->DumpRaw("aec3_processblock_call_order",
|
data_dumper_->DumpRaw("aec3_processblock_call_order",
|
||||||
static_cast<int>(BlockProcessorApiCall::kCapture));
|
static_cast<int>(BlockProcessorApiCall::kCapture));
|
||||||
data_dumper_->DumpWav("aec3_processblock_capture_input", kBlockSize,
|
data_dumper_->DumpWav("aec3_processblock_capture_input",
|
||||||
&(*capture_block)[0][0][0], 16000, 1);
|
capture_block->View(/*band=*/0, /*channel=*/0), 16000,
|
||||||
|
1);
|
||||||
|
|
||||||
if (render_properly_started_) {
|
if (render_properly_started_) {
|
||||||
if (!capture_properly_started_) {
|
if (!capture_properly_started_) {
|
||||||
@ -159,8 +156,9 @@ void BlockProcessorImpl::ProcessCapture(
|
|||||||
delay_controller_->Reset(false);
|
delay_controller_->Reset(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_dumper_->DumpWav("aec3_processblock_capture_input2", kBlockSize,
|
data_dumper_->DumpWav("aec3_processblock_capture_input2",
|
||||||
&(*capture_block)[0][0][0], 16000, 1);
|
capture_block->View(/*band=*/0, /*channel=*/0), 16000,
|
||||||
|
1);
|
||||||
|
|
||||||
bool has_delay_estimator = !config_.delay.use_external_delay_estimator;
|
bool has_delay_estimator = !config_.delay.use_external_delay_estimator;
|
||||||
if (has_delay_estimator) {
|
if (has_delay_estimator) {
|
||||||
@ -169,7 +167,7 @@ void BlockProcessorImpl::ProcessCapture(
|
|||||||
// alignment.
|
// alignment.
|
||||||
estimated_delay_ = delay_controller_->GetDelay(
|
estimated_delay_ = delay_controller_->GetDelay(
|
||||||
render_buffer_->GetDownsampledRenderBuffer(), render_buffer_->Delay(),
|
render_buffer_->GetDownsampledRenderBuffer(), render_buffer_->Delay(),
|
||||||
(*capture_block)[0]);
|
*capture_block);
|
||||||
|
|
||||||
if (estimated_delay_) {
|
if (estimated_delay_) {
|
||||||
bool delay_change =
|
bool delay_change =
|
||||||
@ -202,16 +200,14 @@ void BlockProcessorImpl::ProcessCapture(
|
|||||||
metrics_.UpdateCapture(false);
|
metrics_.UpdateCapture(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockProcessorImpl::BufferRender(
|
void BlockProcessorImpl::BufferRender(const Block& block) {
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) {
|
RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), block.NumBands());
|
||||||
RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), block.size());
|
|
||||||
RTC_DCHECK_EQ(kBlockSize, block[0][0].size());
|
|
||||||
data_dumper_->DumpRaw("aec3_processblock_call_order",
|
data_dumper_->DumpRaw("aec3_processblock_call_order",
|
||||||
static_cast<int>(BlockProcessorApiCall::kRender));
|
static_cast<int>(BlockProcessorApiCall::kRender));
|
||||||
data_dumper_->DumpWav("aec3_processblock_render_input", kBlockSize,
|
data_dumper_->DumpWav("aec3_processblock_render_input",
|
||||||
&block[0][0][0], 16000, 1);
|
block.View(/*band=*/0, /*channel=*/0), 16000, 1);
|
||||||
data_dumper_->DumpWav("aec3_processblock_render_input2", kBlockSize,
|
data_dumper_->DumpWav("aec3_processblock_render_input2",
|
||||||
&block[0][0][0], 16000, 1);
|
block.View(/*band=*/0, /*channel=*/0), 16000, 1);
|
||||||
|
|
||||||
render_event_ = render_buffer_->Insert(block);
|
render_event_ = render_buffer_->Insert(block);
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "api/audio/echo_canceller3_config.h"
|
#include "api/audio/echo_canceller3_config.h"
|
||||||
#include "api/audio/echo_control.h"
|
#include "api/audio/echo_control.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
#include "modules/audio_processing/aec3/echo_remover.h"
|
#include "modules/audio_processing/aec3/echo_remover.h"
|
||||||
#include "modules/audio_processing/aec3/render_delay_buffer.h"
|
#include "modules/audio_processing/aec3/render_delay_buffer.h"
|
||||||
#include "modules/audio_processing/aec3/render_delay_controller.h"
|
#include "modules/audio_processing/aec3/render_delay_controller.h"
|
||||||
@ -56,15 +57,13 @@ class BlockProcessor {
|
|||||||
virtual void SetAudioBufferDelay(int delay_ms) = 0;
|
virtual void SetAudioBufferDelay(int delay_ms) = 0;
|
||||||
|
|
||||||
// Processes a block of capture data.
|
// Processes a block of capture data.
|
||||||
virtual void ProcessCapture(
|
virtual void ProcessCapture(bool echo_path_gain_change,
|
||||||
bool echo_path_gain_change,
|
bool capture_signal_saturation,
|
||||||
bool capture_signal_saturation,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* capture_block) = 0;
|
||||||
std::vector<std::vector<std::vector<float>>>* capture_block) = 0;
|
|
||||||
|
|
||||||
// Buffers a block of render data supplied by a FrameBlocker object.
|
// Buffers a block of render data supplied by a FrameBlocker object.
|
||||||
virtual void BufferRender(
|
virtual void BufferRender(const Block& render_block) = 0;
|
||||||
const std::vector<std::vector<std::vector<float>>>& render_block) = 0;
|
|
||||||
|
|
||||||
// Reports whether echo leakage has been detected in the echo canceller
|
// Reports whether echo leakage has been detected in the echo canceller
|
||||||
// output.
|
// output.
|
||||||
|
|||||||
@ -43,10 +43,7 @@ void RunBasicSetupAndApiCallTest(int sample_rate_hz, int num_iterations) {
|
|||||||
std::unique_ptr<BlockProcessor> block_processor(
|
std::unique_ptr<BlockProcessor> block_processor(
|
||||||
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
||||||
kNumRenderChannels, kNumCaptureChannels));
|
kNumRenderChannels, kNumCaptureChannels));
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(NumBandsForRate(sample_rate_hz), kNumRenderChannels, 1000.f);
|
||||||
NumBandsForRate(sample_rate_hz),
|
|
||||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
|
||||||
std::vector<float>(kBlockSize, 1000.f)));
|
|
||||||
for (int k = 0; k < num_iterations; ++k) {
|
for (int k = 0; k < num_iterations; ++k) {
|
||||||
block_processor->BufferRender(block);
|
block_processor->BufferRender(block);
|
||||||
block_processor->ProcessCapture(false, false, nullptr, &block);
|
block_processor->ProcessCapture(false, false, nullptr, &block);
|
||||||
@ -62,30 +59,11 @@ void RunRenderBlockSizeVerificationTest(int sample_rate_hz) {
|
|||||||
std::unique_ptr<BlockProcessor> block_processor(
|
std::unique_ptr<BlockProcessor> block_processor(
|
||||||
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
||||||
kNumRenderChannels, kNumCaptureChannels));
|
kNumRenderChannels, kNumCaptureChannels));
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(NumBandsForRate(sample_rate_hz), kNumRenderChannels);
|
||||||
NumBandsForRate(sample_rate_hz),
|
|
||||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
|
||||||
std::vector<float>(kBlockSize - 1, 0.f)));
|
|
||||||
|
|
||||||
EXPECT_DEATH(block_processor->BufferRender(block), "");
|
EXPECT_DEATH(block_processor->BufferRender(block), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunCaptureBlockSizeVerificationTest(int sample_rate_hz) {
|
|
||||||
constexpr size_t kNumRenderChannels = 1;
|
|
||||||
constexpr size_t kNumCaptureChannels = 1;
|
|
||||||
|
|
||||||
std::unique_ptr<BlockProcessor> block_processor(
|
|
||||||
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
|
||||||
kNumRenderChannels, kNumCaptureChannels));
|
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
|
||||||
NumBandsForRate(sample_rate_hz),
|
|
||||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
|
||||||
std::vector<float>(kBlockSize - 1, 0.f)));
|
|
||||||
|
|
||||||
EXPECT_DEATH(block_processor->ProcessCapture(false, false, nullptr, &block),
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunRenderNumBandsVerificationTest(int sample_rate_hz) {
|
void RunRenderNumBandsVerificationTest(int sample_rate_hz) {
|
||||||
constexpr size_t kNumRenderChannels = 1;
|
constexpr size_t kNumRenderChannels = 1;
|
||||||
constexpr size_t kNumCaptureChannels = 1;
|
constexpr size_t kNumCaptureChannels = 1;
|
||||||
@ -96,10 +74,7 @@ void RunRenderNumBandsVerificationTest(int sample_rate_hz) {
|
|||||||
std::unique_ptr<BlockProcessor> block_processor(
|
std::unique_ptr<BlockProcessor> block_processor(
|
||||||
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
||||||
kNumRenderChannels, kNumCaptureChannels));
|
kNumRenderChannels, kNumCaptureChannels));
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(wrong_num_bands, kNumRenderChannels);
|
||||||
wrong_num_bands,
|
|
||||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
|
|
||||||
EXPECT_DEATH(block_processor->BufferRender(block), "");
|
EXPECT_DEATH(block_processor->BufferRender(block), "");
|
||||||
}
|
}
|
||||||
@ -114,10 +89,7 @@ void RunCaptureNumBandsVerificationTest(int sample_rate_hz) {
|
|||||||
std::unique_ptr<BlockProcessor> block_processor(
|
std::unique_ptr<BlockProcessor> block_processor(
|
||||||
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
BlockProcessor::Create(EchoCanceller3Config(), sample_rate_hz,
|
||||||
kNumRenderChannels, kNumCaptureChannels));
|
kNumRenderChannels, kNumCaptureChannels));
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(wrong_num_bands, kNumRenderChannels);
|
||||||
wrong_num_bands,
|
|
||||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
|
|
||||||
EXPECT_DEATH(block_processor->ProcessCapture(false, false, nullptr, &block),
|
EXPECT_DEATH(block_processor->ProcessCapture(false, false, nullptr, &block),
|
||||||
"");
|
"");
|
||||||
@ -170,18 +142,14 @@ TEST(BlockProcessor, DISABLED_DelayControllerIntegration) {
|
|||||||
EchoCanceller3Config(), rate, kNumRenderChannels, kNumCaptureChannels,
|
EchoCanceller3Config(), rate, kNumRenderChannels, kNumCaptureChannels,
|
||||||
std::move(render_delay_buffer_mock)));
|
std::move(render_delay_buffer_mock)));
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> render_block(
|
Block render_block(NumBandsForRate(rate), kNumRenderChannels);
|
||||||
NumBandsForRate(rate),
|
Block capture_block(NumBandsForRate(rate), kNumCaptureChannels);
|
||||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> capture_block(
|
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(kNumCaptureChannels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
DelayBuffer<float> signal_delay_buffer(kDelayInSamples);
|
DelayBuffer<float> signal_delay_buffer(kDelayInSamples);
|
||||||
for (size_t k = 0; k < kNumBlocks; ++k) {
|
for (size_t k = 0; k < kNumBlocks; ++k) {
|
||||||
RandomizeSampleVector(&random_generator, render_block[0][0]);
|
RandomizeSampleVector(&random_generator,
|
||||||
signal_delay_buffer.Delay(render_block[0][0], capture_block[0][0]);
|
render_block.View(/*band=*/0, /*capture=*/0));
|
||||||
|
signal_delay_buffer.Delay(render_block.View(/*band=*/0, /*capture=*/0),
|
||||||
|
capture_block.View(/*band=*/0, /*capture=*/0));
|
||||||
block_processor->BufferRender(render_block);
|
block_processor->BufferRender(render_block);
|
||||||
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
||||||
}
|
}
|
||||||
@ -228,18 +196,14 @@ TEST(BlockProcessor, DISABLED_SubmoduleIntegration) {
|
|||||||
std::move(render_delay_buffer_mock),
|
std::move(render_delay_buffer_mock),
|
||||||
std::move(render_delay_controller_mock), std::move(echo_remover_mock)));
|
std::move(render_delay_controller_mock), std::move(echo_remover_mock)));
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> render_block(
|
Block render_block(NumBandsForRate(rate), kNumRenderChannels);
|
||||||
NumBandsForRate(rate),
|
Block capture_block(NumBandsForRate(rate), kNumCaptureChannels);
|
||||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> capture_block(
|
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(kNumCaptureChannels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
DelayBuffer<float> signal_delay_buffer(640);
|
DelayBuffer<float> signal_delay_buffer(640);
|
||||||
for (size_t k = 0; k < kNumBlocks; ++k) {
|
for (size_t k = 0; k < kNumBlocks; ++k) {
|
||||||
RandomizeSampleVector(&random_generator, render_block[0][0]);
|
RandomizeSampleVector(&random_generator,
|
||||||
signal_delay_buffer.Delay(render_block[0][0], capture_block[0][0]);
|
render_block.View(/*band=*/0, /*capture=*/0));
|
||||||
|
signal_delay_buffer.Delay(render_block.View(/*band=*/0, /*capture=*/0),
|
||||||
|
capture_block.View(/*band=*/0, /*capture=*/0));
|
||||||
block_processor->BufferRender(render_block);
|
block_processor->BufferRender(render_block);
|
||||||
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
||||||
block_processor->UpdateEchoLeakageStatus(false);
|
block_processor->UpdateEchoLeakageStatus(false);
|
||||||
@ -268,13 +232,6 @@ TEST(BlockProcessorDeathTest, DISABLED_VerifyRenderBlockSizeCheck) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BlockProcessorDeathTest, VerifyCaptureBlockSizeCheck) {
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(rate));
|
|
||||||
RunCaptureBlockSizeVerificationTest(rate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BlockProcessorDeathTest, VerifyRenderNumBandsCheck) {
|
TEST(BlockProcessorDeathTest, VerifyRenderNumBandsCheck) {
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
for (auto rate : {16000, 32000, 48000}) {
|
||||||
SCOPED_TRACE(ProduceDebugText(rate));
|
SCOPED_TRACE(ProduceDebugText(rate));
|
||||||
@ -333,14 +290,8 @@ TEST(BlockProcessor, ExternalDelayAppliedCorrectlyWithInitialCaptureCalls) {
|
|||||||
std::move(delay_buffer), /*delay_controller=*/nullptr,
|
std::move(delay_buffer), /*delay_controller=*/nullptr,
|
||||||
std::move(echo_remover_mock)));
|
std::move(echo_remover_mock)));
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> render_block(
|
Block render_block(NumBandsForRate(kSampleRateHz), kNumRenderChannels);
|
||||||
NumBandsForRate(kSampleRateHz),
|
Block capture_block(NumBandsForRate(kSampleRateHz), kNumCaptureChannels);
|
||||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> capture_block(
|
|
||||||
NumBandsForRate(kSampleRateHz),
|
|
||||||
std::vector<std::vector<float>>(kNumCaptureChannels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
|
|
||||||
// Process...
|
// Process...
|
||||||
// - 10 capture calls, where no render data is available,
|
// - 10 capture calls, where no render data is available,
|
||||||
@ -354,11 +305,12 @@ TEST(BlockProcessor, ExternalDelayAppliedCorrectlyWithInitialCaptureCalls) {
|
|||||||
int render_call_counter = 0;
|
int render_call_counter = 0;
|
||||||
for (size_t k = 0; k < 10; ++k) {
|
for (size_t k = 0; k < 10; ++k) {
|
||||||
FillSampleVector(++capture_call_counter, kDelayInBlocks,
|
FillSampleVector(++capture_call_counter, kDelayInBlocks,
|
||||||
capture_block[0][0]);
|
capture_block.View(/*band=*/0, /*capture=*/0));
|
||||||
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
||||||
}
|
}
|
||||||
for (size_t k = 0; k < 10; ++k) {
|
for (size_t k = 0; k < 10; ++k) {
|
||||||
FillSampleVector(++render_call_counter, 0, render_block[0][0]);
|
FillSampleVector(++render_call_counter, 0,
|
||||||
|
render_block.View(/*band=*/0, /*capture=*/0));
|
||||||
block_processor->BufferRender(render_block);
|
block_processor->BufferRender(render_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,19 +319,22 @@ TEST(BlockProcessor, ExternalDelayAppliedCorrectlyWithInitialCaptureCalls) {
|
|||||||
[](EchoPathVariability /*echo_path_variability*/,
|
[](EchoPathVariability /*echo_path_variability*/,
|
||||||
bool /*capture_signal_saturation*/,
|
bool /*capture_signal_saturation*/,
|
||||||
const absl::optional<DelayEstimate>& /*external_delay*/,
|
const absl::optional<DelayEstimate>& /*external_delay*/,
|
||||||
RenderBuffer* render_buffer,
|
RenderBuffer* render_buffer, Block* /*linear_output*/,
|
||||||
std::vector<std::vector<std::vector<float>>>* /*linear_output*/,
|
Block* capture) {
|
||||||
std::vector<std::vector<std::vector<float>>>* capture) {
|
|
||||||
const auto& render = render_buffer->Block(0);
|
const auto& render = render_buffer->Block(0);
|
||||||
|
const auto render_view = render.View(/*band=*/0, /*channel=*/0);
|
||||||
|
const auto capture_view = capture->View(/*band=*/0, /*channel=*/0);
|
||||||
for (size_t i = 0; i < kBlockSize; ++i) {
|
for (size_t i = 0; i < kBlockSize; ++i) {
|
||||||
EXPECT_FLOAT_EQ(render[0][0][i], (*capture)[0][0][i]);
|
EXPECT_FLOAT_EQ(render_view[i], capture_view[i]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
FillSampleVector(++capture_call_counter, kDelayInBlocks, capture_block[0][0]);
|
FillSampleVector(++capture_call_counter, kDelayInBlocks,
|
||||||
|
capture_block.View(/*band=*/0, /*capture=*/0));
|
||||||
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
||||||
|
|
||||||
FillSampleVector(++capture_call_counter, kDelayInBlocks, capture_block[0][0]);
|
FillSampleVector(++capture_call_counter, kDelayInBlocks,
|
||||||
|
capture_block.View(/*band=*/0, /*capture=*/0));
|
||||||
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -59,10 +59,7 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
|||||||
CoarseFilterUpdateGain coarse_gain(
|
CoarseFilterUpdateGain coarse_gain(
|
||||||
config.filter.coarse, config.filter.config_change_duration_blocks);
|
config.filter.coarse, config.filter.config_change_duration_blocks);
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(NumBandsForRate(kSampleRateHz), num_render_channels);
|
||||||
NumBandsForRate(kSampleRateHz),
|
|
||||||
std::vector<std::vector<float>>(num_render_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::array<float, kBlockSize> y;
|
std::array<float, kBlockSize> y;
|
||||||
RenderSignalAnalyzer render_signal_analyzer(config);
|
RenderSignalAnalyzer render_signal_analyzer(config);
|
||||||
std::array<float, kFftLength> s;
|
std::array<float, kFftLength> s;
|
||||||
@ -81,12 +78,12 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
|||||||
k) != blocks_with_saturation.end();
|
k) != blocks_with_saturation.end();
|
||||||
|
|
||||||
// Create the render signal.
|
// Create the render signal.
|
||||||
for (size_t band = 0; band < x.size(); ++band) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < x[band].size(); ++channel) {
|
for (int channel = 0; channel < x.NumChannels(); ++channel) {
|
||||||
RandomizeSampleVector(&random_generator, x[band][channel]);
|
RandomizeSampleVector(&random_generator, x.View(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delay_buffer.Delay(x[0][0], y);
|
delay_buffer.Delay(x.View(/*band=*/0, /*channel*/ 0), y);
|
||||||
|
|
||||||
render_delay_buffer->Insert(x);
|
render_delay_buffer->Insert(x);
|
||||||
if (k == 0) {
|
if (k == 0) {
|
||||||
|
|||||||
@ -88,7 +88,7 @@ void EchoAudibility::UpdateRenderNoiseEstimator(
|
|||||||
|
|
||||||
bool EchoAudibility::IsRenderTooLow(const BlockBuffer& block_buffer) {
|
bool EchoAudibility::IsRenderTooLow(const BlockBuffer& block_buffer) {
|
||||||
const int num_render_channels =
|
const int num_render_channels =
|
||||||
static_cast<int>(block_buffer.buffer[0][0].size());
|
static_cast<int>(block_buffer.buffer[0].NumChannels());
|
||||||
bool too_low = false;
|
bool too_low = false;
|
||||||
const int render_block_write_current = block_buffer.write;
|
const int render_block_write_current = block_buffer.write;
|
||||||
if (render_block_write_current == render_block_write_prev_) {
|
if (render_block_write_current == render_block_write_prev_) {
|
||||||
@ -98,7 +98,8 @@ bool EchoAudibility::IsRenderTooLow(const BlockBuffer& block_buffer) {
|
|||||||
idx = block_buffer.IncIndex(idx)) {
|
idx = block_buffer.IncIndex(idx)) {
|
||||||
float max_abs_over_channels = 0.f;
|
float max_abs_over_channels = 0.f;
|
||||||
for (int ch = 0; ch < num_render_channels; ++ch) {
|
for (int ch = 0; ch < num_render_channels; ++ch) {
|
||||||
auto block = block_buffer.buffer[idx][0][ch];
|
rtc::ArrayView<const float, kBlockSize> block =
|
||||||
|
block_buffer.buffer[idx].View(/*band=*/0, /*channel=*/ch);
|
||||||
auto r = std::minmax_element(block.cbegin(), block.cend());
|
auto r = std::minmax_element(block.cbegin(), block.cend());
|
||||||
float max_abs_channel =
|
float max_abs_channel =
|
||||||
std::max(std::fabs(*r.first), std::fabs(*r.second));
|
std::max(std::fabs(*r.first), std::fabs(*r.second));
|
||||||
|
|||||||
@ -154,10 +154,10 @@ void ProcessCaptureFrameContent(
|
|||||||
BlockFramer* linear_output_framer,
|
BlockFramer* linear_output_framer,
|
||||||
BlockFramer* output_framer,
|
BlockFramer* output_framer,
|
||||||
BlockProcessor* block_processor,
|
BlockProcessor* block_processor,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output_block,
|
Block* linear_output_block,
|
||||||
std::vector<std::vector<rtc::ArrayView<float>>>*
|
std::vector<std::vector<rtc::ArrayView<float>>>*
|
||||||
linear_output_sub_frame_view,
|
linear_output_sub_frame_view,
|
||||||
std::vector<std::vector<std::vector<float>>>* capture_block,
|
Block* capture_block,
|
||||||
std::vector<std::vector<rtc::ArrayView<float>>>* capture_sub_frame_view) {
|
std::vector<std::vector<rtc::ArrayView<float>>>* capture_sub_frame_view) {
|
||||||
FillSubFrameView(capture, sub_frame_index, capture_sub_frame_view);
|
FillSubFrameView(capture, sub_frame_index, capture_sub_frame_view);
|
||||||
|
|
||||||
@ -171,10 +171,10 @@ void ProcessCaptureFrameContent(
|
|||||||
|
|
||||||
capture_blocker->InsertSubFrameAndExtractBlock(*capture_sub_frame_view,
|
capture_blocker->InsertSubFrameAndExtractBlock(*capture_sub_frame_view,
|
||||||
capture_block);
|
capture_block);
|
||||||
block_processor->ProcessCapture(/*echo_path_gain_change=*/level_change ||
|
block_processor->ProcessCapture(
|
||||||
aec_reference_is_downmixed_stereo,
|
/*echo_path_gain_change=*/level_change ||
|
||||||
saturated_microphone_signal,
|
aec_reference_is_downmixed_stereo,
|
||||||
linear_output_block, capture_block);
|
saturated_microphone_signal, linear_output_block, capture_block);
|
||||||
output_framer->InsertBlockAndExtractSubFrame(*capture_block,
|
output_framer->InsertBlockAndExtractSubFrame(*capture_block,
|
||||||
capture_sub_frame_view);
|
capture_sub_frame_view);
|
||||||
|
|
||||||
@ -185,16 +185,15 @@ void ProcessCaptureFrameContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessRemainingCaptureFrameContent(
|
void ProcessRemainingCaptureFrameContent(bool level_change,
|
||||||
bool level_change,
|
bool aec_reference_is_downmixed_stereo,
|
||||||
bool aec_reference_is_downmixed_stereo,
|
bool saturated_microphone_signal,
|
||||||
bool saturated_microphone_signal,
|
FrameBlocker* capture_blocker,
|
||||||
FrameBlocker* capture_blocker,
|
BlockFramer* linear_output_framer,
|
||||||
BlockFramer* linear_output_framer,
|
BlockFramer* output_framer,
|
||||||
BlockFramer* output_framer,
|
BlockProcessor* block_processor,
|
||||||
BlockProcessor* block_processor,
|
Block* linear_output_block,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output_block,
|
Block* block) {
|
||||||
std::vector<std::vector<std::vector<float>>>* block) {
|
|
||||||
if (!capture_blocker->IsBlockAvailable()) {
|
if (!capture_blocker->IsBlockAvailable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -218,7 +217,7 @@ void BufferRenderFrameContent(
|
|||||||
size_t sub_frame_index,
|
size_t sub_frame_index,
|
||||||
FrameBlocker* render_blocker,
|
FrameBlocker* render_blocker,
|
||||||
BlockProcessor* block_processor,
|
BlockProcessor* block_processor,
|
||||||
std::vector<std::vector<std::vector<float>>>* block,
|
Block* block,
|
||||||
std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame_view) {
|
std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame_view) {
|
||||||
FillSubFrameView(proper_downmix_needed, render_frame, sub_frame_index,
|
FillSubFrameView(proper_downmix_needed, render_frame, sub_frame_index,
|
||||||
sub_frame_view);
|
sub_frame_view);
|
||||||
@ -226,10 +225,9 @@ void BufferRenderFrameContent(
|
|||||||
block_processor->BufferRender(*block);
|
block_processor->BufferRender(*block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferRemainingRenderFrameContent(
|
void BufferRemainingRenderFrameContent(FrameBlocker* render_blocker,
|
||||||
FrameBlocker* render_blocker,
|
BlockProcessor* block_processor,
|
||||||
BlockProcessor* block_processor,
|
Block* block) {
|
||||||
std::vector<std::vector<std::vector<float>>>* block) {
|
|
||||||
if (!render_blocker->IsBlockAvailable()) {
|
if (!render_blocker->IsBlockAvailable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -753,14 +751,8 @@ EchoCanceller3::EchoCanceller3(
|
|||||||
std::vector<std::vector<float>>(
|
std::vector<std::vector<float>>(
|
||||||
num_render_input_channels_,
|
num_render_input_channels_,
|
||||||
std::vector<float>(AudioBuffer::kSplitBandSize, 0.f))),
|
std::vector<float>(AudioBuffer::kSplitBandSize, 0.f))),
|
||||||
render_block_(
|
render_block_(num_bands_, num_render_input_channels_),
|
||||||
num_bands_,
|
capture_block_(num_bands_, num_capture_channels_),
|
||||||
std::vector<std::vector<float>>(num_render_input_channels_,
|
|
||||||
std::vector<float>(kBlockSize, 0.f))),
|
|
||||||
capture_block_(
|
|
||||||
num_bands_,
|
|
||||||
std::vector<std::vector<float>>(num_capture_channels_,
|
|
||||||
std::vector<float>(kBlockSize, 0.f))),
|
|
||||||
capture_sub_frame_view_(
|
capture_sub_frame_view_(
|
||||||
num_bands_,
|
num_bands_,
|
||||||
std::vector<rtc::ArrayView<float>>(num_capture_channels_)) {
|
std::vector<rtc::ArrayView<float>>(num_capture_channels_)) {
|
||||||
@ -780,11 +772,10 @@ EchoCanceller3::EchoCanceller3(
|
|||||||
RTC_DCHECK_GE(kMaxNumBands, num_bands_);
|
RTC_DCHECK_GE(kMaxNumBands, num_bands_);
|
||||||
|
|
||||||
if (config_selector_.active_config().filter.export_linear_aec_output) {
|
if (config_selector_.active_config().filter.export_linear_aec_output) {
|
||||||
linear_output_framer_.reset(new BlockFramer(1, num_capture_channels_));
|
linear_output_framer_.reset(
|
||||||
|
new BlockFramer(/*num_bands=*/1, num_capture_channels_));
|
||||||
linear_output_block_ =
|
linear_output_block_ =
|
||||||
std::make_unique<std::vector<std::vector<std::vector<float>>>>(
|
std::make_unique<Block>(/*num_bands=*/1, num_capture_channels_),
|
||||||
1, std::vector<std::vector<float>>(
|
|
||||||
num_capture_channels_, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
linear_output_sub_frame_view_ =
|
linear_output_sub_frame_view_ =
|
||||||
std::vector<std::vector<rtc::ArrayView<float>>>(
|
std::vector<std::vector<rtc::ArrayView<float>>>(
|
||||||
1, std::vector<rtc::ArrayView<float>>(num_capture_channels_));
|
1, std::vector<rtc::ArrayView<float>>(num_capture_channels_));
|
||||||
@ -810,12 +801,7 @@ void EchoCanceller3::Initialize() {
|
|||||||
config_selector_.Update(
|
config_selector_.Update(
|
||||||
multichannel_content_detector_.IsProperMultiChannelContentDetected());
|
multichannel_content_detector_.IsProperMultiChannelContentDetected());
|
||||||
|
|
||||||
for (std::vector<std::vector<float>>& block_band : render_block_) {
|
render_block_.SetNumChannels(num_render_channels_to_aec_);
|
||||||
block_band.resize(num_render_channels_to_aec_);
|
|
||||||
for (std::vector<float>& block_channel : block_band) {
|
|
||||||
block_channel.resize(kBlockSize, 0.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render_blocker_.reset(
|
render_blocker_.reset(
|
||||||
new FrameBlocker(num_bands_, num_render_channels_to_aec_));
|
new FrameBlocker(num_bands_, num_render_channels_to_aec_));
|
||||||
|
|||||||
@ -210,12 +210,10 @@ class EchoCanceller3 : public EchoControl {
|
|||||||
RTC_GUARDED_BY(capture_race_checker_);
|
RTC_GUARDED_BY(capture_race_checker_);
|
||||||
bool saturated_microphone_signal_ RTC_GUARDED_BY(capture_race_checker_) =
|
bool saturated_microphone_signal_ RTC_GUARDED_BY(capture_race_checker_) =
|
||||||
false;
|
false;
|
||||||
std::vector<std::vector<std::vector<float>>> render_block_
|
Block render_block_ RTC_GUARDED_BY(capture_race_checker_);
|
||||||
RTC_GUARDED_BY(capture_race_checker_);
|
std::unique_ptr<Block> linear_output_block_
|
||||||
std::unique_ptr<std::vector<std::vector<std::vector<float>>>>
|
|
||||||
linear_output_block_ RTC_GUARDED_BY(capture_race_checker_);
|
|
||||||
std::vector<std::vector<std::vector<float>>> capture_block_
|
|
||||||
RTC_GUARDED_BY(capture_race_checker_);
|
RTC_GUARDED_BY(capture_race_checker_);
|
||||||
|
Block capture_block_ RTC_GUARDED_BY(capture_race_checker_);
|
||||||
std::vector<std::vector<rtc::ArrayView<float>>> render_sub_frame_view_
|
std::vector<std::vector<rtc::ArrayView<float>>> render_sub_frame_view_
|
||||||
RTC_GUARDED_BY(capture_race_checker_);
|
RTC_GUARDED_BY(capture_race_checker_);
|
||||||
std::vector<std::vector<rtc::ArrayView<float>>> linear_output_sub_frame_view_
|
std::vector<std::vector<rtc::ArrayView<float>>> linear_output_sub_frame_view_
|
||||||
|
|||||||
@ -117,14 +117,12 @@ class CaptureTransportVerificationProcessor : public BlockProcessor {
|
|||||||
|
|
||||||
~CaptureTransportVerificationProcessor() override = default;
|
~CaptureTransportVerificationProcessor() override = default;
|
||||||
|
|
||||||
void ProcessCapture(
|
void ProcessCapture(bool level_change,
|
||||||
bool level_change,
|
bool saturated_microphone_signal,
|
||||||
bool saturated_microphone_signal,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* capture_block) override {}
|
||||||
std::vector<std::vector<std::vector<float>>>* capture_block) override {}
|
|
||||||
|
|
||||||
void BufferRender(
|
void BufferRender(const Block& block) override {}
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) override {}
|
|
||||||
|
|
||||||
void UpdateEchoLeakageStatus(bool leakage_detected) override {}
|
void UpdateEchoLeakageStatus(bool leakage_detected) override {}
|
||||||
|
|
||||||
@ -149,19 +147,16 @@ class RenderTransportVerificationProcessor : public BlockProcessor {
|
|||||||
|
|
||||||
~RenderTransportVerificationProcessor() override = default;
|
~RenderTransportVerificationProcessor() override = default;
|
||||||
|
|
||||||
void ProcessCapture(
|
void ProcessCapture(bool level_change,
|
||||||
bool level_change,
|
bool saturated_microphone_signal,
|
||||||
bool saturated_microphone_signal,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* capture_block) override {
|
||||||
std::vector<std::vector<std::vector<float>>>* capture_block) override {
|
Block render_block = received_render_blocks_.front();
|
||||||
std::vector<std::vector<std::vector<float>>> render_block =
|
|
||||||
received_render_blocks_.front();
|
|
||||||
received_render_blocks_.pop_front();
|
received_render_blocks_.pop_front();
|
||||||
capture_block->swap(render_block);
|
capture_block->Swap(render_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferRender(
|
void BufferRender(const Block& block) override {
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) override {
|
|
||||||
received_render_blocks_.push_back(block);
|
received_render_blocks_.push_back(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,8 +169,7 @@ class RenderTransportVerificationProcessor : public BlockProcessor {
|
|||||||
void SetCaptureOutputUsage(bool capture_output_used) {}
|
void SetCaptureOutputUsage(bool capture_output_used) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::deque<std::vector<std::vector<std::vector<float>>>>
|
std::deque<Block> received_render_blocks_;
|
||||||
received_render_blocks_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string ProduceDebugText(int sample_rate_hz) {
|
std::string ProduceDebugText(int sample_rate_hz) {
|
||||||
|
|||||||
@ -59,9 +59,7 @@ void EchoPathDelayEstimator::Reset(bool reset_delay_confidence) {
|
|||||||
|
|
||||||
absl::optional<DelayEstimate> EchoPathDelayEstimator::EstimateDelay(
|
absl::optional<DelayEstimate> EchoPathDelayEstimator::EstimateDelay(
|
||||||
const DownsampledRenderBuffer& render_buffer,
|
const DownsampledRenderBuffer& render_buffer,
|
||||||
const std::vector<std::vector<float>>& capture) {
|
const Block& capture) {
|
||||||
RTC_DCHECK_EQ(kBlockSize, capture[0].size());
|
|
||||||
|
|
||||||
std::array<float, kBlockSize> downsampled_capture_data;
|
std::array<float, kBlockSize> downsampled_capture_data;
|
||||||
rtc::ArrayView<float> downsampled_capture(downsampled_capture_data.data(),
|
rtc::ArrayView<float> downsampled_capture(downsampled_capture_data.data(),
|
||||||
sub_block_size_);
|
sub_block_size_);
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "modules/audio_processing/aec3/alignment_mixer.h"
|
#include "modules/audio_processing/aec3/alignment_mixer.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
#include "modules/audio_processing/aec3/clockdrift_detector.h"
|
#include "modules/audio_processing/aec3/clockdrift_detector.h"
|
||||||
#include "modules/audio_processing/aec3/decimator.h"
|
#include "modules/audio_processing/aec3/decimator.h"
|
||||||
#include "modules/audio_processing/aec3/delay_estimate.h"
|
#include "modules/audio_processing/aec3/delay_estimate.h"
|
||||||
@ -46,7 +47,7 @@ class EchoPathDelayEstimator {
|
|||||||
// Produce a delay estimate if such is avaliable.
|
// Produce a delay estimate if such is avaliable.
|
||||||
absl::optional<DelayEstimate> EstimateDelay(
|
absl::optional<DelayEstimate> EstimateDelay(
|
||||||
const DownsampledRenderBuffer& render_buffer,
|
const DownsampledRenderBuffer& render_buffer,
|
||||||
const std::vector<std::vector<float>>& capture);
|
const Block& capture);
|
||||||
|
|
||||||
// Log delay estimator properties.
|
// Log delay estimator properties.
|
||||||
void LogDelayEstimationProperties(int sample_rate_hz, size_t shift) const {
|
void LogDelayEstimationProperties(int sample_rate_hz, size_t shift) const {
|
||||||
|
|||||||
@ -54,11 +54,8 @@ TEST_P(EchoPathDelayEstimatorMultiChannel, BasicApiCalls) {
|
|||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
||||||
RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels));
|
RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels));
|
||||||
EchoPathDelayEstimator estimator(&data_dumper, config, num_capture_channels);
|
EchoPathDelayEstimator estimator(&data_dumper, config, num_capture_channels);
|
||||||
std::vector<std::vector<std::vector<float>>> render(
|
Block render(kNumBands, num_render_channels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
Block capture(/*num_bands=*/1, num_capture_channels);
|
||||||
num_render_channels, std::vector<float>(kBlockSize)));
|
|
||||||
std::vector<std::vector<float>> capture(num_capture_channels,
|
|
||||||
std::vector<float>(kBlockSize));
|
|
||||||
for (size_t k = 0; k < 100; ++k) {
|
for (size_t k = 0; k < 100; ++k) {
|
||||||
render_delay_buffer->Insert(render);
|
render_delay_buffer->Insert(render);
|
||||||
estimator.EstimateDelay(render_delay_buffer->GetDownsampledRenderBuffer(),
|
estimator.EstimateDelay(render_delay_buffer->GetDownsampledRenderBuffer(),
|
||||||
@ -75,11 +72,8 @@ TEST(EchoPathDelayEstimator, DelayEstimation) {
|
|||||||
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
||||||
|
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
std::vector<std::vector<std::vector<float>>> render(
|
Block render(kNumBands, kNumRenderChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
Block capture(/*num_bands=*/1, kNumCaptureChannels);
|
||||||
kNumRenderChannels, std::vector<float>(kBlockSize)));
|
|
||||||
std::vector<std::vector<float>> capture(kNumCaptureChannels,
|
|
||||||
std::vector<float>(kBlockSize));
|
|
||||||
ApmDataDumper data_dumper(0);
|
ApmDataDumper data_dumper(0);
|
||||||
constexpr size_t kDownSamplingFactors[] = {2, 4, 8};
|
constexpr size_t kDownSamplingFactors[] = {2, 4, 8};
|
||||||
for (auto down_sampling_factor : kDownSamplingFactors) {
|
for (auto down_sampling_factor : kDownSamplingFactors) {
|
||||||
@ -96,8 +90,10 @@ TEST(EchoPathDelayEstimator, DelayEstimation) {
|
|||||||
|
|
||||||
absl::optional<DelayEstimate> estimated_delay_samples;
|
absl::optional<DelayEstimate> estimated_delay_samples;
|
||||||
for (size_t k = 0; k < (500 + (delay_samples) / kBlockSize); ++k) {
|
for (size_t k = 0; k < (500 + (delay_samples) / kBlockSize); ++k) {
|
||||||
RandomizeSampleVector(&random_generator, render[0][0]);
|
RandomizeSampleVector(&random_generator,
|
||||||
signal_delay_buffer.Delay(render[0][0], capture[0]);
|
render.View(/*band=*/0, /*channel=*/0));
|
||||||
|
signal_delay_buffer.Delay(render.View(/*band=*/0, /*channel=*/0),
|
||||||
|
capture.View(/*band=*/0, /*channel=*/0));
|
||||||
render_delay_buffer->Insert(render);
|
render_delay_buffer->Insert(render);
|
||||||
|
|
||||||
if (k == 0) {
|
if (k == 0) {
|
||||||
@ -137,22 +133,22 @@ TEST(EchoPathDelayEstimator, NoDelayEstimatesForLowLevelRenderSignals) {
|
|||||||
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
EchoCanceller3Config config;
|
EchoCanceller3Config config;
|
||||||
std::vector<std::vector<std::vector<float>>> render(
|
Block render(kNumBands, kNumRenderChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
Block capture(/*num_bands=*/1, kNumCaptureChannels);
|
||||||
kNumRenderChannels, std::vector<float>(kBlockSize)));
|
|
||||||
std::vector<std::vector<float>> capture(kNumCaptureChannels,
|
|
||||||
std::vector<float>(kBlockSize));
|
|
||||||
ApmDataDumper data_dumper(0);
|
ApmDataDumper data_dumper(0);
|
||||||
EchoPathDelayEstimator estimator(&data_dumper, config, kNumCaptureChannels);
|
EchoPathDelayEstimator estimator(&data_dumper, config, kNumCaptureChannels);
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
||||||
RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
|
RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
|
||||||
kNumRenderChannels));
|
kNumRenderChannels));
|
||||||
for (size_t k = 0; k < 100; ++k) {
|
for (size_t k = 0; k < 100; ++k) {
|
||||||
RandomizeSampleVector(&random_generator, render[0][0]);
|
RandomizeSampleVector(&random_generator,
|
||||||
for (auto& render_k : render[0][0]) {
|
render.View(/*band=*/0, /*channel=*/0));
|
||||||
|
for (auto& render_k : render.View(/*band=*/0, /*channel=*/0)) {
|
||||||
render_k *= 100.f / 32767.f;
|
render_k *= 100.f / 32767.f;
|
||||||
}
|
}
|
||||||
std::copy(render[0][0].begin(), render[0][0].end(), capture[0].begin());
|
std::copy(render.begin(/*band=*/0, /*channel=*/0),
|
||||||
|
render.end(/*band=*/0, /*channel=*/0),
|
||||||
|
capture.begin(/*band*/ 0, /*channel=*/0));
|
||||||
render_delay_buffer->Insert(render);
|
render_delay_buffer->Insert(render);
|
||||||
render_delay_buffer->PrepareCaptureProcessing();
|
render_delay_buffer->PrepareCaptureProcessing();
|
||||||
EXPECT_FALSE(estimator.EstimateDelay(
|
EXPECT_FALSE(estimator.EstimateDelay(
|
||||||
@ -171,23 +167,7 @@ TEST(EchoPathDelayEstimatorDeathTest, DISABLED_WrongRenderBlockSize) {
|
|||||||
EchoPathDelayEstimator estimator(&data_dumper, config, 1);
|
EchoPathDelayEstimator estimator(&data_dumper, config, 1);
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
||||||
RenderDelayBuffer::Create(config, 48000, 1));
|
RenderDelayBuffer::Create(config, 48000, 1));
|
||||||
std::vector<std::vector<float>> capture(1, std::vector<float>(kBlockSize));
|
Block capture(/*num_bands=*/1, /*num_channels=*/1);
|
||||||
EXPECT_DEATH(estimator.EstimateDelay(
|
|
||||||
render_delay_buffer->GetDownsampledRenderBuffer(), capture),
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verifies the check for the capture blocksize.
|
|
||||||
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
|
|
||||||
// tests on test bots has been fixed.
|
|
||||||
TEST(EchoPathDelayEstimatorDeathTest, WrongCaptureBlockSize) {
|
|
||||||
ApmDataDumper data_dumper(0);
|
|
||||||
EchoCanceller3Config config;
|
|
||||||
EchoPathDelayEstimator estimator(&data_dumper, config, 1);
|
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
|
||||||
RenderDelayBuffer::Create(config, 48000, 1));
|
|
||||||
std::vector<std::vector<float>> capture(1,
|
|
||||||
std::vector<float>(kBlockSize - 1));
|
|
||||||
EXPECT_DEATH(estimator.EstimateDelay(
|
EXPECT_DEATH(estimator.EstimateDelay(
|
||||||
render_delay_buffer->GetDownsampledRenderBuffer(), capture),
|
render_delay_buffer->GetDownsampledRenderBuffer(), capture),
|
||||||
"");
|
"");
|
||||||
|
|||||||
@ -118,13 +118,12 @@ class EchoRemoverImpl final : public EchoRemover {
|
|||||||
// Removes the echo from a block of samples from the capture signal. The
|
// Removes the echo from a block of samples from the capture signal. The
|
||||||
// supplied render signal is assumed to be pre-aligned with the capture
|
// supplied render signal is assumed to be pre-aligned with the capture
|
||||||
// signal.
|
// signal.
|
||||||
void ProcessCapture(
|
void ProcessCapture(EchoPathVariability echo_path_variability,
|
||||||
EchoPathVariability echo_path_variability,
|
bool capture_signal_saturation,
|
||||||
bool capture_signal_saturation,
|
const absl::optional<DelayEstimate>& external_delay,
|
||||||
const absl::optional<DelayEstimate>& external_delay,
|
RenderBuffer* render_buffer,
|
||||||
RenderBuffer* render_buffer,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* capture) override;
|
||||||
std::vector<std::vector<std::vector<float>>>* capture) override;
|
|
||||||
|
|
||||||
// Updates the status on whether echo leakage is detected in the output of the
|
// Updates the status on whether echo leakage is detected in the output of the
|
||||||
// echo remover.
|
// echo remover.
|
||||||
@ -243,20 +242,17 @@ void EchoRemoverImpl::ProcessCapture(
|
|||||||
bool capture_signal_saturation,
|
bool capture_signal_saturation,
|
||||||
const absl::optional<DelayEstimate>& external_delay,
|
const absl::optional<DelayEstimate>& external_delay,
|
||||||
RenderBuffer* render_buffer,
|
RenderBuffer* render_buffer,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* capture) {
|
Block* capture) {
|
||||||
++block_counter_;
|
++block_counter_;
|
||||||
const std::vector<std::vector<std::vector<float>>>& x =
|
const Block& x = render_buffer->Block(0);
|
||||||
render_buffer->Block(0);
|
Block* y = capture;
|
||||||
std::vector<std::vector<std::vector<float>>>* y = capture;
|
|
||||||
RTC_DCHECK(render_buffer);
|
RTC_DCHECK(render_buffer);
|
||||||
RTC_DCHECK(y);
|
RTC_DCHECK(y);
|
||||||
RTC_DCHECK_EQ(x.size(), NumBandsForRate(sample_rate_hz_));
|
RTC_DCHECK_EQ(x.NumBands(), NumBandsForRate(sample_rate_hz_));
|
||||||
RTC_DCHECK_EQ(y->size(), NumBandsForRate(sample_rate_hz_));
|
RTC_DCHECK_EQ(y->NumBands(), NumBandsForRate(sample_rate_hz_));
|
||||||
RTC_DCHECK_EQ(x[0].size(), num_render_channels_);
|
RTC_DCHECK_EQ(x.NumChannels(), num_render_channels_);
|
||||||
RTC_DCHECK_EQ((*y)[0].size(), num_capture_channels_);
|
RTC_DCHECK_EQ(y->NumChannels(), num_capture_channels_);
|
||||||
RTC_DCHECK_EQ(x[0][0].size(), kBlockSize);
|
|
||||||
RTC_DCHECK_EQ((*y)[0][0].size(), kBlockSize);
|
|
||||||
|
|
||||||
// Stack allocated data to use when the number of channels is low.
|
// Stack allocated data to use when the number of channels is low.
|
||||||
std::array<std::array<float, kFftLengthBy2>, kMaxNumChannelsOnStack> e_stack;
|
std::array<std::array<float, kFftLengthBy2>, kMaxNumChannelsOnStack> e_stack;
|
||||||
@ -321,12 +317,14 @@ void EchoRemoverImpl::ProcessCapture(
|
|||||||
subtractor_output_heap_.data(), num_capture_channels_);
|
subtractor_output_heap_.data(), num_capture_channels_);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_dumper_->DumpWav("aec3_echo_remover_capture_input", kBlockSize,
|
data_dumper_->DumpWav("aec3_echo_remover_capture_input",
|
||||||
&(*y)[0][0][0], 16000, 1);
|
y->View(/*band=*/0, /*channel=*/0), 16000, 1);
|
||||||
data_dumper_->DumpWav("aec3_echo_remover_render_input", kBlockSize,
|
data_dumper_->DumpWav("aec3_echo_remover_render_input",
|
||||||
&x[0][0][0], 16000, 1);
|
x.View(/*band=*/0, /*channel=*/0), 16000, 1);
|
||||||
data_dumper_->DumpRaw("aec3_echo_remover_capture_input", (*y)[0][0]);
|
data_dumper_->DumpRaw("aec3_echo_remover_capture_input",
|
||||||
data_dumper_->DumpRaw("aec3_echo_remover_render_input", x[0][0]);
|
y->View(/*band=*/0, /*channel=*/0));
|
||||||
|
data_dumper_->DumpRaw("aec3_echo_remover_render_input",
|
||||||
|
x.View(/*band=*/0, /*channel=*/0));
|
||||||
|
|
||||||
aec_state_.UpdateCaptureSaturation(capture_signal_saturation);
|
aec_state_.UpdateCaptureSaturation(capture_signal_saturation);
|
||||||
|
|
||||||
@ -369,13 +367,13 @@ void EchoRemoverImpl::ProcessCapture(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform linear echo cancellation.
|
// Perform linear echo cancellation.
|
||||||
subtractor_.Process(*render_buffer, (*y)[0], render_signal_analyzer_,
|
subtractor_.Process(*render_buffer, *y, render_signal_analyzer_, aec_state_,
|
||||||
aec_state_, subtractor_output);
|
subtractor_output);
|
||||||
|
|
||||||
// Compute spectra.
|
// Compute spectra.
|
||||||
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
|
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
|
||||||
FormLinearFilterOutput(subtractor_output[ch], e[ch]);
|
FormLinearFilterOutput(subtractor_output[ch], e[ch]);
|
||||||
WindowedPaddedFft(fft_, (*y)[0][ch], y_old_[ch], &Y[ch]);
|
WindowedPaddedFft(fft_, y->View(/*band=*/0, ch), y_old_[ch], &Y[ch]);
|
||||||
WindowedPaddedFft(fft_, e[ch], e_old_[ch], &E[ch]);
|
WindowedPaddedFft(fft_, e[ch], e_old_[ch], &E[ch]);
|
||||||
LinearEchoPower(E[ch], Y[ch], &S2_linear[ch]);
|
LinearEchoPower(E[ch], Y[ch], &S2_linear[ch]);
|
||||||
Y[ch].Spectrum(optimization_, Y2[ch]);
|
Y[ch].Spectrum(optimization_, Y2[ch]);
|
||||||
@ -384,11 +382,11 @@ void EchoRemoverImpl::ProcessCapture(
|
|||||||
|
|
||||||
// Optionally return the linear filter output.
|
// Optionally return the linear filter output.
|
||||||
if (linear_output) {
|
if (linear_output) {
|
||||||
RTC_DCHECK_GE(1, linear_output->size());
|
RTC_DCHECK_GE(1, linear_output->NumBands());
|
||||||
RTC_DCHECK_EQ(num_capture_channels_, linear_output[0].size());
|
RTC_DCHECK_EQ(num_capture_channels_, linear_output->NumChannels());
|
||||||
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
|
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
|
||||||
RTC_DCHECK_EQ(kBlockSize, (*linear_output)[0][ch].size());
|
std::copy(e[ch].begin(), e[ch].end(),
|
||||||
std::copy(e[ch].begin(), e[ch].end(), (*linear_output)[0][ch].begin());
|
linear_output->begin(/*band=*/0, ch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,8 +398,8 @@ void EchoRemoverImpl::ProcessCapture(
|
|||||||
// Choose the linear output.
|
// Choose the linear output.
|
||||||
const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y;
|
const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y;
|
||||||
|
|
||||||
data_dumper_->DumpWav("aec3_output_linear", kBlockSize, &(*y)[0][0][0], 16000,
|
data_dumper_->DumpWav("aec3_output_linear",
|
||||||
1);
|
y->View(/*band=*/0, /*channel=*/0), 16000, 1);
|
||||||
data_dumper_->DumpWav("aec3_output_linear2", kBlockSize, &e[0][0], 16000, 1);
|
data_dumper_->DumpWav("aec3_output_linear2", kBlockSize, &e[0][0], 16000, 1);
|
||||||
|
|
||||||
// Estimate the comfort noise.
|
// Estimate the comfort noise.
|
||||||
@ -455,13 +453,12 @@ void EchoRemoverImpl::ProcessCapture(
|
|||||||
// Debug outputs for the purpose of development and analysis.
|
// Debug outputs for the purpose of development and analysis.
|
||||||
data_dumper_->DumpWav("aec3_echo_estimate", kBlockSize,
|
data_dumper_->DumpWav("aec3_echo_estimate", kBlockSize,
|
||||||
&subtractor_output[0].s_refined[0], 16000, 1);
|
&subtractor_output[0].s_refined[0], 16000, 1);
|
||||||
data_dumper_->DumpRaw("aec3_output", (*y)[0][0]);
|
data_dumper_->DumpRaw("aec3_output", y->View(/*band=*/0, /*channel=*/0));
|
||||||
data_dumper_->DumpRaw("aec3_narrow_render",
|
data_dumper_->DumpRaw("aec3_narrow_render",
|
||||||
render_signal_analyzer_.NarrowPeakBand() ? 1 : 0);
|
render_signal_analyzer_.NarrowPeakBand() ? 1 : 0);
|
||||||
data_dumper_->DumpRaw("aec3_N2", cng_.NoiseSpectrum()[0]);
|
data_dumper_->DumpRaw("aec3_N2", cng_.NoiseSpectrum()[0]);
|
||||||
data_dumper_->DumpRaw("aec3_suppressor_gain", G);
|
data_dumper_->DumpRaw("aec3_suppressor_gain", G);
|
||||||
data_dumper_->DumpWav("aec3_output",
|
data_dumper_->DumpWav("aec3_output", y->View(/*band=*/0, /*channel=*/0),
|
||||||
rtc::ArrayView<const float>(&(*y)[0][0][0], kBlockSize),
|
|
||||||
16000, 1);
|
16000, 1);
|
||||||
data_dumper_->DumpRaw("aec3_using_subtractor_output[0]",
|
data_dumper_->DumpRaw("aec3_using_subtractor_output[0]",
|
||||||
aec_state_.UseLinearFilterOutput() ? 1 : 0);
|
aec_state_.UseLinearFilterOutput() ? 1 : 0);
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/audio/echo_canceller3_config.h"
|
#include "api/audio/echo_canceller3_config.h"
|
||||||
#include "api/audio/echo_control.h"
|
#include "api/audio/echo_control.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
#include "modules/audio_processing/aec3/delay_estimate.h"
|
#include "modules/audio_processing/aec3/delay_estimate.h"
|
||||||
#include "modules/audio_processing/aec3/echo_path_variability.h"
|
#include "modules/audio_processing/aec3/echo_path_variability.h"
|
||||||
#include "modules/audio_processing/aec3/render_buffer.h"
|
#include "modules/audio_processing/aec3/render_buffer.h"
|
||||||
@ -42,8 +43,8 @@ class EchoRemover {
|
|||||||
bool capture_signal_saturation,
|
bool capture_signal_saturation,
|
||||||
const absl::optional<DelayEstimate>& external_delay,
|
const absl::optional<DelayEstimate>& external_delay,
|
||||||
RenderBuffer* render_buffer,
|
RenderBuffer* render_buffer,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* capture) = 0;
|
Block* capture) = 0;
|
||||||
|
|
||||||
// Updates the status on whether echo leakage is detected in the output of the
|
// Updates the status on whether echo leakage is detected in the output of the
|
||||||
// echo remover.
|
// echo remover.
|
||||||
|
|||||||
@ -62,14 +62,8 @@ TEST_P(EchoRemoverMultiChannel, BasicApiCalls) {
|
|||||||
std::unique_ptr<RenderDelayBuffer> render_buffer(RenderDelayBuffer::Create(
|
std::unique_ptr<RenderDelayBuffer> render_buffer(RenderDelayBuffer::Create(
|
||||||
EchoCanceller3Config(), rate, num_render_channels));
|
EchoCanceller3Config(), rate, num_render_channels));
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> render(
|
Block render(NumBandsForRate(rate), num_render_channels);
|
||||||
NumBandsForRate(rate),
|
Block capture(NumBandsForRate(rate), num_capture_channels);
|
||||||
std::vector<std::vector<float>>(num_render_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> capture(
|
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(num_capture_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
for (size_t k = 0; k < 100; ++k) {
|
for (size_t k = 0; k < 100; ++k) {
|
||||||
EchoPathVariability echo_path_variability(
|
EchoPathVariability echo_path_variability(
|
||||||
k % 3 == 0 ? true : false,
|
k % 3 == 0 ? true : false,
|
||||||
@ -97,27 +91,6 @@ TEST(EchoRemoverDeathTest, DISABLED_WrongSampleRate) {
|
|||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies the check for the capture block size.
|
|
||||||
TEST(EchoRemoverDeathTest, WrongCaptureBlockSize) {
|
|
||||||
absl::optional<DelayEstimate> delay_estimate;
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(rate));
|
|
||||||
std::unique_ptr<EchoRemover> remover(
|
|
||||||
EchoRemover::Create(EchoCanceller3Config(), rate, 1, 1));
|
|
||||||
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
|
||||||
RenderDelayBuffer::Create(EchoCanceller3Config(), rate, 1));
|
|
||||||
std::vector<std::vector<std::vector<float>>> capture(
|
|
||||||
NumBandsForRate(rate), std::vector<std::vector<float>>(
|
|
||||||
1, std::vector<float>(kBlockSize - 1, 0.f)));
|
|
||||||
EchoPathVariability echo_path_variability(
|
|
||||||
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
|
||||||
EXPECT_DEATH(remover->ProcessCapture(
|
|
||||||
echo_path_variability, false, delay_estimate,
|
|
||||||
render_buffer->GetRenderBuffer(), nullptr, &capture),
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verifies the check for the number of capture bands.
|
// Verifies the check for the number of capture bands.
|
||||||
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
|
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
|
||||||
// tests on test bots has been fixed.c
|
// tests on test bots has been fixed.c
|
||||||
@ -129,10 +102,7 @@ TEST(EchoRemoverDeathTest, DISABLED_WrongCaptureNumBands) {
|
|||||||
EchoRemover::Create(EchoCanceller3Config(), rate, 1, 1));
|
EchoRemover::Create(EchoCanceller3Config(), rate, 1, 1));
|
||||||
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
std::unique_ptr<RenderDelayBuffer> render_buffer(
|
||||||
RenderDelayBuffer::Create(EchoCanceller3Config(), rate, 1));
|
RenderDelayBuffer::Create(EchoCanceller3Config(), rate, 1));
|
||||||
std::vector<std::vector<std::vector<float>>> capture(
|
Block capture(NumBandsForRate(rate == 48000 ? 16000 : rate + 16000), 1);
|
||||||
NumBandsForRate(rate == 48000 ? 16000 : rate + 16000),
|
|
||||||
std::vector<std::vector<float>>(1,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
EchoPathVariability echo_path_variability(
|
EchoPathVariability echo_path_variability(
|
||||||
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
||||||
EXPECT_DEATH(remover->ProcessCapture(
|
EXPECT_DEATH(remover->ProcessCapture(
|
||||||
@ -167,14 +137,8 @@ TEST(EchoRemover, BasicEchoRemoval) {
|
|||||||
absl::optional<DelayEstimate> delay_estimate;
|
absl::optional<DelayEstimate> delay_estimate;
|
||||||
for (size_t num_channels : {1, 2, 4}) {
|
for (size_t num_channels : {1, 2, 4}) {
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
for (auto rate : {16000, 32000, 48000}) {
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(NumBandsForRate(rate), num_channels);
|
||||||
NumBandsForRate(rate),
|
Block y(NumBandsForRate(rate), num_channels);
|
||||||
std::vector<std::vector<float>>(num_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> y(
|
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(num_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
EchoPathVariability echo_path_variability(
|
EchoPathVariability echo_path_variability(
|
||||||
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
||||||
for (size_t delay_samples : {0, 64, 150, 200, 301}) {
|
for (size_t delay_samples : {0, 64, 150, 200, 301}) {
|
||||||
@ -187,13 +151,13 @@ TEST(EchoRemover, BasicEchoRemoval) {
|
|||||||
render_buffer->AlignFromDelay(delay_samples / kBlockSize);
|
render_buffer->AlignFromDelay(delay_samples / kBlockSize);
|
||||||
|
|
||||||
std::vector<std::vector<std::unique_ptr<DelayBuffer<float>>>>
|
std::vector<std::vector<std::unique_ptr<DelayBuffer<float>>>>
|
||||||
delay_buffers(x.size());
|
delay_buffers(x.NumBands());
|
||||||
for (size_t band = 0; band < delay_buffers.size(); ++band) {
|
for (size_t band = 0; band < delay_buffers.size(); ++band) {
|
||||||
delay_buffers[band].resize(x[0].size());
|
delay_buffers[band].resize(x.NumChannels());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t band = 0; band < x.size(); ++band) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < x[0].size(); ++channel) {
|
for (int channel = 0; channel < x.NumChannels(); ++channel) {
|
||||||
delay_buffers[band][channel].reset(
|
delay_buffers[band][channel].reset(
|
||||||
new DelayBuffer<float>(delay_samples));
|
new DelayBuffer<float>(delay_samples));
|
||||||
}
|
}
|
||||||
@ -204,22 +168,23 @@ TEST(EchoRemover, BasicEchoRemoval) {
|
|||||||
for (int k = 0; k < kNumBlocksToProcess; ++k) {
|
for (int k = 0; k < kNumBlocksToProcess; ++k) {
|
||||||
const bool silence = k < 100 || (k % 100 >= 10);
|
const bool silence = k < 100 || (k % 100 >= 10);
|
||||||
|
|
||||||
for (size_t band = 0; band < x.size(); ++band) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < x[0].size(); ++channel) {
|
for (int channel = 0; channel < x.NumChannels(); ++channel) {
|
||||||
if (silence) {
|
if (silence) {
|
||||||
std::fill(x[band][channel].begin(), x[band][channel].end(),
|
std::fill(x.begin(band, channel), x.end(band, channel), 0.f);
|
||||||
0.f);
|
|
||||||
} else {
|
} else {
|
||||||
RandomizeSampleVector(&random_generator, x[band][channel]);
|
RandomizeSampleVector(&random_generator, x.View(band, channel));
|
||||||
}
|
}
|
||||||
delay_buffers[band][channel]->Delay(x[band][channel],
|
delay_buffers[band][channel]->Delay(x.View(band, channel),
|
||||||
y[band][channel]);
|
y.View(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (k > kNumBlocksToProcess / 2) {
|
if (k > kNumBlocksToProcess / 2) {
|
||||||
input_energy = std::inner_product(y[0][0].begin(), y[0][0].end(),
|
input_energy = std::inner_product(
|
||||||
y[0][0].begin(), input_energy);
|
y.begin(/*band=*/0, /*channel=*/0),
|
||||||
|
y.end(/*band=*/0, /*channel=*/0),
|
||||||
|
y.begin(/*band=*/0, /*channel=*/0), input_energy);
|
||||||
}
|
}
|
||||||
|
|
||||||
render_buffer->Insert(x);
|
render_buffer->Insert(x);
|
||||||
@ -230,8 +195,10 @@ TEST(EchoRemover, BasicEchoRemoval) {
|
|||||||
&y);
|
&y);
|
||||||
|
|
||||||
if (k > kNumBlocksToProcess / 2) {
|
if (k > kNumBlocksToProcess / 2) {
|
||||||
output_energy = std::inner_product(y[0][0].begin(), y[0][0].end(),
|
output_energy = std::inner_product(
|
||||||
y[0][0].begin(), output_energy);
|
y.begin(/*band=*/0, /*channel=*/0),
|
||||||
|
y.end(/*band=*/0, /*channel=*/0),
|
||||||
|
y.begin(/*band=*/0, /*channel=*/0), output_energy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPECT_GT(input_energy, 10.f * output_energy);
|
EXPECT_GT(input_energy, 10.f * output_energy);
|
||||||
|
|||||||
@ -60,7 +60,7 @@ void VerifyErleGreaterOrEqual(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormFarendTimeFrame(std::vector<std::vector<std::vector<float>>>* x) {
|
void FormFarendTimeFrame(Block* x) {
|
||||||
const std::array<float, kBlockSize> frame = {
|
const std::array<float, kBlockSize> frame = {
|
||||||
7459.88, 17209.6, 17383, 20768.9, 16816.7, 18386.3, 4492.83, 9675.85,
|
7459.88, 17209.6, 17383, 20768.9, 16816.7, 18386.3, 4492.83, 9675.85,
|
||||||
6665.52, 14808.6, 9342.3, 7483.28, 19261.7, 4145.98, 1622.18, 13475.2,
|
6665.52, 14808.6, 9342.3, 7483.28, 19261.7, 4145.98, 1622.18, 13475.2,
|
||||||
@ -70,10 +70,10 @@ void FormFarendTimeFrame(std::vector<std::vector<std::vector<float>>>* x) {
|
|||||||
11405, 15031.4, 14541.6, 19765.5, 18346.3, 19350.2, 3157.47, 18095.8,
|
11405, 15031.4, 14541.6, 19765.5, 18346.3, 19350.2, 3157.47, 18095.8,
|
||||||
1743.68, 21328.2, 19727.5, 7295.16, 10332.4, 11055.5, 20107.4, 14708.4,
|
1743.68, 21328.2, 19727.5, 7295.16, 10332.4, 11055.5, 20107.4, 14708.4,
|
||||||
12416.2, 16434, 2454.69, 9840.8, 6867.23, 1615.75, 6059.9, 8394.19};
|
12416.2, 16434, 2454.69, 9840.8, 6867.23, 1615.75, 6059.9, 8394.19};
|
||||||
for (size_t band = 0; band < x->size(); ++band) {
|
for (int band = 0; band < x->NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < (*x)[band].size(); ++channel) {
|
for (int channel = 0; channel < x->NumChannels(); ++channel) {
|
||||||
RTC_DCHECK_GE((*x)[band][channel].size(), frame.size());
|
RTC_DCHECK_GE(kBlockSize, frame.size());
|
||||||
std::copy(frame.begin(), frame.end(), (*x)[band][channel].begin());
|
std::copy(frame.begin(), frame.end(), x->begin(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,13 +104,13 @@ void FormFarendFrame(const RenderBuffer& render_buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FormNearendFrame(
|
void FormNearendFrame(
|
||||||
std::vector<std::vector<std::vector<float>>>* x,
|
Block* x,
|
||||||
std::array<float, kFftLengthBy2Plus1>* X2,
|
std::array<float, kFftLengthBy2Plus1>* X2,
|
||||||
rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> E2,
|
rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> E2,
|
||||||
rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> Y2) {
|
rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> Y2) {
|
||||||
for (size_t band = 0; band < x->size(); ++band) {
|
for (int band = 0; band < x->NumBands(); ++band) {
|
||||||
for (size_t ch = 0; ch < (*x)[band].size(); ++ch) {
|
for (int ch = 0; ch < x->NumChannels(); ++ch) {
|
||||||
std::fill((*x)[band][ch].begin(), (*x)[band][ch].end(), 0.f);
|
std::fill(x->begin(band, ch), x->end(band, ch), 0.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,9 +162,7 @@ TEST_P(ErleEstimatorMultiChannel, VerifyErleIncreaseAndHold) {
|
|||||||
EchoCanceller3Config config;
|
EchoCanceller3Config config;
|
||||||
config.erle.onset_detection = true;
|
config.erle.onset_detection = true;
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_render_channels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
||||||
filter_frequency_response(
|
filter_frequency_response(
|
||||||
config.filter.refined.length_blocks,
|
config.filter.refined.length_blocks,
|
||||||
@ -227,9 +225,7 @@ TEST_P(ErleEstimatorMultiChannel, VerifyErleTrackingOnOnsets) {
|
|||||||
std::vector<bool> converged_filters(num_capture_channels, true);
|
std::vector<bool> converged_filters(num_capture_channels, true);
|
||||||
EchoCanceller3Config config;
|
EchoCanceller3Config config;
|
||||||
config.erle.onset_detection = true;
|
config.erle.onset_detection = true;
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_render_channels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
||||||
filter_frequency_response(
|
filter_frequency_response(
|
||||||
config.filter.refined.length_blocks,
|
config.filter.refined.length_blocks,
|
||||||
|
|||||||
@ -131,7 +131,7 @@ void FilterAnalyzer::AnalyzeRegion(
|
|||||||
|
|
||||||
st_ch.consistent_estimate = st_ch.consistent_filter_detector.Detect(
|
st_ch.consistent_estimate = st_ch.consistent_filter_detector.Detect(
|
||||||
h_highpass_[ch], region_,
|
h_highpass_[ch], region_,
|
||||||
render_buffer.Block(-filter_delays_blocks_[ch])[0], st_ch.peak_index,
|
render_buffer.Block(-filter_delays_blocks_[ch]), st_ch.peak_index,
|
||||||
filter_delays_blocks_[ch]);
|
filter_delays_blocks_[ch]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ void FilterAnalyzer::ConsistentFilterDetector::Reset() {
|
|||||||
bool FilterAnalyzer::ConsistentFilterDetector::Detect(
|
bool FilterAnalyzer::ConsistentFilterDetector::Detect(
|
||||||
rtc::ArrayView<const float> filter_to_analyze,
|
rtc::ArrayView<const float> filter_to_analyze,
|
||||||
const FilterRegion& region,
|
const FilterRegion& region,
|
||||||
rtc::ArrayView<const std::vector<float>> x_block,
|
const Block& x_block,
|
||||||
size_t peak_index,
|
size_t peak_index,
|
||||||
int delay_blocks) {
|
int delay_blocks) {
|
||||||
if (region.start_sample_ == 0) {
|
if (region.start_sample_ == 0) {
|
||||||
@ -265,7 +265,9 @@ bool FilterAnalyzer::ConsistentFilterDetector::Detect(
|
|||||||
|
|
||||||
if (significant_peak_) {
|
if (significant_peak_) {
|
||||||
bool active_render_block = false;
|
bool active_render_block = false;
|
||||||
for (auto& x_channel : x_block) {
|
for (int ch = 0; ch < x_block.NumChannels(); ++ch) {
|
||||||
|
rtc::ArrayView<const float, kBlockSize> x_channel =
|
||||||
|
x_block.View(/*band=*/0, ch);
|
||||||
const float x_energy = std::inner_product(
|
const float x_energy = std::inner_product(
|
||||||
x_channel.begin(), x_channel.end(), x_channel.begin(), 0.f);
|
x_channel.begin(), x_channel.end(), x_channel.begin(), 0.f);
|
||||||
if (x_energy > active_render_threshold_) {
|
if (x_energy > active_render_threshold_) {
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "api/audio/echo_canceller3_config.h"
|
#include "api/audio/echo_canceller3_config.h"
|
||||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ class FilterAnalyzer {
|
|||||||
void Reset();
|
void Reset();
|
||||||
bool Detect(rtc::ArrayView<const float> filter_to_analyze,
|
bool Detect(rtc::ArrayView<const float> filter_to_analyze,
|
||||||
const FilterRegion& region,
|
const FilterRegion& region,
|
||||||
rtc::ArrayView<const std::vector<float>> x_block,
|
const Block& x_block,
|
||||||
size_t peak_index,
|
size_t peak_index,
|
||||||
int delay_blocks);
|
int delay_blocks);
|
||||||
|
|
||||||
|
|||||||
@ -33,26 +33,22 @@ FrameBlocker::~FrameBlocker() = default;
|
|||||||
|
|
||||||
void FrameBlocker::InsertSubFrameAndExtractBlock(
|
void FrameBlocker::InsertSubFrameAndExtractBlock(
|
||||||
const std::vector<std::vector<rtc::ArrayView<float>>>& sub_frame,
|
const std::vector<std::vector<rtc::ArrayView<float>>>& sub_frame,
|
||||||
std::vector<std::vector<std::vector<float>>>* block) {
|
Block* block) {
|
||||||
RTC_DCHECK(block);
|
RTC_DCHECK(block);
|
||||||
RTC_DCHECK_EQ(num_bands_, block->size());
|
RTC_DCHECK_EQ(num_bands_, block->NumBands());
|
||||||
RTC_DCHECK_EQ(num_bands_, sub_frame.size());
|
RTC_DCHECK_EQ(num_bands_, sub_frame.size());
|
||||||
for (size_t band = 0; band < num_bands_; ++band) {
|
for (size_t band = 0; band < num_bands_; ++band) {
|
||||||
RTC_DCHECK_EQ(num_channels_, (*block)[band].size());
|
RTC_DCHECK_EQ(num_channels_, block->NumChannels());
|
||||||
RTC_DCHECK_EQ(num_channels_, sub_frame[band].size());
|
RTC_DCHECK_EQ(num_channels_, sub_frame[band].size());
|
||||||
for (size_t channel = 0; channel < num_channels_; ++channel) {
|
for (size_t channel = 0; channel < num_channels_; ++channel) {
|
||||||
RTC_DCHECK_GE(kBlockSize - 16, buffer_[band][channel].size());
|
RTC_DCHECK_GE(kBlockSize - 16, buffer_[band][channel].size());
|
||||||
RTC_DCHECK_EQ(kBlockSize, (*block)[band][channel].size());
|
|
||||||
RTC_DCHECK_EQ(kSubFrameLength, sub_frame[band][channel].size());
|
RTC_DCHECK_EQ(kSubFrameLength, sub_frame[band][channel].size());
|
||||||
const int samples_to_block = kBlockSize - buffer_[band][channel].size();
|
const int samples_to_block = kBlockSize - buffer_[band][channel].size();
|
||||||
(*block)[band][channel].clear();
|
std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(),
|
||||||
(*block)[band][channel].insert((*block)[band][channel].begin(),
|
block->begin(band, channel));
|
||||||
buffer_[band][channel].begin(),
|
std::copy(sub_frame[band][channel].begin(),
|
||||||
buffer_[band][channel].end());
|
sub_frame[band][channel].begin() + samples_to_block,
|
||||||
(*block)[band][channel].insert(
|
block->begin(band, channel) + kBlockSize - samples_to_block);
|
||||||
(*block)[band][channel].begin() + buffer_[band][channel].size(),
|
|
||||||
sub_frame[band][channel].begin(),
|
|
||||||
sub_frame[band][channel].begin() + samples_to_block);
|
|
||||||
buffer_[band][channel].clear();
|
buffer_[band][channel].clear();
|
||||||
buffer_[band][channel].insert(
|
buffer_[band][channel].insert(
|
||||||
buffer_[band][channel].begin(),
|
buffer_[band][channel].begin(),
|
||||||
@ -66,20 +62,16 @@ bool FrameBlocker::IsBlockAvailable() const {
|
|||||||
return kBlockSize == buffer_[0][0].size();
|
return kBlockSize == buffer_[0][0].size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameBlocker::ExtractBlock(
|
void FrameBlocker::ExtractBlock(Block* block) {
|
||||||
std::vector<std::vector<std::vector<float>>>* block) {
|
|
||||||
RTC_DCHECK(block);
|
RTC_DCHECK(block);
|
||||||
RTC_DCHECK_EQ(num_bands_, block->size());
|
RTC_DCHECK_EQ(num_bands_, block->NumBands());
|
||||||
|
RTC_DCHECK_EQ(num_channels_, block->NumChannels());
|
||||||
RTC_DCHECK(IsBlockAvailable());
|
RTC_DCHECK(IsBlockAvailable());
|
||||||
for (size_t band = 0; band < num_bands_; ++band) {
|
for (size_t band = 0; band < num_bands_; ++band) {
|
||||||
RTC_DCHECK_EQ(num_channels_, (*block)[band].size());
|
|
||||||
for (size_t channel = 0; channel < num_channels_; ++channel) {
|
for (size_t channel = 0; channel < num_channels_; ++channel) {
|
||||||
RTC_DCHECK_EQ(kBlockSize, buffer_[band][channel].size());
|
RTC_DCHECK_EQ(kBlockSize, buffer_[band][channel].size());
|
||||||
RTC_DCHECK_EQ(kBlockSize, (*block)[band][channel].size());
|
std::copy(buffer_[band][channel].begin(), buffer_[band][channel].end(),
|
||||||
(*block)[band][channel].clear();
|
block->begin(band, channel));
|
||||||
(*block)[band][channel].insert((*block)[band][channel].begin(),
|
|
||||||
buffer_[band][channel].begin(),
|
|
||||||
buffer_[band][channel].end());
|
|
||||||
buffer_[band][channel].clear();
|
buffer_[band][channel].clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -33,12 +34,12 @@ class FrameBlocker {
|
|||||||
// extracts one 64 sample multiband block.
|
// extracts one 64 sample multiband block.
|
||||||
void InsertSubFrameAndExtractBlock(
|
void InsertSubFrameAndExtractBlock(
|
||||||
const std::vector<std::vector<rtc::ArrayView<float>>>& sub_frame,
|
const std::vector<std::vector<rtc::ArrayView<float>>>& sub_frame,
|
||||||
std::vector<std::vector<std::vector<float>>>* block);
|
Block* block);
|
||||||
// Reports whether a multiband block of 64 samples is available for
|
// Reports whether a multiband block of 64 samples is available for
|
||||||
// extraction.
|
// extraction.
|
||||||
bool IsBlockAvailable() const;
|
bool IsBlockAvailable() const;
|
||||||
// Extracts a multiband block of 64 samples.
|
// Extracts a multiband block of 64 samples.
|
||||||
void ExtractBlock(std::vector<std::vector<std::vector<float>>>* block);
|
void ExtractBlock(Block* block);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const size_t num_bands_;
|
const size_t num_bands_;
|
||||||
|
|||||||
@ -86,15 +86,14 @@ bool VerifySubFrame(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VerifyBlock(size_t block_counter,
|
bool VerifyBlock(size_t block_counter, int offset, const Block& block) {
|
||||||
int offset,
|
for (int band = 0; band < block.NumBands(); ++band) {
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) {
|
for (int channel = 0; channel < block.NumChannels(); ++channel) {
|
||||||
for (size_t band = 0; band < block.size(); ++band) {
|
for (size_t sample = 0; sample < kBlockSize; ++sample) {
|
||||||
for (size_t channel = 0; channel < block[band].size(); ++channel) {
|
auto it = block.begin(band, channel) + sample;
|
||||||
for (size_t sample = 0; sample < block[band][channel].size(); ++sample) {
|
|
||||||
const float reference_value = ComputeSampleValue(
|
const float reference_value = ComputeSampleValue(
|
||||||
block_counter, kBlockSize, band, channel, sample, offset);
|
block_counter, kBlockSize, band, channel, sample, offset);
|
||||||
if (reference_value != block[band][channel][sample]) {
|
if (reference_value != *it) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,9 +107,7 @@ void RunBlockerTest(int sample_rate_hz, size_t num_channels) {
|
|||||||
constexpr size_t kNumSubFramesToProcess = 20;
|
constexpr size_t kNumSubFramesToProcess = 20;
|
||||||
const size_t num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(num_bands, num_channels);
|
||||||
num_bands, std::vector<std::vector<float>>(
|
|
||||||
num_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
||||||
num_bands, std::vector<std::vector<float>>(
|
num_bands, std::vector<std::vector<float>>(
|
||||||
num_channels, std::vector<float>(kSubFrameLength, 0.f)));
|
num_channels, std::vector<float>(kSubFrameLength, 0.f)));
|
||||||
@ -145,9 +142,7 @@ void RunBlockerAndFramerTest(int sample_rate_hz, size_t num_channels) {
|
|||||||
const size_t kNumSubFramesToProcess = 20;
|
const size_t kNumSubFramesToProcess = 20;
|
||||||
const size_t num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(num_bands, num_channels);
|
||||||
num_bands, std::vector<std::vector<float>>(
|
|
||||||
num_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
||||||
num_bands, std::vector<std::vector<float>>(
|
num_bands, std::vector<std::vector<float>>(
|
||||||
num_channels, std::vector<float>(kSubFrameLength, 0.f)));
|
num_channels, std::vector<float>(kSubFrameLength, 0.f)));
|
||||||
@ -194,16 +189,12 @@ void RunWronglySizedInsertAndExtractParametersTest(
|
|||||||
size_t correct_num_channels,
|
size_t correct_num_channels,
|
||||||
size_t num_block_bands,
|
size_t num_block_bands,
|
||||||
size_t num_block_channels,
|
size_t num_block_channels,
|
||||||
size_t block_length,
|
|
||||||
size_t num_sub_frame_bands,
|
size_t num_sub_frame_bands,
|
||||||
size_t num_sub_frame_channels,
|
size_t num_sub_frame_channels,
|
||||||
size_t sub_frame_length) {
|
size_t sub_frame_length) {
|
||||||
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(num_block_bands, num_block_channels);
|
||||||
num_block_bands,
|
|
||||||
std::vector<std::vector<float>>(num_block_channels,
|
|
||||||
std::vector<float>(block_length, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
||||||
num_sub_frame_bands,
|
num_sub_frame_bands,
|
||||||
std::vector<std::vector<float>>(
|
std::vector<std::vector<float>>(
|
||||||
@ -222,18 +213,11 @@ void RunWronglySizedInsertAndExtractParametersTest(
|
|||||||
void RunWronglySizedExtractParameterTest(int sample_rate_hz,
|
void RunWronglySizedExtractParameterTest(int sample_rate_hz,
|
||||||
size_t correct_num_channels,
|
size_t correct_num_channels,
|
||||||
size_t num_block_bands,
|
size_t num_block_bands,
|
||||||
size_t num_block_channels,
|
size_t num_block_channels) {
|
||||||
size_t block_length) {
|
|
||||||
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> correct_block(
|
Block correct_block(correct_num_bands, correct_num_channels);
|
||||||
correct_num_bands,
|
Block wrong_block(num_block_bands, num_block_channels);
|
||||||
std::vector<std::vector<float>>(correct_num_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> wrong_block(
|
|
||||||
num_block_bands,
|
|
||||||
std::vector<std::vector<float>>(num_block_channels,
|
|
||||||
std::vector<float>(block_length, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
||||||
correct_num_bands,
|
correct_num_bands,
|
||||||
std::vector<std::vector<float>>(
|
std::vector<std::vector<float>>(
|
||||||
@ -259,9 +243,7 @@ void RunWrongExtractOrderTest(int sample_rate_hz,
|
|||||||
size_t num_preceeding_api_calls) {
|
size_t num_preceeding_api_calls) {
|
||||||
const size_t num_bands = NumBandsForRate(sample_rate_hz);
|
const size_t num_bands = NumBandsForRate(sample_rate_hz);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> block(
|
Block block(num_bands, num_channels);
|
||||||
num_bands, std::vector<std::vector<float>>(
|
|
||||||
num_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
std::vector<std::vector<std::vector<float>>> input_sub_frame(
|
||||||
num_bands, std::vector<std::vector<float>>(
|
num_bands, std::vector<std::vector<float>>(
|
||||||
num_channels, std::vector<float>(kSubFrameLength, 0.f)));
|
num_channels, std::vector<float>(kSubFrameLength, 0.f)));
|
||||||
@ -296,7 +278,7 @@ TEST(FrameBlockerDeathTest,
|
|||||||
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, wrong_num_bands, correct_num_channels,
|
rate, correct_num_channels, wrong_num_bands, correct_num_channels,
|
||||||
kBlockSize, correct_num_bands, correct_num_channels, kSubFrameLength);
|
correct_num_bands, correct_num_channels, kSubFrameLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,7 +292,7 @@ TEST(FrameBlockerDeathTest,
|
|||||||
const size_t wrong_num_channels = correct_num_channels + 1;
|
const size_t wrong_num_channels = correct_num_channels + 1;
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, correct_num_bands, wrong_num_channels,
|
rate, correct_num_channels, correct_num_bands, wrong_num_channels,
|
||||||
kBlockSize, correct_num_bands, correct_num_channels, kSubFrameLength);
|
correct_num_bands, correct_num_channels, kSubFrameLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,7 +306,7 @@ TEST(FrameBlockerDeathTest,
|
|||||||
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
||||||
kBlockSize, wrong_num_bands, correct_num_channels, kSubFrameLength);
|
wrong_num_bands, correct_num_channels, kSubFrameLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,21 +320,7 @@ TEST(FrameBlockerDeathTest,
|
|||||||
const size_t wrong_num_channels = correct_num_channels + 1;
|
const size_t wrong_num_channels = correct_num_channels + 1;
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, correct_num_bands, wrong_num_channels,
|
rate, correct_num_channels, correct_num_bands, wrong_num_channels,
|
||||||
kBlockSize, correct_num_bands, wrong_num_channels, kSubFrameLength);
|
correct_num_bands, wrong_num_channels, kSubFrameLength);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FrameBlockerDeathTest,
|
|
||||||
WrongNumberOfSamplesInBlockForInsertSubFrameAndExtractBlock) {
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
|
||||||
for (size_t correct_num_channels : {1, 2, 4, 8}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
|
|
||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
|
||||||
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
|
||||||
kBlockSize - 1, correct_num_bands, correct_num_channels,
|
|
||||||
kSubFrameLength);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,8 +333,7 @@ TEST(FrameBlockerDeathTest,
|
|||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
const size_t correct_num_bands = NumBandsForRate(rate);
|
||||||
RunWronglySizedInsertAndExtractParametersTest(
|
RunWronglySizedInsertAndExtractParametersTest(
|
||||||
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
rate, correct_num_channels, correct_num_bands, correct_num_channels,
|
||||||
kBlockSize, correct_num_bands, correct_num_channels,
|
correct_num_bands, correct_num_channels, kSubFrameLength - 1);
|
||||||
kSubFrameLength - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,9 +344,8 @@ TEST(FrameBlockerDeathTest, WrongNumberOfBandsInBlockForExtractBlock) {
|
|||||||
SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
|
SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
|
||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
const size_t correct_num_bands = NumBandsForRate(rate);
|
||||||
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
|
||||||
RunWronglySizedExtractParameterTest(rate, correct_num_channels,
|
RunWronglySizedExtractParameterTest(
|
||||||
wrong_num_bands, correct_num_channels,
|
rate, correct_num_channels, wrong_num_bands, correct_num_channels);
|
||||||
kBlockSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,21 +356,8 @@ TEST(FrameBlockerDeathTest, WrongNumberOfChannelsInBlockForExtractBlock) {
|
|||||||
SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
|
SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
|
||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
const size_t correct_num_bands = NumBandsForRate(rate);
|
||||||
const size_t wrong_num_channels = correct_num_channels + 1;
|
const size_t wrong_num_channels = correct_num_channels + 1;
|
||||||
RunWronglySizedExtractParameterTest(rate, correct_num_channels,
|
RunWronglySizedExtractParameterTest(
|
||||||
correct_num_bands, wrong_num_channels,
|
rate, correct_num_channels, correct_num_bands, wrong_num_channels);
|
||||||
kBlockSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FrameBlockerDeathTest, WrongNumberOfSamplesInBlockForExtractBlock) {
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
|
||||||
for (size_t correct_num_channels : {1, 2, 4, 8}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
|
|
||||||
const size_t correct_num_bands = NumBandsForRate(rate);
|
|
||||||
RunWronglySizedExtractParameterTest(rate, correct_num_channels,
|
|
||||||
correct_num_bands,
|
|
||||||
correct_num_channels, kBlockSize - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -210,9 +210,7 @@ TEST(MatchedFilter, LagEstimation) {
|
|||||||
for (auto down_sampling_factor : kDownSamplingFactors) {
|
for (auto down_sampling_factor : kDownSamplingFactors) {
|
||||||
const size_t sub_block_size = kBlockSize / down_sampling_factor;
|
const size_t sub_block_size = kBlockSize / down_sampling_factor;
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> render(
|
Block render(kNumBands, kNumChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
kNumChannels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<float>> capture(
|
std::vector<std::vector<float>> capture(
|
||||||
1, std::vector<float>(kBlockSize, 0.f));
|
1, std::vector<float>(kBlockSize, 0.f));
|
||||||
ApmDataDumper data_dumper(0);
|
ApmDataDumper data_dumper(0);
|
||||||
@ -238,10 +236,12 @@ TEST(MatchedFilter, LagEstimation) {
|
|||||||
for (size_t k = 0; k < (600 + delay_samples / sub_block_size); ++k) {
|
for (size_t k = 0; k < (600 + delay_samples / sub_block_size); ++k) {
|
||||||
for (size_t band = 0; band < kNumBands; ++band) {
|
for (size_t band = 0; band < kNumBands; ++band) {
|
||||||
for (size_t channel = 0; channel < kNumChannels; ++channel) {
|
for (size_t channel = 0; channel < kNumChannels; ++channel) {
|
||||||
RandomizeSampleVector(&random_generator, render[band][channel]);
|
RandomizeSampleVector(&random_generator,
|
||||||
|
render.View(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signal_delay_buffer.Delay(render[0][0], capture[0]);
|
signal_delay_buffer.Delay(render.View(/*band=*/0, /*channel=*/0),
|
||||||
|
capture[0]);
|
||||||
render_delay_buffer->Insert(render);
|
render_delay_buffer->Insert(render);
|
||||||
|
|
||||||
if (k == 0) {
|
if (k == 0) {
|
||||||
@ -328,9 +328,7 @@ TEST(MatchedFilter, LagNotReliableForUncorrelatedRenderAndCapture) {
|
|||||||
config.delay.num_filters = kNumMatchedFilters;
|
config.delay.num_filters = kNumMatchedFilters;
|
||||||
const size_t sub_block_size = kBlockSize / down_sampling_factor;
|
const size_t sub_block_size = kBlockSize / down_sampling_factor;
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> render(
|
Block render(kNumBands, kNumChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
kNumChannels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::array<float, kBlockSize> capture_data;
|
std::array<float, kBlockSize> capture_data;
|
||||||
rtc::ArrayView<float> capture(capture_data.data(), sub_block_size);
|
rtc::ArrayView<float> capture(capture_data.data(), sub_block_size);
|
||||||
std::fill(capture.begin(), capture.end(), 0.f);
|
std::fill(capture.begin(), capture.end(), 0.f);
|
||||||
@ -346,7 +344,8 @@ TEST(MatchedFilter, LagNotReliableForUncorrelatedRenderAndCapture) {
|
|||||||
|
|
||||||
// Analyze the correlation between render and capture.
|
// Analyze the correlation between render and capture.
|
||||||
for (size_t k = 0; k < 100; ++k) {
|
for (size_t k = 0; k < 100; ++k) {
|
||||||
RandomizeSampleVector(&random_generator, render[0][0]);
|
RandomizeSampleVector(&random_generator,
|
||||||
|
render.View(/*band=*/0, /*channel=*/0));
|
||||||
RandomizeSampleVector(&random_generator, capture);
|
RandomizeSampleVector(&random_generator, capture);
|
||||||
render_delay_buffer->Insert(render);
|
render_delay_buffer->Insert(render);
|
||||||
filter.Update(render_delay_buffer->GetDownsampledRenderBuffer(), capture,
|
filter.Update(render_delay_buffer->GetDownsampledRenderBuffer(), capture,
|
||||||
|
|||||||
@ -28,13 +28,10 @@ class MockBlockProcessor : public BlockProcessor {
|
|||||||
ProcessCapture,
|
ProcessCapture,
|
||||||
(bool level_change,
|
(bool level_change,
|
||||||
bool saturated_microphone_signal,
|
bool saturated_microphone_signal,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* capture_block),
|
Block* capture_block),
|
||||||
(override));
|
|
||||||
MOCK_METHOD(void,
|
|
||||||
BufferRender,
|
|
||||||
(const std::vector<std::vector<std::vector<float>>>& block),
|
|
||||||
(override));
|
(override));
|
||||||
|
MOCK_METHOD(void, BufferRender, (const Block& block), (override));
|
||||||
MOCK_METHOD(void,
|
MOCK_METHOD(void,
|
||||||
UpdateEchoLeakageStatus,
|
UpdateEchoLeakageStatus,
|
||||||
(bool leakage_detected),
|
(bool leakage_detected),
|
||||||
|
|||||||
@ -33,8 +33,8 @@ class MockEchoRemover : public EchoRemover {
|
|||||||
bool capture_signal_saturation,
|
bool capture_signal_saturation,
|
||||||
const absl::optional<DelayEstimate>& delay_estimate,
|
const absl::optional<DelayEstimate>& delay_estimate,
|
||||||
RenderBuffer* render_buffer,
|
RenderBuffer* render_buffer,
|
||||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
Block* linear_output,
|
||||||
std::vector<std::vector<std::vector<float>>>* capture),
|
Block* capture),
|
||||||
(override));
|
(override));
|
||||||
MOCK_METHOD(void,
|
MOCK_METHOD(void,
|
||||||
UpdateEchoLeakageStatus,
|
UpdateEchoLeakageStatus,
|
||||||
|
|||||||
@ -17,8 +17,7 @@ MockRenderDelayBuffer::MockRenderDelayBuffer(int sample_rate_hz,
|
|||||||
size_t num_channels)
|
size_t num_channels)
|
||||||
: block_buffer_(GetRenderDelayBufferSize(4, 4, 12),
|
: block_buffer_(GetRenderDelayBufferSize(4, 4, 12),
|
||||||
NumBandsForRate(sample_rate_hz),
|
NumBandsForRate(sample_rate_hz),
|
||||||
num_channels,
|
num_channels),
|
||||||
kBlockSize),
|
|
||||||
spectrum_buffer_(block_buffer_.buffer.size(), num_channels),
|
spectrum_buffer_(block_buffer_.buffer.size(), num_channels),
|
||||||
fft_buffer_(block_buffer_.buffer.size(), num_channels),
|
fft_buffer_(block_buffer_.buffer.size(), num_channels),
|
||||||
render_buffer_(&block_buffer_, &spectrum_buffer_, &fft_buffer_),
|
render_buffer_(&block_buffer_, &spectrum_buffer_, &fft_buffer_),
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class MockRenderDelayBuffer : public RenderDelayBuffer {
|
|||||||
MOCK_METHOD(void, Reset, (), (override));
|
MOCK_METHOD(void, Reset, (), (override));
|
||||||
MOCK_METHOD(RenderDelayBuffer::BufferingEvent,
|
MOCK_METHOD(RenderDelayBuffer::BufferingEvent,
|
||||||
Insert,
|
Insert,
|
||||||
(const std::vector<std::vector<std::vector<float>>>& block),
|
(const Block& block),
|
||||||
(override));
|
(override));
|
||||||
MOCK_METHOD(void, HandleSkippedCaptureProcessing, (), (override));
|
MOCK_METHOD(void, HandleSkippedCaptureProcessing, (), (override));
|
||||||
MOCK_METHOD(RenderDelayBuffer::BufferingEvent,
|
MOCK_METHOD(RenderDelayBuffer::BufferingEvent,
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class MockRenderDelayController : public RenderDelayController {
|
|||||||
GetDelay,
|
GetDelay,
|
||||||
(const DownsampledRenderBuffer& render_buffer,
|
(const DownsampledRenderBuffer& render_buffer,
|
||||||
size_t render_delay_buffer_delay,
|
size_t render_delay_buffer_delay,
|
||||||
const std::vector<std::vector<float>>& capture),
|
const Block& capture),
|
||||||
(override));
|
(override));
|
||||||
MOCK_METHOD(bool, HasClockdrift, (), (const, override));
|
MOCK_METHOD(bool, HasClockdrift, (), (const, override));
|
||||||
};
|
};
|
||||||
|
|||||||
@ -84,9 +84,7 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
|||||||
RefinedFilterUpdateGain refined_gain(
|
RefinedFilterUpdateGain refined_gain(
|
||||||
config.filter.refined, config.filter.config_change_duration_blocks);
|
config.filter.refined, config.filter.config_change_duration_blocks);
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, kNumRenderChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
kNumRenderChannels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<float> y(kBlockSize, 0.f);
|
std::vector<float> y(kBlockSize, 0.f);
|
||||||
config.delay.default_delay = 1;
|
config.delay.default_delay = 1;
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
||||||
@ -131,19 +129,19 @@ void RunFilterUpdateTest(int num_blocks_to_process,
|
|||||||
|
|
||||||
// Create the render signal.
|
// Create the render signal.
|
||||||
if (use_silent_render_in_second_half && k > num_blocks_to_process / 2) {
|
if (use_silent_render_in_second_half && k > num_blocks_to_process / 2) {
|
||||||
for (size_t band = 0; band < x.size(); ++band) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < x[band].size(); ++channel) {
|
for (int channel = 0; channel < x.NumChannels(); ++channel) {
|
||||||
std::fill(x[band][channel].begin(), x[band][channel].end(), 0.f);
|
std::fill(x.begin(band, channel), x.end(band, channel), 0.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t band = 0; band < x.size(); ++band) {
|
for (int band = 0; band < x.NumChannels(); ++band) {
|
||||||
for (size_t channel = 0; channel < x[band].size(); ++channel) {
|
for (int channel = 0; channel < x.NumChannels(); ++channel) {
|
||||||
RandomizeSampleVector(&random_generator, x[band][channel]);
|
RandomizeSampleVector(&random_generator, x.View(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delay_buffer.Delay(x[0][0], y);
|
delay_buffer.Delay(x.View(/*band=*/0, /*channel=*/0), y);
|
||||||
|
|
||||||
render_delay_buffer->Insert(x);
|
render_delay_buffer->Insert(x);
|
||||||
if (k == 0) {
|
if (k == 0) {
|
||||||
|
|||||||
@ -40,8 +40,7 @@ class RenderBuffer {
|
|||||||
~RenderBuffer();
|
~RenderBuffer();
|
||||||
|
|
||||||
// Get a block.
|
// Get a block.
|
||||||
const std::vector<std::vector<std::vector<float>>>& Block(
|
const Block& Block(int buffer_offset_blocks) const {
|
||||||
int buffer_offset_blocks) const {
|
|
||||||
int position =
|
int position =
|
||||||
block_buffer_->OffsetIndex(block_buffer_->read, buffer_offset_blocks);
|
block_buffer_->OffsetIndex(block_buffer_->read, buffer_offset_blocks);
|
||||||
return block_buffer_->buffer[position];
|
return block_buffer_->buffer[position];
|
||||||
|
|||||||
@ -22,7 +22,7 @@ namespace webrtc {
|
|||||||
|
|
||||||
// Verifies the check for non-null fft buffer.
|
// Verifies the check for non-null fft buffer.
|
||||||
TEST(RenderBufferDeathTest, NullExternalFftBuffer) {
|
TEST(RenderBufferDeathTest, NullExternalFftBuffer) {
|
||||||
BlockBuffer block_buffer(10, 3, 1, kBlockSize);
|
BlockBuffer block_buffer(10, 3, 1);
|
||||||
SpectrumBuffer spectrum_buffer(10, 1);
|
SpectrumBuffer spectrum_buffer(10, 1);
|
||||||
EXPECT_DEATH(RenderBuffer(&block_buffer, &spectrum_buffer, nullptr), "");
|
EXPECT_DEATH(RenderBuffer(&block_buffer, &spectrum_buffer, nullptr), "");
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@ TEST(RenderBufferDeathTest, NullExternalFftBuffer) {
|
|||||||
// Verifies the check for non-null spectrum buffer.
|
// Verifies the check for non-null spectrum buffer.
|
||||||
TEST(RenderBufferDeathTest, NullExternalSpectrumBuffer) {
|
TEST(RenderBufferDeathTest, NullExternalSpectrumBuffer) {
|
||||||
FftBuffer fft_buffer(10, 1);
|
FftBuffer fft_buffer(10, 1);
|
||||||
BlockBuffer block_buffer(10, 3, 1, kBlockSize);
|
BlockBuffer block_buffer(10, 3, 1);
|
||||||
EXPECT_DEATH(RenderBuffer(&block_buffer, nullptr, &fft_buffer), "");
|
EXPECT_DEATH(RenderBuffer(&block_buffer, nullptr, &fft_buffer), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -54,8 +54,7 @@ class RenderDelayBufferImpl final : public RenderDelayBuffer {
|
|||||||
~RenderDelayBufferImpl() override;
|
~RenderDelayBufferImpl() override;
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
BufferingEvent Insert(
|
BufferingEvent Insert(const Block& block) override;
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) override;
|
|
||||||
BufferingEvent PrepareCaptureProcessing() override;
|
BufferingEvent PrepareCaptureProcessing() override;
|
||||||
void HandleSkippedCaptureProcessing() override;
|
void HandleSkippedCaptureProcessing() override;
|
||||||
bool AlignFromDelay(size_t delay) override;
|
bool AlignFromDelay(size_t delay) override;
|
||||||
@ -110,8 +109,7 @@ class RenderDelayBufferImpl final : public RenderDelayBuffer {
|
|||||||
int MapDelayToTotalDelay(size_t delay) const;
|
int MapDelayToTotalDelay(size_t delay) const;
|
||||||
int ComputeDelay() const;
|
int ComputeDelay() const;
|
||||||
void ApplyTotalDelay(int delay);
|
void ApplyTotalDelay(int delay);
|
||||||
void InsertBlock(const std::vector<std::vector<std::vector<float>>>& block,
|
void InsertBlock(const Block& block, int previous_write);
|
||||||
int previous_write);
|
|
||||||
bool DetectActiveRender(rtc::ArrayView<const float> x) const;
|
bool DetectActiveRender(rtc::ArrayView<const float> x) const;
|
||||||
bool DetectExcessRenderBlocks();
|
bool DetectExcessRenderBlocks();
|
||||||
void IncrementWriteIndices();
|
void IncrementWriteIndices();
|
||||||
@ -145,8 +143,7 @@ RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
|
|||||||
config.delay.num_filters,
|
config.delay.num_filters,
|
||||||
config.filter.refined.length_blocks),
|
config.filter.refined.length_blocks),
|
||||||
NumBandsForRate(sample_rate_hz),
|
NumBandsForRate(sample_rate_hz),
|
||||||
num_render_channels,
|
num_render_channels),
|
||||||
kBlockSize),
|
|
||||||
spectra_(blocks_.buffer.size(), num_render_channels),
|
spectra_(blocks_.buffer.size(), num_render_channels),
|
||||||
ffts_(blocks_.buffer.size(), num_render_channels),
|
ffts_(blocks_.buffer.size(), num_render_channels),
|
||||||
delay_(config_.delay.default_delay),
|
delay_(config_.delay.default_delay),
|
||||||
@ -161,7 +158,7 @@ RenderDelayBufferImpl::RenderDelayBufferImpl(const EchoCanceller3Config& config,
|
|||||||
RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size());
|
RTC_DCHECK_EQ(blocks_.buffer.size(), ffts_.buffer.size());
|
||||||
RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size());
|
RTC_DCHECK_EQ(spectra_.buffer.size(), ffts_.buffer.size());
|
||||||
for (size_t i = 0; i < blocks_.buffer.size(); ++i) {
|
for (size_t i = 0; i < blocks_.buffer.size(); ++i) {
|
||||||
RTC_DCHECK_EQ(blocks_.buffer[i][0].size(), ffts_.buffer[i].size());
|
RTC_DCHECK_EQ(blocks_.buffer[i].NumChannels(), ffts_.buffer[i].size());
|
||||||
RTC_DCHECK_EQ(spectra_.buffer[i].size(), ffts_.buffer[i].size());
|
RTC_DCHECK_EQ(spectra_.buffer[i].size(), ffts_.buffer[i].size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +208,7 @@ void RenderDelayBufferImpl::Reset() {
|
|||||||
|
|
||||||
// Inserts a new block into the render buffers.
|
// Inserts a new block into the render buffers.
|
||||||
RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert(
|
RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert(
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) {
|
const Block& block) {
|
||||||
++render_call_counter_;
|
++render_call_counter_;
|
||||||
if (delay_) {
|
if (delay_) {
|
||||||
if (!last_call_was_render_) {
|
if (!last_call_was_render_) {
|
||||||
@ -239,7 +236,8 @@ RenderDelayBuffer::BufferingEvent RenderDelayBufferImpl::Insert(
|
|||||||
|
|
||||||
// Detect and update render activity.
|
// Detect and update render activity.
|
||||||
if (!render_activity_) {
|
if (!render_activity_) {
|
||||||
render_activity_counter_ += DetectActiveRender(block[0][0]) ? 1 : 0;
|
render_activity_counter_ +=
|
||||||
|
DetectActiveRender(block.View(/*band=*/0, /*channel=*/0)) ? 1 : 0;
|
||||||
render_activity_ = render_activity_counter_ >= 20;
|
render_activity_ = render_activity_counter_ >= 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,46 +392,45 @@ void RenderDelayBufferImpl::AlignFromExternalDelay() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inserts a block into the render buffers.
|
// Inserts a block into the render buffers.
|
||||||
void RenderDelayBufferImpl::InsertBlock(
|
void RenderDelayBufferImpl::InsertBlock(const Block& block,
|
||||||
const std::vector<std::vector<std::vector<float>>>& block,
|
int previous_write) {
|
||||||
int previous_write) {
|
|
||||||
auto& b = blocks_;
|
auto& b = blocks_;
|
||||||
auto& lr = low_rate_;
|
auto& lr = low_rate_;
|
||||||
auto& ds = render_ds_;
|
auto& ds = render_ds_;
|
||||||
auto& f = ffts_;
|
auto& f = ffts_;
|
||||||
auto& s = spectra_;
|
auto& s = spectra_;
|
||||||
const size_t num_bands = b.buffer[b.write].size();
|
const size_t num_bands = b.buffer[b.write].NumBands();
|
||||||
const size_t num_render_channels = b.buffer[b.write][0].size();
|
const size_t num_render_channels = b.buffer[b.write].NumChannels();
|
||||||
RTC_DCHECK_EQ(block.size(), b.buffer[b.write].size());
|
RTC_DCHECK_EQ(block.NumBands(), num_bands);
|
||||||
|
RTC_DCHECK_EQ(block.NumChannels(), num_render_channels);
|
||||||
for (size_t band = 0; band < num_bands; ++band) {
|
for (size_t band = 0; band < num_bands; ++band) {
|
||||||
RTC_DCHECK_EQ(block[band].size(), num_render_channels);
|
|
||||||
RTC_DCHECK_EQ(b.buffer[b.write][band].size(), num_render_channels);
|
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||||
RTC_DCHECK_EQ(block[band][ch].size(), b.buffer[b.write][band][ch].size());
|
std::copy(block.begin(band, ch), block.end(band, ch),
|
||||||
std::copy(block[band][ch].begin(), block[band][ch].end(),
|
b.buffer[b.write].begin(band, ch));
|
||||||
b.buffer[b.write][band][ch].begin());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (render_linear_amplitude_gain_ != 1.f) {
|
if (render_linear_amplitude_gain_ != 1.f) {
|
||||||
for (size_t band = 0; band < num_bands; ++band) {
|
for (size_t band = 0; band < num_bands; ++band) {
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||||
for (size_t k = 0; k < 64; ++k) {
|
rtc::ArrayView<float, kBlockSize> b_view =
|
||||||
b.buffer[b.write][band][ch][k] *= render_linear_amplitude_gain_;
|
b.buffer[b.write].View(band, ch);
|
||||||
|
for (float& sample : b_view) {
|
||||||
|
sample *= render_linear_amplitude_gain_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<float, kBlockSize> downmixed_render;
|
std::array<float, kBlockSize> downmixed_render;
|
||||||
render_mixer_.ProduceOutput(b.buffer[b.write][0], downmixed_render);
|
render_mixer_.ProduceOutput(b.buffer[b.write], downmixed_render);
|
||||||
render_decimator_.Decimate(downmixed_render, ds);
|
render_decimator_.Decimate(downmixed_render, ds);
|
||||||
data_dumper_->DumpWav("aec3_render_decimator_output", ds.size(), ds.data(),
|
data_dumper_->DumpWav("aec3_render_decimator_output", ds.size(), ds.data(),
|
||||||
16000 / down_sampling_factor_, 1);
|
16000 / down_sampling_factor_, 1);
|
||||||
std::copy(ds.rbegin(), ds.rend(), lr.buffer.begin() + lr.write);
|
std::copy(ds.rbegin(), ds.rend(), lr.buffer.begin() + lr.write);
|
||||||
for (size_t channel = 0; channel < b.buffer[b.write][0].size(); ++channel) {
|
for (int channel = 0; channel < b.buffer[b.write].NumChannels(); ++channel) {
|
||||||
fft_.PaddedFft(b.buffer[b.write][0][channel],
|
fft_.PaddedFft(b.buffer[b.write].View(/*band=*/0, channel),
|
||||||
b.buffer[previous_write][0][channel],
|
b.buffer[previous_write].View(/*band=*/0, channel),
|
||||||
&f.buffer[f.write][channel]);
|
&f.buffer[f.write][channel]);
|
||||||
f.buffer[f.write][channel].Spectrum(optimization_,
|
f.buffer[f.write][channel].Spectrum(optimization_,
|
||||||
s.buffer[s.write][channel]);
|
s.buffer[s.write][channel]);
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "api/audio/echo_canceller3_config.h"
|
#include "api/audio/echo_canceller3_config.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
|
#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
|
||||||
#include "modules/audio_processing/aec3/render_buffer.h"
|
#include "modules/audio_processing/aec3/render_buffer.h"
|
||||||
|
|
||||||
@ -41,8 +42,7 @@ class RenderDelayBuffer {
|
|||||||
virtual void Reset() = 0;
|
virtual void Reset() = 0;
|
||||||
|
|
||||||
// Inserts a block into the buffer.
|
// Inserts a block into the buffer.
|
||||||
virtual BufferingEvent Insert(
|
virtual BufferingEvent Insert(const Block& block) = 0;
|
||||||
const std::vector<std::vector<std::vector<float>>>& block) = 0;
|
|
||||||
|
|
||||||
// Updates the buffers one step based on the specified buffer delay. Returns
|
// Updates the buffers one step based on the specified buffer delay. Returns
|
||||||
// an enum indicating whether there was a special event that occurred.
|
// an enum indicating whether there was a special event that occurred.
|
||||||
|
|||||||
@ -40,10 +40,7 @@ TEST(RenderDelayBuffer, BufferOverflow) {
|
|||||||
SCOPED_TRACE(ProduceDebugText(rate));
|
SCOPED_TRACE(ProduceDebugText(rate));
|
||||||
std::unique_ptr<RenderDelayBuffer> delay_buffer(
|
std::unique_ptr<RenderDelayBuffer> delay_buffer(
|
||||||
RenderDelayBuffer::Create(config, rate, num_channels));
|
RenderDelayBuffer::Create(config, rate, num_channels));
|
||||||
std::vector<std::vector<std::vector<float>>> block_to_insert(
|
Block block_to_insert(NumBandsForRate(rate), num_channels);
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(num_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
for (size_t k = 0; k < 10; ++k) {
|
for (size_t k = 0; k < 10; ++k) {
|
||||||
EXPECT_EQ(RenderDelayBuffer::BufferingEvent::kNone,
|
EXPECT_EQ(RenderDelayBuffer::BufferingEvent::kNone,
|
||||||
delay_buffer->Insert(block_to_insert));
|
delay_buffer->Insert(block_to_insert));
|
||||||
@ -69,9 +66,7 @@ TEST(RenderDelayBuffer, AvailableBlock) {
|
|||||||
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
||||||
std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create(
|
std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create(
|
||||||
EchoCanceller3Config(), kSampleRateHz, kNumChannels));
|
EchoCanceller3Config(), kSampleRateHz, kNumChannels));
|
||||||
std::vector<std::vector<std::vector<float>>> input_block(
|
Block input_block(kNumBands, kNumChannels, 1.0f);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
kNumChannels, std::vector<float>(kBlockSize, 1.f)));
|
|
||||||
EXPECT_EQ(RenderDelayBuffer::BufferingEvent::kNone,
|
EXPECT_EQ(RenderDelayBuffer::BufferingEvent::kNone,
|
||||||
delay_buffer->Insert(input_block));
|
delay_buffer->Insert(input_block));
|
||||||
delay_buffer->PrepareCaptureProcessing();
|
delay_buffer->PrepareCaptureProcessing();
|
||||||
@ -110,10 +105,8 @@ TEST(RenderDelayBufferDeathTest, WrongNumberOfBands) {
|
|||||||
SCOPED_TRACE(ProduceDebugText(rate));
|
SCOPED_TRACE(ProduceDebugText(rate));
|
||||||
std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create(
|
std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create(
|
||||||
EchoCanceller3Config(), rate, num_channels));
|
EchoCanceller3Config(), rate, num_channels));
|
||||||
std::vector<std::vector<std::vector<float>>> block_to_insert(
|
Block block_to_insert(
|
||||||
NumBandsForRate(rate < 48000 ? rate + 16000 : 16000),
|
NumBandsForRate(rate < 48000 ? rate + 16000 : 16000), num_channels);
|
||||||
std::vector<std::vector<float>>(num_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
EXPECT_DEATH(delay_buffer->Insert(block_to_insert), "");
|
EXPECT_DEATH(delay_buffer->Insert(block_to_insert), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,26 +119,7 @@ TEST(RenderDelayBufferDeathTest, WrongNumberOfChannels) {
|
|||||||
SCOPED_TRACE(ProduceDebugText(rate));
|
SCOPED_TRACE(ProduceDebugText(rate));
|
||||||
std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create(
|
std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create(
|
||||||
EchoCanceller3Config(), rate, num_channels));
|
EchoCanceller3Config(), rate, num_channels));
|
||||||
std::vector<std::vector<std::vector<float>>> block_to_insert(
|
Block block_to_insert(NumBandsForRate(rate), num_channels + 1);
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(num_channels + 1,
|
|
||||||
std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
EXPECT_DEATH(delay_buffer->Insert(block_to_insert), "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verifies the check of the length of the inserted blocks.
|
|
||||||
TEST(RenderDelayBufferDeathTest, WrongBlockLength) {
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
|
||||||
for (size_t num_channels : {1, 2, 8}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(rate));
|
|
||||||
std::unique_ptr<RenderDelayBuffer> delay_buffer(RenderDelayBuffer::Create(
|
|
||||||
EchoCanceller3Config(), rate, num_channels));
|
|
||||||
std::vector<std::vector<std::vector<float>>> block_to_insert(
|
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(
|
|
||||||
num_channels, std::vector<float>(kBlockSize - 1, 0.f)));
|
|
||||||
EXPECT_DEATH(delay_buffer->Insert(block_to_insert), "");
|
EXPECT_DEATH(delay_buffer->Insert(block_to_insert), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ class RenderDelayControllerImpl final : public RenderDelayController {
|
|||||||
absl::optional<DelayEstimate> GetDelay(
|
absl::optional<DelayEstimate> GetDelay(
|
||||||
const DownsampledRenderBuffer& render_buffer,
|
const DownsampledRenderBuffer& render_buffer,
|
||||||
size_t render_delay_buffer_delay,
|
size_t render_delay_buffer_delay,
|
||||||
const std::vector<std::vector<float>>& capture) override;
|
const Block& capture) override;
|
||||||
bool HasClockdrift() const override;
|
bool HasClockdrift() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -124,8 +124,7 @@ void RenderDelayControllerImpl::LogRenderCall() {}
|
|||||||
absl::optional<DelayEstimate> RenderDelayControllerImpl::GetDelay(
|
absl::optional<DelayEstimate> RenderDelayControllerImpl::GetDelay(
|
||||||
const DownsampledRenderBuffer& render_buffer,
|
const DownsampledRenderBuffer& render_buffer,
|
||||||
size_t render_delay_buffer_delay,
|
size_t render_delay_buffer_delay,
|
||||||
const std::vector<std::vector<float>>& capture) {
|
const Block& capture) {
|
||||||
RTC_DCHECK_EQ(kBlockSize, capture[0].size());
|
|
||||||
++capture_call_counter_;
|
++capture_call_counter_;
|
||||||
|
|
||||||
auto delay_samples = delay_estimator_.EstimateDelay(render_buffer, capture);
|
auto delay_samples = delay_estimator_.EstimateDelay(render_buffer, capture);
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "api/audio/echo_canceller3_config.h"
|
#include "api/audio/echo_canceller3_config.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
#include "modules/audio_processing/aec3/delay_estimate.h"
|
#include "modules/audio_processing/aec3/delay_estimate.h"
|
||||||
#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
|
#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
|
||||||
#include "modules/audio_processing/aec3/render_delay_buffer.h"
|
#include "modules/audio_processing/aec3/render_delay_buffer.h"
|
||||||
@ -40,7 +41,7 @@ class RenderDelayController {
|
|||||||
virtual absl::optional<DelayEstimate> GetDelay(
|
virtual absl::optional<DelayEstimate> GetDelay(
|
||||||
const DownsampledRenderBuffer& render_buffer,
|
const DownsampledRenderBuffer& render_buffer,
|
||||||
size_t render_delay_buffer_delay,
|
size_t render_delay_buffer_delay,
|
||||||
const std::vector<std::vector<float>>& capture) = 0;
|
const Block& capture) = 0;
|
||||||
|
|
||||||
// Returns true if clockdrift has been detected.
|
// Returns true if clockdrift has been detected.
|
||||||
virtual bool HasClockdrift() const = 0;
|
virtual bool HasClockdrift() const = 0;
|
||||||
|
|||||||
@ -53,8 +53,7 @@ constexpr size_t kDownSamplingFactors[] = {2, 4, 8};
|
|||||||
// TODO(bugs.webrtc.org/11161): Re-enable tests.
|
// TODO(bugs.webrtc.org/11161): Re-enable tests.
|
||||||
TEST(RenderDelayController, DISABLED_NoRenderSignal) {
|
TEST(RenderDelayController, DISABLED_NoRenderSignal) {
|
||||||
for (size_t num_render_channels : {1, 2, 8}) {
|
for (size_t num_render_channels : {1, 2, 8}) {
|
||||||
std::vector<std::vector<float>> block(1,
|
Block block(/*num_bands=1*/ 1, /*num_channels=*/1);
|
||||||
std::vector<float>(kBlockSize, 0.f));
|
|
||||||
EchoCanceller3Config config;
|
EchoCanceller3Config config;
|
||||||
for (size_t num_matched_filters = 4; num_matched_filters <= 10;
|
for (size_t num_matched_filters = 4; num_matched_filters <= 10;
|
||||||
num_matched_filters++) {
|
num_matched_filters++) {
|
||||||
@ -85,8 +84,7 @@ TEST(RenderDelayController, DISABLED_NoRenderSignal) {
|
|||||||
TEST(RenderDelayController, DISABLED_BasicApiCalls) {
|
TEST(RenderDelayController, DISABLED_BasicApiCalls) {
|
||||||
for (size_t num_capture_channels : {1, 2, 4}) {
|
for (size_t num_capture_channels : {1, 2, 4}) {
|
||||||
for (size_t num_render_channels : {1, 2, 8}) {
|
for (size_t num_render_channels : {1, 2, 8}) {
|
||||||
std::vector<std::vector<float>> capture_block(
|
Block capture_block(/*num_bands=*/1, num_capture_channels);
|
||||||
num_capture_channels, std::vector<float>(kBlockSize, 0.f));
|
|
||||||
absl::optional<DelayEstimate> delay_blocks;
|
absl::optional<DelayEstimate> delay_blocks;
|
||||||
for (size_t num_matched_filters = 4; num_matched_filters <= 10;
|
for (size_t num_matched_filters = 4; num_matched_filters <= 10;
|
||||||
num_matched_filters++) {
|
num_matched_filters++) {
|
||||||
@ -98,10 +96,7 @@ TEST(RenderDelayController, DISABLED_BasicApiCalls) {
|
|||||||
config.delay.capture_alignment_mixing.adaptive_selection = false;
|
config.delay.capture_alignment_mixing.adaptive_selection = false;
|
||||||
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
for (auto rate : {16000, 32000, 48000}) {
|
||||||
std::vector<std::vector<std::vector<float>>> render_block(
|
Block render_block(NumBandsForRate(rate), num_render_channels);
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
||||||
RenderDelayBuffer::Create(config, rate, num_render_channels));
|
RenderDelayBuffer::Create(config, rate, num_render_channels));
|
||||||
std::unique_ptr<RenderDelayController> delay_controller(
|
std::unique_ptr<RenderDelayController> delay_controller(
|
||||||
@ -130,8 +125,7 @@ TEST(RenderDelayController, DISABLED_BasicApiCalls) {
|
|||||||
TEST(RenderDelayController, DISABLED_Alignment) {
|
TEST(RenderDelayController, DISABLED_Alignment) {
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
for (size_t num_capture_channels : {1, 2, 4}) {
|
for (size_t num_capture_channels : {1, 2, 4}) {
|
||||||
std::vector<std::vector<float>> capture_block(
|
Block capture_block(/*num_bands=*/1, num_capture_channels);
|
||||||
num_capture_channels, std::vector<float>(kBlockSize, 0.f));
|
|
||||||
for (size_t num_matched_filters = 4; num_matched_filters <= 10;
|
for (size_t num_matched_filters = 4; num_matched_filters <= 10;
|
||||||
num_matched_filters++) {
|
num_matched_filters++) {
|
||||||
for (auto down_sampling_factor : kDownSamplingFactors) {
|
for (auto down_sampling_factor : kDownSamplingFactors) {
|
||||||
@ -143,10 +137,7 @@ TEST(RenderDelayController, DISABLED_Alignment) {
|
|||||||
|
|
||||||
for (size_t num_render_channels : {1, 2, 8}) {
|
for (size_t num_render_channels : {1, 2, 8}) {
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
for (auto rate : {16000, 32000, 48000}) {
|
||||||
std::vector<std::vector<std::vector<float>>> render_block(
|
Block render_block(NumBandsForRate(rate), num_render_channels);
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
|
|
||||||
for (size_t delay_samples : {15, 50, 150, 200, 800, 4000}) {
|
for (size_t delay_samples : {15, 50, 150, 200, 800, 4000}) {
|
||||||
absl::optional<DelayEstimate> delay_blocks;
|
absl::optional<DelayEstimate> delay_blocks;
|
||||||
@ -160,14 +151,16 @@ TEST(RenderDelayController, DISABLED_Alignment) {
|
|||||||
num_capture_channels));
|
num_capture_channels));
|
||||||
DelayBuffer<float> signal_delay_buffer(delay_samples);
|
DelayBuffer<float> signal_delay_buffer(delay_samples);
|
||||||
for (size_t k = 0; k < (400 + delay_samples / kBlockSize); ++k) {
|
for (size_t k = 0; k < (400 + delay_samples / kBlockSize); ++k) {
|
||||||
for (size_t band = 0; band < render_block.size(); ++band) {
|
for (int band = 0; band < render_block.NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < render_block[band].size();
|
for (int channel = 0; channel < render_block.NumChannels();
|
||||||
++channel) {
|
++channel) {
|
||||||
RandomizeSampleVector(&random_generator,
|
RandomizeSampleVector(&random_generator,
|
||||||
render_block[band][channel]);
|
render_block.View(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signal_delay_buffer.Delay(render_block[0][0], capture_block[0]);
|
signal_delay_buffer.Delay(
|
||||||
|
render_block.View(/*band=*/0, /*channel=*/0),
|
||||||
|
capture_block.View(/*band=*/0, /*channel=*/0));
|
||||||
render_delay_buffer->Insert(render_block);
|
render_delay_buffer->Insert(render_block);
|
||||||
render_delay_buffer->PrepareCaptureProcessing();
|
render_delay_buffer->PrepareCaptureProcessing();
|
||||||
delay_blocks = delay_controller->GetDelay(
|
delay_blocks = delay_controller->GetDelay(
|
||||||
@ -206,14 +199,8 @@ TEST(RenderDelayController, DISABLED_NonCausalAlignment) {
|
|||||||
config.delay.capture_alignment_mixing.downmix = false;
|
config.delay.capture_alignment_mixing.downmix = false;
|
||||||
config.delay.capture_alignment_mixing.adaptive_selection = false;
|
config.delay.capture_alignment_mixing.adaptive_selection = false;
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
for (auto rate : {16000, 32000, 48000}) {
|
||||||
std::vector<std::vector<std::vector<float>>> render_block(
|
Block render_block(NumBandsForRate(rate), num_render_channels);
|
||||||
NumBandsForRate(rate),
|
Block capture_block(NumBandsForRate(rate), num_capture_channels);
|
||||||
std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> capture_block(
|
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(
|
|
||||||
num_capture_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
|
|
||||||
for (int delay_samples : {-15, -50, -150, -200}) {
|
for (int delay_samples : {-15, -50, -150, -200}) {
|
||||||
absl::optional<DelayEstimate> delay_blocks;
|
absl::optional<DelayEstimate> delay_blocks;
|
||||||
@ -229,14 +216,17 @@ TEST(RenderDelayController, DISABLED_NonCausalAlignment) {
|
|||||||
for (int k = 0;
|
for (int k = 0;
|
||||||
k < (400 - delay_samples / static_cast<int>(kBlockSize));
|
k < (400 - delay_samples / static_cast<int>(kBlockSize));
|
||||||
++k) {
|
++k) {
|
||||||
RandomizeSampleVector(&random_generator, capture_block[0][0]);
|
RandomizeSampleVector(
|
||||||
signal_delay_buffer.Delay(capture_block[0][0],
|
&random_generator,
|
||||||
render_block[0][0]);
|
capture_block.View(/*band=*/0, /*channel=*/0));
|
||||||
|
signal_delay_buffer.Delay(
|
||||||
|
capture_block.View(/*band=*/0, /*channel=*/0),
|
||||||
|
render_block.View(/*band=*/0, /*channel=*/0));
|
||||||
render_delay_buffer->Insert(render_block);
|
render_delay_buffer->Insert(render_block);
|
||||||
render_delay_buffer->PrepareCaptureProcessing();
|
render_delay_buffer->PrepareCaptureProcessing();
|
||||||
delay_blocks = delay_controller->GetDelay(
|
delay_blocks = delay_controller->GetDelay(
|
||||||
render_delay_buffer->GetDownsampledRenderBuffer(),
|
render_delay_buffer->GetDownsampledRenderBuffer(),
|
||||||
render_delay_buffer->Delay(), capture_block[0]);
|
render_delay_buffer->Delay(), capture_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_FALSE(delay_blocks);
|
ASSERT_FALSE(delay_blocks);
|
||||||
@ -255,8 +245,8 @@ TEST(RenderDelayController, DISABLED_AlignmentWithJitter) {
|
|||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
for (size_t num_capture_channels : {1, 2, 4}) {
|
for (size_t num_capture_channels : {1, 2, 4}) {
|
||||||
for (size_t num_render_channels : {1, 2, 8}) {
|
for (size_t num_render_channels : {1, 2, 8}) {
|
||||||
std::vector<std::vector<float>> capture_block(
|
Block capture_block(
|
||||||
num_capture_channels, std::vector<float>(kBlockSize, 0.f));
|
/*num_bands=*/1, num_capture_channels);
|
||||||
for (size_t num_matched_filters = 4; num_matched_filters <= 10;
|
for (size_t num_matched_filters = 4; num_matched_filters <= 10;
|
||||||
num_matched_filters++) {
|
num_matched_filters++) {
|
||||||
for (auto down_sampling_factor : kDownSamplingFactors) {
|
for (auto down_sampling_factor : kDownSamplingFactors) {
|
||||||
@ -267,10 +257,7 @@ TEST(RenderDelayController, DISABLED_AlignmentWithJitter) {
|
|||||||
config.delay.capture_alignment_mixing.adaptive_selection = false;
|
config.delay.capture_alignment_mixing.adaptive_selection = false;
|
||||||
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
for (auto rate : {16000, 32000, 48000}) {
|
||||||
std::vector<std::vector<std::vector<float>>> render_block(
|
Block render_block(NumBandsForRate(rate), num_render_channels);
|
||||||
NumBandsForRate(rate),
|
|
||||||
std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
for (size_t delay_samples : {15, 50, 300, 800}) {
|
for (size_t delay_samples : {15, 50, 300, 800}) {
|
||||||
absl::optional<DelayEstimate> delay_blocks;
|
absl::optional<DelayEstimate> delay_blocks;
|
||||||
SCOPED_TRACE(ProduceDebugText(rate, delay_samples,
|
SCOPED_TRACE(ProduceDebugText(rate, delay_samples,
|
||||||
@ -287,12 +274,14 @@ TEST(RenderDelayController, DISABLED_AlignmentWithJitter) {
|
|||||||
kMaxTestJitterBlocks +
|
kMaxTestJitterBlocks +
|
||||||
1;
|
1;
|
||||||
++j) {
|
++j) {
|
||||||
std::vector<std::vector<std::vector<float>>>
|
std::vector<Block> capture_block_buffer;
|
||||||
capture_block_buffer;
|
|
||||||
for (size_t k = 0; k < (kMaxTestJitterBlocks - 1); ++k) {
|
for (size_t k = 0; k < (kMaxTestJitterBlocks - 1); ++k) {
|
||||||
RandomizeSampleVector(&random_generator, render_block[0][0]);
|
RandomizeSampleVector(
|
||||||
signal_delay_buffer.Delay(render_block[0][0],
|
&random_generator,
|
||||||
capture_block[0]);
|
render_block.View(/*band=*/0, /*channel=*/0));
|
||||||
|
signal_delay_buffer.Delay(
|
||||||
|
render_block.View(/*band=*/0, /*channel=*/0),
|
||||||
|
capture_block.View(/*band=*/0, /*channel=*/0));
|
||||||
capture_block_buffer.push_back(capture_block);
|
capture_block_buffer.push_back(capture_block);
|
||||||
render_delay_buffer->Insert(render_block);
|
render_delay_buffer->Insert(render_block);
|
||||||
}
|
}
|
||||||
@ -324,24 +313,6 @@ TEST(RenderDelayController, DISABLED_AlignmentWithJitter) {
|
|||||||
|
|
||||||
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||||
|
|
||||||
// Verifies the check for the capture signal block size.
|
|
||||||
TEST(RenderDelayControllerDeathTest, WrongCaptureSize) {
|
|
||||||
std::vector<std::vector<float>> block(
|
|
||||||
1, std::vector<float>(kBlockSize - 1, 0.f));
|
|
||||||
EchoCanceller3Config config;
|
|
||||||
for (auto rate : {16000, 32000, 48000}) {
|
|
||||||
SCOPED_TRACE(ProduceDebugText(rate));
|
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
|
||||||
RenderDelayBuffer::Create(config, rate, 1));
|
|
||||||
EXPECT_DEATH(
|
|
||||||
std::unique_ptr<RenderDelayController>(
|
|
||||||
RenderDelayController::Create(EchoCanceller3Config(), rate, 1))
|
|
||||||
->GetDelay(render_delay_buffer->GetDownsampledRenderBuffer(),
|
|
||||||
render_delay_buffer->Delay(), block),
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verifies the check for correct sample rate.
|
// Verifies the check for correct sample rate.
|
||||||
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
|
// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
|
||||||
// tests on test bots has been fixed.
|
// tests on test bots has been fixed.
|
||||||
|
|||||||
@ -66,10 +66,9 @@ void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer,
|
|||||||
*narrow_peak_band = absl::nullopt;
|
*narrow_peak_band = absl::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::vector<std::vector<float>>>& x_latest =
|
const Block& x_latest = render_buffer.Block(0);
|
||||||
render_buffer.Block(0);
|
|
||||||
float max_peak_level = 0.f;
|
float max_peak_level = 0.f;
|
||||||
for (size_t channel = 0; channel < x_latest[0].size(); ++channel) {
|
for (int channel = 0; channel < x_latest.NumChannels(); ++channel) {
|
||||||
rtc::ArrayView<const float, kFftLengthBy2Plus1> X2_latest =
|
rtc::ArrayView<const float, kFftLengthBy2Plus1> X2_latest =
|
||||||
render_buffer.Spectrum(0)[channel];
|
render_buffer.Spectrum(0)[channel];
|
||||||
|
|
||||||
@ -90,13 +89,14 @@ void IdentifyStrongNarrowBandComponent(const RenderBuffer& render_buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assess the render signal strength.
|
// Assess the render signal strength.
|
||||||
auto result0 = std::minmax_element(x_latest[0][channel].begin(),
|
auto result0 = std::minmax_element(x_latest.begin(/*band=*/0, channel),
|
||||||
x_latest[0][channel].end());
|
x_latest.end(/*band=*/0, channel));
|
||||||
float max_abs = std::max(fabs(*result0.first), fabs(*result0.second));
|
float max_abs = std::max(fabs(*result0.first), fabs(*result0.second));
|
||||||
|
|
||||||
if (x_latest.size() > 1) {
|
if (x_latest.NumBands() > 1) {
|
||||||
const auto result1 = std::minmax_element(x_latest[1][channel].begin(),
|
const auto result1 =
|
||||||
x_latest[1][channel].end());
|
std::minmax_element(x_latest.begin(/*band=*/1, channel),
|
||||||
|
x_latest.end(/*band=*/1, channel));
|
||||||
max_abs =
|
max_abs =
|
||||||
std::max(max_abs, static_cast<float>(std::max(
|
std::max(max_abs, static_cast<float>(std::max(
|
||||||
fabs(*result1.first), fabs(*result1.second))));
|
fabs(*result1.first), fabs(*result1.second))));
|
||||||
|
|||||||
@ -36,18 +36,18 @@ void ProduceSinusoidInNoise(int sample_rate_hz,
|
|||||||
float sinusoidal_frequency_hz,
|
float sinusoidal_frequency_hz,
|
||||||
Random* random_generator,
|
Random* random_generator,
|
||||||
size_t* sample_counter,
|
size_t* sample_counter,
|
||||||
std::vector<std::vector<std::vector<float>>>* x) {
|
Block* x) {
|
||||||
// Fill x with low-amplitude noise.
|
// Fill x with low-amplitude noise.
|
||||||
for (auto& band : *x) {
|
for (int band = 0; band < x->NumBands(); ++band) {
|
||||||
for (auto& channel : band) {
|
for (int channel = 0; channel < x->NumChannels(); ++channel) {
|
||||||
RandomizeSampleVector(random_generator, channel,
|
RandomizeSampleVector(random_generator, x->View(band, channel),
|
||||||
/*amplitude=*/500.f);
|
/*amplitude=*/500.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Produce a sinusoid of the specified frequency in the specified channel.
|
// Produce a sinusoid of the specified frequency in the specified channel.
|
||||||
for (size_t k = *sample_counter, j = 0; k < (*sample_counter + kBlockSize);
|
for (size_t k = *sample_counter, j = 0; k < (*sample_counter + kBlockSize);
|
||||||
++k, ++j) {
|
++k, ++j) {
|
||||||
(*x)[0][sinusoid_channel][j] +=
|
x->View(/*band=*/0, sinusoid_channel)[j] +=
|
||||||
32000.f *
|
32000.f *
|
||||||
std::sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz);
|
std::sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz);
|
||||||
}
|
}
|
||||||
@ -59,9 +59,7 @@ void RunNarrowBandDetectionTest(size_t num_channels) {
|
|||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
constexpr int kSampleRateHz = 48000;
|
constexpr int kSampleRateHz = 48000;
|
||||||
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_channels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
num_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::array<float, kBlockSize> x_old;
|
std::array<float, kBlockSize> x_old;
|
||||||
Aec3Fft fft;
|
Aec3Fft fft;
|
||||||
EchoCanceller3Config config;
|
EchoCanceller3Config config;
|
||||||
@ -130,19 +128,17 @@ TEST(RenderSignalAnalyzer, NoFalseDetectionOfNarrowBands) {
|
|||||||
SCOPED_TRACE(ProduceDebugText(num_channels));
|
SCOPED_TRACE(ProduceDebugText(num_channels));
|
||||||
RenderSignalAnalyzer analyzer(EchoCanceller3Config{});
|
RenderSignalAnalyzer analyzer(EchoCanceller3Config{});
|
||||||
Random random_generator(42U);
|
Random random_generator(42U);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(3, num_channels);
|
||||||
3, std::vector<std::vector<float>>(
|
|
||||||
num_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::array<float, kBlockSize> x_old;
|
std::array<float, kBlockSize> x_old;
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
||||||
RenderDelayBuffer::Create(EchoCanceller3Config(), 48000, num_channels));
|
RenderDelayBuffer::Create(EchoCanceller3Config(), 48000, num_channels));
|
||||||
std::array<float, kFftLengthBy2Plus1> mask;
|
std::array<float, kFftLengthBy2Plus1> mask;
|
||||||
x_old.fill(0.f);
|
x_old.fill(0.f);
|
||||||
|
|
||||||
for (size_t k = 0; k < 100; ++k) {
|
for (int k = 0; k < 100; ++k) {
|
||||||
for (auto& band : x) {
|
for (int band = 0; band < x.NumBands(); ++band) {
|
||||||
for (auto& channel : band) {
|
for (int channel = 0; channel < x.NumChannels(); ++channel) {
|
||||||
RandomizeSampleVector(&random_generator, channel);
|
RandomizeSampleVector(&random_generator, x.View(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -47,10 +47,7 @@ class ResidualEchoEstimatorTest {
|
|||||||
Y2_(num_capture_channels_),
|
Y2_(num_capture_channels_),
|
||||||
R2_(num_capture_channels_),
|
R2_(num_capture_channels_),
|
||||||
R2_unbounded_(num_capture_channels_),
|
R2_unbounded_(num_capture_channels_),
|
||||||
x_(kNumBands,
|
x_(kNumBands, num_render_channels_),
|
||||||
std::vector<std::vector<float>>(
|
|
||||||
num_render_channels_,
|
|
||||||
std::vector<float>(kBlockSize, 0.0f))),
|
|
||||||
H2_(num_capture_channels_,
|
H2_(num_capture_channels_,
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>>(10)),
|
std::vector<std::array<float, kFftLengthBy2Plus1>>(10)),
|
||||||
h_(num_capture_channels_,
|
h_(num_capture_channels_,
|
||||||
@ -84,7 +81,8 @@ class ResidualEchoEstimatorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RunOneFrame(bool dominant_nearend) {
|
void RunOneFrame(bool dominant_nearend) {
|
||||||
RandomizeSampleVector(&random_generator_, x_[0][0]);
|
RandomizeSampleVector(&random_generator_,
|
||||||
|
x_.View(/*band=*/0, /*channel=*/0));
|
||||||
render_delay_buffer_->Insert(x_);
|
render_delay_buffer_->Insert(x_);
|
||||||
if (first_frame_) {
|
if (first_frame_) {
|
||||||
render_delay_buffer_->Reset();
|
render_delay_buffer_->Reset();
|
||||||
@ -116,7 +114,7 @@ class ResidualEchoEstimatorTest {
|
|||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2_;
|
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2_;
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> R2_;
|
std::vector<std::array<float, kFftLengthBy2Plus1>> R2_;
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> R2_unbounded_;
|
std::vector<std::array<float, kFftLengthBy2Plus1>> R2_unbounded_;
|
||||||
std::vector<std::vector<std::vector<float>>> x_;
|
Block x_;
|
||||||
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> H2_;
|
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> H2_;
|
||||||
std::vector<std::vector<float>> h_;
|
std::vector<std::vector<float>> h_;
|
||||||
Random random_generator_;
|
Random random_generator_;
|
||||||
|
|||||||
@ -24,7 +24,7 @@ namespace webrtc {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void GetActiveFrame(std::vector<std::vector<std::vector<float>>>* x) {
|
void GetActiveFrame(Block* x) {
|
||||||
const std::array<float, kBlockSize> frame = {
|
const std::array<float, kBlockSize> frame = {
|
||||||
7459.88, 17209.6, 17383, 20768.9, 16816.7, 18386.3, 4492.83, 9675.85,
|
7459.88, 17209.6, 17383, 20768.9, 16816.7, 18386.3, 4492.83, 9675.85,
|
||||||
6665.52, 14808.6, 9342.3, 7483.28, 19261.7, 4145.98, 1622.18, 13475.2,
|
6665.52, 14808.6, 9342.3, 7483.28, 19261.7, 4145.98, 1622.18, 13475.2,
|
||||||
@ -34,10 +34,10 @@ void GetActiveFrame(std::vector<std::vector<std::vector<float>>>* x) {
|
|||||||
11405, 15031.4, 14541.6, 19765.5, 18346.3, 19350.2, 3157.47, 18095.8,
|
11405, 15031.4, 14541.6, 19765.5, 18346.3, 19350.2, 3157.47, 18095.8,
|
||||||
1743.68, 21328.2, 19727.5, 7295.16, 10332.4, 11055.5, 20107.4, 14708.4,
|
1743.68, 21328.2, 19727.5, 7295.16, 10332.4, 11055.5, 20107.4, 14708.4,
|
||||||
12416.2, 16434, 2454.69, 9840.8, 6867.23, 1615.75, 6059.9, 8394.19};
|
12416.2, 16434, 2454.69, 9840.8, 6867.23, 1615.75, 6059.9, 8394.19};
|
||||||
for (size_t band = 0; band < x->size(); ++band) {
|
for (int band = 0; band < x->NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < (*x)[band].size(); ++channel) {
|
for (int channel = 0; channel < x->NumChannels(); ++channel) {
|
||||||
RTC_DCHECK_GE((*x)[band][channel].size(), frame.size());
|
RTC_DCHECK_GE(kBlockSize, frame.size());
|
||||||
std::copy(frame.begin(), frame.end(), (*x)[band][channel].begin());
|
std::copy(frame.begin(), frame.end(), x->begin(band, channel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ class TestInputs {
|
|||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2_;
|
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2_;
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> E2_;
|
std::vector<std::array<float, kFftLengthBy2Plus1>> E2_;
|
||||||
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> H2_;
|
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> H2_;
|
||||||
std::vector<std::vector<std::vector<float>>> x_;
|
Block x_;
|
||||||
std::vector<bool> converged_filters_;
|
std::vector<bool> converged_filters_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -88,9 +88,7 @@ TestInputs::TestInputs(const EchoCanceller3Config& cfg,
|
|||||||
H2_(num_capture_channels,
|
H2_(num_capture_channels,
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>>(
|
std::vector<std::array<float, kFftLengthBy2Plus1>>(
|
||||||
cfg.filter.refined.length_blocks)),
|
cfg.filter.refined.length_blocks)),
|
||||||
x_(1,
|
x_(1, num_render_channels),
|
||||||
std::vector<std::vector<float>>(num_render_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f))),
|
|
||||||
converged_filters_(num_capture_channels, true) {
|
converged_filters_(num_capture_channels, true) {
|
||||||
render_delay_buffer_->AlignFromDelay(4);
|
render_delay_buffer_->AlignFromDelay(4);
|
||||||
render_buffer_ = render_delay_buffer_->GetRenderBuffer();
|
render_buffer_ = render_delay_buffer_->GetRenderBuffer();
|
||||||
@ -108,7 +106,8 @@ TestInputs::~TestInputs() = default;
|
|||||||
|
|
||||||
void TestInputs::Update() {
|
void TestInputs::Update() {
|
||||||
if (n_ % 2 == 0) {
|
if (n_ % 2 == 0) {
|
||||||
std::fill(x_[0][0].begin(), x_[0][0].end(), 0.f);
|
std::fill(x_.begin(/*band=*/0, /*channel=*/0),
|
||||||
|
x_.end(/*band=*/0, /*channel=*/0), 0.f);
|
||||||
} else {
|
} else {
|
||||||
GetActiveFrame(&x_);
|
GetActiveFrame(&x_);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,11 +176,11 @@ void Subtractor::ExitInitialState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Subtractor::Process(const RenderBuffer& render_buffer,
|
void Subtractor::Process(const RenderBuffer& render_buffer,
|
||||||
const std::vector<std::vector<float>>& capture,
|
const Block& capture,
|
||||||
const RenderSignalAnalyzer& render_signal_analyzer,
|
const RenderSignalAnalyzer& render_signal_analyzer,
|
||||||
const AecState& aec_state,
|
const AecState& aec_state,
|
||||||
rtc::ArrayView<SubtractorOutput> outputs) {
|
rtc::ArrayView<SubtractorOutput> outputs) {
|
||||||
RTC_DCHECK_EQ(num_capture_channels_, capture.size());
|
RTC_DCHECK_EQ(num_capture_channels_, capture.NumChannels());
|
||||||
|
|
||||||
// Compute the render powers.
|
// Compute the render powers.
|
||||||
const bool same_filter_sizes = refined_filters_[0]->SizePartitions() ==
|
const bool same_filter_sizes = refined_filters_[0]->SizePartitions() ==
|
||||||
@ -204,9 +204,8 @@ void Subtractor::Process(const RenderBuffer& render_buffer,
|
|||||||
|
|
||||||
// Process all capture channels
|
// Process all capture channels
|
||||||
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
|
for (size_t ch = 0; ch < num_capture_channels_; ++ch) {
|
||||||
RTC_DCHECK_EQ(kBlockSize, capture[ch].size());
|
|
||||||
SubtractorOutput& output = outputs[ch];
|
SubtractorOutput& output = outputs[ch];
|
||||||
rtc::ArrayView<const float> y = capture[ch];
|
rtc::ArrayView<const float> y = capture.View(/*band=*/0, ch);
|
||||||
FftData& E_refined = output.E_refined;
|
FftData& E_refined = output.E_refined;
|
||||||
FftData E_coarse;
|
FftData E_coarse;
|
||||||
std::array<float, kBlockSize>& e_refined = output.e_refined;
|
std::array<float, kBlockSize>& e_refined = output.e_refined;
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||||
#include "modules/audio_processing/aec3/aec3_fft.h"
|
#include "modules/audio_processing/aec3/aec3_fft.h"
|
||||||
#include "modules/audio_processing/aec3/aec_state.h"
|
#include "modules/audio_processing/aec3/aec_state.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
#include "modules/audio_processing/aec3/coarse_filter_update_gain.h"
|
#include "modules/audio_processing/aec3/coarse_filter_update_gain.h"
|
||||||
#include "modules/audio_processing/aec3/echo_path_variability.h"
|
#include "modules/audio_processing/aec3/echo_path_variability.h"
|
||||||
#include "modules/audio_processing/aec3/refined_filter_update_gain.h"
|
#include "modules/audio_processing/aec3/refined_filter_update_gain.h"
|
||||||
@ -48,7 +49,7 @@ class Subtractor {
|
|||||||
|
|
||||||
// Performs the echo subtraction.
|
// Performs the echo subtraction.
|
||||||
void Process(const RenderBuffer& render_buffer,
|
void Process(const RenderBuffer& render_buffer,
|
||||||
const std::vector<std::vector<float>>& capture,
|
const Block& capture,
|
||||||
const RenderSignalAnalyzer& render_signal_analyzer,
|
const RenderSignalAnalyzer& render_signal_analyzer,
|
||||||
const AecState& aec_state,
|
const AecState& aec_state,
|
||||||
rtc::ArrayView<SubtractorOutput> outputs);
|
rtc::ArrayView<SubtractorOutput> outputs);
|
||||||
|
|||||||
@ -45,11 +45,8 @@ std::vector<float> RunSubtractorTest(
|
|||||||
Subtractor subtractor(config, num_render_channels, num_capture_channels,
|
Subtractor subtractor(config, num_render_channels, num_capture_channels,
|
||||||
&data_dumper, DetectOptimization());
|
&data_dumper, DetectOptimization());
|
||||||
absl::optional<DelayEstimate> delay_estimate;
|
absl::optional<DelayEstimate> delay_estimate;
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, num_render_channels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
Block y(/*num_bands=*/1, num_capture_channels);
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<float>> y(num_capture_channels,
|
|
||||||
std::vector<float>(kBlockSize, 0.f));
|
|
||||||
std::array<float, kBlockSize> x_old;
|
std::array<float, kBlockSize> x_old;
|
||||||
std::vector<SubtractorOutput> output(num_capture_channels);
|
std::vector<SubtractorOutput> output(num_capture_channels);
|
||||||
config.delay.default_delay = 1;
|
config.delay.default_delay = 1;
|
||||||
@ -101,32 +98,34 @@ std::vector<float> RunSubtractorTest(
|
|||||||
|
|
||||||
for (int k = 0; k < num_blocks_to_process; ++k) {
|
for (int k = 0; k < num_blocks_to_process; ++k) {
|
||||||
for (size_t render_ch = 0; render_ch < num_render_channels; ++render_ch) {
|
for (size_t render_ch = 0; render_ch < num_render_channels; ++render_ch) {
|
||||||
RandomizeSampleVector(&random_generator, x[0][render_ch]);
|
RandomizeSampleVector(&random_generator, x.View(/*band=*/0, render_ch));
|
||||||
}
|
}
|
||||||
if (uncorrelated_inputs) {
|
if (uncorrelated_inputs) {
|
||||||
for (size_t capture_ch = 0; capture_ch < num_capture_channels;
|
for (size_t capture_ch = 0; capture_ch < num_capture_channels;
|
||||||
++capture_ch) {
|
++capture_ch) {
|
||||||
RandomizeSampleVector(&random_generator, y[capture_ch]);
|
RandomizeSampleVector(&random_generator,
|
||||||
|
y.View(/*band=*/0, capture_ch));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (size_t capture_ch = 0; capture_ch < num_capture_channels;
|
for (size_t capture_ch = 0; capture_ch < num_capture_channels;
|
||||||
++capture_ch) {
|
++capture_ch) {
|
||||||
|
rtc::ArrayView<float> y_view = y.View(/*band=*/0, capture_ch);
|
||||||
for (size_t render_ch = 0; render_ch < num_render_channels;
|
for (size_t render_ch = 0; render_ch < num_render_channels;
|
||||||
++render_ch) {
|
++render_ch) {
|
||||||
std::array<float, kBlockSize> y_channel;
|
std::array<float, kBlockSize> y_channel;
|
||||||
delay_buffer[capture_ch][render_ch]->Delay(x[0][render_ch],
|
delay_buffer[capture_ch][render_ch]->Delay(
|
||||||
y_channel);
|
x.View(/*band=*/0, render_ch), y_channel);
|
||||||
for (size_t k = 0; k < y.size(); ++k) {
|
for (size_t k = 0; k < kBlockSize; ++k) {
|
||||||
y[capture_ch][k] += y_channel[k] / num_render_channels;
|
y_view[k] += y_channel[k] / num_render_channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||||
x_hp_filter[ch]->Process(x[0][ch]);
|
x_hp_filter[ch]->Process(x.View(/*band=*/0, ch));
|
||||||
}
|
}
|
||||||
for (size_t ch = 0; ch < num_capture_channels; ++ch) {
|
for (size_t ch = 0; ch < num_capture_channels; ++ch) {
|
||||||
y_hp_filter[ch]->Process(y[ch]);
|
y_hp_filter[ch]->Process(y.View(/*band=*/0, ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
render_delay_buffer->Insert(x);
|
render_delay_buffer->Insert(x);
|
||||||
@ -162,7 +161,8 @@ std::vector<float> RunSubtractorTest(
|
|||||||
output[ch].e_refined.begin(), output[ch].e_refined.end(),
|
output[ch].e_refined.begin(), output[ch].e_refined.end(),
|
||||||
output[ch].e_refined.begin(), 0.f);
|
output[ch].e_refined.begin(), 0.f);
|
||||||
const float y_power =
|
const float y_power =
|
||||||
std::inner_product(y[ch].begin(), y[ch].end(), y[ch].begin(), 0.f);
|
std::inner_product(y.begin(/*band=*/0, ch), y.end(/*band=*/0, ch),
|
||||||
|
y.begin(/*band=*/0, ch), 0.f);
|
||||||
if (y_power == 0.f) {
|
if (y_power == 0.f) {
|
||||||
ADD_FAILURE();
|
ADD_FAILURE();
|
||||||
results[ch] = -1.f;
|
results[ch] = -1.f;
|
||||||
@ -195,23 +195,6 @@ TEST(SubtractorDeathTest, NullDataDumper) {
|
|||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies the check for the capture signal size.
|
|
||||||
TEST(Subtractor, WrongCaptureSize) {
|
|
||||||
ApmDataDumper data_dumper(42);
|
|
||||||
EchoCanceller3Config config;
|
|
||||||
Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization());
|
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
|
||||||
RenderDelayBuffer::Create(config, 48000, 1));
|
|
||||||
RenderSignalAnalyzer render_signal_analyzer(config);
|
|
||||||
std::vector<std::vector<float>> y(1, std::vector<float>(kBlockSize - 1, 0.f));
|
|
||||||
std::array<SubtractorOutput, 1> output;
|
|
||||||
|
|
||||||
EXPECT_DEATH(
|
|
||||||
subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
|
|
||||||
render_signal_analyzer, AecState(config, 1), output),
|
|
||||||
"");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Verifies that the subtractor is able to converge on correlated data.
|
// Verifies that the subtractor is able to converge on correlated data.
|
||||||
|
|||||||
@ -86,9 +86,9 @@ void SuppressionFilter::ApplyGain(
|
|||||||
const std::array<float, kFftLengthBy2Plus1>& suppression_gain,
|
const std::array<float, kFftLengthBy2Plus1>& suppression_gain,
|
||||||
float high_bands_gain,
|
float high_bands_gain,
|
||||||
rtc::ArrayView<const FftData> E_lowest_band,
|
rtc::ArrayView<const FftData> E_lowest_band,
|
||||||
std::vector<std::vector<std::vector<float>>>* e) {
|
Block* e) {
|
||||||
RTC_DCHECK(e);
|
RTC_DCHECK(e);
|
||||||
RTC_DCHECK_EQ(e->size(), NumBandsForRate(sample_rate_hz_));
|
RTC_DCHECK_EQ(e->NumBands(), NumBandsForRate(sample_rate_hz_));
|
||||||
|
|
||||||
// Comfort noise gain is sqrt(1-g^2), where g is the suppression gain.
|
// Comfort noise gain is sqrt(1-g^2), where g is the suppression gain.
|
||||||
std::array<float, kFftLengthBy2Plus1> noise_gain;
|
std::array<float, kFftLengthBy2Plus1> noise_gain;
|
||||||
@ -121,7 +121,7 @@ void SuppressionFilter::ApplyGain(
|
|||||||
constexpr float kIfftNormalization = 2.f / kFftLength;
|
constexpr float kIfftNormalization = 2.f / kFftLength;
|
||||||
fft_.Ifft(E, &e_extended);
|
fft_.Ifft(E, &e_extended);
|
||||||
|
|
||||||
float* e0 = (*e)[0][ch].data();
|
auto e0 = e->View(/*band=*/0, ch);
|
||||||
float* e0_old = e_output_old_[0][ch].data();
|
float* e0_old = e_output_old_[0][ch].data();
|
||||||
|
|
||||||
// Window and add the first half of e_extended with the second half of
|
// Window and add the first half of e_extended with the second half of
|
||||||
@ -138,20 +138,20 @@ void SuppressionFilter::ApplyGain(
|
|||||||
std::begin(e_output_old_[0][ch]));
|
std::begin(e_output_old_[0][ch]));
|
||||||
|
|
||||||
// Apply suppression gain to upper bands.
|
// Apply suppression gain to upper bands.
|
||||||
for (size_t b = 1; b < e->size(); ++b) {
|
for (int b = 1; b < e->NumBands(); ++b) {
|
||||||
float* e_band = (*e)[b][ch].data();
|
auto e_band = e->View(b, ch);
|
||||||
for (size_t i = 0; i < kFftLengthBy2; ++i) {
|
for (size_t i = 0; i < kFftLengthBy2; ++i) {
|
||||||
e_band[i] *= high_bands_gain;
|
e_band[i] *= high_bands_gain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add comfort noise to band 1.
|
// Add comfort noise to band 1.
|
||||||
if (e->size() > 1) {
|
if (e->NumBands() > 1) {
|
||||||
E.Assign(comfort_noise_high_band[ch]);
|
E.Assign(comfort_noise_high_band[ch]);
|
||||||
std::array<float, kFftLength> time_domain_high_band_noise;
|
std::array<float, kFftLength> time_domain_high_band_noise;
|
||||||
fft_.Ifft(E, &time_domain_high_band_noise);
|
fft_.Ifft(E, &time_domain_high_band_noise);
|
||||||
|
|
||||||
float* e1 = (*e)[1][ch].data();
|
auto e1 = e->View(/*band=*/1, ch);
|
||||||
const float gain = high_bands_noise_scaling * kIfftNormalization;
|
const float gain = high_bands_noise_scaling * kIfftNormalization;
|
||||||
for (size_t i = 0; i < kFftLengthBy2; ++i) {
|
for (size_t i = 0; i < kFftLengthBy2; ++i) {
|
||||||
e1[i] += time_domain_high_band_noise[i] * gain;
|
e1[i] += time_domain_high_band_noise[i] * gain;
|
||||||
@ -159,8 +159,8 @@ void SuppressionFilter::ApplyGain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delay upper bands to match the delay of the filter bank.
|
// Delay upper bands to match the delay of the filter bank.
|
||||||
for (size_t b = 1; b < e->size(); ++b) {
|
for (int b = 1; b < e->NumBands(); ++b) {
|
||||||
float* e_band = (*e)[b][ch].data();
|
auto e_band = e->View(b, ch);
|
||||||
float* e_band_old = e_output_old_[b][ch].data();
|
float* e_band_old = e_output_old_[b][ch].data();
|
||||||
for (size_t i = 0; i < kFftLengthBy2; ++i) {
|
for (size_t i = 0; i < kFftLengthBy2; ++i) {
|
||||||
std::swap(e_band[i], e_band_old[i]);
|
std::swap(e_band[i], e_band_old[i]);
|
||||||
@ -168,8 +168,8 @@ void SuppressionFilter::ApplyGain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clamp output of all bands.
|
// Clamp output of all bands.
|
||||||
for (size_t b = 0; b < e->size(); ++b) {
|
for (int b = 0; b < e->NumBands(); ++b) {
|
||||||
float* e_band = (*e)[b][ch].data();
|
auto e_band = e->View(b, ch);
|
||||||
for (size_t i = 0; i < kFftLengthBy2; ++i) {
|
for (size_t i = 0; i < kFftLengthBy2; ++i) {
|
||||||
e_band[i] = rtc::SafeClamp(e_band[i], -32768.f, 32767.f);
|
e_band[i] = rtc::SafeClamp(e_band[i], -32768.f, 32767.f);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||||
#include "modules/audio_processing/aec3/aec3_fft.h"
|
#include "modules/audio_processing/aec3/aec3_fft.h"
|
||||||
|
#include "modules/audio_processing/aec3/block.h"
|
||||||
#include "modules/audio_processing/aec3/fft_data.h"
|
#include "modules/audio_processing/aec3/fft_data.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -35,7 +36,7 @@ class SuppressionFilter {
|
|||||||
const std::array<float, kFftLengthBy2Plus1>& suppression_gain,
|
const std::array<float, kFftLengthBy2Plus1>& suppression_gain,
|
||||||
float high_bands_gain,
|
float high_bands_gain,
|
||||||
rtc::ArrayView<const FftData> E_lowest_band,
|
rtc::ArrayView<const FftData> E_lowest_band,
|
||||||
std::vector<std::vector<std::vector<float>>>* e);
|
Block* e);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Aec3Optimization optimization_;
|
const Aec3Optimization optimization_;
|
||||||
|
|||||||
@ -26,21 +26,21 @@ constexpr float kPi = 3.141592f;
|
|||||||
void ProduceSinusoid(int sample_rate_hz,
|
void ProduceSinusoid(int sample_rate_hz,
|
||||||
float sinusoidal_frequency_hz,
|
float sinusoidal_frequency_hz,
|
||||||
size_t* sample_counter,
|
size_t* sample_counter,
|
||||||
std::vector<std::vector<std::vector<float>>>* x) {
|
Block* x) {
|
||||||
// Produce a sinusoid of the specified frequency.
|
// Produce a sinusoid of the specified frequency.
|
||||||
for (size_t k = *sample_counter, j = 0; k < (*sample_counter + kBlockSize);
|
for (size_t k = *sample_counter, j = 0; k < (*sample_counter + kBlockSize);
|
||||||
++k, ++j) {
|
++k, ++j) {
|
||||||
for (size_t channel = 0; channel < (*x)[0].size(); ++channel) {
|
for (int channel = 0; channel < x->NumChannels(); ++channel) {
|
||||||
(*x)[0][channel][j] =
|
x->View(/*band=*/0, channel)[j] =
|
||||||
32767.f *
|
32767.f *
|
||||||
std::sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz);
|
std::sin(2.f * kPi * sinusoidal_frequency_hz * k / sample_rate_hz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*sample_counter = *sample_counter + kBlockSize;
|
*sample_counter = *sample_counter + kBlockSize;
|
||||||
|
|
||||||
for (size_t band = 1; band < x->size(); ++band) {
|
for (int band = 1; band < x->NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < (*x)[band].size(); ++channel) {
|
for (int channel = 0; channel < x->NumChannels(); ++channel) {
|
||||||
std::fill((*x)[band][channel].begin(), (*x)[band][channel].end(), 0.f);
|
std::fill(x->begin(band, channel), x->end(band, channel), 0.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,21 +84,23 @@ TEST(SuppressionFilter, ComfortNoiseInUnityGain) {
|
|||||||
cn_high_bands[0].re.fill(1.f);
|
cn_high_bands[0].re.fill(1.f);
|
||||||
cn_high_bands[0].im.fill(1.f);
|
cn_high_bands[0].im.fill(1.f);
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<float>>> e(
|
Block e(3, kBlockSize);
|
||||||
3,
|
Block e_ref = e;
|
||||||
std::vector<std::vector<float>>(1, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::vector<float>>> e_ref = e;
|
|
||||||
|
|
||||||
std::vector<FftData> E(1);
|
std::vector<FftData> E(1);
|
||||||
fft.PaddedFft(e[0][0], e_old_, Aec3Fft::Window::kSqrtHanning, &E[0]);
|
fft.PaddedFft(e.View(/*band=*/0, /*channel=*/0), e_old_,
|
||||||
std::copy(e[0][0].begin(), e[0][0].end(), e_old_.begin());
|
Aec3Fft::Window::kSqrtHanning, &E[0]);
|
||||||
|
std::copy(e.begin(/*band=*/0, /*channel=*/0),
|
||||||
|
e.end(/*band=*/0, /*channel=*/0), e_old_.begin());
|
||||||
|
|
||||||
filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e);
|
filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e);
|
||||||
|
|
||||||
for (size_t band = 0; band < e.size(); ++band) {
|
for (int band = 0; band < e.NumBands(); ++band) {
|
||||||
for (size_t channel = 0; channel < e[band].size(); ++channel) {
|
for (int channel = 0; channel < e.NumChannels(); ++channel) {
|
||||||
for (size_t sample = 0; sample < e[band][channel].size(); ++sample) {
|
const auto e_view = e.View(band, channel);
|
||||||
EXPECT_EQ(e_ref[band][channel][sample], e[band][channel][sample]);
|
const auto e_ref_view = e_ref.View(band, channel);
|
||||||
|
for (size_t sample = 0; sample < e_view.size(); ++sample) {
|
||||||
|
EXPECT_EQ(e_ref_view[sample], e_view[sample]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,9 +118,7 @@ TEST(SuppressionFilter, SignalSuppression) {
|
|||||||
std::array<float, kFftLengthBy2> e_old_;
|
std::array<float, kFftLengthBy2> e_old_;
|
||||||
Aec3Fft fft;
|
Aec3Fft fft;
|
||||||
std::array<float, kFftLengthBy2Plus1> gain;
|
std::array<float, kFftLengthBy2Plus1> gain;
|
||||||
std::vector<std::vector<std::vector<float>>> e(
|
Block e(kNumBands, kNumChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
kNumChannels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
e_old_.fill(0.f);
|
e_old_.fill(0.f);
|
||||||
|
|
||||||
gain.fill(1.f);
|
gain.fill(1.f);
|
||||||
@ -135,16 +135,20 @@ TEST(SuppressionFilter, SignalSuppression) {
|
|||||||
float e0_output = 0.f;
|
float e0_output = 0.f;
|
||||||
for (size_t k = 0; k < 100; ++k) {
|
for (size_t k = 0; k < 100; ++k) {
|
||||||
ProduceSinusoid(16000, 16000 * 40 / kFftLengthBy2 / 2, &sample_counter, &e);
|
ProduceSinusoid(16000, 16000 * 40 / kFftLengthBy2 / 2, &sample_counter, &e);
|
||||||
e0_input = std::inner_product(e[0][0].begin(), e[0][0].end(),
|
e0_input = std::inner_product(e.begin(/*band=*/0, /*channel=*/0),
|
||||||
e[0][0].begin(), e0_input);
|
e.end(/*band=*/0, /*channel=*/0),
|
||||||
|
e.begin(/*band=*/0, /*channel=*/0), e0_input);
|
||||||
|
|
||||||
std::vector<FftData> E(1);
|
std::vector<FftData> E(1);
|
||||||
fft.PaddedFft(e[0][0], e_old_, Aec3Fft::Window::kSqrtHanning, &E[0]);
|
fft.PaddedFft(e.View(/*band=*/0, /*channel=*/0), e_old_,
|
||||||
std::copy(e[0][0].begin(), e[0][0].end(), e_old_.begin());
|
Aec3Fft::Window::kSqrtHanning, &E[0]);
|
||||||
|
std::copy(e.begin(/*band=*/0, /*channel=*/0),
|
||||||
|
e.end(/*band=*/0, /*channel=*/0), e_old_.begin());
|
||||||
|
|
||||||
filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e);
|
filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e);
|
||||||
e0_output = std::inner_product(e[0][0].begin(), e[0][0].end(),
|
e0_output = std::inner_product(
|
||||||
e[0][0].begin(), e0_output);
|
e.begin(/*band=*/0, /*channel=*/0), e.end(/*band=*/0, /*channel=*/0),
|
||||||
|
e.begin(/*band=*/0, /*channel=*/0), e0_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_LT(e0_output, e0_input / 1000.f);
|
EXPECT_LT(e0_output, e0_input / 1000.f);
|
||||||
@ -163,9 +167,7 @@ TEST(SuppressionFilter, SignalTransparency) {
|
|||||||
Aec3Fft fft;
|
Aec3Fft fft;
|
||||||
std::vector<FftData> cn_high_bands(1);
|
std::vector<FftData> cn_high_bands(1);
|
||||||
std::array<float, kFftLengthBy2Plus1> gain;
|
std::array<float, kFftLengthBy2Plus1> gain;
|
||||||
std::vector<std::vector<std::vector<float>>> e(
|
Block e(kNumBands, kNumChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
kNumChannels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
e_old_.fill(0.f);
|
e_old_.fill(0.f);
|
||||||
gain.fill(1.f);
|
gain.fill(1.f);
|
||||||
std::for_each(gain.begin() + 30, gain.end(), [](float& a) { a = 0.f; });
|
std::for_each(gain.begin() + 30, gain.end(), [](float& a) { a = 0.f; });
|
||||||
@ -181,16 +183,20 @@ TEST(SuppressionFilter, SignalTransparency) {
|
|||||||
float e0_output = 0.f;
|
float e0_output = 0.f;
|
||||||
for (size_t k = 0; k < 100; ++k) {
|
for (size_t k = 0; k < 100; ++k) {
|
||||||
ProduceSinusoid(16000, 16000 * 10 / kFftLengthBy2 / 2, &sample_counter, &e);
|
ProduceSinusoid(16000, 16000 * 10 / kFftLengthBy2 / 2, &sample_counter, &e);
|
||||||
e0_input = std::inner_product(e[0][0].begin(), e[0][0].end(),
|
e0_input = std::inner_product(e.begin(/*band=*/0, /*channel=*/0),
|
||||||
e[0][0].begin(), e0_input);
|
e.end(/*band=*/0, /*channel=*/0),
|
||||||
|
e.begin(/*band=*/0, /*channel=*/0), e0_input);
|
||||||
|
|
||||||
std::vector<FftData> E(1);
|
std::vector<FftData> E(1);
|
||||||
fft.PaddedFft(e[0][0], e_old_, Aec3Fft::Window::kSqrtHanning, &E[0]);
|
fft.PaddedFft(e.View(/*band=*/0, /*channel=*/0), e_old_,
|
||||||
std::copy(e[0][0].begin(), e[0][0].end(), e_old_.begin());
|
Aec3Fft::Window::kSqrtHanning, &E[0]);
|
||||||
|
std::copy(e.begin(/*band=*/0, /*channel=*/0),
|
||||||
|
e.end(/*band=*/0, /*channel=*/0), e_old_.begin());
|
||||||
|
|
||||||
filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e);
|
filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e);
|
||||||
e0_output = std::inner_product(e[0][0].begin(), e[0][0].end(),
|
e0_output = std::inner_product(
|
||||||
e[0][0].begin(), e0_output);
|
e.begin(/*band=*/0, /*channel=*/0), e.end(/*band=*/0, /*channel=*/0),
|
||||||
|
e.begin(/*band=*/0, /*channel=*/0), e0_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_LT(0.9f * e0_input, e0_output);
|
EXPECT_LT(0.9f * e0_input, e0_output);
|
||||||
@ -208,9 +214,7 @@ TEST(SuppressionFilter, Delay) {
|
|||||||
std::array<float, kFftLengthBy2> e_old_;
|
std::array<float, kFftLengthBy2> e_old_;
|
||||||
Aec3Fft fft;
|
Aec3Fft fft;
|
||||||
std::array<float, kFftLengthBy2Plus1> gain;
|
std::array<float, kFftLengthBy2Plus1> gain;
|
||||||
std::vector<std::vector<std::vector<float>>> e(
|
Block e(kNumBands, kNumChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
kNumChannels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
|
|
||||||
gain.fill(1.f);
|
gain.fill(1.f);
|
||||||
|
|
||||||
@ -222,23 +226,27 @@ TEST(SuppressionFilter, Delay) {
|
|||||||
for (size_t k = 0; k < 100; ++k) {
|
for (size_t k = 0; k < 100; ++k) {
|
||||||
for (size_t band = 0; band < kNumBands; ++band) {
|
for (size_t band = 0; band < kNumBands; ++band) {
|
||||||
for (size_t channel = 0; channel < kNumChannels; ++channel) {
|
for (size_t channel = 0; channel < kNumChannels; ++channel) {
|
||||||
|
auto e_view = e.View(band, channel);
|
||||||
for (size_t sample = 0; sample < kBlockSize; ++sample) {
|
for (size_t sample = 0; sample < kBlockSize; ++sample) {
|
||||||
e[band][channel][sample] = k * kBlockSize + sample + channel;
|
e_view[sample] = k * kBlockSize + sample + channel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FftData> E(1);
|
std::vector<FftData> E(1);
|
||||||
fft.PaddedFft(e[0][0], e_old_, Aec3Fft::Window::kSqrtHanning, &E[0]);
|
fft.PaddedFft(e.View(/*band=*/0, /*channel=*/0), e_old_,
|
||||||
std::copy(e[0][0].begin(), e[0][0].end(), e_old_.begin());
|
Aec3Fft::Window::kSqrtHanning, &E[0]);
|
||||||
|
std::copy(e.begin(/*band=*/0, /*channel=*/0),
|
||||||
|
e.end(/*band=*/0, /*channel=*/0), e_old_.begin());
|
||||||
|
|
||||||
filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e);
|
filter.ApplyGain(cn, cn_high_bands, gain, 1.f, E, &e);
|
||||||
if (k > 2) {
|
if (k > 2) {
|
||||||
for (size_t band = 0; band < kNumBands; ++band) {
|
for (size_t band = 0; band < kNumBands; ++band) {
|
||||||
for (size_t channel = 0; channel < kNumChannels; ++channel) {
|
for (size_t channel = 0; channel < kNumChannels; ++channel) {
|
||||||
|
const auto e_view = e.View(band, channel);
|
||||||
for (size_t sample = 0; sample < kBlockSize; ++sample) {
|
for (size_t sample = 0; sample < kBlockSize; ++sample) {
|
||||||
EXPECT_NEAR(k * kBlockSize + sample - kBlockSize + channel,
|
EXPECT_NEAR(k * kBlockSize + sample - kBlockSize + channel,
|
||||||
e[band][channel][sample], 0.01);
|
e_view[sample], 0.01);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,13 +110,13 @@ float SuppressionGain::UpperBandsGain(
|
|||||||
comfort_noise_spectrum,
|
comfort_noise_spectrum,
|
||||||
const absl::optional<int>& narrow_peak_band,
|
const absl::optional<int>& narrow_peak_band,
|
||||||
bool saturated_echo,
|
bool saturated_echo,
|
||||||
const std::vector<std::vector<std::vector<float>>>& render,
|
const Block& render,
|
||||||
const std::array<float, kFftLengthBy2Plus1>& low_band_gain) const {
|
const std::array<float, kFftLengthBy2Plus1>& low_band_gain) const {
|
||||||
RTC_DCHECK_LT(0, render.size());
|
RTC_DCHECK_LT(0, render.NumBands());
|
||||||
if (render.size() == 1) {
|
if (render.NumBands() == 1) {
|
||||||
return 1.f;
|
return 1.f;
|
||||||
}
|
}
|
||||||
const size_t num_render_channels = render[0].size();
|
const int num_render_channels = render.NumChannels();
|
||||||
|
|
||||||
if (narrow_peak_band &&
|
if (narrow_peak_band &&
|
||||||
(*narrow_peak_band > static_cast<int>(kFftLengthBy2Plus1 - 10))) {
|
(*narrow_peak_band > static_cast<int>(kFftLengthBy2Plus1 - 10))) {
|
||||||
@ -135,16 +135,19 @@ float SuppressionGain::UpperBandsGain(
|
|||||||
// Compute the upper and lower band energies.
|
// Compute the upper and lower band energies.
|
||||||
const auto sum_of_squares = [](float a, float b) { return a + b * b; };
|
const auto sum_of_squares = [](float a, float b) { return a + b * b; };
|
||||||
float low_band_energy = 0.f;
|
float low_band_energy = 0.f;
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (int ch = 0; ch < num_render_channels; ++ch) {
|
||||||
|
// TODO(bugs.webrtc.org/14108): Fix the computation below to compute the
|
||||||
|
// energy for each channel.
|
||||||
const float channel_energy = std::accumulate(
|
const float channel_energy = std::accumulate(
|
||||||
render[0][0].begin(), render[0][0].end(), 0.f, sum_of_squares);
|
render.begin(/*band=0*/ 0, /*channel=*/0),
|
||||||
|
render.end(/*band=0*/ 0, /*channel=*/0), 0.f, sum_of_squares);
|
||||||
low_band_energy = std::max(low_band_energy, channel_energy);
|
low_band_energy = std::max(low_band_energy, channel_energy);
|
||||||
}
|
}
|
||||||
float high_band_energy = 0.f;
|
float high_band_energy = 0.f;
|
||||||
for (size_t k = 1; k < render.size(); ++k) {
|
for (int k = 1; k < render.NumBands(); ++k) {
|
||||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
for (int ch = 0; ch < num_render_channels; ++ch) {
|
||||||
const float energy = std::accumulate(
|
const float energy = std::accumulate(
|
||||||
render[k][ch].begin(), render[k][ch].end(), 0.f, sum_of_squares);
|
render.begin(k, ch), render.end(k, ch), 0.f, sum_of_squares);
|
||||||
high_band_energy = std::max(high_band_energy, energy);
|
high_band_energy = std::max(high_band_energy, energy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,7 +375,7 @@ void SuppressionGain::GetGain(
|
|||||||
comfort_noise_spectrum,
|
comfort_noise_spectrum,
|
||||||
const RenderSignalAnalyzer& render_signal_analyzer,
|
const RenderSignalAnalyzer& render_signal_analyzer,
|
||||||
const AecState& aec_state,
|
const AecState& aec_state,
|
||||||
const std::vector<std::vector<std::vector<float>>>& render,
|
const Block& render,
|
||||||
bool clock_drift,
|
bool clock_drift,
|
||||||
float* high_bands_gain,
|
float* high_bands_gain,
|
||||||
std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
|
std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
|
||||||
@ -417,20 +420,17 @@ void SuppressionGain::SetInitialState(bool state) {
|
|||||||
|
|
||||||
// Detects when the render signal can be considered to have low power and
|
// Detects when the render signal can be considered to have low power and
|
||||||
// consist of stationary noise.
|
// consist of stationary noise.
|
||||||
bool SuppressionGain::LowNoiseRenderDetector::Detect(
|
bool SuppressionGain::LowNoiseRenderDetector::Detect(const Block& render) {
|
||||||
const std::vector<std::vector<std::vector<float>>>& render) {
|
|
||||||
float x2_sum = 0.f;
|
float x2_sum = 0.f;
|
||||||
float x2_max = 0.f;
|
float x2_max = 0.f;
|
||||||
for (const auto& x_ch : render[0]) {
|
for (int ch = 0; ch < render.NumChannels(); ++ch) {
|
||||||
for (const auto& x_k : x_ch) {
|
for (float x_k : render.View(/*band=*/0, ch)) {
|
||||||
const float x2 = x_k * x_k;
|
const float x2 = x_k * x_k;
|
||||||
x2_sum += x2;
|
x2_sum += x2;
|
||||||
x2_max = std::max(x2_max, x2);
|
x2_max = std::max(x2_max, x2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const size_t num_render_channels = render[0].size();
|
x2_sum = x2_sum / render.NumChannels();
|
||||||
x2_sum = x2_sum / num_render_channels;
|
|
||||||
;
|
|
||||||
|
|
||||||
constexpr float kThreshold = 50.f * 50.f * 64.f;
|
constexpr float kThreshold = 50.f * 50.f * 64.f;
|
||||||
const bool low_noise_render =
|
const bool low_noise_render =
|
||||||
|
|||||||
@ -51,7 +51,7 @@ class SuppressionGain {
|
|||||||
comfort_noise_spectrum,
|
comfort_noise_spectrum,
|
||||||
const RenderSignalAnalyzer& render_signal_analyzer,
|
const RenderSignalAnalyzer& render_signal_analyzer,
|
||||||
const AecState& aec_state,
|
const AecState& aec_state,
|
||||||
const std::vector<std::vector<std::vector<float>>>& render,
|
const Block& render,
|
||||||
bool clock_drift,
|
bool clock_drift,
|
||||||
float* high_bands_gain,
|
float* high_bands_gain,
|
||||||
std::array<float, kFftLengthBy2Plus1>* low_band_gain);
|
std::array<float, kFftLengthBy2Plus1>* low_band_gain);
|
||||||
@ -71,7 +71,7 @@ class SuppressionGain {
|
|||||||
comfort_noise_spectrum,
|
comfort_noise_spectrum,
|
||||||
const absl::optional<int>& narrow_peak_band,
|
const absl::optional<int>& narrow_peak_band,
|
||||||
bool saturated_echo,
|
bool saturated_echo,
|
||||||
const std::vector<std::vector<std::vector<float>>>& render,
|
const Block& render,
|
||||||
const std::array<float, kFftLengthBy2Plus1>& low_band_gain) const;
|
const std::array<float, kFftLengthBy2Plus1>& low_band_gain) const;
|
||||||
|
|
||||||
void GainToNoAudibleEcho(const std::array<float, kFftLengthBy2Plus1>& nearend,
|
void GainToNoAudibleEcho(const std::array<float, kFftLengthBy2Plus1>& nearend,
|
||||||
@ -100,7 +100,7 @@ class SuppressionGain {
|
|||||||
|
|
||||||
class LowNoiseRenderDetector {
|
class LowNoiseRenderDetector {
|
||||||
public:
|
public:
|
||||||
bool Detect(const std::vector<std::vector<std::vector<float>>>& render);
|
bool Detect(const Block& render);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float average_power_ = 32768.f * 32768.f;
|
float average_power_ = 32768.f * 32768.f;
|
||||||
|
|||||||
@ -47,10 +47,7 @@ TEST(SuppressionGainDeathTest, NullOutputGains) {
|
|||||||
SuppressionGain(EchoCanceller3Config{}, DetectOptimization(), 16000, 1)
|
SuppressionGain(EchoCanceller3Config{}, DetectOptimization(), 16000, 1)
|
||||||
.GetGain(E2, S2, R2, R2_unbounded, N2,
|
.GetGain(E2, S2, R2, R2_unbounded, N2,
|
||||||
RenderSignalAnalyzer((EchoCanceller3Config{})), aec_state,
|
RenderSignalAnalyzer((EchoCanceller3Config{})), aec_state,
|
||||||
std::vector<std::vector<std::vector<float>>>(
|
Block(3, 1), false, &high_bands_gain, nullptr),
|
||||||
3, std::vector<std::vector<float>>(
|
|
||||||
1, std::vector<float>(kBlockSize, 0.0f))),
|
|
||||||
false, &high_bands_gain, nullptr),
|
|
||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,9 +73,7 @@ TEST(SuppressionGain, BasicGainComputation) {
|
|||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> N2(kNumCaptureChannels);
|
std::vector<std::array<float, kFftLengthBy2Plus1>> N2(kNumCaptureChannels);
|
||||||
std::array<float, kFftLengthBy2Plus1> g;
|
std::array<float, kFftLengthBy2Plus1> g;
|
||||||
std::vector<SubtractorOutput> output(kNumCaptureChannels);
|
std::vector<SubtractorOutput> output(kNumCaptureChannels);
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
Block x(kNumBands, kNumRenderChannels);
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
kNumRenderChannels, std::vector<float>(kBlockSize, 0.0f)));
|
|
||||||
EchoCanceller3Config config;
|
EchoCanceller3Config config;
|
||||||
AecState aec_state(config, kNumCaptureChannels);
|
AecState aec_state(config, kNumCaptureChannels);
|
||||||
ApmDataDumper data_dumper(42);
|
ApmDataDumper data_dumper(42);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user