Commit 22c11390 authored by Sam Zackrisson's avatar Sam Zackrisson Committed by Commit Bot

Remove AEC interface usage in MediaStreamAudioProcessor and AudioProcessor

echo_control_mobile() and echo_cancellation() interfaces are replaced
with AudioProcessing::Config.

Some configuration is now hardcoded defaults in APM, and hence should
not (can not) be configured in these processors.

Statistics are now accessed through AudioProcessing::GetStatistics.

A UMA metric disappears.

Bug: webrtc:9535
Change-Id: Ia23d58cf1a1315605beef3ec72e080844bb94e5d
Reviewed-on: https://chromium-review.googlesource.com/1243123Reviewed-by: default avatarOskar Sundbom <ossu@chromium.org>
Reviewed-by: default avatarMax Morin <maxmorin@chromium.org>
Commit-Queue: Sam Zackrisson <saza@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595806}
parent 46f49dac
......@@ -471,11 +471,6 @@ void MediaStreamAudioProcessor::OnPlayoutData(media::AudioBus* audio_bus,
int sample_rate,
int audio_delay_milliseconds) {
DCHECK(render_thread_checker_.CalledOnValidThread());
#if defined(OS_ANDROID)
DCHECK(!audio_processing_->echo_cancellation()->is_enabled());
#else
DCHECK(!audio_processing_->echo_control_mobile()->is_enabled());
#endif
DCHECK_GE(audio_bus->channels(), 1);
DCHECK_LE(audio_bus->channels(), 2);
int frames_per_10_ms = sample_rate / 100;
......@@ -792,7 +787,8 @@ int MediaStreamAudioProcessor::ProcessData(const float* const* process_ptrs,
void MediaStreamAudioProcessor::UpdateAecStats() {
DCHECK(main_thread_runner_->BelongsToCurrentThread());
if (echo_information_)
echo_information_->UpdateAecStats(audio_processing_->echo_cancellation());
echo_information_->UpdateAecStats(
audio_processing_->GetStatistics(true /* has_remote_tracks */));
}
} // namespace content
......@@ -91,25 +91,11 @@ AudioProcessingProperties::ToAudioProcessingSettings() const {
}
void EnableEchoCancellation(AudioProcessing* audio_processing) {
// TODO(bugs.webrtc.org/9535): Remove double-booking AEC toggle when the
// config applies (from 2018-08-16).
webrtc::AudioProcessing::Config apm_config = audio_processing->GetConfig();
apm_config.echo_canceller.enabled = true;
#if defined(OS_ANDROID)
// Mobile devices are using AECM.
CHECK_EQ(0, audio_processing->echo_control_mobile()->set_routing_mode(
webrtc::EchoControlMobile::kSpeakerphone));
CHECK_EQ(0, audio_processing->echo_control_mobile()->Enable(true));
apm_config.echo_canceller.mobile_mode = true;
#else
int err = audio_processing->echo_cancellation()->set_suppression_level(
webrtc::EchoCancellation::kHighSuppression);
// Enable the metrics for AEC.
err |= audio_processing->echo_cancellation()->enable_metrics(true);
err |= audio_processing->echo_cancellation()->enable_delay_logging(true);
err |= audio_processing->echo_cancellation()->Enable(true);
CHECK_EQ(err, 0);
apm_config.echo_canceller.mobile_mode = false;
#endif
audio_processing->ApplyConfig(apm_config);
......
......@@ -117,13 +117,7 @@ class MediaStreamAudioProcessorTest : public ::testing::Test {
// |audio_processor| does nothing when the audio processing is off in
// the processor.
webrtc::AudioProcessing* ap = audio_processor->audio_processing_.get();
#if defined(OS_ANDROID)
const bool is_aec_enabled = ap && ap->echo_control_mobile()->is_enabled();
// AEC should be turned off for mobiles.
DCHECK(!ap || !ap->echo_cancellation()->is_enabled());
#else
const bool is_aec_enabled = ap && ap->echo_cancellation()->is_enabled();
#endif
const bool is_aec_enabled = ap && ap->GetConfig().echo_canceller.enabled;
if (is_aec_enabled) {
if (params.channels() > kMaxNumberOfPlayoutDataChannels) {
for (int i = 0; i < kMaxNumberOfPlayoutDataChannels; ++i) {
......@@ -159,22 +153,15 @@ class MediaStreamAudioProcessorTest : public ::testing::Test {
void VerifyDefaultComponents(MediaStreamAudioProcessor* audio_processor) {
webrtc::AudioProcessing* audio_processing =
audio_processor->audio_processing_.get();
const webrtc::AudioProcessing::Config apm_config =
const webrtc::AudioProcessing::Config config =
audio_processing->GetConfig();
EXPECT_TRUE(apm_config.high_pass_filter.enabled);
EXPECT_TRUE(config.echo_canceller.enabled);
#if defined(OS_ANDROID)
EXPECT_TRUE(audio_processing->echo_control_mobile()->is_enabled());
EXPECT_TRUE(audio_processing->echo_control_mobile()->routing_mode() ==
webrtc::EchoControlMobile::kSpeakerphone);
EXPECT_FALSE(audio_processing->echo_cancellation()->is_enabled());
EXPECT_TRUE(config.echo_canceller.mobile_mode);
#else
EXPECT_TRUE(audio_processing->echo_cancellation()->is_enabled());
EXPECT_TRUE(audio_processing->echo_cancellation()->suppression_level() ==
webrtc::EchoCancellation::kHighSuppression);
EXPECT_TRUE(audio_processing->echo_cancellation()->are_metrics_enabled());
EXPECT_TRUE(
audio_processing->echo_cancellation()->is_delay_logging_enabled());
EXPECT_FALSE(config.echo_canceller.mobile_mode);
#endif
EXPECT_TRUE(config.high_pass_filter.enabled);
EXPECT_TRUE(audio_processing->noise_suppression()->is_enabled());
EXPECT_TRUE(audio_processing->noise_suppression()->level() ==
......
......@@ -129,7 +129,8 @@ void AudioProcessor::AnalyzePlayout(const AudioBus& audio,
void AudioProcessor::UpdateInternalStats() {
if (audio_processing_)
echo_information_.UpdateAecStats(audio_processing_->echo_cancellation());
echo_information_.UpdateAecStats(
audio_processing_->GetStatistics(has_reverse_stream_));
}
void AudioProcessor::GetStats(GetStatsCB callback) {
......@@ -250,22 +251,6 @@ void AudioProcessor::InitializeAPM() {
// Audio processing module construction.
audio_processing_ = base::WrapUnique(ap_builder.Create(ap_config));
// AEC setup part 2.
switch (settings_.echo_cancellation) {
case EchoCancellationType::kSystemAec:
case EchoCancellationType::kDisabled:
break;
case EchoCancellationType::kAec2:
case EchoCancellationType::kAec3:
int err = audio_processing_->echo_cancellation()->set_suppression_level(
webrtc::EchoCancellation::kHighSuppression);
err |= audio_processing_->echo_cancellation()->enable_metrics(true);
err |= audio_processing_->echo_cancellation()->enable_delay_logging(true);
err |= audio_processing_->echo_cancellation()->Enable(true);
DCHECK_EQ(err, 0);
break;
}
// Noise suppression setup part 2.
if (settings_.noise_suppression != NoiseSuppressionType::kDisabled) {
int err = audio_processing_->noise_suppression()->set_level(
......@@ -302,8 +287,7 @@ void AudioProcessor::InitializeAPM() {
webrtc::AudioProcessing::Config apm_config = audio_processing_->GetConfig();
// AEC setup part 3.
// New-fangled echo cancellation setup. (see: https://bugs.webrtc.org/9535).
// AEC setup part 2.
apm_config.echo_canceller.enabled =
settings_.echo_cancellation == EchoCancellationType::kAec2 ||
settings_.echo_cancellation == EchoCancellationType::kAec3;
......
......@@ -105,7 +105,7 @@ class WebRtcAudioProcessorTest : public ::testing::Test {
// |audio_processor| does nothing when the audio processing is off in
// the processor.
webrtc::AudioProcessing* ap = audio_processor->audio_processing_.get();
const bool is_aec_enabled = ap && ap->echo_cancellation()->is_enabled();
const bool is_aec_enabled = ap && ap->GetConfig().echo_canceller.enabled;
if (is_aec_enabled) {
if (params.channels() > kMaxNumberOfPlayoutDataChannels) {
for (int i = 0; i < kMaxNumberOfPlayoutDataChannels; ++i) {
......@@ -128,12 +128,9 @@ class WebRtcAudioProcessorTest : public ::testing::Test {
void VerifyEnabledComponents(AudioProcessor* audio_processor) {
webrtc::AudioProcessing* audio_processing =
audio_processor->audio_processing_.get();
EXPECT_TRUE(audio_processing->echo_cancellation()->is_enabled());
EXPECT_TRUE(audio_processing->echo_cancellation()->suppression_level() ==
webrtc::EchoCancellation::kHighSuppression);
EXPECT_TRUE(audio_processing->echo_cancellation()->are_metrics_enabled());
EXPECT_TRUE(
audio_processing->echo_cancellation()->is_delay_logging_enabled());
webrtc::AudioProcessing::Config ap_config = audio_processing->GetConfig();
EXPECT_TRUE(ap_config.echo_canceller.enabled);
EXPECT_FALSE(ap_config.echo_canceller.mobile_mode);
EXPECT_TRUE(audio_processing->noise_suppression()->is_enabled());
EXPECT_TRUE(audio_processing->noise_suppression()->level() ==
......
......@@ -9,44 +9,8 @@
namespace media {
namespace {
// Used to log echo quality based on delay estimates.
enum DelayBasedEchoQuality {
DELAY_BASED_ECHO_QUALITY_GOOD = 0,
DELAY_BASED_ECHO_QUALITY_SPURIOUS,
DELAY_BASED_ECHO_QUALITY_BAD,
DELAY_BASED_ECHO_QUALITY_INVALID,
DELAY_BASED_ECHO_QUALITY_MAX = DELAY_BASED_ECHO_QUALITY_INVALID
};
DelayBasedEchoQuality EchoDelayFrequencyToQuality(float delay_frequency) {
const float kEchoDelayFrequencyLowerLimit = 0.1f;
const float kEchoDelayFrequencyUpperLimit = 0.8f;
// DELAY_BASED_ECHO_QUALITY_GOOD
// delay is out of bounds during at most 10 % of the time.
// DELAY_BASED_ECHO_QUALITY_SPURIOUS
// delay is out of bounds 10-80 % of the time.
// DELAY_BASED_ECHO_QUALITY_BAD
// delay is mostly out of bounds >= 80 % of the time.
// DELAY_BASED_ECHO_QUALITY_INVALID
// delay_frequency is negative which happens if we have insufficient data.
if (delay_frequency < 0)
return DELAY_BASED_ECHO_QUALITY_INVALID;
else if (delay_frequency <= kEchoDelayFrequencyLowerLimit)
return DELAY_BASED_ECHO_QUALITY_GOOD;
else if (delay_frequency < kEchoDelayFrequencyUpperLimit)
return DELAY_BASED_ECHO_QUALITY_SPURIOUS;
else
return DELAY_BASED_ECHO_QUALITY_BAD;
}
} // namespace
EchoInformation::EchoInformation()
: delay_stats_time_ms_(0),
echo_frames_received_(false),
divergent_filter_stats_time_ms_(0),
: divergent_filter_stats_time_ms_(0),
num_divergent_filter_fraction_(0),
num_non_zero_divergent_filter_fraction_(0) {}
......@@ -56,85 +20,30 @@ EchoInformation::~EchoInformation() {
}
void EchoInformation::UpdateAecStats(
webrtc::EchoCancellation* echo_cancellation) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!echo_cancellation->is_enabled())
return;
UpdateAecDelayStats(echo_cancellation);
UpdateAecDivergentFilterStats(echo_cancellation);
}
void EchoInformation::UpdateAecDelayStats(
webrtc::EchoCancellation* echo_cancellation) {
const webrtc::AudioProcessingStats& audio_processing_stats) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Only start collecting stats if we know echo cancellation has measured an
// echo. Otherwise we clutter the stats with for example cases where only the
// microphone is used.
if (!echo_frames_received_ & !echo_cancellation->stream_has_echo())
return;
echo_frames_received_ = true;
// In WebRTC, three echo delay metrics are calculated and updated every
// five seconds. We use one of them, |fraction_poor_delays| to log in a UMA
// histogram an Echo Cancellation quality metric. The stat in WebRTC has a
// fixed aggregation window of five seconds, so we use the same query
// frequency to avoid logging old values.
if (!echo_cancellation->is_delay_logging_enabled())
return;
delay_stats_time_ms_ += webrtc::AudioProcessing::kChunkSizeMs;
if (delay_stats_time_ms_ <
500 * webrtc::AudioProcessing::kChunkSizeMs) { // 5 seconds
if (!audio_processing_stats.divergent_filter_fraction) {
return;
}
int dummy_median = 0, dummy_std = 0;
float fraction_poor_delays = 0;
if (echo_cancellation->GetDelayMetrics(&dummy_median, &dummy_std,
&fraction_poor_delays) ==
webrtc::AudioProcessing::kNoError) {
delay_stats_time_ms_ = 0;
// Map |fraction_poor_delays| to an Echo Cancellation quality and log in UMA
// histogram. See DelayBasedEchoQuality for information on histogram
// buckets.
UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality",
EchoDelayFrequencyToQuality(fraction_poor_delays),
DELAY_BASED_ECHO_QUALITY_MAX + 1);
}
}
void EchoInformation::UpdateAecDivergentFilterStats(
webrtc::EchoCancellation* echo_cancellation) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!echo_cancellation->are_metrics_enabled())
return;
divergent_filter_stats_time_ms_ += webrtc::AudioProcessing::kChunkSizeMs;
if (divergent_filter_stats_time_ms_ <
100 * webrtc::AudioProcessing::kChunkSizeMs) { // 1 second
return;
}
webrtc::EchoCancellation::Metrics metrics;
if (echo_cancellation->GetMetrics(&metrics) ==
webrtc::AudioProcessing::kNoError) {
double divergent_filter_fraction =
*audio_processing_stats.divergent_filter_fraction;
// If not yet calculated, |metrics.divergent_filter_fraction| is -1.0. After
// being calculated the first time, it is updated periodically.
if (metrics.divergent_filter_fraction < 0.0f) {
if (divergent_filter_fraction < 0.0f) {
DCHECK_EQ(num_divergent_filter_fraction_, 0);
return;
}
if (metrics.divergent_filter_fraction > 0.0f) {
if (divergent_filter_fraction > 0.0f) {
++num_non_zero_divergent_filter_fraction_;
}
} else {
DLOG(WARNING) << "Get echo cancellation metrics failed.";
}
++num_divergent_filter_fraction_;
divergent_filter_stats_time_ms_ = 0;
}
......
......@@ -11,32 +11,24 @@
namespace media {
// A helper class to log echo information in general and Echo Cancellation
// A helper class to log echo information in general and AEC2
// quality in particular.
class COMPONENT_EXPORT(MEDIA_WEBRTC) EchoInformation {
public:
EchoInformation();
virtual ~EchoInformation();
// Updates stats, and reports delay metrics as UMA stats every 5 seconds.
// Updates stats, and reports metrics as UMA stats every 5 seconds.
// Must be called every time AudioProcessing::ProcessStream() is called.
void UpdateAecStats(webrtc::EchoCancellation* echo_cancellation);
void UpdateAecStats(
const webrtc::AudioProcessingStats& audio_processing_stats);
// Reports AEC divergent filter metrics as UMA and resets the associated data.
void ReportAndResetAecDivergentFilterStats();
private:
void UpdateAecDelayStats(webrtc::EchoCancellation* echo_cancellation);
void UpdateAecDivergentFilterStats(
webrtc::EchoCancellation* echo_cancellation);
// Counter to track 5 seconds of data in order to query a new metric from
// webrtc::EchoCancellation::GetEchoDelayMetrics().
int delay_stats_time_ms_;
bool echo_frames_received_;
// Counter to track 1 second of data in order to query a new divergent filter
// fraction metric from webrtc::EchoCancellation::GetMetrics().
// Counter to store a new value for the divergent filter fraction metric in
// AEC2, once every second.
int divergent_filter_stats_time_ms_;
// Total number of times we queried for the divergent filter fraction metric.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment