Allow extracting the linear AEC output
This CL enables extracting the linear AEC output, allowing for more straightforward testing/development. Bug: b/140823178 Change-Id: I14f7934008d87066b35500466cb6e6d96f811688 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/153672 Commit-Queue: Per Åhgren <peah@webrtc.org> Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29789}
This commit is contained in:
@ -42,7 +42,8 @@ constexpr int kMaxAdaptiveFilterLength = 50;
|
||||
constexpr int kRenderTransferQueueSizeFrames = 100;
|
||||
|
||||
constexpr size_t kMaxNumBands = 3;
|
||||
constexpr size_t kSubFrameLength = 80;
|
||||
constexpr size_t kFrameSize = 160;
|
||||
constexpr size_t kSubFrameLength = kFrameSize / 2;
|
||||
|
||||
constexpr size_t kBlockSize = kFftLengthBy2;
|
||||
constexpr size_t kBlockSizeLog2 = kFftLengthBy2Log2;
|
||||
|
||||
@ -52,6 +52,7 @@ class BlockProcessorImpl final : public BlockProcessor {
|
||||
void ProcessCapture(
|
||||
bool echo_path_gain_change,
|
||||
bool capture_signal_saturation,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture_block) override;
|
||||
|
||||
void BufferRender(
|
||||
@ -105,6 +106,7 @@ BlockProcessorImpl::~BlockProcessorImpl() = default;
|
||||
void BlockProcessorImpl::ProcessCapture(
|
||||
bool echo_path_gain_change,
|
||||
bool capture_signal_saturation,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture_block) {
|
||||
RTC_DCHECK(capture_block);
|
||||
RTC_DCHECK_EQ(NumBandsForRate(sample_rate_hz_), capture_block->size());
|
||||
@ -191,7 +193,7 @@ void BlockProcessorImpl::ProcessCapture(
|
||||
if (has_delay_estimator || render_buffer_->HasReceivedBufferDelay()) {
|
||||
echo_remover_->ProcessCapture(
|
||||
echo_path_variability, capture_signal_saturation, estimated_delay_,
|
||||
render_buffer_->GetRenderBuffer(), capture_block);
|
||||
render_buffer_->GetRenderBuffer(), linear_output, capture_block);
|
||||
}
|
||||
|
||||
// Update the metrics.
|
||||
|
||||
@ -59,6 +59,7 @@ class BlockProcessor {
|
||||
virtual void ProcessCapture(
|
||||
bool echo_path_gain_change,
|
||||
bool capture_signal_saturation,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture_block) = 0;
|
||||
|
||||
// Buffers a block of render data supplied by a FrameBlocker object.
|
||||
|
||||
@ -48,7 +48,7 @@ void RunBasicSetupAndApiCallTest(int sample_rate_hz, int num_iterations) {
|
||||
std::vector<float>(kBlockSize, 1000.f)));
|
||||
for (int k = 0; k < num_iterations; ++k) {
|
||||
block_processor->BufferRender(block);
|
||||
block_processor->ProcessCapture(false, false, &block);
|
||||
block_processor->ProcessCapture(false, false, nullptr, &block);
|
||||
block_processor->UpdateEchoLeakageStatus(false);
|
||||
}
|
||||
}
|
||||
@ -81,7 +81,8 @@ void RunCaptureBlockSizeVerificationTest(int sample_rate_hz) {
|
||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
||||
std::vector<float>(kBlockSize - 1, 0.f)));
|
||||
|
||||
EXPECT_DEATH(block_processor->ProcessCapture(false, false, &block), "");
|
||||
EXPECT_DEATH(block_processor->ProcessCapture(false, false, nullptr, &block),
|
||||
"");
|
||||
}
|
||||
|
||||
void RunRenderNumBandsVerificationTest(int sample_rate_hz) {
|
||||
@ -117,7 +118,8 @@ void RunCaptureNumBandsVerificationTest(int sample_rate_hz) {
|
||||
std::vector<std::vector<float>>(kNumRenderChannels,
|
||||
std::vector<float>(kBlockSize, 0.f)));
|
||||
|
||||
EXPECT_DEATH(block_processor->ProcessCapture(false, false, &block), "");
|
||||
EXPECT_DEATH(block_processor->ProcessCapture(false, false, nullptr, &block),
|
||||
"");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -172,7 +174,7 @@ TEST(BlockProcessor, DISABLED_DelayControllerIntegration) {
|
||||
RandomizeSampleVector(&random_generator, render_block[0][0]);
|
||||
signal_delay_buffer.Delay(render_block[0][0], capture_block[0][0]);
|
||||
block_processor->BufferRender(render_block);
|
||||
block_processor->ProcessCapture(false, false, &capture_block);
|
||||
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -207,7 +209,7 @@ TEST(BlockProcessor, DISABLED_SubmoduleIntegration) {
|
||||
.WillRepeatedly(Return(0));
|
||||
EXPECT_CALL(*render_delay_controller_mock, GetDelay(_, _, _))
|
||||
.Times(kNumBlocks);
|
||||
EXPECT_CALL(*echo_remover_mock, ProcessCapture(_, _, _, _, _))
|
||||
EXPECT_CALL(*echo_remover_mock, ProcessCapture(_, _, _, _, _, _))
|
||||
.Times(kNumBlocks);
|
||||
EXPECT_CALL(*echo_remover_mock, UpdateEchoLeakageStatus(_))
|
||||
.Times(kNumBlocks);
|
||||
@ -230,7 +232,7 @@ TEST(BlockProcessor, DISABLED_SubmoduleIntegration) {
|
||||
RandomizeSampleVector(&random_generator, render_block[0][0]);
|
||||
signal_delay_buffer.Delay(render_block[0][0], capture_block[0][0]);
|
||||
block_processor->BufferRender(render_block);
|
||||
block_processor->ProcessCapture(false, false, &capture_block);
|
||||
block_processor->ProcessCapture(false, false, nullptr, &capture_block);
|
||||
block_processor->UpdateEchoLeakageStatus(false);
|
||||
}
|
||||
}
|
||||
@ -284,7 +286,7 @@ TEST(BlockProcessor, VerifyCaptureNumBandsCheck) {
|
||||
TEST(BlockProcessor, NullProcessCaptureParameter) {
|
||||
EXPECT_DEATH(std::unique_ptr<BlockProcessor>(
|
||||
BlockProcessor::Create(EchoCanceller3Config(), 16000, 1, 1))
|
||||
->ProcessCapture(false, false, nullptr),
|
||||
->ProcessCapture(false, false, nullptr, nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include "modules/audio_processing/high_pass_filter.h"
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/atomic_ops.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -87,28 +88,52 @@ void FillSubFrameView(
|
||||
}
|
||||
|
||||
void ProcessCaptureFrameContent(
|
||||
AudioBuffer* linear_output,
|
||||
AudioBuffer* capture,
|
||||
bool level_change,
|
||||
bool saturated_microphone_signal,
|
||||
size_t sub_frame_index,
|
||||
FrameBlocker* capture_blocker,
|
||||
BlockFramer* linear_output_framer,
|
||||
BlockFramer* output_framer,
|
||||
BlockProcessor* block_processor,
|
||||
std::vector<std::vector<std::vector<float>>>* block,
|
||||
std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame_view) {
|
||||
FillSubFrameView(capture, sub_frame_index, sub_frame_view);
|
||||
capture_blocker->InsertSubFrameAndExtractBlock(*sub_frame_view, block);
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output_block,
|
||||
std::vector<std::vector<rtc::ArrayView<float>>>*
|
||||
linear_output_sub_frame_view,
|
||||
std::vector<std::vector<std::vector<float>>>* capture_block,
|
||||
std::vector<std::vector<rtc::ArrayView<float>>>* capture_sub_frame_view) {
|
||||
FillSubFrameView(capture, sub_frame_index, capture_sub_frame_view);
|
||||
|
||||
if (linear_output) {
|
||||
RTC_DCHECK(linear_output_framer);
|
||||
RTC_DCHECK(linear_output_block);
|
||||
RTC_DCHECK(linear_output_sub_frame_view);
|
||||
FillSubFrameView(linear_output, sub_frame_index,
|
||||
linear_output_sub_frame_view);
|
||||
}
|
||||
|
||||
capture_blocker->InsertSubFrameAndExtractBlock(*capture_sub_frame_view,
|
||||
capture_block);
|
||||
block_processor->ProcessCapture(level_change, saturated_microphone_signal,
|
||||
block);
|
||||
output_framer->InsertBlockAndExtractSubFrame(*block, sub_frame_view);
|
||||
linear_output_block, capture_block);
|
||||
output_framer->InsertBlockAndExtractSubFrame(*capture_block,
|
||||
capture_sub_frame_view);
|
||||
|
||||
if (linear_output) {
|
||||
RTC_DCHECK(linear_output_framer);
|
||||
linear_output_framer->InsertBlockAndExtractSubFrame(
|
||||
*linear_output_block, linear_output_sub_frame_view);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessRemainingCaptureFrameContent(
|
||||
bool level_change,
|
||||
bool saturated_microphone_signal,
|
||||
FrameBlocker* capture_blocker,
|
||||
BlockFramer* linear_output_framer,
|
||||
BlockFramer* output_framer,
|
||||
BlockProcessor* block_processor,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output_block,
|
||||
std::vector<std::vector<std::vector<float>>>* block) {
|
||||
if (!capture_blocker->IsBlockAvailable()) {
|
||||
return;
|
||||
@ -116,8 +141,13 @@ void ProcessRemainingCaptureFrameContent(
|
||||
|
||||
capture_blocker->ExtractBlock(block);
|
||||
block_processor->ProcessCapture(level_change, saturated_microphone_signal,
|
||||
block);
|
||||
linear_output_block, block);
|
||||
output_framer->InsertBlock(*block);
|
||||
|
||||
if (linear_output_framer) {
|
||||
RTC_DCHECK(linear_output_block);
|
||||
linear_output_framer->InsertBlock(*linear_output_block);
|
||||
}
|
||||
}
|
||||
|
||||
void BufferRenderFrameContent(
|
||||
@ -295,12 +325,24 @@ EchoCanceller3::EchoCanceller3(const EchoCanceller3Config& config,
|
||||
|
||||
RTC_DCHECK_EQ(num_bands_, std::max(sample_rate_hz_, 16000) / 16000);
|
||||
RTC_DCHECK_GE(kMaxNumBands, num_bands_);
|
||||
|
||||
if (config_.filter.export_linear_aec_output) {
|
||||
linear_output_framer_.reset(new BlockFramer(1, num_capture_channels_));
|
||||
linear_output_block_ =
|
||||
std::make_unique<std::vector<std::vector<std::vector<float>>>>(
|
||||
1, std::vector<std::vector<float>>(
|
||||
num_capture_channels_, std::vector<float>(kBlockSize, 0.f)));
|
||||
linear_output_sub_frame_view_ =
|
||||
std::vector<std::vector<rtc::ArrayView<float>>>(
|
||||
1, std::vector<rtc::ArrayView<float>>(num_capture_channels_));
|
||||
}
|
||||
}
|
||||
|
||||
EchoCanceller3::~EchoCanceller3() = default;
|
||||
|
||||
void EchoCanceller3::AnalyzeRender(const AudioBuffer& render) {
|
||||
RTC_DCHECK_RUNS_SERIALIZED(&render_race_checker_);
|
||||
|
||||
RTC_DCHECK_EQ(render.num_channels(), num_render_channels_);
|
||||
data_dumper_->DumpRaw("aec3_call_order",
|
||||
static_cast<int>(EchoCanceller3ApiCall::kRender));
|
||||
@ -312,7 +354,6 @@ void EchoCanceller3::AnalyzeCapture(const AudioBuffer& capture) {
|
||||
RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
|
||||
data_dumper_->DumpWav("aec3_capture_analyze_input", capture.num_frames(),
|
||||
capture.channels_const()[0], sample_rate_hz_, 1);
|
||||
|
||||
saturated_microphone_signal_ = false;
|
||||
for (size_t channel = 0; channel < capture.num_channels(); ++channel) {
|
||||
saturated_microphone_signal_ |=
|
||||
@ -325,6 +366,12 @@ void EchoCanceller3::AnalyzeCapture(const AudioBuffer& capture) {
|
||||
}
|
||||
|
||||
void EchoCanceller3::ProcessCapture(AudioBuffer* capture, bool level_change) {
|
||||
ProcessCapture(capture, nullptr, level_change);
|
||||
}
|
||||
|
||||
void EchoCanceller3::ProcessCapture(AudioBuffer* capture,
|
||||
AudioBuffer* linear_output,
|
||||
bool level_change) {
|
||||
RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
|
||||
RTC_DCHECK(capture);
|
||||
RTC_DCHECK_EQ(num_bands_, capture->num_bands());
|
||||
@ -333,6 +380,12 @@ void EchoCanceller3::ProcessCapture(AudioBuffer* capture, bool level_change) {
|
||||
data_dumper_->DumpRaw("aec3_call_order",
|
||||
static_cast<int>(EchoCanceller3ApiCall::kCapture));
|
||||
|
||||
if (linear_output && !linear_output_framer_) {
|
||||
RTC_LOG(LS_ERROR) << "Trying to retrieve the linear AEC output without "
|
||||
"properly configuring AEC3.";
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
|
||||
// Report capture call in the metrics and periodically update API call
|
||||
// metrics.
|
||||
api_call_metrics_.ReportCaptureCall();
|
||||
@ -349,19 +402,24 @@ void EchoCanceller3::ProcessCapture(AudioBuffer* capture, bool level_change) {
|
||||
|
||||
EmptyRenderQueue();
|
||||
|
||||
ProcessCaptureFrameContent(capture, level_change,
|
||||
ProcessCaptureFrameContent(linear_output, capture, level_change,
|
||||
saturated_microphone_signal_, 0, &capture_blocker_,
|
||||
&output_framer_, block_processor_.get(),
|
||||
&capture_block_, &capture_sub_frame_view_);
|
||||
linear_output_framer_.get(), &output_framer_,
|
||||
block_processor_.get(), linear_output_block_.get(),
|
||||
&linear_output_sub_frame_view_, &capture_block_,
|
||||
&capture_sub_frame_view_);
|
||||
|
||||
ProcessCaptureFrameContent(capture, level_change,
|
||||
ProcessCaptureFrameContent(linear_output, capture, level_change,
|
||||
saturated_microphone_signal_, 1, &capture_blocker_,
|
||||
&output_framer_, block_processor_.get(),
|
||||
&capture_block_, &capture_sub_frame_view_);
|
||||
linear_output_framer_.get(), &output_framer_,
|
||||
block_processor_.get(), linear_output_block_.get(),
|
||||
&linear_output_sub_frame_view_, &capture_block_,
|
||||
&capture_sub_frame_view_);
|
||||
|
||||
ProcessRemainingCaptureFrameContent(
|
||||
level_change, saturated_microphone_signal_, &capture_blocker_,
|
||||
&output_framer_, block_processor_.get(), &capture_block_);
|
||||
linear_output_framer_.get(), &output_framer_, block_processor_.get(),
|
||||
linear_output_block_.get(), &capture_block_);
|
||||
|
||||
data_dumper_->DumpWav("aec3_capture_output", AudioBuffer::kSplitBandSize,
|
||||
&capture->split_bands(0)[0][0], 16000, 1);
|
||||
|
||||
@ -70,8 +70,6 @@ class Aec3RenderQueueItemVerifier {
|
||||
// Main class for the echo canceller3.
|
||||
// It does 4 things:
|
||||
// -Receives 10 ms frames of band-split audio.
|
||||
// -Optionally applies an anti-hum (high-pass) filter on the
|
||||
// received signals.
|
||||
// -Provides the lower level echo canceller functionality with
|
||||
// blocks of 64 samples of audio data.
|
||||
// -Partially handles the jitter in the render and capture API
|
||||
@ -106,6 +104,10 @@ class EchoCanceller3 : public EchoControl {
|
||||
// Processes the split-band domain capture signal in order to remove any echo
|
||||
// present in the signal.
|
||||
void ProcessCapture(AudioBuffer* capture, bool level_change) override;
|
||||
// As above, but also returns the linear filter output.
|
||||
void ProcessCapture(AudioBuffer* capture,
|
||||
AudioBuffer* linear_output,
|
||||
bool level_change) override;
|
||||
// Collect current metrics from the echo canceller.
|
||||
Metrics GetMetrics() const override;
|
||||
// Provides an optional external estimate of the audio buffer delay.
|
||||
@ -149,6 +151,8 @@ class EchoCanceller3 : public EchoControl {
|
||||
const int num_bands_;
|
||||
const size_t num_render_channels_;
|
||||
const size_t num_capture_channels_;
|
||||
std::unique_ptr<BlockFramer> linear_output_framer_
|
||||
RTC_GUARDED_BY(capture_race_checker_);
|
||||
BlockFramer output_framer_ RTC_GUARDED_BY(capture_race_checker_);
|
||||
FrameBlocker capture_blocker_ RTC_GUARDED_BY(capture_race_checker_);
|
||||
FrameBlocker render_blocker_ RTC_GUARDED_BY(capture_race_checker_);
|
||||
@ -163,10 +167,14 @@ class EchoCanceller3 : public EchoControl {
|
||||
false;
|
||||
std::vector<std::vector<std::vector<float>>> render_block_
|
||||
RTC_GUARDED_BY(capture_race_checker_);
|
||||
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_);
|
||||
std::vector<std::vector<rtc::ArrayView<float>>> render_sub_frame_view_
|
||||
RTC_GUARDED_BY(capture_race_checker_);
|
||||
std::vector<std::vector<rtc::ArrayView<float>>> linear_output_sub_frame_view_
|
||||
RTC_GUARDED_BY(capture_race_checker_);
|
||||
std::vector<std::vector<rtc::ArrayView<float>>> capture_sub_frame_view_
|
||||
RTC_GUARDED_BY(capture_race_checker_);
|
||||
BlockDelayBuffer block_delay_buffer_ RTC_GUARDED_BY(capture_race_checker_);
|
||||
|
||||
@ -112,6 +112,7 @@ class CaptureTransportVerificationProcessor : public BlockProcessor {
|
||||
void ProcessCapture(
|
||||
bool level_change,
|
||||
bool saturated_microphone_signal,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture_block) override {}
|
||||
|
||||
void BufferRender(
|
||||
@ -137,6 +138,7 @@ class RenderTransportVerificationProcessor : public BlockProcessor {
|
||||
void ProcessCapture(
|
||||
bool level_change,
|
||||
bool saturated_microphone_signal,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture_block) override {
|
||||
std::vector<std::vector<std::vector<float>>> render_block =
|
||||
received_render_blocks_.front();
|
||||
@ -267,17 +269,17 @@ class EchoCanceller3Tester {
|
||||
|
||||
switch (echo_path_change_test_variant) {
|
||||
case EchoPathChangeTestVariant::kNone:
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(false, _, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(false, _, _, _))
|
||||
.Times(kExpectedNumBlocksToProcess);
|
||||
break;
|
||||
case EchoPathChangeTestVariant::kOneSticky:
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(true, _, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(true, _, _, _))
|
||||
.Times(kExpectedNumBlocksToProcess);
|
||||
break;
|
||||
case EchoPathChangeTestVariant::kOneNonSticky:
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(true, _, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(true, _, _, _))
|
||||
.Times(kNumFullBlocksPerFrame);
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(false, _, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(false, _, _, _))
|
||||
.Times(kExpectedNumBlocksToProcess - kNumFullBlocksPerFrame);
|
||||
break;
|
||||
}
|
||||
@ -338,7 +340,7 @@ class EchoCanceller3Tester {
|
||||
new StrictMock<webrtc::test::MockBlockProcessor>());
|
||||
EXPECT_CALL(*block_processor_mock, BufferRender(_))
|
||||
.Times(kExpectedNumBlocksToProcess);
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, _, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, _, _, _))
|
||||
.Times(kExpectedNumBlocksToProcess);
|
||||
|
||||
switch (leakage_report_variant) {
|
||||
@ -429,21 +431,21 @@ class EchoCanceller3Tester {
|
||||
|
||||
switch (saturation_variant) {
|
||||
case SaturationTestVariant::kNone:
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _, _))
|
||||
.Times(kExpectedNumBlocksToProcess);
|
||||
break;
|
||||
case SaturationTestVariant::kOneNegative: {
|
||||
::testing::InSequence s;
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, true, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, true, _, _))
|
||||
.Times(kNumFullBlocksPerFrame);
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _, _))
|
||||
.Times(kExpectedNumBlocksToProcess - kNumFullBlocksPerFrame);
|
||||
} break;
|
||||
case SaturationTestVariant::kOnePositive: {
|
||||
::testing::InSequence s;
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, true, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, true, _, _))
|
||||
.Times(kNumFullBlocksPerFrame);
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _))
|
||||
EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _, _))
|
||||
.Times(kExpectedNumBlocksToProcess - kNumFullBlocksPerFrame);
|
||||
} break;
|
||||
}
|
||||
|
||||
@ -123,6 +123,7 @@ class EchoRemoverImpl final : public EchoRemover {
|
||||
bool capture_signal_saturation,
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
RenderBuffer* render_buffer,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture) override;
|
||||
|
||||
// Updates the status on whether echo leakage is detected in the output of the
|
||||
@ -235,6 +236,7 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
bool capture_signal_saturation,
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
RenderBuffer* render_buffer,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture) {
|
||||
++block_counter_;
|
||||
const std::vector<std::vector<std::vector<float>>>& x =
|
||||
@ -367,6 +369,16 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
E[ch].Spectrum(optimization_, E2[ch]);
|
||||
}
|
||||
|
||||
// Optionally return the linear filter output.
|
||||
if (linear_output) {
|
||||
RTC_DCHECK_GE(1, linear_output->size());
|
||||
RTC_DCHECK_EQ(num_capture_channels_, linear_output[0].size());
|
||||
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(), (*linear_output)[0][ch].begin());
|
||||
}
|
||||
}
|
||||
|
||||
// Update the AEC state information.
|
||||
aec_state_.Update(external_delay, subtractor_.FilterFrequencyResponses(),
|
||||
subtractor_.FilterImpulseResponses(), *render_buffer, E2,
|
||||
|
||||
@ -42,6 +42,7 @@ class EchoRemover {
|
||||
bool capture_signal_saturation,
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
RenderBuffer* render_buffer,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture) = 0;
|
||||
|
||||
// Updates the status on whether echo leakage is detected in the output of the
|
||||
|
||||
@ -73,9 +73,9 @@ TEST(EchoRemover, BasicApiCalls) {
|
||||
render_buffer->Insert(render);
|
||||
render_buffer->PrepareCaptureProcessing();
|
||||
|
||||
remover->ProcessCapture(echo_path_variability,
|
||||
k % 2 == 0 ? true : false, delay_estimate,
|
||||
render_buffer->GetRenderBuffer(), &capture);
|
||||
remover->ProcessCapture(
|
||||
echo_path_variability, k % 2 == 0 ? true : false, delay_estimate,
|
||||
render_buffer->GetRenderBuffer(), nullptr, &capture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,10 +107,10 @@ TEST(EchoRemover, WrongCaptureBlockSize) {
|
||||
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(), &capture),
|
||||
"");
|
||||
EXPECT_DEATH(remover->ProcessCapture(
|
||||
echo_path_variability, false, delay_estimate,
|
||||
render_buffer->GetRenderBuffer(), nullptr, &capture),
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,10 +131,10 @@ TEST(EchoRemover, DISABLED_WrongCaptureNumBands) {
|
||||
std::vector<float>(kBlockSize, 0.f)));
|
||||
EchoPathVariability echo_path_variability(
|
||||
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
||||
EXPECT_DEATH(
|
||||
remover->ProcessCapture(echo_path_variability, false, delay_estimate,
|
||||
render_buffer->GetRenderBuffer(), &capture),
|
||||
"");
|
||||
EXPECT_DEATH(remover->ProcessCapture(
|
||||
echo_path_variability, false, delay_estimate,
|
||||
render_buffer->GetRenderBuffer(), nullptr, &capture),
|
||||
"");
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,10 +147,10 @@ TEST(EchoRemover, NullCapture) {
|
||||
RenderDelayBuffer::Create(EchoCanceller3Config(), 16000, 1));
|
||||
EchoPathVariability echo_path_variability(
|
||||
false, EchoPathVariability::DelayAdjustment::kNone, false);
|
||||
EXPECT_DEATH(
|
||||
remover->ProcessCapture(echo_path_variability, false, delay_estimate,
|
||||
render_buffer->GetRenderBuffer(), nullptr),
|
||||
"");
|
||||
EXPECT_DEATH(remover->ProcessCapture(
|
||||
echo_path_variability, false, delay_estimate,
|
||||
render_buffer->GetRenderBuffer(), nullptr, nullptr),
|
||||
"");
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -222,7 +222,8 @@ TEST(EchoRemover, BasicEchoRemoval) {
|
||||
render_buffer->PrepareCaptureProcessing();
|
||||
|
||||
remover->ProcessCapture(echo_path_variability, false, delay_estimate,
|
||||
render_buffer->GetRenderBuffer(), &y);
|
||||
render_buffer->GetRenderBuffer(), nullptr,
|
||||
&y);
|
||||
|
||||
if (k > kNumBlocksToProcess / 2) {
|
||||
output_energy = std::inner_product(y[0][0].begin(), y[0][0].end(),
|
||||
|
||||
@ -24,10 +24,11 @@ class MockBlockProcessor : public BlockProcessor {
|
||||
MockBlockProcessor();
|
||||
virtual ~MockBlockProcessor();
|
||||
|
||||
MOCK_METHOD3(
|
||||
MOCK_METHOD4(
|
||||
ProcessCapture,
|
||||
void(bool level_change,
|
||||
bool saturated_microphone_signal,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture_block));
|
||||
MOCK_METHOD1(BufferRender,
|
||||
void(const std::vector<std::vector<std::vector<float>>>& block));
|
||||
|
||||
@ -27,11 +27,12 @@ class MockEchoRemover : public EchoRemover {
|
||||
MockEchoRemover();
|
||||
virtual ~MockEchoRemover();
|
||||
|
||||
MOCK_METHOD5(ProcessCapture,
|
||||
MOCK_METHOD6(ProcessCapture,
|
||||
void(EchoPathVariability echo_path_variability,
|
||||
bool capture_signal_saturation,
|
||||
const absl::optional<DelayEstimate>& delay_estimate,
|
||||
RenderBuffer* render_buffer,
|
||||
std::vector<std::vector<std::vector<float>>>* linear_output,
|
||||
std::vector<std::vector<std::vector<float>>>* capture));
|
||||
MOCK_CONST_METHOD0(Delay, absl::optional<int>());
|
||||
MOCK_METHOD1(UpdateEchoLeakageStatus, void(bool leakage_detected));
|
||||
|
||||
@ -343,13 +343,6 @@ void SuppressionGain::GetGain(
|
||||
std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
|
||||
RTC_DCHECK(high_bands_gain);
|
||||
RTC_DCHECK(low_band_gain);
|
||||
const auto& cfg = config_.suppressor;
|
||||
|
||||
if (cfg.enforce_transparent) {
|
||||
low_band_gain->fill(1.f);
|
||||
*high_bands_gain = cfg.enforce_empty_higher_bands ? 0.f : 1.f;
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the nearend state selection.
|
||||
dominant_nearend_detector_.Update(nearend_spectrum, residual_echo_spectrum,
|
||||
@ -360,11 +353,6 @@ void SuppressionGain::GetGain(
|
||||
LowerBandGain(low_noise_render, aec_state, nearend_spectrum,
|
||||
residual_echo_spectrum, comfort_noise_spectrum, low_band_gain);
|
||||
|
||||
if (cfg.enforce_empty_higher_bands) {
|
||||
*high_bands_gain = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute the gain for the upper bands.
|
||||
const absl::optional<int> narrow_peak_band =
|
||||
render_signal_analyzer.NarrowPeakBand();
|
||||
|
||||
Reference in New Issue
Block a user