Skip to content

Commit

Permalink
Add system/DSP AEC logic to audio_manager_cras
Browse files Browse the repository at this point in the history
Enable CrAS-based System AEC/APM on LaCrOS by porting the existing
logic from audio_manager_chromeos to audio_manager_cras.

To be specific the functions covered in two prior CLs:

(1) https://chromium-review.googlesource.com/c/chromium/src/+/2782443
Allow Chrome to talk to Chrome OS to enable audio processing
functionalities (AEC, AGC, NS) in CrAS. Through new flags via
finch experimentation.

(2) https://chromium-review.googlesource.com/c/chromium/src/+/3475131
Adds the control logic in Chrome to provide finch-control over
the AEC, NS and AGC, DSP effects in CrAS, allowing safe fallbacks to the
browser counterparts.

BUG=b:205074860

(cherry picked from commit e46eb59)

Change-Id: I1b5af08d4b763b1fcecd4fda1264d5d667cd8992
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3535499
Reviewed-by: Henrik Andreasson <henrika@chromium.org>
Reviewed-by: Per Åhgren <peah@chromium.org>
Reviewed-by: Olga Sharonova <olka@chromium.org>
Reviewed-by: Hsinyu Chao <hychao@chromium.org>
Commit-Queue: Hsinyu Chao <hychao@chromium.org>
Auto-Submit: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Yu-Hsuan Hsu <yuhsuan@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#982686}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3539606
Cr-Commit-Position: refs/branch-heads/4951@{chromium#43}
Cr-Branched-From: 27de622-refs/heads/main@{#982481}
  • Loading branch information
Hsin-Yu Chao authored and Chromium LUCI CQ committed Mar 22, 2022
1 parent 8b4c1f1 commit 8045888
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 86 deletions.
17 changes: 9 additions & 8 deletions chrome/browser/about_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5801,28 +5801,29 @@ const FeatureEntry kFeatureEntries[] = {
"CCTResizableThirdPartiesDefaultPolicy")},
#endif

#if BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
{"allow-dsp-based-aec", flag_descriptions::kCrOSDspBasedAecAllowedName,
flag_descriptions::kCrOSDspBasedAecAllowedDescription, kOsCrOS,
flag_descriptions::kCrOSDspBasedAecAllowedDescription, kOsCrOS | kOsLinux,
FEATURE_VALUE_TYPE(features::kCrOSDspBasedAecAllowed)},
{"allow-dsp-based-ns", flag_descriptions::kCrOSDspBasedNsAllowedName,
flag_descriptions::kCrOSDspBasedNsAllowedDescription, kOsCrOS,
flag_descriptions::kCrOSDspBasedNsAllowedDescription, kOsCrOS | kOsLinux,
FEATURE_VALUE_TYPE(features::kCrOSDspBasedNsAllowed)},
{"allow-dsp-based-agc", flag_descriptions::kCrOSDspBasedAgcAllowedName,
flag_descriptions::kCrOSDspBasedAgcAllowedDescription, kOsCrOS,
flag_descriptions::kCrOSDspBasedAgcAllowedDescription, kOsCrOS | kOsLinux,
FEATURE_VALUE_TYPE(features::kCrOSDspBasedAgcAllowed)},
{"enforce-system-aec", flag_descriptions::kCrOSEnforceSystemAecName,
flag_descriptions::kCrOSEnforceSystemAecDescription, kOsCrOS,
flag_descriptions::kCrOSEnforceSystemAecDescription, kOsCrOS | kOsLinux,
FEATURE_VALUE_TYPE(features::kCrOSEnforceSystemAec)},
{"enforce-system-aec-agc", flag_descriptions::kCrOSEnforceSystemAecAgcName,
flag_descriptions::kCrOSEnforceSystemAecAgcDescription, kOsCrOS,
flag_descriptions::kCrOSEnforceSystemAecAgcDescription, kOsCrOS | kOsLinux,
FEATURE_VALUE_TYPE(features::kCrOSEnforceSystemAecAgc)},
{"enforce-system-aec-ns-agc",
flag_descriptions::kCrOSEnforceSystemAecNsAgcName,
flag_descriptions::kCrOSEnforceSystemAecNsAgcDescription, kOsCrOS,
flag_descriptions::kCrOSEnforceSystemAecNsAgcDescription,
kOsCrOS | kOsLinux,
FEATURE_VALUE_TYPE(features::kCrOSEnforceSystemAecNsAgc)},
{"enforce-system-aec-ns", flag_descriptions::kCrOSEnforceSystemAecNsName,
flag_descriptions::kCrOSEnforceSystemAecNsDescription, kOsCrOS,
flag_descriptions::kCrOSEnforceSystemAecNsDescription, kOsCrOS | kOsLinux,
FEATURE_VALUE_TYPE(features::kCrOSEnforceSystemAecNs)},
#endif

Expand Down
68 changes: 34 additions & 34 deletions chrome/browser/flag_descriptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4547,40 +4547,6 @@ const char kDriveFsBidirectionalNativeMessagingName[] =
const char kDriveFsBidirectionalNativeMessagingDescription[] =
"Enable enhanced native messaging host to communicate with DriveFS.";

const char kCrOSDspBasedAecAllowedName[] =
"Allow CRAS to use a DSP-based AEC if available";
const char kCrOSDspBasedAecAllowedDescription[] =
"Allows the system variant of the AEC in CRAS to be run on DSP ";

const char kCrOSDspBasedNsAllowedName[] =
"Allow CRAS to use a DSP-based NS if available";
const char kCrOSDspBasedNsAllowedDescription[] =
"Allows the system variant of the NS in CRAS to be run on DSP ";

const char kCrOSDspBasedAgcAllowedName[] =
"Allow CRAS to use a DSP-based AGC if available";
const char kCrOSDspBasedAgcAllowedDescription[] =
"Allows the system variant of the AGC in CRAS to be run on DSP ";

const char kCrOSEnforceSystemAecName[] = "Enforce using the system AEC in CrAS";
const char kCrOSEnforceSystemAecDescription[] =
"Enforces using the system variant in CrAS of the AEC";

const char kCrOSEnforceSystemAecAgcName[] =
"Enforce using the system AEC and AGC in CrAS";
const char kCrOSEnforceSystemAecAgcDescription[] =
"Enforces using the system variants in CrAS of the AEC and AGC.";

const char kCrOSEnforceSystemAecNsName[] =
"Enforce using the system AEC and NS in CrAS";
const char kCrOSEnforceSystemAecNsDescription[] =
"Enforces using the system variants in CrAS of the AEC and NS.";

const char kCrOSEnforceSystemAecNsAgcName[] =
"Enforce using the system AEC, NS and AGC in CrAS";
const char kCrOSEnforceSystemAecNsAgcDescription[] =
"Enforces using the system variants in CrAS of the AEC, NS and AGC.";

const char kEnableAppReinstallZeroStateName[] =
"Enable Zero State App Reinstall Suggestions.";
const char kEnableAppReinstallZeroStateDescription[] =
Expand Down Expand Up @@ -5582,6 +5548,40 @@ const char kBluetoothAdvertisementMonitoringDescription[] =
"scanners that filter low energy advertisements in a power-efficient "
"manner.";

const char kCrOSDspBasedAecAllowedName[] =
"Allow CRAS to use a DSP-based AEC if available";
const char kCrOSDspBasedAecAllowedDescription[] =
"Allows the system variant of the AEC in CRAS to be run on DSP ";

const char kCrOSDspBasedNsAllowedName[] =
"Allow CRAS to use a DSP-based NS if available";
const char kCrOSDspBasedNsAllowedDescription[] =
"Allows the system variant of the NS in CRAS to be run on DSP ";

const char kCrOSDspBasedAgcAllowedName[] =
"Allow CRAS to use a DSP-based AGC if available";
const char kCrOSDspBasedAgcAllowedDescription[] =
"Allows the system variant of the AGC in CRAS to be run on DSP ";

const char kCrOSEnforceSystemAecName[] = "Enforce using the system AEC in CrAS";
const char kCrOSEnforceSystemAecDescription[] =
"Enforces using the system variant in CrAS of the AEC";

const char kCrOSEnforceSystemAecAgcName[] =
"Enforce using the system AEC and AGC in CrAS";
const char kCrOSEnforceSystemAecAgcDescription[] =
"Enforces using the system variants in CrAS of the AEC and AGC.";

const char kCrOSEnforceSystemAecNsName[] =
"Enforce using the system AEC and NS in CrAS";
const char kCrOSEnforceSystemAecNsDescription[] =
"Enforces using the system variants in CrAS of the AEC and NS.";

const char kCrOSEnforceSystemAecNsAgcName[] =
"Enforce using the system AEC, NS and AGC in CrAS";
const char kCrOSEnforceSystemAecNsAgcDescription[] =
"Enforces using the system variants in CrAS of the AEC, NS and AGC.";

const char kDefaultCalculatorWebAppName[] = "Default install Calculator PWA";
const char kDefaultCalculatorWebAppDescription[] =
"Enable default installing of the calculator PWA instead of the deprecated "
Expand Down
42 changes: 21 additions & 21 deletions chrome/browser/flag_descriptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2606,27 +2606,6 @@ extern const char kQuickSettingsPWANotificationsDescription[];
extern const char kDriveFsBidirectionalNativeMessagingName[];
extern const char kDriveFsBidirectionalNativeMessagingDescription[];

extern const char kCrOSDspBasedAecAllowedName[];
extern const char kCrOSDspBasedAecAllowedDescription[];

extern const char kCrOSDspBasedNsAllowedName[];
extern const char kCrOSDspBasedNsAllowedDescription[];

extern const char kCrOSDspBasedAgcAllowedName[];
extern const char kCrOSDspBasedAgcAllowedDescription[];

extern const char kCrOSEnforceSystemAecName[];
extern const char kCrOSEnforceSystemAecDescription[];

extern const char kCrOSEnforceSystemAecAgcName[];
extern const char kCrOSEnforceSystemAecAgcDescription[];

extern const char kCrOSEnforceSystemAecNsName[];
extern const char kCrOSEnforceSystemAecNsDescription[];

extern const char kCrOSEnforceSystemAecNsAgcName[];
extern const char kCrOSEnforceSystemAecNsAgcDescription[];

extern const char kEnableAppReinstallZeroStateName[];
extern const char kEnableAppReinstallZeroStateDescription[];

Expand Down Expand Up @@ -3212,6 +3191,27 @@ extern const char
extern const char kBluetoothAdvertisementMonitoringName[];
extern const char kBluetoothAdvertisementMonitoringDescription[];

extern const char kCrOSDspBasedAecAllowedName[];
extern const char kCrOSDspBasedAecAllowedDescription[];

extern const char kCrOSDspBasedNsAllowedName[];
extern const char kCrOSDspBasedNsAllowedDescription[];

extern const char kCrOSDspBasedAgcAllowedName[];
extern const char kCrOSDspBasedAgcAllowedDescription[];

extern const char kCrOSEnforceSystemAecName[];
extern const char kCrOSEnforceSystemAecDescription[];

extern const char kCrOSEnforceSystemAecAgcName[];
extern const char kCrOSEnforceSystemAecAgcDescription[];

extern const char kCrOSEnforceSystemAecNsName[];
extern const char kCrOSEnforceSystemAecNsDescription[];

extern const char kCrOSEnforceSystemAecNsAgcName[];
extern const char kCrOSEnforceSystemAecNsAgcDescription[];

extern const char kDefaultCalculatorWebAppName[];
extern const char kDefaultCalculatorWebAppDescription[];
#endif // BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
Expand Down
182 changes: 159 additions & 23 deletions media/audio/cras/audio_manager_cras.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,44 +79,180 @@ void AudioManagerCras::GetAudioOutputDeviceNames(
}
}

