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, ...@@ -471,11 +471,6 @@ void MediaStreamAudioProcessor::OnPlayoutData(media::AudioBus* audio_bus,
int sample_rate, int sample_rate,
int audio_delay_milliseconds) { int audio_delay_milliseconds) {
DCHECK(render_thread_checker_.CalledOnValidThread()); 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_GE(audio_bus->channels(), 1);
DCHECK_LE(audio_bus->channels(), 2); DCHECK_LE(audio_bus->channels(), 2);
int frames_per_10_ms = sample_rate / 100; int frames_per_10_ms = sample_rate / 100;
...@@ -792,7 +787,8 @@ int MediaStreamAudioProcessor::ProcessData(const float* const* process_ptrs, ...@@ -792,7 +787,8 @@ int MediaStreamAudioProcessor::ProcessData(const float* const* process_ptrs,
void MediaStreamAudioProcessor::UpdateAecStats() { void MediaStreamAudioProcessor::UpdateAecStats() {
DCHECK(main_thread_runner_->BelongsToCurrentThread()); DCHECK(main_thread_runner_->BelongsToCurrentThread());
if (echo_information_) if (echo_information_)
echo_information_->UpdateAecStats(audio_processing_->echo_cancellation()); echo_information_->UpdateAecStats(
audio_processing_->GetStatistics(true /* has_remote_tracks */));
} }
} // namespace content } // namespace content
...@@ -91,25 +91,11 @@ AudioProcessingProperties::ToAudioProcessingSettings() const { ...@@ -91,25 +91,11 @@ AudioProcessingProperties::ToAudioProcessingSettings() const {
} }
void EnableEchoCancellation(AudioProcessing* audio_processing) { 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(); webrtc::AudioProcessing::Config apm_config = audio_processing->GetConfig();
apm_config.echo_canceller.enabled = true; apm_config.echo_canceller.enabled = true;
#if defined(OS_ANDROID) #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; apm_config.echo_canceller.mobile_mode = true;
#else #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; apm_config.echo_canceller.mobile_mode = false;
#endif #endif
audio_processing->ApplyConfig(apm_config); audio_processing->ApplyConfig(apm_config);
......
...@@ -117,13 +117,7 @@ class MediaStreamAudioProcessorTest : public ::testing::Test { ...@@ -117,13 +117,7 @@ class MediaStreamAudioProcessorTest : public ::testing::Test {
// |audio_processor| does nothing when the audio processing is off in // |audio_processor| does nothing when the audio processing is off in
// the processor. // the processor.
webrtc::AudioProcessing* ap = audio_processor->audio_processing_.get(); webrtc::AudioProcessing* ap = audio_processor->audio_processing_.get();
#if defined(OS_ANDROID) const bool is_aec_enabled = ap && ap->GetConfig().echo_canceller.enabled;
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
if (is_aec_enabled) { if (is_aec_enabled) {
if (params.channels() > kMaxNumberOfPlayoutDataChannels) { if (params.channels() > kMaxNumberOfPlayoutDataChannels) {
for (int i = 0; i < kMaxNumberOfPlayoutDataChannels; ++i) { for (int i = 0; i < kMaxNumberOfPlayoutDataChannels; ++i) {
...@@ -159,22 +153,15 @@ class MediaStreamAudioProcessorTest : public ::testing::Test { ...@@ -159,22 +153,15 @@ class MediaStreamAudioProcessorTest : public ::testing::Test {
void VerifyDefaultComponents(MediaStreamAudioProcessor* audio_processor) { void VerifyDefaultComponents(MediaStreamAudioProcessor* audio_processor) {
webrtc::AudioProcessing* audio_processing = webrtc::AudioProcessing* audio_processing =
audio_processor->audio_processing_.get(); audio_processor->audio_processing_.get();
const webrtc::AudioProcessing::Config apm_config = const webrtc::AudioProcessing::Config config =
audio_processing->GetConfig(); audio_processing->GetConfig();
EXPECT_TRUE(apm_config.high_pass_filter.enabled); EXPECT_TRUE(config.echo_canceller.enabled);
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
EXPECT_TRUE(audio_processing->echo_control_mobile()->is_enabled()); EXPECT_TRUE(config.echo_canceller.mobile_mode);
EXPECT_TRUE(audio_processing->echo_control_mobile()->routing_mode() ==
webrtc::EchoControlMobile::kSpeakerphone);
EXPECT_FALSE(audio_processing->echo_cancellation()->is_enabled());
#else #else
EXPECT_TRUE(audio_processing->echo_cancellation()->is_enabled()); EXPECT_FALSE(config.echo_canceller.mobile_mode);
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());
#endif #endif
EXPECT_TRUE(config.high_pass_filter.enabled);
EXPECT_TRUE(audio_processing->noise_suppression()->is_enabled()); EXPECT_TRUE(audio_processing->noise_suppression()->is_enabled());
EXPECT_TRUE(audio_processing->noise_suppression()->level() == EXPECT_TRUE(audio_processing->noise_suppression()->level() ==
......
...@@ -129,7 +129,8 @@ void AudioProcessor::AnalyzePlayout(const AudioBus& audio, ...@@ -129,7 +129,8 @@ void AudioProcessor::AnalyzePlayout(const AudioBus& audio,
void AudioProcessor::UpdateInternalStats() { void AudioProcessor::UpdateInternalStats() {
if (audio_processing_) if (audio_processing_)
echo_information_.UpdateAecStats(audio_processing_->echo_cancellation()); echo_information_.UpdateAecStats(
audio_processing_->GetStatistics(has_reverse_stream_));
} }
void AudioProcessor::GetStats(GetStatsCB callback) { void AudioProcessor::GetStats(GetStatsCB callback) {
...@@ -250,22 +251,6 @@ void AudioProcessor::InitializeAPM() { ...@@ -250,22 +251,6 @@ void AudioProcessor::InitializeAPM() {
// Audio processing module construction. // Audio processing module construction.
audio_processing_ = base::WrapUnique(ap_builder.Create(ap_config)); 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. // Noise suppression setup part 2.
if (settings_.noise_suppression != NoiseSuppressionType::kDisabled) { if (settings_.noise_suppression != NoiseSuppressionType::kDisabled) {
int err = audio_processing_->noise_suppression()->set_level( int err = audio_processing_->noise_suppression()->set_level(
...@@ -302,8 +287,7 @@ void AudioProcessor::InitializeAPM() { ...@@ -302,8 +287,7 @@ void AudioProcessor::InitializeAPM() {
webrtc::AudioProcessing::Config apm_config = audio_processing_->GetConfig(); webrtc::AudioProcessing::Config apm_config = audio_processing_->GetConfig();
// AEC setup part 3. // AEC setup part 2.
// New-fangled echo cancellation setup. (see: https://bugs.webrtc.org/9535).
apm_config.echo_canceller.enabled = apm_config.echo_canceller.enabled =
settings_.echo_cancellation == EchoCancellationType::kAec2 || settings_.echo_cancellation == EchoCancellationType::kAec2 ||
settings_.echo_cancellation == EchoCancellationType::kAec3; settings_.echo_cancellation == EchoCancellationType::kAec3;
......
...@@ -105,7 +105,7 @@ class WebRtcAudioProcessorTest : public ::testing::Test { ...@@ -105,7 +105,7 @@ class WebRtcAudioProcessorTest : public ::testing::Test {
// |audio_processor| does nothing when the audio processing is off in // |audio_processor| does nothing when the audio processing is off in
// the processor. // the processor.
webrtc::AudioProcessing* ap = audio_processor->audio_processing_.get(); 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 (is_aec_enabled) {
if (params.channels() > kMaxNumberOfPlayoutDataChannels) { if (params.channels() > kMaxNumberOfPlayoutDataChannels) {
for (int i = 0; i < kMaxNumberOfPlayoutDataChannels; ++i) { for (int i = 0; i < kMaxNumberOfPlayoutDataChannels; ++i) {
...@@ -128,12 +128,9 @@ class WebRtcAudioProcessorTest : public ::testing::Test { ...@@ -128,12 +128,9 @@ class WebRtcAudioProcessorTest : public ::testing::Test {
void VerifyEnabledComponents(AudioProcessor* audio_processor) { void VerifyEnabledComponents(AudioProcessor* audio_processor) {
webrtc::AudioProcessing* audio_processing = webrtc::AudioProcessing* audio_processing =
audio_processor->audio_processing_.get(); audio_processor->audio_processing_.get();
EXPECT_TRUE(audio_processing->echo_cancellation()->is_enabled()); webrtc::AudioProcessing::Config ap_config = audio_processing->GetConfig();
EXPECT_TRUE(audio_processing->echo_cancellation()->suppression_level() == EXPECT_TRUE(ap_config.echo_canceller.enabled);
webrtc::EchoCancellation::kHighSuppression); EXPECT_FALSE(ap_config.echo_canceller.mobile_mode);
EXPECT_TRUE(audio_processing->echo_cancellation()->are_metrics_enabled());
EXPECT_TRUE(
audio_processing->echo_cancellation()->is_delay_logging_enabled());
EXPECT_TRUE(audio_processing->noise_suppression()->is_enabled()); EXPECT_TRUE(audio_processing->noise_suppression()->is_enabled());
EXPECT_TRUE(audio_processing->noise_suppression()->level() == EXPECT_TRUE(audio_processing->noise_suppression()->level() ==
......
...@@ -9,44 +9,8 @@ ...@@ -9,44 +9,8 @@
namespace media { 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() EchoInformation::EchoInformation()
: delay_stats_time_ms_(0), : divergent_filter_stats_time_ms_(0),
echo_frames_received_(false),
divergent_filter_stats_time_ms_(0),
num_divergent_filter_fraction_(0), num_divergent_filter_fraction_(0),
num_non_zero_divergent_filter_fraction_(0) {} num_non_zero_divergent_filter_fraction_(0) {}
...@@ -56,84 +20,29 @@ EchoInformation::~EchoInformation() { ...@@ -56,84 +20,29 @@ EchoInformation::~EchoInformation() {
} }
void EchoInformation::UpdateAecStats( void EchoInformation::UpdateAecStats(
webrtc::EchoCancellation* echo_cancellation) { const webrtc::AudioProcessingStats& audio_processing_stats) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!echo_cancellation->is_enabled()) if (!audio_processing_stats.divergent_filter_fraction) {
return;
UpdateAecDelayStats(echo_cancellation);
UpdateAecDivergentFilterStats(echo_cancellation);
}
void EchoInformation::UpdateAecDelayStats(
webrtc::EchoCancellation* echo_cancellation) {
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
return; 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; divergent_filter_stats_time_ms_ += webrtc::AudioProcessing::kChunkSizeMs;
if (divergent_filter_stats_time_ms_ < if (divergent_filter_stats_time_ms_ <
100 * webrtc::AudioProcessing::kChunkSizeMs) { // 1 second 100 * webrtc::AudioProcessing::kChunkSizeMs) { // 1 second
return; return;
} }
webrtc::EchoCancellation::Metrics metrics; double divergent_filter_fraction =
if (echo_cancellation->GetMetrics(&metrics) == *audio_processing_stats.divergent_filter_fraction;
webrtc::AudioProcessing::kNoError) { // If not yet calculated, |metrics.divergent_filter_fraction| is -1.0. After
// If not yet calculated, |metrics.divergent_filter_fraction| is -1.0. After // being calculated the first time, it is updated periodically.
// being calculated the first time, it is updated periodically. if (divergent_filter_fraction < 0.0f) {
if (metrics.divergent_filter_fraction < 0.0f) { DCHECK_EQ(num_divergent_filter_fraction_, 0);
DCHECK_EQ(num_divergent_filter_fraction_, 0); return;
return; }
} if (divergent_filter_fraction > 0.0f) {
if (metrics.divergent_filter_fraction > 0.0f) { ++num_non_zero_divergent_filter_fraction_;
++num_non_zero_divergent_filter_fraction_;
}
} else {
DLOG(WARNING) << "Get echo cancellation metrics failed.";
} }
++num_divergent_filter_fraction_; ++num_divergent_filter_fraction_;
divergent_filter_stats_time_ms_ = 0; divergent_filter_stats_time_ms_ = 0;
......
...@@ -11,32 +11,24 @@ ...@@ -11,32 +11,24 @@
namespace media { 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. // quality in particular.
class COMPONENT_EXPORT(MEDIA_WEBRTC) EchoInformation { class COMPONENT_EXPORT(MEDIA_WEBRTC) EchoInformation {
public: public:
EchoInformation(); EchoInformation();
virtual ~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. // 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. // Reports AEC divergent filter metrics as UMA and resets the associated data.
void ReportAndResetAecDivergentFilterStats(); void ReportAndResetAecDivergentFilterStats();
private: private:
void UpdateAecDelayStats(webrtc::EchoCancellation* echo_cancellation); // Counter to store a new value for the divergent filter fraction metric in
void UpdateAecDivergentFilterStats( // AEC2, once every second.
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().
int divergent_filter_stats_time_ms_; int divergent_filter_stats_time_ms_;
// Total number of times we queried for the divergent filter fraction metric. // 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