Revert "Remove APM internal usage of EchoCancellation"

This reverts commit 1a03960e63.

Reason for revert: breaks downstream projects.

Original change's description:
> Remove APM internal usage of EchoCancellation
> 
> This CL:
>  - Changes EchoCancellationImpl to inherit privately from
>    EchoCancellation.
>  - Removes usage of AudioProcessing::echo_cancellation() inside most of
>    the audio processing module and unit tests.
>  - Default-enables metrics collection in AEC2.
> 
> This CL breaks audioproc_f backwards compatibility: It can no longer
> use all recorded settings (drift compensation, suppression level), but
> prints an error message when such settings are encountered.
> 
> Some code in audio_processing_unittest.cc still uses the old interface.
> I'll handle that in a separate change, as it is not as straightforward
> to preserve coverage.
> 
> Bug: webrtc:9535
> Change-Id: Ia4d4b8d117ccbe516e5345c15d37298418590686
> Reviewed-on: https://webrtc-review.googlesource.com/97603
> Commit-Queue: Sam Zackrisson <saza@webrtc.org>
> Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#24724}

TBR=gustaf@webrtc.org,saza@webrtc.org

Change-Id: Ifdc4235f9c5ee8a8a5d32cc8e1dda0853b941693
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: webrtc:9535
Reviewed-on: https://webrtc-review.googlesource.com/100305
Reviewed-by: Sergey Silkin <ssilkin@webrtc.org>
Commit-Queue: Sergey Silkin <ssilkin@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24729}
This commit is contained in:
Sergey Silkin 2018-09-13 14:55:17 +00:00 committed by Commit Bot
parent cd56486ffd
commit 271812a893
17 changed files with 345 additions and 268 deletions

View file

@ -672,17 +672,13 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) {
rtc::CritScope cs_render(&crit_render_); rtc::CritScope cs_render(&crit_render_);
rtc::CritScope cs_capture(&crit_capture_); rtc::CritScope cs_capture(&crit_capture_);
public_submodules_->echo_cancellation->Enable( static_cast<EchoCancellation*>(public_submodules_->echo_cancellation.get())
config_.echo_canceller.enabled && !config_.echo_canceller.mobile_mode); ->Enable(config_.echo_canceller.enabled &&
!config_.echo_canceller.mobile_mode);
static_cast<EchoControlMobile*>(public_submodules_->echo_control_mobile.get()) static_cast<EchoControlMobile*>(public_submodules_->echo_control_mobile.get())
->Enable(config_.echo_canceller.enabled && ->Enable(config_.echo_canceller.enabled &&
config_.echo_canceller.mobile_mode); config_.echo_canceller.mobile_mode);
public_submodules_->echo_cancellation->set_suppression_level(
config.echo_canceller.legacy_moderate_suppression_level
? EchoCancellation::SuppressionLevel::kModerateSuppression
: EchoCancellation::SuppressionLevel::kHighSuppression);
InitializeLowCutFilter(); InitializeLowCutFilter();
RTC_LOG(LS_INFO) << "Highpass filter activated: " RTC_LOG(LS_INFO) << "Highpass filter activated: "
@ -1310,8 +1306,7 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
capture_buffer->num_frames_per_band(), capture_nonlocked_.split_rate); capture_buffer->num_frames_per_band(), capture_nonlocked_.split_rate);
} }
RETURN_ON_ERR(public_submodules_->gain_control->ProcessCaptureAudio( RETURN_ON_ERR(public_submodules_->gain_control->ProcessCaptureAudio(
capture_buffer, capture_buffer, echo_cancellation()->stream_has_echo()));
public_submodules_->echo_cancellation->stream_has_echo()));
if (submodule_states_.CaptureMultiBandProcessingActive() && if (submodule_states_.CaptureMultiBandProcessingActive() &&
SampleRateSupportsMultiBand( SampleRateSupportsMultiBand(
@ -1857,15 +1852,15 @@ void AudioProcessingImpl::InitializePreProcessor() {
void AudioProcessingImpl::MaybeUpdateHistograms() { void AudioProcessingImpl::MaybeUpdateHistograms() {
static const int kMinDiffDelayMs = 60; static const int kMinDiffDelayMs = 60;
if (public_submodules_->echo_cancellation->is_enabled()) { if (echo_cancellation()->is_enabled()) {
// Activate delay_jumps_ counters if we know echo_cancellation is running. // Activate delay_jumps_ counters if we know echo_cancellation is running.
// If a stream has echo we know that the echo_cancellation is in process. // If a stream has echo we know that the echo_cancellation is in process.
if (capture_.stream_delay_jumps == -1 && if (capture_.stream_delay_jumps == -1 &&
public_submodules_->echo_cancellation->stream_has_echo()) { echo_cancellation()->stream_has_echo()) {
capture_.stream_delay_jumps = 0; capture_.stream_delay_jumps = 0;
} }
if (capture_.aec_system_delay_jumps == -1 && if (capture_.aec_system_delay_jumps == -1 &&
public_submodules_->echo_cancellation->stream_has_echo()) { echo_cancellation()->stream_has_echo()) {
capture_.aec_system_delay_jumps = 0; capture_.aec_system_delay_jumps = 0;
} }

View file

@ -540,23 +540,31 @@ void AudioProcessingImplLockTest::SetUp() {
ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true)); ASSERT_EQ(apm_->kNoError, apm_->noise_suppression()->Enable(true));
ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true)); ASSERT_EQ(apm_->kNoError, apm_->voice_detection()->Enable(true));
AudioProcessing::Config apm_config;
apm_config.echo_canceller.enabled =
(test_config_.aec_type != AecType::AecTurnedOff);
apm_config.echo_canceller.mobile_mode =
(test_config_.aec_type == AecType::BasicWebRtcAecSettingsWithAecMobile);
apm_->ApplyConfig(apm_config);
Config config; Config config;
config.Set<ExtendedFilter>( if (test_config_.aec_type == AecType::AecTurnedOff) {
new ExtendedFilter(test_config_.aec_type == ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false));
AecType::BasicWebRtcAecSettingsWithExtentedFilter)); ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
} else if (test_config_.aec_type ==
AecType::BasicWebRtcAecSettingsWithAecMobile) {
ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(true));
ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
} else {
ASSERT_EQ(apm_->kNoError, apm_->echo_control_mobile()->Enable(false));
ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
ASSERT_EQ(apm_->kNoError, apm_->echo_cancellation()->enable_metrics(true));
ASSERT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_delay_logging(true));
config.Set<DelayAgnostic>( config.Set<ExtendedFilter>(
new DelayAgnostic(test_config_.aec_type == new ExtendedFilter(test_config_.aec_type ==
AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec)); AecType::BasicWebRtcAecSettingsWithExtentedFilter));
apm_->SetExtraOptions(config); config.Set<DelayAgnostic>(
new DelayAgnostic(test_config_.aec_type ==
AecType::BasicWebRtcAecSettingsWithDelayAgnosticAec));
apm_->SetExtraOptions(config);
}
} }
void AudioProcessingImplLockTest::TearDown() { void AudioProcessingImplLockTest::TearDown() {
@ -577,15 +585,15 @@ StatsProcessor::StatsProcessor(RandomGenerator* rand_gen,
bool StatsProcessor::Process() { bool StatsProcessor::Process() {
SleepRandomMs(100, rand_gen_); SleepRandomMs(100, rand_gen_);
AudioProcessing::Config apm_config = apm_->GetConfig(); EXPECT_EQ(apm_->echo_cancellation()->is_enabled(),
if (test_config_->aec_type != AecType::AecTurnedOff) { ((test_config_->aec_type != AecType::AecTurnedOff) &&
EXPECT_TRUE(apm_config.echo_canceller.enabled); (test_config_->aec_type !=
EXPECT_EQ(apm_config.echo_canceller.mobile_mode, AecType::BasicWebRtcAecSettingsWithAecMobile)));
(test_config_->aec_type == apm_->echo_cancellation()->stream_drift_samples();
AecType::BasicWebRtcAecSettingsWithAecMobile)); EXPECT_EQ(apm_->echo_control_mobile()->is_enabled(),
} else { (test_config_->aec_type != AecType::AecTurnedOff) &&
EXPECT_FALSE(apm_config.echo_canceller.enabled); (test_config_->aec_type ==
} AecType::BasicWebRtcAecSettingsWithAecMobile));
EXPECT_TRUE(apm_->gain_control()->is_enabled()); EXPECT_TRUE(apm_->gain_control()->is_enabled());
EXPECT_TRUE(apm_->noise_suppression()->is_enabled()); EXPECT_TRUE(apm_->noise_suppression()->is_enabled());

View file

@ -452,10 +452,11 @@ class CallSimulator : public ::testing::TestWithParam<SimulationConfig> {
ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
AudioProcessing::Config apm_config = apm->GetConfig(); ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(false));
apm_config.echo_canceller.enabled = true; ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(true));
apm_config.echo_canceller.mobile_mode = false; ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->enable_metrics(true));
apm->ApplyConfig(apm_config); ASSERT_EQ(apm->kNoError,
apm->echo_cancellation()->enable_delay_logging(true));
}; };
// Lambda function for setting the default APM runtime settings for mobile. // Lambda function for setting the default APM runtime settings for mobile.
@ -467,10 +468,8 @@ class CallSimulator : public ::testing::TestWithParam<SimulationConfig> {
ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true)); ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(true));
ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true)); ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(true));
ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true)); ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(true));
AudioProcessing::Config apm_config = apm->GetConfig(); ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(true));
apm_config.echo_canceller.enabled = true; ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(false));
apm_config.echo_canceller.mobile_mode = true;
apm->ApplyConfig(apm_config);
}; };
// Lambda function for turning off all of the APM runtime settings // Lambda function for turning off all of the APM runtime settings
@ -483,9 +482,11 @@ class CallSimulator : public ::testing::TestWithParam<SimulationConfig> {
ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(false)); ASSERT_EQ(apm->kNoError, apm->gain_control()->Enable(false));
ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(false)); ASSERT_EQ(apm->kNoError, apm->noise_suppression()->Enable(false));
ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(false)); ASSERT_EQ(apm->kNoError, apm->voice_detection()->Enable(false));
AudioProcessing::Config apm_config = apm->GetConfig(); ASSERT_EQ(apm->kNoError, apm->echo_control_mobile()->Enable(false));
apm_config.echo_canceller.enabled = false; ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->Enable(false));
apm->ApplyConfig(apm_config); ASSERT_EQ(apm->kNoError, apm->echo_cancellation()->enable_metrics(false));
ASSERT_EQ(apm->kNoError,
apm->echo_cancellation()->enable_delay_logging(false));
}; };
// Lambda function for adding default desktop APM settings to a config. // Lambda function for adding default desktop APM settings to a config.