AudioParameters AudioManagerCras::GetInputStreamParameters(
const std::string& device_id) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
// Checks if a system AEC with a specific group ID is flagged to be deactivated
// by the field trial.
bool IsSystemAecDeactivated(int aec_group_id) {
return base::GetFieldTrialParamByFeatureAsBool(
features::kCrOSSystemAECDeactivatedGroups,
base::NumberToString(aec_group_id), false);
}

int user_buffer_size = GetUserBufferSize();
int buffer_size =
user_buffer_size ? user_buffer_size : kDefaultInputBufferSize;
// Checks if the board with `aec_group_id` is flagged by the field trial to not
// allow using DSP-based AEC effect.
bool IsDspBasedAecDeactivated(int aec_group_id) {
return base::GetFieldTrialParamByFeatureAsBool(
features::kCrOSDspBasedAecDeactivatedGroups,
base::NumberToString(aec_group_id), false) ||
!base::FeatureList::IsEnabled(features::kCrOSDspBasedAecAllowed);
}

// Checks if the board with `aec_group_id` is flagged by the field trial to not
// allow using DSP-based NS effect.
bool IsDspBasedNsDeactivated(int aec_group_id) {
return base::GetFieldTrialParamByFeatureAsBool(
features::kCrOSDspBasedNsDeactivatedGroups,
base::NumberToString(aec_group_id), false) ||
!base::FeatureList::IsEnabled(features::kCrOSDspBasedNsAllowed);
}

