Add WebRTC Media Constraint to force using Delay Agnostic AEC on Android
If built-in Echo Cancellation is available on a device it is automatically enabled. The reason is that it in most cases performs better than the WebRTC software echo control for mobile. The drawback is that we can not develop, test and rollout the delay agnostic AEC (DA-AEC) on Android as for desktops. This CL includes - adding a media constraint to enable/disable DA-AEC. - automatically turning on echo cancellation if DA-AEC is enabled. - a fix in the AEC that enables delay estimation when DA-AEC is enabled, but delay metrics is disabled. - sets the Config struct ReportedDelay, which controls DA-AEC internally in the AEC. The test code to verify that it works in AppRTCDemo can be found here: https://webrtc-codereview.appspot.com/50479004/ BUG=4472 TESTED=locally on N7, N6, Android One R=glaznev@webrtc.org, perkj@webrtc.org Review URL: https://webrtc-codereview.appspot.com/48699004 Cr-Commit-Position: refs/heads/master@{#8861}
This commit is contained in:
parent
caae5d47c1
commit
bf395c1fc0
@ -60,6 +60,8 @@ void FromConstraints(const MediaConstraintsInterface::Constraints& constraints,
|
||||
else if (iter->key ==
|
||||
MediaConstraintsInterface::kExperimentalEchoCancellation)
|
||||
options->experimental_aec.Set(value);
|
||||
else if (iter->key == MediaConstraintsInterface::kDAEchoCancellation)
|
||||
options->delay_agnostic_aec.Set(value);
|
||||
else if (iter->key == MediaConstraintsInterface::kAutoGainControl)
|
||||
options->auto_gain_control.Set(value);
|
||||
else if (iter->key ==
|
||||
|
||||
@ -46,6 +46,8 @@ TEST(LocalAudioSourceTest, SetValidOptions) {
|
||||
constraints.AddMandatory(MediaConstraintsInterface::kEchoCancellation, false);
|
||||
constraints.AddOptional(
|
||||
MediaConstraintsInterface::kExperimentalEchoCancellation, true);
|
||||
constraints.AddOptional(
|
||||
MediaConstraintsInterface::kDAEchoCancellation, false);
|
||||
constraints.AddOptional(MediaConstraintsInterface::kAutoGainControl, true);
|
||||
constraints.AddOptional(
|
||||
MediaConstraintsInterface::kExperimentalAutoGainControl, true);
|
||||
@ -61,6 +63,8 @@ TEST(LocalAudioSourceTest, SetValidOptions) {
|
||||
EXPECT_FALSE(value);
|
||||
EXPECT_TRUE(source->options().experimental_aec.Get(&value));
|
||||
EXPECT_TRUE(value);
|
||||
EXPECT_TRUE(source->options().delay_agnostic_aec.Get(&value));
|
||||
EXPECT_FALSE(value);
|
||||
EXPECT_TRUE(source->options().auto_gain_control.Get(&value));
|
||||
EXPECT_TRUE(value);
|
||||
EXPECT_TRUE(source->options().experimental_agc.Get(&value));
|
||||
|
||||
@ -50,6 +50,8 @@ const char MediaConstraintsInterface::kEchoCancellation[] =
|
||||
"googEchoCancellation";
|
||||
const char MediaConstraintsInterface::kExperimentalEchoCancellation[] =
|
||||
"googEchoCancellation2";
|
||||
const char MediaConstraintsInterface::kDAEchoCancellation[] =
|
||||
"googDAEchoCancellation";
|
||||
const char MediaConstraintsInterface::kAutoGainControl[] =
|
||||
"googAutoGainControl";
|
||||
const char MediaConstraintsInterface::kExperimentalAutoGainControl[] =
|
||||
|
||||
@ -75,6 +75,7 @@ class MediaConstraintsInterface {
|
||||
// These keys are google specific.
|
||||
static const char kEchoCancellation[]; // googEchoCancellation
|
||||
static const char kExperimentalEchoCancellation[]; // googEchoCancellation2
|
||||
static const char kDAEchoCancellation[]; // googDAEchoCancellation
|
||||
static const char kAutoGainControl[]; // googAutoGainControl
|
||||
static const char kExperimentalAutoGainControl[]; // googAutoGainControl2
|
||||
static const char kNoiseSuppression[]; // googNoiseSuppression
|
||||
|
||||
@ -156,6 +156,7 @@ struct AudioOptions {
|
||||
adjust_agc_delta.SetFrom(change.adjust_agc_delta);
|
||||
experimental_agc.SetFrom(change.experimental_agc);
|
||||
experimental_aec.SetFrom(change.experimental_aec);
|
||||
delay_agnostic_aec.SetFrom(change.delay_agnostic_aec);
|
||||
experimental_ns.SetFrom(change.experimental_ns);
|
||||
aec_dump.SetFrom(change.aec_dump);
|
||||
tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov);
|
||||
@ -184,6 +185,7 @@ struct AudioOptions {
|
||||
conference_mode == o.conference_mode &&
|
||||
experimental_agc == o.experimental_agc &&
|
||||
experimental_aec == o.experimental_aec &&
|
||||
delay_agnostic_aec == o.delay_agnostic_aec &&
|
||||
experimental_ns == o.experimental_ns &&
|
||||
adjust_agc_delta == o.adjust_agc_delta &&
|
||||
aec_dump == o.aec_dump &&
|
||||
@ -214,6 +216,7 @@ struct AudioOptions {
|
||||
ost << ToStringIfSet("agc_delta", adjust_agc_delta);
|
||||
ost << ToStringIfSet("experimental_agc", experimental_agc);
|
||||
ost << ToStringIfSet("experimental_aec", experimental_aec);
|
||||
ost << ToStringIfSet("delay_agnostic_aec", delay_agnostic_aec);
|
||||
ost << ToStringIfSet("experimental_ns", experimental_ns);
|
||||
ost << ToStringIfSet("aec_dump", aec_dump);
|
||||
ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov);
|
||||
@ -252,6 +255,7 @@ struct AudioOptions {
|
||||
Settable<int> adjust_agc_delta;
|
||||
Settable<bool> experimental_agc;
|
||||
Settable<bool> experimental_aec;
|
||||
Settable<bool> delay_agnostic_aec;
|
||||
Settable<bool> experimental_ns;
|
||||
Settable<bool> aec_dump;
|
||||
// Note that tx_agc_* only applies to non-experimental AGC.
|
||||
|
||||
@ -250,6 +250,7 @@ static AudioOptions GetDefaultEngineOptions() {
|
||||
options.adjust_agc_delta.Set(0);
|
||||
options.experimental_agc.Set(false);
|
||||
options.experimental_aec.Set(false);
|
||||
options.delay_agnostic_aec.Set(false);
|
||||
options.experimental_ns.Set(false);
|
||||
options.aec_dump.Set(false);
|
||||
return options;
|
||||
@ -806,6 +807,19 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
|
||||
options.experimental_ns.Set(false);
|
||||
#endif
|
||||
|
||||
// Delay Agnostic AEC automatically turns on EC if not set except on iOS
|
||||
// where the feature is not supported.
|
||||
bool use_delay_agnostic_aec = false;
|
||||
#if !defined(IOS)
|
||||
if (options.delay_agnostic_aec.Get(&use_delay_agnostic_aec)) {
|
||||
if (use_delay_agnostic_aec) {
|
||||
options.echo_cancellation.Set(true);
|
||||
options.experimental_aec.Set(true);
|
||||
ec_mode = webrtc::kEcConference;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG(LS_INFO) << "Applying audio options: " << options.ToString();
|
||||
|
||||
webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing();
|
||||
@ -818,10 +832,14 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
|
||||
// in combination with Open SL ES audio.
|
||||
const bool built_in_aec = voe_wrapper_->hw()->BuiltInAECIsAvailable();
|
||||
if (built_in_aec) {
|
||||
// Enabled built-in EC if the device has one and delay agnostic AEC is not
|
||||
// enabled.
|
||||
const bool enable_built_in_aec = echo_cancellation &
|
||||
!use_delay_agnostic_aec;
|
||||
// Set mode of built-in EC according to the audio options.
|
||||
voe_wrapper_->hw()->EnableBuiltInAEC(echo_cancellation);
|
||||
if (echo_cancellation) {
|
||||
// Disable internal software EC if device has its own built-in EC,
|
||||
voe_wrapper_->hw()->EnableBuiltInAEC(enable_built_in_aec);
|
||||
if (enable_built_in_aec) {
|
||||
// Disable internal software EC if built-in EC is enabled,
|
||||
// i.e., replace the software EC with the built-in EC.
|
||||
options.echo_cancellation.Set(false);
|
||||
echo_cancellation = false;
|
||||
@ -948,6 +966,14 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
|
||||
|
||||
webrtc::Config config;
|
||||
|
||||
delay_agnostic_aec_.SetFrom(options.delay_agnostic_aec);
|
||||
bool delay_agnostic_aec;
|
||||
if (delay_agnostic_aec_.Get(&delay_agnostic_aec)) {
|
||||
LOG(LS_INFO) << "Delay agnostic aec is enabled? " << delay_agnostic_aec;
|
||||
config.Set<webrtc::ReportedDelay>(
|
||||
new webrtc::ReportedDelay(!delay_agnostic_aec));
|
||||
}
|
||||
|
||||
experimental_aec_.SetFrom(options.experimental_aec);
|
||||
bool experimental_aec;
|
||||
if (experimental_aec_.Get(&experimental_aec)) {
|
||||
|
||||
@ -290,11 +290,12 @@ class WebRtcVoiceEngine
|
||||
|
||||
rtc::CriticalSection signal_media_critical_;
|
||||
|
||||
// Cache received experimental_aec and experimental_ns values, and apply them
|
||||
// in case they are missing in the audio options. We need to do this because
|
||||
// SetExtraOptions() will revert to defaults for options which are not
|
||||
// provided.
|
||||
// Cache received experimental_aec, delay_agnostic_aec and experimental_ns
|
||||
// values, and apply them in case they are missing in the audio options. We
|
||||
// need to do this because SetExtraOptions() will revert to defaults for
|
||||
// options which are not provided.
|
||||
Settable<bool> experimental_aec_;
|
||||
Settable<bool> delay_agnostic_aec_;
|
||||
Settable<bool> experimental_ns_;
|
||||
};
|
||||
|
||||
|
||||
@ -2834,6 +2834,33 @@ TEST_F(WebRtcVoiceEngineTestFake, SetAudioOptions) {
|
||||
EXPECT_EQ(ec_mode, webrtc::kEcConference);
|
||||
EXPECT_EQ(ns_mode, webrtc::kNsHighSuppression);
|
||||
|
||||
// Turn on delay agnostic aec and make sure nothing change w.r.t. echo
|
||||
// control.
|
||||
options.delay_agnostic_aec.Set(true);
|
||||
ASSERT_TRUE(engine_.SetOptions(options));
|
||||
voe_.GetEcStatus(ec_enabled, ec_mode);
|
||||
voe_.GetEcMetricsStatus(ec_metrics_enabled);
|
||||
voe_.GetAecmMode(aecm_mode, cng_enabled);
|
||||
EXPECT_TRUE(ec_enabled);
|
||||
EXPECT_TRUE(ec_metrics_enabled);
|
||||
EXPECT_EQ(ec_mode, webrtc::kEcConference);
|
||||
|
||||
// Turn off echo cancellation and delay agnostic aec.
|
||||
options.delay_agnostic_aec.Set(false);
|
||||
options.experimental_aec.Set(false);
|
||||
options.echo_cancellation.Set(false);
|
||||
ASSERT_TRUE(engine_.SetOptions(options));
|
||||
voe_.GetEcStatus(ec_enabled, ec_mode);
|
||||
EXPECT_FALSE(ec_enabled);
|
||||
// Turning delay agnostic aec back on should also turn on echo cancellation.
|
||||
options.delay_agnostic_aec.Set(true);
|
||||
ASSERT_TRUE(engine_.SetOptions(options));
|
||||
voe_.GetEcStatus(ec_enabled, ec_mode);
|
||||
voe_.GetEcMetricsStatus(ec_metrics_enabled);
|
||||
EXPECT_TRUE(ec_enabled);
|
||||
EXPECT_TRUE(ec_metrics_enabled);
|
||||
EXPECT_EQ(ec_mode, webrtc::kEcConference);
|
||||
|
||||
// Turn off AGC
|
||||
options.auto_gain_control.Set(false);
|
||||
ASSERT_TRUE(engine_.SetOptions(options));
|
||||
|
||||
@ -1899,7 +1899,9 @@ void WebRtcAec_SetConfigCore(AecCore* self,
|
||||
if (self->metricsMode) {
|
||||
InitMetrics(self);
|
||||
}
|
||||
self->delay_logging_enabled = delay_logging;
|
||||
// Turn on delay logging if it is either set explicitly or if delay agnostic
|
||||
// AEC is enabled (which requires delay estimates).
|
||||
self->delay_logging_enabled = delay_logging || !self->reported_delay_enabled;
|
||||
if (self->delay_logging_enabled) {
|
||||
memset(self->delay_histogram, 0, sizeof(self->delay_histogram));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user