View file

@ -188,7 +188,11 @@ void EnableAllAPComponents(AudioProcessing* ap) {
EXPECT_NOERR(ap->gain_control()->Enable(true)); EXPECT_NOERR(ap->gain_control()->Enable(true));
#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE) #elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
apm_config.echo_canceller.mobile_mode = false; apm_config.echo_canceller.mobile_mode = false;
apm_config.echo_canceller.legacy_moderate_suppression_level = true; EXPECT_NOERR(ap->echo_cancellation()->enable_drift_compensation(true));
EXPECT_NOERR(ap->echo_cancellation()->enable_metrics(true));
EXPECT_NOERR(ap->echo_cancellation()->enable_delay_logging(true));
EXPECT_NOERR(ap->echo_cancellation()->set_suppression_level(
EchoCancellation::SuppressionLevel::kModerateSuppression));
EXPECT_NOERR(ap->gain_control()->set_mode(GainControl::kAdaptiveAnalog)); EXPECT_NOERR(ap->gain_control()->set_mode(GainControl::kAdaptiveAnalog));
EXPECT_NOERR(ap->gain_control()->set_analog_level_limits(0, 255)); EXPECT_NOERR(ap->gain_control()->set_analog_level_limits(0, 255));
@ -594,6 +598,7 @@ void ApmTest::ReadFrameWithRewind(FILE* file, AudioFrame* frame) {
void ApmTest::ProcessWithDefaultStreamParameters(AudioFrame* frame) { void ApmTest::ProcessWithDefaultStreamParameters(AudioFrame* frame) {
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0)); EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kNoError, EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_stream_analog_level(127)); apm_->gain_control()->set_stream_analog_level(127));
EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame)); EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame));
@ -678,8 +683,13 @@ void ApmTest::ProcessDelayVerificationTest(int delay_ms, int system_delay_ms,
delete frame; delete frame;
if (frame_count == 250) { if (frame_count == 250) {
int median;
int std;
float poor_fraction;
// Discard the first delay metrics to avoid convergence effects. // Discard the first delay metrics to avoid convergence effects.
static_cast<void>(apm_->GetStatistics(true /* has_remote_tracks */)); EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->GetDelayMetrics(&median, &std,
&poor_fraction));
} }
} }
@ -702,10 +712,12 @@ void ApmTest::ProcessDelayVerificationTest(int delay_ms, int system_delay_ms,
expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min, expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
delay_max); delay_max);
// Verify delay metrics. // Verify delay metrics.
AudioProcessingStats stats = int median;
apm_->GetStatistics(true /* has_remote_tracks */); int std;
ASSERT_TRUE(stats.delay_median_ms.has_value()); float poor_fraction;
int32_t median = *stats.delay_median_ms; EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->GetDelayMetrics(&median, &std,
&poor_fraction));
EXPECT_GE(expected_median_high, median); EXPECT_GE(expected_median_high, median);
EXPECT_LE(expected_median_low, median); EXPECT_LE(expected_median_low, median);
} }
@ -727,16 +739,19 @@ void ApmTest::StreamParametersTest(Format format) {
ProcessStreamChooser(format)); ProcessStreamChooser(format));
// Other stream parameters set correctly. // Other stream parameters set correctly.
AudioProcessing::Config apm_config = apm_->GetConfig(); EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
apm_config.echo_canceller.enabled = true; EXPECT_EQ(apm_->kNoError,
apm_config.echo_canceller.mobile_mode = false; apm_->echo_cancellation()->enable_drift_compensation(true));
apm_->ApplyConfig(apm_config);
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100)); EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kStreamParameterNotSetError, EXPECT_EQ(apm_->kStreamParameterNotSetError,
ProcessStreamChooser(format)); ProcessStreamChooser(format));
EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false)); EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_drift_compensation(false));
// -- Missing delay -- // -- Missing delay --
EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format)); EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
EXPECT_EQ(apm_->kStreamParameterNotSetError, EXPECT_EQ(apm_->kStreamParameterNotSetError,
ProcessStreamChooser(format)); ProcessStreamChooser(format));
@ -749,12 +764,34 @@ void ApmTest::StreamParametersTest(Format format) {
// Other stream parameters set correctly. // Other stream parameters set correctly.
EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true)); EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_drift_compensation(true));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kNoError, EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_stream_analog_level(127)); apm_->gain_control()->set_stream_analog_level(127));
EXPECT_EQ(apm_->kStreamParameterNotSetError, EXPECT_EQ(apm_->kStreamParameterNotSetError,
ProcessStreamChooser(format)); ProcessStreamChooser(format));
EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false)); EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(false));
// -- Missing drift --
EXPECT_EQ(apm_->kStreamParameterNotSetError,
ProcessStreamChooser(format));
// Resets after successful ProcessStream().
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
EXPECT_EQ(apm_->kStreamParameterNotSetError,
ProcessStreamChooser(format));
// Other stream parameters set correctly.
EXPECT_EQ(apm_->kNoError, apm_->gain_control()->Enable(true));
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_stream_analog_level(127));
EXPECT_EQ(apm_->kStreamParameterNotSetError,
ProcessStreamChooser(format));
// -- No stream parameters -- // -- No stream parameters --
EXPECT_EQ(apm_->kNoError, EXPECT_EQ(apm_->kNoError,
AnalyzeReverseStreamChooser(format)); AnalyzeReverseStreamChooser(format));
@ -763,6 +800,7 @@ void ApmTest::StreamParametersTest(Format format) {
// -- All there -- // -- All there --
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100)); EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kNoError, EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_stream_analog_level(127)); apm_->gain_control()->set_stream_analog_level(127));
EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format)); EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
@ -886,13 +924,79 @@ TEST_F(ApmTest, SampleRatesInt) {
} }
} }
TEST_F(ApmTest, EchoCancellation) {
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_drift_compensation(true));
EXPECT_TRUE(apm_->echo_cancellation()->is_drift_compensation_enabled());
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_drift_compensation(false));
EXPECT_FALSE(apm_->echo_cancellation()->is_drift_compensation_enabled());
EchoCancellation::SuppressionLevel level[] = {
EchoCancellation::kLowSuppression,
EchoCancellation::kModerateSuppression,
EchoCancellation::kHighSuppression,
};
for (size_t i = 0; i < arraysize(level); i++) {
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->set_suppression_level(level[i]));
EXPECT_EQ(level[i],
apm_->echo_cancellation()->suppression_level());
}
EchoCancellation::Metrics metrics;
EXPECT_EQ(apm_->kNotEnabledError,
apm_->echo_cancellation()->GetMetrics(&metrics));
EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
EXPECT_TRUE(apm_->echo_cancellation()->is_enabled());
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_metrics(true));
EXPECT_TRUE(apm_->echo_cancellation()->are_metrics_enabled());
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_metrics(false));
EXPECT_FALSE(apm_->echo_cancellation()->are_metrics_enabled());
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_delay_logging(true));
EXPECT_TRUE(apm_->echo_cancellation()->is_delay_logging_enabled());
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_delay_logging(false));
EXPECT_FALSE(apm_->echo_cancellation()->is_delay_logging_enabled());
EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
int median = 0;
int std = 0;
float poor_fraction = 0;
EXPECT_EQ(apm_->kNotEnabledError, apm_->echo_cancellation()->GetDelayMetrics(
&median, &std, &poor_fraction));
EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
EXPECT_TRUE(apm_->echo_cancellation()->is_enabled());
EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
EXPECT_TRUE(apm_->echo_cancellation()->is_enabled());
EXPECT_TRUE(apm_->echo_cancellation()->aec_core() != NULL);
EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(false));
EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
EXPECT_FALSE(apm_->echo_cancellation()->aec_core() != NULL);
}
TEST_F(ApmTest, DISABLED_EchoCancellationReportsCorrectDelays) { TEST_F(ApmTest, DISABLED_EchoCancellationReportsCorrectDelays) {
// TODO(bjornv): Fix this test to work with DA-AEC. // TODO(bjornv): Fix this test to work with DA-AEC.
// Enable AEC only. // Enable AEC only.
AudioProcessing::Config apm_config = apm_->GetConfig(); EXPECT_EQ(apm_->kNoError,
apm_config.echo_canceller.enabled = true; apm_->echo_cancellation()->enable_drift_compensation(false));
apm_config.echo_canceller.mobile_mode = false; EXPECT_EQ(apm_->kNoError,
apm_->ApplyConfig(apm_config); apm_->echo_cancellation()->enable_metrics(false));
EXPECT_EQ(apm_->kNoError,
apm_->echo_cancellation()->enable_delay_logging(true));
EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
Config config; Config config;
config.Set<DelayAgnostic>(new DelayAgnostic(false)); config.Set<DelayAgnostic>(new DelayAgnostic(false));
apm_->SetExtraOptions(config); apm_->SetExtraOptions(config);
@ -1360,9 +1464,8 @@ TEST_F(ApmTest, VoiceDetection) {
} }
TEST_F(ApmTest, AllProcessingDisabledByDefault) { TEST_F(ApmTest, AllProcessingDisabledByDefault) {
AudioProcessing::Config config = apm_->GetConfig(); EXPECT_FALSE(apm_->echo_cancellation()->is_enabled());
EXPECT_FALSE(config.echo_canceller.enabled); EXPECT_FALSE(apm_->echo_control_mobile()->is_enabled());
EXPECT_FALSE(config.high_pass_filter.enabled);
EXPECT_FALSE(apm_->gain_control()->is_enabled()); EXPECT_FALSE(apm_->gain_control()->is_enabled());
EXPECT_FALSE(apm_->high_pass_filter()->is_enabled()); EXPECT_FALSE(apm_->high_pass_filter()->is_enabled());
EXPECT_FALSE(apm_->level_estimator()->is_enabled()); EXPECT_FALSE(apm_->level_estimator()->is_enabled());
@ -1445,6 +1548,7 @@ TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
frame_->vad_activity_ = AudioFrame::kVadUnknown; frame_->vad_activity_ = AudioFrame::kVadUnknown;
ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0)); ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
apm_->echo_cancellation()->set_stream_drift_samples(0);
ASSERT_EQ(kNoErr, ASSERT_EQ(kNoErr,
apm_->gain_control()->set_stream_analog_level(analog_level)); apm_->gain_control()->set_stream_analog_level(analog_level));
ASSERT_EQ(kNoErr, apm_->ProcessStream(frame_)); ASSERT_EQ(kNoErr, apm_->ProcessStream(frame_));
@ -1504,10 +1608,7 @@ TEST_F(ApmTest, SplittingFilter) {
// first few frames of data being unaffected by the AEC. // first few frames of data being unaffected by the AEC.
// TODO(andrew): This test, and the one below, rely rather tenuously on the // TODO(andrew): This test, and the one below, rely rather tenuously on the
// behavior of the AEC. Think of something more robust. // behavior of the AEC. Think of something more robust.
AudioProcessing::Config apm_config = apm_->GetConfig(); EXPECT_EQ(apm_->kNoError, apm_->echo_cancellation()->Enable(true));
apm_config.echo_canceller.enabled = true;
apm_config.echo_canceller.mobile_mode = false;
apm_->ApplyConfig(apm_config);
// Make sure we have extended filter enabled. This makes sure nothing is // Make sure we have extended filter enabled. This makes sure nothing is
// touched until we have a farend frame. // touched until we have a farend frame.
Config config; Config config;
@ -1516,8 +1617,10 @@ TEST_F(ApmTest, SplittingFilter) {
SetFrameTo(frame_, 1000); SetFrameTo(frame_, 1000);
frame_copy.CopyFrom(*frame_); frame_copy.CopyFrom(*frame_);
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0)); EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0)); EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy)); EXPECT_TRUE(FrameDataAreEqual(*frame_, frame_copy));
@ -1529,6 +1632,7 @@ TEST_F(ApmTest, SplittingFilter) {
SetFrameTo(frame_, 1000); SetFrameTo(frame_, 1000);
frame_copy.CopyFrom(*frame_); frame_copy.CopyFrom(*frame_);
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0)); EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_)); EXPECT_EQ(apm_->kNoError, apm_->ProcessStream(frame_));
EXPECT_FALSE(FrameDataAreEqual(*frame_, frame_copy)); EXPECT_FALSE(FrameDataAreEqual(*frame_, frame_copy));
} }
@ -1600,6 +1704,7 @@ void ApmTest::ProcessDebugDump(const std::string& in_filename,
EXPECT_NOERR(apm_->gain_control()->set_stream_analog_level(msg.level())); EXPECT_NOERR(apm_->gain_control()->set_stream_analog_level(msg.level()));
EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay())); EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
apm_->echo_cancellation()->set_stream_drift_samples(msg.drift());
if (msg.has_keypress()) { if (msg.has_keypress()) {
apm_->set_stream_key_pressed(msg.keypress()); apm_->set_stream_key_pressed(msg.keypress());
} else { } else {
@ -1820,6 +1925,8 @@ TEST_F(ApmTest, FloatAndIntInterfacesGiveSimilarResults) {
EXPECT_NOERR(apm_->set_stream_delay_ms(0)); EXPECT_NOERR(apm_->set_stream_delay_ms(0));
EXPECT_NOERR(fapm->set_stream_delay_ms(0)); EXPECT_NOERR(fapm->set_stream_delay_ms(0));
apm_->echo_cancellation()->set_stream_drift_samples(0);
fapm->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_NOERR(apm_->gain_control()->set_stream_analog_level(analog_level)); EXPECT_NOERR(apm_->gain_control()->set_stream_analog_level(analog_level));
EXPECT_NOERR(fapm->gain_control()->set_stream_analog_level(analog_level)); EXPECT_NOERR(fapm->gain_control()->set_stream_analog_level(analog_level));
@ -1856,6 +1963,8 @@ TEST_F(ApmTest, FloatAndIntInterfacesGiveSimilarResults) {
analog_level = fapm->gain_control()->stream_analog_level(); analog_level = fapm->gain_control()->stream_analog_level();
EXPECT_EQ(apm_->gain_control()->stream_analog_level(), EXPECT_EQ(apm_->gain_control()->stream_analog_level(),
fapm->gain_control()->stream_analog_level()); fapm->gain_control()->stream_analog_level());
EXPECT_EQ(apm_->echo_cancellation()->stream_has_echo(),
fapm->echo_cancellation()->stream_has_echo());
EXPECT_NEAR(apm_->noise_suppression()->speech_probability(), EXPECT_NEAR(apm_->noise_suppression()->speech_probability(),
fapm->noise_suppression()->speech_probability(), fapm->noise_suppression()->speech_probability(),
0.01); 0.01);
@ -1955,6 +2064,7 @@ TEST_F(ApmTest, Process) {
frame_->vad_activity_ = AudioFrame::kVadUnknown; frame_->vad_activity_ = AudioFrame::kVadUnknown;
EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0)); EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
apm_->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_EQ(apm_->kNoError, EXPECT_EQ(apm_->kNoError,
apm_->gain_control()->set_stream_analog_level(analog_level)); apm_->gain_control()->set_stream_analog_level(analog_level));
@ -2325,6 +2435,7 @@ class AudioProcessingTest
processing_config.reverse_output_stream(), rev_out_cb.channels())); processing_config.reverse_output_stream(), rev_out_cb.channels()));
EXPECT_NOERR(ap->set_stream_delay_ms(0)); EXPECT_NOERR(ap->set_stream_delay_ms(0));
ap->echo_cancellation()->set_stream_drift_samples(0);
EXPECT_NOERR(ap->gain_control()->set_stream_analog_level(analog_level)); EXPECT_NOERR(ap->gain_control()->set_stream_analog_level(analog_level));
EXPECT_NOERR(ap->ProcessStream( EXPECT_NOERR(ap->ProcessStream(
@ -2783,17 +2894,25 @@ std::unique_ptr<AudioProcessing> CreateApm(bool use_AEC2) {
} }
// Disable all components except for an AEC and the residual echo detector. // Disable all components except for an AEC and the residual echo detector.
AudioProcessing::Config apm_config; AudioProcessing::Config config;
apm_config.residual_echo_detector.enabled = true; config.residual_echo_detector.enabled = true;
apm_config.high_pass_filter.enabled = false; config.high_pass_filter.enabled = false;
apm_config.gain_controller2.enabled = false; config.gain_controller2.enabled = false;
apm_config.echo_canceller.enabled = true; apm->ApplyConfig(config);
apm_config.echo_canceller.mobile_mode = !use_AEC2;
apm->ApplyConfig(apm_config);
EXPECT_EQ(apm->gain_control()->Enable(false), 0); EXPECT_EQ(apm->gain_control()->Enable(false), 0);
EXPECT_EQ(apm->level_estimator()->Enable(false), 0); EXPECT_EQ(apm->level_estimator()->Enable(false), 0);
EXPECT_EQ(apm->noise_suppression()->Enable(false), 0); EXPECT_EQ(apm->noise_suppression()->Enable(false), 0);
EXPECT_EQ(apm->voice_detection()->Enable(false), 0); EXPECT_EQ(apm->voice_detection()->Enable(false), 0);
if (use_AEC2) {
EXPECT_EQ(apm->echo_control_mobile()->Enable(false), 0);
EXPECT_EQ(apm->echo_cancellation()->enable_metrics(true), 0);
EXPECT_EQ(apm->echo_cancellation()->enable_delay_logging(true), 0);
EXPECT_EQ(apm->echo_cancellation()->Enable(true), 0);
} else {
EXPECT_EQ(apm->echo_cancellation()->Enable(false), 0);
EXPECT_EQ(apm->echo_control_mobile()->Enable(true), 0);
}
return apm; return apm;
} }

View file

@ -26,9 +26,10 @@ void SetupComponent(int sample_rate_hz,
bool drift_compensation_enabled, bool drift_compensation_enabled,
EchoCancellationImpl* echo_canceller) { EchoCancellationImpl* echo_canceller) {
echo_canceller->Initialize(sample_rate_hz, 1, 1, 1); echo_canceller->Initialize(sample_rate_hz, 1, 1, 1);
echo_canceller->Enable(true); EchoCancellation* ec = static_cast<EchoCancellation*>(echo_canceller);
echo_canceller->set_suppression_level(suppression_level); ec->Enable(true);
echo_canceller->enable_drift_compensation(drift_compensation_enabled); ec->set_suppression_level(suppression_level);
ec->enable_drift_compensation(drift_compensation_enabled);
Config config; Config config;
config.Set<DelayAgnostic>(new DelayAgnostic(true)); config.Set<DelayAgnostic>(new DelayAgnostic(true));
@ -55,7 +56,8 @@ void ProcessOneFrame(int sample_rate_hz,
echo_canceller->ProcessRenderAudio(render_audio); echo_canceller->ProcessRenderAudio(render_audio);
if (drift_compensation_enabled) { if (drift_compensation_enabled) {
echo_canceller->set_stream_drift_samples(stream_drift_samples); static_cast<EchoCancellation*>(echo_canceller)
->set_stream_drift_samples(stream_drift_samples);
} }
echo_canceller->ProcessCaptureAudio(capture_audio_buffer, stream_delay_ms); echo_canceller->ProcessCaptureAudio(capture_audio_buffer, stream_delay_ms);
@ -116,7 +118,8 @@ void RunBitexactnessTest(int sample_rate_hz,
test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer, test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer,
&capture_output); &capture_output);
EXPECT_EQ(stream_has_echo_reference, echo_canceller.stream_has_echo()); EXPECT_EQ(stream_has_echo_reference,
static_cast<EchoCancellation*>(&echo_canceller)->stream_has_echo());
// Compare the output with the reference. Only the first values of the output // Compare the output with the reference. Only the first values of the output
// from last frame processed are compared in order not having to specify all // from last frame processed are compared in order not having to specify all

View file

@ -108,12 +108,12 @@ EchoCancellationImpl::EchoCancellationImpl(rtc::CriticalSection* crit_render,
: crit_render_(crit_render), : crit_render_(crit_render),
crit_capture_(crit_capture), crit_capture_(crit_capture),
drift_compensation_enabled_(false), drift_compensation_enabled_(false),
metrics_enabled_(true), metrics_enabled_(false),
suppression_level_(kHighSuppression), suppression_level_(kHighSuppression),
stream_drift_samples_(0), stream_drift_samples_(0),
was_stream_drift_set_(false), was_stream_drift_set_(false),
stream_has_echo_(false), stream_has_echo_(false),
delay_logging_enabled_(true), delay_logging_enabled_(false),
extended_filter_enabled_(false), extended_filter_enabled_(false),
delay_agnostic_enabled_(false), delay_agnostic_enabled_(false),
enforce_zero_stream_delay_(EnforceZeroStreamDelay()) { enforce_zero_stream_delay_(EnforceZeroStreamDelay()) {

View file

@ -22,7 +22,7 @@ namespace webrtc {
class AudioBuffer; class AudioBuffer;
class EchoCancellationImpl : EchoCancellation { class EchoCancellationImpl : public EchoCancellation {
public: public:
EchoCancellationImpl(rtc::CriticalSection* crit_render, EchoCancellationImpl(rtc::CriticalSection* crit_render,
rtc::CriticalSection* crit_capture); rtc::CriticalSection* crit_capture);
@ -32,29 +32,10 @@ class EchoCancellationImpl : EchoCancellation {
int ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms); int ProcessCaptureAudio(AudioBuffer* audio, int stream_delay_ms);
// EchoCancellation implementation. // EchoCancellation implementation.
int Enable(bool enable) override;
bool is_enabled() const override; bool is_enabled() const override;
int enable_drift_compensation(bool enable) override;
bool is_drift_compensation_enabled() const override;
void set_stream_drift_samples(int drift) override;
int stream_drift_samples() const override; int stream_drift_samples() const override;
int set_suppression_level(SuppressionLevel level) override;
SuppressionLevel suppression_level() const override; SuppressionLevel suppression_level() const override;
bool stream_has_echo() const override; bool is_drift_compensation_enabled() const override;
// Enable logging of various AEC statistics.
int enable_metrics(bool enable) override;
bool are_metrics_enabled() const override;
// Provides various statistics about the AEC.
int GetMetrics(Metrics* metrics) override;
// Enable logging of delay metrics.
int enable_delay_logging(bool enable) override;
bool is_delay_logging_enabled() const override;
// Provides delay metrics.
int GetDelayMetrics(int* median, int* std) override;
int GetDelayMetrics(int* median,
int* std,
float* fraction_poor_delays) override;
struct AecCore* aec_core() const override;
void Initialize(int sample_rate_hz, void Initialize(int sample_rate_hz,
size_t num_reverse_channels_, size_t num_reverse_channels_,
@ -76,10 +57,36 @@ class EchoCancellationImpl : EchoCancellation {
static size_t NumCancellersRequired(size_t num_output_channels, static size_t NumCancellersRequired(size_t num_output_channels,
size_t num_reverse_channels); size_t num_reverse_channels);
// Enable logging of various AEC statistics.
int enable_metrics(bool enable) override;
// Provides various statistics about the AEC.
int GetMetrics(Metrics* metrics) override;
// Enable logging of delay metrics.
int enable_delay_logging(bool enable) override;
// Provides delay metrics.
int GetDelayMetrics(int* median,
int* std,
float* fraction_poor_delays) override;
private: private:
class Canceller; class Canceller;
struct StreamProperties; struct StreamProperties;
// EchoCancellation implementation.
int Enable(bool enable) override;
int enable_drift_compensation(bool enable) override;
void set_stream_drift_samples(int drift) override;
int set_suppression_level(SuppressionLevel level) override;
bool are_metrics_enabled() const override;
bool stream_has_echo() const override;
bool is_delay_logging_enabled() const override;
int GetDelayMetrics(int* median, int* std) override;
struct AecCore* aec_core() const override;
void AllocateRenderQueue(); void AllocateRenderQueue();
int Configure(); int Configure();

View file

@ -11,136 +11,69 @@
#include <memory> #include <memory>
#include "modules/audio_processing/aec/aec_core.h" #include "modules/audio_processing/aec/aec_core.h"
#include "modules/audio_processing/echo_cancellation_impl.h"
#include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/include/audio_processing.h"
#include "rtc_base/criticalsection.h"
#include "test/gtest.h" #include "test/gtest.h"
namespace webrtc { namespace webrtc {
TEST(EchoCancellationInternalTest, ExtendedFilter) { TEST(EchoCancellationInternalTest, ExtendedFilter) {
rtc::CriticalSection crit_render; std::unique_ptr<AudioProcessing> ap(AudioProcessingBuilder().Create());
rtc::CriticalSection crit_capture; EXPECT_TRUE(ap->echo_cancellation()->aec_core() == NULL);
EchoCancellationImpl echo_canceller(&crit_render, &crit_capture);
echo_canceller.Initialize(AudioProcessing::kSampleRate32kHz, 2, 2, 2);
EXPECT_TRUE(echo_canceller.aec_core() == nullptr); EXPECT_EQ(ap->kNoError, ap->echo_cancellation()->Enable(true));
EXPECT_TRUE(ap->echo_cancellation()->is_enabled());
echo_canceller.Enable(true); AecCore* aec_core = ap->echo_cancellation()->aec_core();
AecCore* aec_core = echo_canceller.aec_core();
ASSERT_TRUE(aec_core != NULL); ASSERT_TRUE(aec_core != NULL);
// Disabled by default. // Disabled by default.
EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core)); EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core));
Config config; Config config;
config.Set<ExtendedFilter>(new ExtendedFilter(true)); config.Set<ExtendedFilter>(new ExtendedFilter(true));
echo_canceller.SetExtraOptions(config); ap->SetExtraOptions(config);
EXPECT_EQ(1, WebRtcAec_extended_filter_enabled(aec_core)); EXPECT_EQ(1, WebRtcAec_extended_filter_enabled(aec_core));
// Retains setting after initialization. // Retains setting after initialization.
echo_canceller.Initialize(AudioProcessing::kSampleRate16kHz, 2, 2, 2); EXPECT_EQ(ap->kNoError, ap->Initialize());
EXPECT_EQ(1, WebRtcAec_extended_filter_enabled(aec_core)); EXPECT_EQ(1, WebRtcAec_extended_filter_enabled(aec_core));
config.Set<ExtendedFilter>(new ExtendedFilter(false)); config.Set<ExtendedFilter>(new ExtendedFilter(false));
echo_canceller.SetExtraOptions(config); ap->SetExtraOptions(config);
EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core)); EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core));
// Retains setting after initialization. // Retains setting after initialization.
echo_canceller.Initialize(AudioProcessing::kSampleRate16kHz, 1, 1, 1); EXPECT_EQ(ap->kNoError, ap->Initialize());
EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core)); EXPECT_EQ(0, WebRtcAec_extended_filter_enabled(aec_core));
} }
TEST(EchoCancellationInternalTest, DelayAgnostic) { TEST(EchoCancellationInternalTest, DelayAgnostic) {
rtc::CriticalSection crit_render; std::unique_ptr<AudioProcessing> ap(AudioProcessingBuilder().Create());
rtc::CriticalSection crit_capture; EXPECT_TRUE(ap->echo_cancellation()->aec_core() == NULL);
EchoCancellationImpl echo_canceller(&crit_render, &crit_capture);
echo_canceller.Initialize(AudioProcessing::kSampleRate32kHz, 1, 1, 1);
EXPECT_TRUE(echo_canceller.aec_core() == NULL); EXPECT_EQ(ap->kNoError, ap->echo_cancellation()->Enable(true));
EXPECT_TRUE(ap->echo_cancellation()->is_enabled());
EXPECT_EQ(0, echo_canceller.Enable(true)); AecCore* aec_core = ap->echo_cancellation()->aec_core();
EXPECT_TRUE(echo_canceller.is_enabled());
AecCore* aec_core = echo_canceller.aec_core();
ASSERT_TRUE(aec_core != NULL); ASSERT_TRUE(aec_core != NULL);
// Enabled by default. // Enabled by default.
EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core)); EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core));
Config config; Config config;
config.Set<DelayAgnostic>(new DelayAgnostic(true)); config.Set<DelayAgnostic>(new DelayAgnostic(true));
echo_canceller.SetExtraOptions(config); ap->SetExtraOptions(config);
EXPECT_EQ(1, WebRtcAec_delay_agnostic_enabled(aec_core)); EXPECT_EQ(1, WebRtcAec_delay_agnostic_enabled(aec_core));
// Retains setting after initialization. // Retains setting after initialization.
echo_canceller.Initialize(AudioProcessing::kSampleRate32kHz, 2, 2, 2); EXPECT_EQ(ap->kNoError, ap->Initialize());
EXPECT_EQ(1, WebRtcAec_delay_agnostic_enabled(aec_core)); EXPECT_EQ(1, WebRtcAec_delay_agnostic_enabled(aec_core));
config.Set<DelayAgnostic>(new DelayAgnostic(false)); config.Set<DelayAgnostic>(new DelayAgnostic(false));
echo_canceller.SetExtraOptions(config); ap->SetExtraOptions(config);
EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core)); EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core));
// Retains setting after initialization. // Retains setting after initialization.
echo_canceller.Initialize(AudioProcessing::kSampleRate16kHz, 2, 2, 2); EXPECT_EQ(ap->kNoError, ap->Initialize());
EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core)); EXPECT_EQ(0, WebRtcAec_delay_agnostic_enabled(aec_core));
} }
TEST(EchoCancellationInternalTest, InterfaceConfiguration) {
rtc::CriticalSection crit_render;
rtc::CriticalSection crit_capture;
EchoCancellationImpl echo_canceller(&crit_render, &crit_capture);
echo_canceller.Initialize(AudioProcessing::kSampleRate16kHz, 1, 1, 1);
EXPECT_EQ(0, echo_canceller.enable_drift_compensation(true));
EXPECT_TRUE(echo_canceller.is_drift_compensation_enabled());
EXPECT_EQ(0, echo_canceller.enable_drift_compensation(false));
EXPECT_FALSE(echo_canceller.is_drift_compensation_enabled());
EchoCancellation::SuppressionLevel level[] = {
EchoCancellation::kLowSuppression, EchoCancellation::kModerateSuppression,
EchoCancellation::kHighSuppression,
};
for (size_t i = 0; i < arraysize(level); i++) {
EXPECT_EQ(0, echo_canceller.set_suppression_level(level[i]));
EXPECT_EQ(level[i], echo_canceller.suppression_level());
}
EchoCancellation::Metrics metrics;
EXPECT_EQ(AudioProcessing::kNotEnabledError,
echo_canceller.GetMetrics(&metrics));
EXPECT_EQ(0, echo_canceller.Enable(true));
EXPECT_TRUE(echo_canceller.is_enabled());
EXPECT_EQ(0, echo_canceller.enable_metrics(true));
EXPECT_TRUE(echo_canceller.are_metrics_enabled());
EXPECT_EQ(0, echo_canceller.enable_metrics(false));
EXPECT_FALSE(echo_canceller.are_metrics_enabled());
EXPECT_EQ(0, echo_canceller.enable_delay_logging(true));
EXPECT_TRUE(echo_canceller.is_delay_logging_enabled());
EXPECT_EQ(0, echo_canceller.enable_delay_logging(false));
EXPECT_FALSE(echo_canceller.is_delay_logging_enabled());
EXPECT_EQ(0, echo_canceller.Enable(false));
EXPECT_FALSE(echo_canceller.is_enabled());
int median = 0;
int std = 0;
float poor_fraction = 0;
EXPECT_EQ(AudioProcessing::kNotEnabledError,
echo_canceller.GetDelayMetrics(&median, &std, &poor_fraction));
EXPECT_EQ(0, echo_canceller.Enable(true));
EXPECT_TRUE(echo_canceller.is_enabled());
EXPECT_EQ(0, echo_canceller.Enable(false));
EXPECT_FALSE(echo_canceller.is_enabled());
EXPECT_EQ(0, echo_canceller.Enable(true));
EXPECT_TRUE(echo_canceller.is_enabled());
EXPECT_TRUE(echo_canceller.aec_core() != NULL);
EXPECT_EQ(0, echo_canceller.Enable(false));
EXPECT_FALSE(echo_canceller.is_enabled());
EXPECT_FALSE(echo_canceller.aec_core() != NULL);
}
} // namespace webrtc } // namespace webrtc