// Checks if the board with `aec_group_id` is flagged by the field trial to not
// allow using DSP-based AGC effect.
bool IsDspBasedAgcDeactivated(int aec_group_id) {
return base::GetFieldTrialParamByFeatureAsBool(
features::kCrOSDspBasedAgcDeactivatedGroups,
base::NumberToString(aec_group_id), false) ||
!base::FeatureList::IsEnabled(features::kCrOSDspBasedAgcAllowed);
}

// Specifies which DSP-based effects are allowed based on media constraints and
// any finch field trials.
void SetAllowedDspBasedEffects(int aec_group_id, AudioParameters& params) {
int effects = params.effects();

// Allow AEC to be applied by CRAS on DSP if the AEC is active in CRAS and if
// using the AEC on DSP has not been deactivated by any field trials.
if ((effects & AudioParameters::ECHO_CANCELLER) &&
!IsDspBasedAecDeactivated(aec_group_id)) {
effects = effects | AudioParameters::ALLOW_DSP_ECHO_CANCELLER;
} else {
effects = effects & ~AudioParameters::ALLOW_DSP_ECHO_CANCELLER;
}

// Allow NS to be applied by CRAS on DSP if the NS is active in CRAS and if
// using the NS on DSP has not been deactivated by any field trials.
if ((effects & AudioParameters::NOISE_SUPPRESSION) &&
!IsDspBasedNsDeactivated(aec_group_id)) {
effects = effects | AudioParameters::ALLOW_DSP_NOISE_SUPPRESSION;
} else {
effects = effects & ~AudioParameters::ALLOW_DSP_NOISE_SUPPRESSION;
}

// Allow AGC to be applied by CRAS on DSP if the AGC is active in CRAS and if
// using the AGC on DSP has not been deactivated by any field trials.
if ((effects & AudioParameters::AUTOMATIC_GAIN_CONTROL) &&
!IsDspBasedAgcDeactivated(aec_group_id)) {
effects = effects | AudioParameters::ALLOW_DSP_AUTOMATIC_GAIN_CONTROL;
} else {
effects = effects & ~AudioParameters::ALLOW_DSP_AUTOMATIC_GAIN_CONTROL;
}

params.set_effects(effects);
}


// Collects flags values for whether, and in what way, the AEC, NS or AGC
// effects should be enforced in spite of them not being flagged as supported by
// the board.
void RetrieveSystemEffectFeatures(bool& enforce_system_aec,
bool& enforce_system_ns,
bool& enforce_system_agc,
bool& tuned_system_aec_allowed) {
const bool enforce_system_aec_ns_agc_feature =
base::FeatureList::IsEnabled(features::kCrOSEnforceSystemAecNsAgc);
const bool enforce_system_aec_ns_feature =
base::FeatureList::IsEnabled(features::kCrOSEnforceSystemAecNs);
const bool enforce_system_aec_agc_feature =
base::FeatureList::IsEnabled(features::kCrOSEnforceSystemAecAgc);
const bool enforce_system_aec_feature =
base::FeatureList::IsEnabled(features::kCrOSEnforceSystemAec);

enforce_system_aec =
enforce_system_aec_feature || enforce_system_aec_ns_agc_feature ||
enforce_system_aec_ns_feature || enforce_system_aec_agc_feature;
enforce_system_ns =
enforce_system_aec_ns_agc_feature || enforce_system_aec_ns_feature;
enforce_system_agc =
enforce_system_aec_ns_agc_feature || enforce_system_aec_agc_feature;

tuned_system_aec_allowed =
base::FeatureList::IsEnabled(features::kCrOSSystemAEC);
}