View file

@ -10,13 +10,11 @@
#include "modules/audio_processing/echo_cancellation_proxy.h" #include "modules/audio_processing/echo_cancellation_proxy.h"
#include "rtc_base/logging.h"
namespace webrtc { namespace webrtc {
EchoCancellationProxy::EchoCancellationProxy( EchoCancellationProxy::EchoCancellationProxy(
AudioProcessing* audio_processing, AudioProcessing* audio_processing,
EchoCancellationImpl* echo_cancellation) EchoCancellation* echo_cancellation)
: audio_processing_(audio_processing), : audio_processing_(audio_processing),
echo_cancellation_(echo_cancellation) {} echo_cancellation_(echo_cancellation) {}
@ -24,6 +22,8 @@ EchoCancellationProxy::~EchoCancellationProxy() = default;
int EchoCancellationProxy::Enable(bool enable) { int EchoCancellationProxy::Enable(bool enable) {
// Change the config in APM to mirror the applied settings. // Change the config in APM to mirror the applied settings.
// TODO(bugs.webrtc.org/9535): Remove the call to EchoCancellation::Enable
// when APM starts taking the config into account.
AudioProcessing::Config apm_config = audio_processing_->GetConfig(); AudioProcessing::Config apm_config = audio_processing_->GetConfig();
bool aec2_enabled = apm_config.echo_canceller.enabled && bool aec2_enabled = apm_config.echo_canceller.enabled &&
!apm_config.echo_canceller.mobile_mode; !apm_config.echo_canceller.mobile_mode;
@ -32,6 +32,7 @@ int EchoCancellationProxy::Enable(bool enable) {
apm_config.echo_canceller.mobile_mode = false; apm_config.echo_canceller.mobile_mode = false;
audio_processing_->ApplyConfig(apm_config); audio_processing_->ApplyConfig(apm_config);
} }
echo_cancellation_->Enable(enable);
return AudioProcessing::kNoError; return AudioProcessing::kNoError;
} }
@ -57,15 +58,7 @@ int EchoCancellationProxy::stream_drift_samples() const {
int EchoCancellationProxy::set_suppression_level( int EchoCancellationProxy::set_suppression_level(
EchoCancellation::SuppressionLevel level) { EchoCancellation::SuppressionLevel level) {
if (level == EchoCancellation::SuppressionLevel::kLowSuppression) { return echo_cancellation_->set_suppression_level(level);
RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AEC2 low suppression";
return AudioProcessing::kBadParameterError;
}
AudioProcessing::Config apm_config = audio_processing_->GetConfig();
apm_config.echo_canceller.legacy_moderate_suppression_level =
(level == EchoCancellation::SuppressionLevel::kModerateSuppression);
audio_processing_->ApplyConfig(apm_config);
return AudioProcessing::kNoError;
} }
EchoCancellation::SuppressionLevel EchoCancellationProxy::suppression_level() EchoCancellation::SuppressionLevel EchoCancellationProxy::suppression_level()

View file

@ -11,7 +11,6 @@
#ifndef MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_PROXY_H_ #ifndef MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_PROXY_H_
#define MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_PROXY_H_ #define MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_PROXY_H_
#include "modules/audio_processing/echo_cancellation_impl.h"
#include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/include/audio_processing.h"
#include "rtc_base/constructormagic.h" #include "rtc_base/constructormagic.h"
#include "rtc_base/scoped_ref_ptr.h" #include "rtc_base/scoped_ref_ptr.h"
@ -22,7 +21,7 @@ namespace webrtc {
class EchoCancellationProxy : public EchoCancellation { class EchoCancellationProxy : public EchoCancellation {
public: public:
EchoCancellationProxy(AudioProcessing* audio_processing, EchoCancellationProxy(AudioProcessing* audio_processing,
EchoCancellationImpl* echo_cancellation); EchoCancellation* echo_cancellation);
~EchoCancellationProxy() override; ~EchoCancellationProxy() override;
int Enable(bool enable) override; int Enable(bool enable) override;
@ -47,7 +46,7 @@ class EchoCancellationProxy : public EchoCancellation {
private: private:
AudioProcessing* audio_processing_; AudioProcessing* audio_processing_;
EchoCancellationImpl* echo_cancellation_; EchoCancellation* echo_cancellation_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EchoCancellationProxy); RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EchoCancellationProxy);
}; };

View file

@ -193,12 +193,13 @@ struct ExperimentalNs {
// AudioProcessing* apm = AudioProcessingBuilder().Create(); // AudioProcessing* apm = AudioProcessingBuilder().Create();
// //
// AudioProcessing::Config config; // AudioProcessing::Config config;
// config.echo_canceller.enabled = true;
// config.echo_canceller.mobile_mode = false;
// config.high_pass_filter.enabled = true; // config.high_pass_filter.enabled = true;
// config.gain_controller2.enabled = true; // config.gain_controller2.enabled = true;
// apm->ApplyConfig(config) // apm->ApplyConfig(config)
// //
// apm->echo_cancellation()->enable_drift_compensation(false);
// apm->echo_cancellation()->Enable(true);
//
// apm->noise_reduction()->set_level(kHighSuppression); // apm->noise_reduction()->set_level(kHighSuppression);
// apm->noise_reduction()->Enable(true); // apm->noise_reduction()->Enable(true);
// //

View file

@ -15,7 +15,6 @@
#include "modules/audio_processing/test/protobuf_utils.h" #include "modules/audio_processing/test/protobuf_utils.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/numerics/safe_conversions.h"
namespace webrtc { namespace webrtc {
@ -147,6 +146,15 @@ void AecDumpBasedSimulator::PrepareProcessStreamCall(
} }
} }
if (!settings_.stream_drift_samples) {
if (msg.has_drift()) {
ap_->echo_cancellation()->set_stream_drift_samples(msg.drift());
}
} else {
ap_->echo_cancellation()->set_stream_drift_samples(
*settings_.stream_drift_samples);
}
if (!settings_.use_ts) { if (!settings_.use_ts) {
if (msg.has_keypress()) { if (msg.has_keypress()) {
ap_->set_stream_key_pressed(msg.keypress()); ap_->set_stream_key_pressed(msg.keypress());
@ -298,11 +306,14 @@ void AecDumpBasedSimulator::HandleMessage(
if (msg.has_aec_drift_compensation_enabled() || if (msg.has_aec_drift_compensation_enabled() ||
settings_.use_drift_compensation) { settings_.use_drift_compensation) {
if (settings_.use_drift_compensation bool enable = settings_.use_drift_compensation
? *settings_.use_drift_compensation ? *settings_.use_drift_compensation
: msg.aec_drift_compensation_enabled()) { : msg.aec_drift_compensation_enabled();
RTC_LOG(LS_ERROR) RTC_CHECK_EQ(AudioProcessing::kNoError,
<< "Ignoring deprecated setting: AEC2 drift compensation"; ap_->echo_cancellation()->enable_drift_compensation(enable));
if (settings_.use_verbose_logging) {
std::cout << " aec_drift_compensation_enabled: "
<< (enable ? "true" : "false") << std::endl;
} }
} }
@ -319,20 +330,15 @@ void AecDumpBasedSimulator::HandleMessage(
} }
if (msg.has_aec_suppression_level() || settings_.aec_suppression_level) { if (msg.has_aec_suppression_level() || settings_.aec_suppression_level) {
auto level = static_cast<webrtc::EchoCancellation::SuppressionLevel>( int level = settings_.aec_suppression_level
settings_.aec_suppression_level ? *settings_.aec_suppression_level ? *settings_.aec_suppression_level
: msg.aec_suppression_level()); : msg.aec_suppression_level();
if (level == RTC_CHECK_EQ(
webrtc::EchoCancellation::SuppressionLevel::kLowSuppression) { AudioProcessing::kNoError,
RTC_LOG(LS_ERROR) ap_->echo_cancellation()->set_suppression_level(
<< "Ignoring deprecated setting: AEC2 low suppression"; static_cast<webrtc::EchoCancellation::SuppressionLevel>(level)));
} else { if (settings_.use_verbose_logging) {
apm_config.echo_canceller.legacy_moderate_suppression_level = std::cout << " aec_suppression_level: " << level << std::endl;
(level ==
webrtc::EchoCancellation::SuppressionLevel::kModerateSuppression);
if (settings_.use_verbose_logging) {
std::cout << " aec_suppression_level: " << level << std::endl;
}
} }
} }

View file

@ -705,13 +705,6 @@ void AudioProcessingSimulator::CreateAudioProcessor() {
settings_.pre_amplifier_gain_factor; settings_.pre_amplifier_gain_factor;
} }
bool use_aec2 = settings_.use_aec && *settings_.use_aec;
bool use_aec3 = settings_.use_aec3 && *settings_.use_aec3;
bool use_aecm = settings_.use_aecm && *settings_.use_aecm;
if (use_aec2 || use_aec3 || use_aecm) {
apm_config.echo_canceller.enabled = true;
apm_config.echo_canceller.mobile_mode = use_aecm;
}
if (settings_.use_aec3 && *settings_.use_aec3) { if (settings_.use_aec3 && *settings_.use_aec3) {
EchoCanceller3Config cfg; EchoCanceller3Config cfg;
if (settings_.aec3_settings_filename) { if (settings_.aec3_settings_filename) {
@ -720,21 +713,6 @@ void AudioProcessingSimulator::CreateAudioProcessor() {
} }
echo_control_factory.reset(new EchoCanceller3Factory(cfg)); echo_control_factory.reset(new EchoCanceller3Factory(cfg));
} }
if (settings_.use_drift_compensation && *settings_.use_drift_compensation) {
RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AEC2 drift compensation";
}
if (settings_.aec_suppression_level) {
auto level = static_cast<webrtc::EchoCancellation::SuppressionLevel>(
*settings_.aec_suppression_level);
if (level == webrtc::EchoCancellation::SuppressionLevel::kLowSuppression) {
RTC_LOG(LS_ERROR) << "Ignoring deprecated setting: AEC2 low suppression";
} else {
apm_config.echo_canceller.legacy_moderate_suppression_level =
(level ==
webrtc::EchoCancellation::SuppressionLevel::kModerateSuppression);
}
}
if (settings_.use_hpf) { if (settings_.use_hpf) {
apm_config.high_pass_filter.enabled = *settings_.use_hpf; apm_config.high_pass_filter.enabled = *settings_.use_hpf;
} }
@ -767,6 +745,14 @@ void AudioProcessingSimulator::CreateAudioProcessor() {
ap_->ApplyConfig(apm_config); ap_->ApplyConfig(apm_config);
if (settings_.use_aec) {
RTC_CHECK_EQ(AudioProcessing::kNoError,
ap_->echo_cancellation()->Enable(*settings_.use_aec));
}
if (settings_.use_aecm) {
RTC_CHECK_EQ(AudioProcessing::kNoError,
ap_->echo_control_mobile()->Enable(*settings_.use_aecm));
}
if (settings_.use_agc) { if (settings_.use_agc) {
RTC_CHECK_EQ(AudioProcessing::kNoError, RTC_CHECK_EQ(AudioProcessing::kNoError,
ap_->gain_control()->Enable(*settings_.use_agc)); ap_->gain_control()->Enable(*settings_.use_agc));
@ -804,6 +790,19 @@ void AudioProcessingSimulator::CreateAudioProcessor() {
static_cast<webrtc::GainControl::Mode>(*settings_.agc_mode))); static_cast<webrtc::GainControl::Mode>(*settings_.agc_mode)));
} }
if (settings_.use_drift_compensation) {
RTC_CHECK_EQ(AudioProcessing::kNoError,
ap_->echo_cancellation()->enable_drift_compensation(
*settings_.use_drift_compensation));
}
if (settings_.aec_suppression_level) {
RTC_CHECK_EQ(AudioProcessing::kNoError,
ap_->echo_cancellation()->set_suppression_level(
static_cast<webrtc::EchoCancellation::SuppressionLevel>(
*settings_.aec_suppression_level)));
}
if (settings_.aecm_routing_mode) { if (settings_.aecm_routing_mode) {
RTC_CHECK_EQ(AudioProcessing::kNoError, RTC_CHECK_EQ(AudioProcessing::kNoError,
ap_->echo_control_mobile()->set_routing_mode( ap_->echo_control_mobile()->set_routing_mode(

View file

@ -106,6 +106,9 @@ DEFINE_int(delay_agnostic,
DEFINE_int(extended_filter, DEFINE_int(extended_filter,
kParameterNotSpecifiedValue, kParameterNotSpecifiedValue,
"Activate (1) or deactivate(0) the AEC extended filter mode"); "Activate (1) or deactivate(0) the AEC extended filter mode");
DEFINE_int(drift_compensation,
kParameterNotSpecifiedValue,
"Activate (1) or deactivate(0) the drift compensation");
DEFINE_int(aec3, DEFINE_int(aec3,
kParameterNotSpecifiedValue, kParameterNotSpecifiedValue,
"Activate (1) or deactivate(0) the experimental AEC mode AEC3"); "Activate (1) or deactivate(0) the experimental AEC mode AEC3");
@ -256,6 +259,8 @@ SimulationSettings CreateSettings() {
&settings.aec_suppression_level); &settings.aec_suppression_level);
SetSettingIfFlagSet(FLAG_delay_agnostic, &settings.use_delay_agnostic); SetSettingIfFlagSet(FLAG_delay_agnostic, &settings.use_delay_agnostic);
SetSettingIfFlagSet(FLAG_extended_filter, &settings.use_extended_filter); SetSettingIfFlagSet(FLAG_extended_filter, &settings.use_extended_filter);
SetSettingIfFlagSet(FLAG_drift_compensation,
&settings.use_drift_compensation);
SetSettingIfFlagSet(FLAG_refined_adaptive_filter, SetSettingIfFlagSet(FLAG_refined_adaptive_filter,
&settings.use_refined_adaptive_filter); &settings.use_refined_adaptive_filter);
@ -356,12 +361,11 @@ void PerformBasicParameterSanityChecks(const SimulationSettings& settings) {
*settings.reverse_output_num_channels <= 0, *settings.reverse_output_num_channels <= 0,
"Error: --reverse_output_num_channels must be positive!\n"); "Error: --reverse_output_num_channels must be positive!\n");
ReportConditionalErrorAndExit(settings.aec_suppression_level && ReportConditionalErrorAndExit(
((*settings.aec_suppression_level) < 1 || settings.aec_suppression_level &&
(*settings.aec_suppression_level) > 2), ((*settings.aec_suppression_level) < 0 ||
"Error: --aec_suppression_level must be " (*settings.aec_suppression_level) > 2),
"specified between 1 and 2. 0 is " "Error: --aec_suppression_level must be specified between 0 and 2.\n");
"deprecated.\n");
ReportConditionalErrorAndExit( ReportConditionalErrorAndExit(
settings.aecm_routing_mode && ((*settings.aecm_routing_mode) < 0 || settings.aecm_routing_mode && ((*settings.aecm_routing_mode) < 0 ||

View file

@ -123,6 +123,7 @@ void DebugDumpReplayer::OnStreamEvent(const audioproc::Stream& msg) {
RTC_CHECK_EQ(AudioProcessing::kNoError, RTC_CHECK_EQ(AudioProcessing::kNoError,
apm_->set_stream_delay_ms(msg.delay())); apm_->set_stream_delay_ms(msg.delay()));
apm_->echo_cancellation()->set_stream_drift_samples(msg.drift());
if (msg.has_keypress()) { if (msg.has_keypress()) {
apm_->set_stream_key_pressed(msg.keypress()); apm_->set_stream_key_pressed(msg.keypress());
} else { } else {
@ -212,11 +213,16 @@ void DebugDumpReplayer::ConfigureApm(const audioproc::Config& msg) {
apm_config.echo_canceller.enabled = msg.aec_enabled() || msg.aecm_enabled(); apm_config.echo_canceller.enabled = msg.aec_enabled() || msg.aecm_enabled();
apm_config.echo_canceller.mobile_mode = msg.aecm_enabled(); apm_config.echo_canceller.mobile_mode = msg.aecm_enabled();
RTC_CHECK(msg.has_aec_drift_compensation_enabled());
RTC_CHECK_EQ(AudioProcessing::kNoError,
apm_->echo_cancellation()->enable_drift_compensation(
msg.aec_drift_compensation_enabled()));
RTC_CHECK(msg.has_aec_suppression_level()); RTC_CHECK(msg.has_aec_suppression_level());
apm_config.echo_canceller.legacy_moderate_suppression_level = RTC_CHECK_EQ(AudioProcessing::kNoError,
static_cast<EchoCancellation::SuppressionLevel>( apm_->echo_cancellation()->set_suppression_level(
msg.aec_suppression_level()) == static_cast<EchoCancellation::SuppressionLevel>(
EchoCancellation::SuppressionLevel::kModerateSuppression; msg.aec_suppression_level())));
RTC_CHECK(msg.has_aecm_comfort_noise_enabled()); RTC_CHECK(msg.has_aecm_comfort_noise_enabled());
RTC_CHECK_EQ(AudioProcessing::kNoError, RTC_CHECK_EQ(AudioProcessing::kNoError,

View file

@ -359,13 +359,12 @@ TEST_F(DebugDumpTest, ChangeOutputFormat) {
TEST_F(DebugDumpTest, ToggleAec) { TEST_F(DebugDumpTest, ToggleAec) {
Config config; Config config;
AudioProcessing::Config apm_config; DebugDumpGenerator generator(config, AudioProcessing::Config());
DebugDumpGenerator generator(config, apm_config);
generator.StartRecording(); generator.StartRecording();
generator.Process(100); generator.Process(100);
apm_config.echo_canceller.enabled = true; EchoCancellation* aec = generator.apm()->echo_cancellation();
generator.apm()->ApplyConfig(apm_config); EXPECT_EQ(AudioProcessing::kNoError, aec->Enable(!aec->is_enabled()));
generator.Process(100); generator.Process(100);
generator.StopRecording(); generator.StopRecording();
@ -375,13 +374,12 @@ TEST_F(DebugDumpTest, ToggleAec) {
TEST_F(DebugDumpTest, ToggleDelayAgnosticAec) { TEST_F(DebugDumpTest, ToggleDelayAgnosticAec) {
Config config; Config config;
config.Set<DelayAgnostic>(new DelayAgnostic(true)); config.Set<DelayAgnostic>(new DelayAgnostic(true));
AudioProcessing::Config apm_config; DebugDumpGenerator generator(config, AudioProcessing::Config());
DebugDumpGenerator generator(config, apm_config);
generator.StartRecording(); generator.StartRecording();
generator.Process(100); generator.Process(100);
apm_config.echo_canceller.enabled = true; EchoCancellation* aec = generator.apm()->echo_cancellation();
generator.apm()->ApplyConfig(apm_config); EXPECT_EQ(AudioProcessing::kNoError, aec->Enable(!aec->is_enabled()));
generator.Process(100); generator.Process(100);
generator.StopRecording(); generator.StopRecording();
@ -550,13 +548,15 @@ TEST_F(DebugDumpTest, ToggleAecLevel) {
AudioProcessing::Config apm_config; AudioProcessing::Config apm_config;
apm_config.echo_canceller.enabled = true; apm_config.echo_canceller.enabled = true;
apm_config.echo_canceller.mobile_mode = false; apm_config.echo_canceller.mobile_mode = false;
apm_config.echo_canceller.legacy_moderate_suppression_level = true;
DebugDumpGenerator generator(config, apm_config); DebugDumpGenerator generator(config, apm_config);
EchoCancellation* aec = generator.apm()->echo_cancellation();
EXPECT_EQ(AudioProcessing::kNoError,
aec->set_suppression_level(EchoCancellation::kLowSuppression));
generator.StartRecording(); generator.StartRecording();
generator.Process(100); generator.Process(100);
apm_config.echo_canceller.legacy_moderate_suppression_level = false; EXPECT_EQ(AudioProcessing::kNoError,
generator.apm()->ApplyConfig(apm_config); aec->set_suppression_level(EchoCancellation::kHighSuppression));
generator.Process(100); generator.Process(100);
generator.StopRecording(); generator.StopRecording();
VerifyDebugDump(generator.dump_file_name()); VerifyDebugDump(generator.dump_file_name());

View file

@ -79,6 +79,9 @@ void WavBasedSimulator::PrepareProcessStreamCall() {
ap_->set_stream_delay_ms( ap_->set_stream_delay_ms(
settings_.stream_delay ? *settings_.stream_delay : 0)); settings_.stream_delay ? *settings_.stream_delay : 0));
} }
ap_->echo_cancellation()->set_stream_drift_samples(
settings_.stream_drift_samples ? *settings_.stream_drift_samples : 0);
} }
void WavBasedSimulator::PrepareReverseProcessStreamCall() { void WavBasedSimulator::PrepareReverseProcessStreamCall() {