AudioParameters AudioManagerCras::GetStreamParametersForSystem(
int user_buffer_size) {
AudioParameters params(
AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
kDefaultSampleRate, buffer_size,
kDefaultSampleRate, user_buffer_size,
AudioParameters::HardwareCapabilities(limits::kMinAudioBufferSize,
limits::kMaxAudioBufferSize));

// Allow experimentation with system echo cancellation with all devices,
// but enable it by default on devices that actually support it.
bool enforce_system_aec;
bool enforce_system_ns;
bool enforce_system_agc;
bool tuned_system_aec_allowed;
RetrieveSystemEffectFeatures(enforce_system_aec, enforce_system_ns,
enforce_system_agc, tuned_system_aec_allowed);

// Activation of the system AEC. Allow experimentation with system AEC with
// all devices, but enable it by default on devices that actually support it.
params.set_effects(params.effects() |
AudioParameters::EXPERIMENTAL_ECHO_CANCELLER);
if (base::FeatureList::IsEnabled(features::kCrOSSystemAEC)) {
if (cras_util_->CrasGetAecSupported()) {
const int32_t aec_group_id = cras_util_->CrasGetAecGroupId();

// Check if the system AEC has a group ID which is flagged to be
// deactivated by the field trial.
const bool system_aec_deactivated =
base::GetFieldTrialParamByFeatureAsBool(
features::kCrOSSystemAECDeactivatedGroups,
base::NumberToString(aec_group_id), false);

if (!system_aec_deactivated) {
params.set_effects(params.effects() | AudioParameters::ECHO_CANCELLER);
}

// Rephrase the field aec_supported to properly reflect its meaning in this
// context (since it currently signals whether an CrAS APM with tuned settings
// is available).
// TODO(crbug.com/1307680): add unit tests and caching cras_util_ results.
const bool tuned_system_apm_available = cras_util_->CrasGetAecSupported();

// Don't use the system AEC if it is deactivated for this group ID. Also never
// activate NS nor AGC for this board if the AEC is not activated, since this
// will cause issues for the Browser AEC.
bool use_system_aec =
(tuned_system_apm_available && tuned_system_aec_allowed) ||
enforce_system_aec;

// TODO(hychao): query from CRAS
bool system_ns_supported = true;
bool system_agc_supported = true;

int aec_group_id = cras_util_->CrasGetAecGroupId();
if (!use_system_aec || IsSystemAecDeactivated(aec_group_id)) {
SetAllowedDspBasedEffects(aec_group_id, params);
return params;
}

// Activation of the system AEC.
params.set_effects(params.effects() | AudioParameters::ECHO_CANCELLER);

// Don't use system NS or AGC if the AEC has board-specific tunings.
if (!tuned_system_apm_available) {
// Activation of the system NS.
if (system_ns_supported || enforce_system_ns) {
params.set_effects(params.effects() | AudioParameters::NOISE_SUPPRESSION);
}

// Activation of the system AGC.
if (system_agc_supported || enforce_system_agc) {
params.set_effects(params.effects() |
AudioParameters::AUTOMATIC_GAIN_CONTROL);
}
}

SetAllowedDspBasedEffects(aec_group_id, params);
return params;
}

AudioParameters AudioManagerCras::GetInputStreamParameters(
const std::string& device_id) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());

int user_buffer_size = GetUserBufferSize();
user_buffer_size =
user_buffer_size ? user_buffer_size : kDefaultInputBufferSize;

return GetStreamParametersForSystem(user_buffer_size);
}

std::string AudioManagerCras::GetDefaultInputDeviceID() {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
return base::NumberToString(GetPrimaryActiveInputNode());
Expand Down
5 changes: 5 additions & 0 deletions media/audio/cras/audio_manager_cras.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerCrasBase {
bool IsDefault(const std::string& device_id, bool is_input) override;
enum CRAS_CLIENT_TYPE GetClientType() override;

// Produces AudioParameters for the system, including audio processing
// capabilities tailored for the system,
AudioParameters GetStreamParametersForSystem(
int user_buffer_size);

protected:
AudioParameters GetPreferredOutputStreamParameters(
const std::string& output_device_id,
Expand Down

0 comments on commit 8045888

Please sign in to comment.