0

capture_audio_mixing: Add new settings options

This CL adds the two new audio settings options for
recording the system audio, and system+microphone
audio. No behavior changes, as the backend has not been
implemented yet.

Fixed: b/280324309
Test: Manually, existing and new unit tests
Change-Id: I01f90717a8abdf0359a663442f14e8ea5ab8be3e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4499401
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: Min Chen <minch@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1139723}
This commit is contained in:
Ahmed Fakhry
2023-05-04 19:45:24 +00:00
committed by Chromium LUCI CQ
parent 604865633f
commit 3073e19ff7
23 changed files with 284 additions and 74 deletions

@ -342,7 +342,6 @@ component("ash") {
"capture_mode/capture_mode_settings_view.h",
"capture_mode/capture_mode_source_view.cc",
"capture_mode/capture_mode_source_view.h",
"capture_mode/capture_mode_test_api.cc",
"capture_mode/capture_mode_toast_controller.cc",
"capture_mode/capture_mode_toast_controller.h",
"capture_mode/capture_mode_type_view.cc",
@ -914,7 +913,6 @@ component("ash") {
"public/cpp/autotest_desks_api.h",
"public/cpp/autotest_private_api_utils.h",
"public/cpp/capture_mode/capture_mode_api.h",
"public/cpp/capture_mode/capture_mode_test_api.h",
"public/cpp/debug_utils.h",
"public/cpp/event_rewriter_controller.h",
"public/cpp/multi_user_window_manager.h",
@ -3917,6 +3915,7 @@ static_library("test_support") {
"capture_mode/capture_mode_session_test_api.h",
"capture_mode/capture_mode_settings_test_api.cc",
"capture_mode/capture_mode_settings_test_api.h",
"capture_mode/capture_mode_test_api.cc",
"capture_mode/capture_mode_test_util.cc",
"capture_mode/capture_mode_test_util.h",
"capture_mode/fake_camera_device.cc",
@ -4006,6 +4005,7 @@ static_library("test_support") {
# These headers declare functions that are implemented inside of //ash, so
# they cannot live in //ash/public/cpp/BUILD.gn.
"public/cpp/capture_mode/capture_mode_test_api.h",
"public/cpp/holding_space/holding_space_test_api.h",
"public/cpp/system_tray_test_api.h",
"public/cpp/test/accessibility_controller_test_api.h",

@ -5668,6 +5668,12 @@ Here are some things you can try to get started.
<message name="IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_MICROPHONE" desc="The label of the menu option button for microphone audio input.">
Microphone
</message>
<message name="IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_SYSTEM" desc="The label of the menu option button for the device's system audio input.">
Device audio
</message>
<message name="IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_SYSTEM_AND_MICROPHONE" desc="The label of the menu option button for mixing the microphone and the device's system audio input together.">
Device audio and microphone
</message>
<message name="IDS_ASH_SCREEN_CAPTURE_CAMERA" desc="The label of the camera menu group header in capture mode settings.">
Camera
</message>

@ -0,0 +1 @@
640627d73ec29a6f6387f484249f5ba594a69abb

@ -0,0 +1 @@
1902074b88e3cf012ccef38396f00e1990a1df90

@ -8,6 +8,7 @@
#include <memory>
#include <vector>
#include "ash/ash_export.h"
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
@ -53,7 +54,8 @@ class BufferHandleHolder {
// Defines an object that will subscribe to a camera device, whose remote video
// source is the given `camera_video_source`. It will handle the reception of
// the video frames from that device and provide them to its `Delegate`.
class CameraVideoFrameHandler : public video_capture::mojom::VideoFrameHandler {
class ASH_EXPORT CameraVideoFrameHandler
: public video_capture::mojom::VideoFrameHandler {
public:
// Defines an interface for a delegate of this class, which will be provided
// by the video frames received from the camera device.

@ -2,7 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/capture_mode/capture_mode_controller.h"
#include "ash/capture_mode/capture_mode_menu_group.h"
#include "ash/capture_mode/capture_mode_session_test_api.h"
#include "ash/capture_mode/capture_mode_settings_test_api.h"
#include "ash/capture_mode/capture_mode_settings_view.h"
#include "ash/capture_mode/capture_mode_test_util.h"
#include "ash/capture_mode/capture_mode_types.h"
#include "ash/constants/ash_features.h"
#include "ash/style/icon_button.h"
#include "ash/test/ash_test_base.h"
#include "base/test/scoped_feature_list.h"
@ -16,12 +24,109 @@ class CaptureAudioMixingTest : public AshTestBase {
CaptureAudioMixingTest& operator=(const CaptureAudioMixingTest&) = delete;
~CaptureAudioMixingTest() override = default;
CaptureModeController* StartSession() {
return StartCaptureSession(CaptureModeSource::kFullscreen,
CaptureModeType::kVideo);
}
bool IsAudioOptionChecked(int option_id) const {
return CaptureModeSettingsTestApi()
.GetAudioInputMenuGroup()
->IsOptionChecked(option_id);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(CaptureAudioMixingTest, Basic) {
EXPECT_TRUE(features::IsCaptureModeAudioMixingEnabled());
TEST_F(CaptureAudioMixingTest, AudioSettingsMenu) {
auto* controller = StartSession();
auto* event_generator = GetEventGenerator();
// Open the settings menu, and check the currently selected audio mode.
ClickOnView(GetSettingsButton(), event_generator);
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
{
CaptureModeSettingsTestApi test_api;
views::View* microphone_option = test_api.GetMicrophoneOption();
views::View* system_option = test_api.GetSystemAudioOption();
views::View* system_and_microphone_option =
test_api.GetSystemAndMicrophoneAudioOption();
// All the options should exist, but only the "off" option should be
// selected.
EXPECT_TRUE(microphone_option);
EXPECT_TRUE(system_option);
EXPECT_TRUE(system_and_microphone_option);
EXPECT_TRUE(IsAudioOptionChecked(kAudioOff));
EXPECT_FALSE(IsAudioOptionChecked(kAudioMicrophone));
EXPECT_FALSE(IsAudioOptionChecked(kAudioSystem));
EXPECT_FALSE(IsAudioOptionChecked(kAudioSystemAndMicrophone));
// Clicking on the system audio should select that option and update the
// controller.
ClickOnView(system_option, event_generator);
EXPECT_FALSE(IsAudioOptionChecked(kAudioOff));
EXPECT_FALSE(IsAudioOptionChecked(kAudioMicrophone));
EXPECT_TRUE(IsAudioOptionChecked(kAudioSystem));
EXPECT_FALSE(IsAudioOptionChecked(kAudioSystemAndMicrophone));
EXPECT_EQ(AudioRecordingMode::kSystem,
controller->GetEffectiveAudioRecordingMode());
// Likewise for the system+microphone option.
ClickOnView(system_and_microphone_option, event_generator);
EXPECT_FALSE(IsAudioOptionChecked(kAudioOff));
EXPECT_FALSE(IsAudioOptionChecked(kAudioMicrophone));
EXPECT_FALSE(IsAudioOptionChecked(kAudioSystem));
EXPECT_TRUE(IsAudioOptionChecked(kAudioSystemAndMicrophone));
EXPECT_EQ(AudioRecordingMode::kSystemAndMicrophone,
controller->GetEffectiveAudioRecordingMode());
}
// Exit the session, and start a new one. The most recent audio setting will
// be remembered.
SendKey(ui::VKEY_ESCAPE, event_generator);
StartSession();
ClickOnView(GetSettingsButton(), event_generator);
EXPECT_FALSE(IsAudioOptionChecked(kAudioOff));
EXPECT_FALSE(IsAudioOptionChecked(kAudioMicrophone));
EXPECT_FALSE(IsAudioOptionChecked(kAudioSystem));
EXPECT_TRUE(IsAudioOptionChecked(kAudioSystemAndMicrophone));
}
TEST_F(CaptureAudioMixingTest, KeyboardNavigation) {
auto* controller = StartSession();
using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup;
CaptureModeSessionTestApi test_api(controller->capture_mode_session());
auto* event_generator = GetEventGenerator();
SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/6);
EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(), GetSettingsButton());
// Press the space bar, and the settings menu should open, ready for keyboard
// navigation.
SendKey(ui::VKEY_SPACE, event_generator);
EXPECT_EQ(FocusGroup::kPendingSettings, test_api.GetCurrentFocusGroup());
CaptureModeSettingsView* settings_menu =
test_api.GetCaptureModeSettingsView();
ASSERT_TRUE(settings_menu);
CaptureModeSettingsTestApi settings_test_api;
// Tab twice, the current focused view is the "Off" option.
SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/2);
EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
settings_test_api.GetAudioOffOption());
// Next tabs will go through all the audio options.
SendKey(ui::VKEY_TAB, event_generator);
EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
settings_test_api.GetSystemAudioOption());
SendKey(ui::VKEY_TAB, event_generator);
EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
settings_test_api.GetMicrophoneOption());
SendKey(ui::VKEY_TAB, event_generator);
EXPECT_EQ(test_api.GetCurrentFocusedView()->GetView(),
settings_test_api.GetSystemAndMicrophoneAudioOption());
}
} // namespace ash

@ -4608,7 +4608,7 @@ TEST_F(CaptureModePrivacyIndicatorsTest, DuringRecordingPrivacyIndicators) {
// When the user selects audio recording, the idicators won't change.
// Recording has to start first.
capture_controller->EnableAudioRecording(true);
capture_controller->SetAudioRecordingMode(AudioRecordingMode::kMicrophone);
EXPECT_FALSE(IsMicrophoneIndicatorIconVisible());
StartRecordingFromSource(CaptureModeSource::kFullscreen);

@ -550,8 +550,10 @@ bool CaptureModeController::IsActive() const {
return capture_mode_session_ && !capture_mode_session_->is_shutting_down();
}
bool CaptureModeController::GetAudioRecordingEnabled() const {
return enable_audio_recording_ && !IsAudioCaptureDisabledByPolicy();
AudioRecordingMode CaptureModeController::GetEffectiveAudioRecordingMode()
const {
return IsAudioCaptureDisabledByPolicy() ? AudioRecordingMode::kOff
: audio_recording_mode_;
}
bool CaptureModeController::IsAudioCaptureDisabledByPolicy() const {
@ -957,7 +959,7 @@ void CaptureModeController::MaybeRestoreCachedCaptureConfigurations() {
type_ = cached_normal_session_configs_->type;
source_ = cached_normal_session_configs_->source;
recording_type_ = cached_normal_session_configs_->recording_type;
enable_audio_recording_ = cached_normal_session_configs_->audio_on;
audio_recording_mode_ = cached_normal_session_configs_->audio_recording_mode;
enable_demo_tools_ = cached_normal_session_configs_->demo_tools_enabled;
cached_normal_session_configs_.reset();
}
@ -1639,7 +1641,8 @@ void CaptureModeController::BeginVideoRecording(
Stop();
const bool should_record_audio =
SupportsAudioRecording(recording_type_) && GetAudioRecordingEnabled();
SupportsAudioRecording(recording_type_) &&
GetEffectiveAudioRecordingMode() != AudioRecordingMode::kOff;
mojo::PendingRemote<viz::mojom::FrameSinkVideoCaptureOverlay>
cursor_capture_overlay;
auto cursor_overlay_receiver =
@ -1670,7 +1673,7 @@ void CaptureModeController::BeginVideoRecording(
RecordRecordingStartsWithDemoTools(enable_demo_tools_, for_projector);
// Restore the capture mode configurations that include the `type_`, `source_`
// and `enable_audio_recording_` after projector-inititated recording starts
// and `audio_recording_mode` after projector-inititated recording starts
// if any of them was overridden in projector-initiated capture mode session.
MaybeRestoreCachedCaptureConfigurations();
@ -1783,7 +1786,7 @@ void CaptureModeController::OnDlpRestrictionCheckedAtCountDownFinished(
CaptureModeBehavior* active_behavior =
capture_mode_session_->active_behavior();
if (active_behavior->IsAudioRecordingRequired() &&
!GetAudioRecordingEnabled()) {
GetEffectiveAudioRecordingMode() == AudioRecordingMode::kOff) {
// Before asking the client to create a folder to host the video file, we
// check if they require audio recording to be enabled, but it can't be
// allowed due to admin policy. In this case we just abort the recording by
@ -1862,9 +1865,9 @@ void CaptureModeController::OnDlpRestrictionCheckedAtSessionInit(
// restoration when switching to the normal capture mode session if needed.
cached_normal_session_configs_ =
CaptureSessionConfigs{type_, source_, recording_type_,
enable_audio_recording_, enable_demo_tools_};
audio_recording_mode_, enable_demo_tools_};
enable_audio_recording_ = true;
audio_recording_mode_ = AudioRecordingMode::kMicrophone;
enable_demo_tools_ = true;
SetType(CaptureModeType::kVideo);
SetSource(CaptureModeSource::kFullscreen);

@ -109,9 +109,9 @@ class ASH_EXPORT CaptureModeController
// capture_mode_util::IsCaptureModeActive().
bool IsActive() const;
// Returns true if audio recording is enabled. This takes into account the
// Returns the effective audio recording mode, taking into account the
// `AudioCaptureAllowed` policy.
bool GetAudioRecordingEnabled() const;
AudioRecordingMode GetEffectiveAudioRecordingMode() const;
// Returns true if audio recording is forced disabled by the
// `AudioCaptureAllowed` policy.
@ -127,12 +127,12 @@ class ASH_EXPORT CaptureModeController
void SetType(CaptureModeType type);
void SetRecordingType(RecordingType recording_type);
// Sets the audio recording flag, which will be applied to any future
// Sets the audio recording mode, which will be applied to any future
// recordings (cannot be set mid recording), or to a future capture mode
// session when Start() is called. The effective enabled state takes into
// account the `AudioCaptureAllowed` policy.
void EnableAudioRecording(bool enable_audio_recording) {
enable_audio_recording_ = enable_audio_recording;
void SetAudioRecordingMode(AudioRecordingMode mode) {
audio_recording_mode_ = mode;
}
// Sets the flag to enable the demo tools feature, which will be applied to
@ -284,7 +284,7 @@ class ASH_EXPORT CaptureModeController
void StartVideoRecordingImmediatelyForTesting();
// Restores the capture mode configurations that include the `type_`,
// `source_`, `enable_audio_recording_`, `recording_type_` and
// `source_`, `audio_recording_mode_`, `recording_type_` and
// `enable_demo_tools_` if any of them gets overridden in the
// projector-initiated capture mode session.
void MaybeRestoreCachedCaptureConfigurations();
@ -314,7 +314,7 @@ class ASH_EXPORT CaptureModeController
CaptureModeType type;
CaptureModeSource source;
RecordingType recording_type;
bool audio_on;
AudioRecordingMode audio_recording_mode;
bool demo_tools_enabled;
};
@ -582,12 +582,12 @@ class ASH_EXPORT CaptureModeController
std::unique_ptr<CaptureModeSession> capture_mode_session_;
// Remember the user selected audio preference of whether to record audio or
// not for a video, between sessions. Initially, this value is set to false,
// ensuring that this is an opt-in feature. Note that this value will always
// be overwritten by the `AudioCaptureAllowed` policy, when
// `GetAudioRecordingEnabled()` is called.
bool enable_audio_recording_ = false;
// Remember the user selected preference for audio recording between sessions.
// Initially, this value is set to `kOff`, ensuring that this is an opt-in
// feature. Note that this value will always be overwritten by the
// `AudioCaptureAllowed` policy, when `GetEffectiveAudioRecordingMode()` is
// called.
AudioRecordingMode audio_recording_mode_ = AudioRecordingMode::kOff;
// If true, the 3-second countdown UI will be skipped, and video recording
// will start immediately.

@ -782,9 +782,11 @@ void CaptureModeSession::ReportSessionHistograms() {
num_capture_region_adjusted_ = 0;
RecordCaptureModeSwitchesFromInitialMode(capture_source_changed_);
RecordCaptureModeConfiguration(controller_->type(), source, recording_type,
controller_->GetAudioRecordingEnabled(),
is_in_projector_mode_);
RecordCaptureModeConfiguration(
controller_->type(), source, recording_type,
/*audio_on=*/controller_->GetEffectiveAudioRecordingMode() !=
AudioRecordingMode::kOff,
is_in_projector_mode_);
}
void CaptureModeSession::StartCountDown(

@ -42,6 +42,15 @@ views::View* CaptureModeSettingsTestApi::GetAudioOffOption() {
return GetAudioInputMenuGroup()->GetOptionForTesting(kAudioOff);
}
views::View* CaptureModeSettingsTestApi::GetSystemAudioOption() {
return GetAudioInputMenuGroup()->GetOptionForTesting(kAudioSystem);
}
views::View* CaptureModeSettingsTestApi::GetSystemAndMicrophoneAudioOption() {
return GetAudioInputMenuGroup()->GetOptionForTesting(
kAudioSystemAndMicrophone);
}
CaptureModeMenuGroup* CaptureModeSettingsTestApi::GetSaveToMenuGroup() {
return settings_view_->save_to_menu_group_;
}

@ -35,6 +35,8 @@ class CaptureModeSettingsTestApi {
CaptureModeMenuGroup* GetAudioInputMenuGroup();
views::View* GetMicrophoneOption();
views::View* GetAudioOffOption();
views::View* GetSystemAudioOption();
views::View* GetSystemAndMicrophoneAudioOption();
// Returns the save-to settings menu group and the views for its options.
CaptureModeMenuGroup* GetSaveToMenuGroup();

@ -14,6 +14,7 @@
#include "ash/capture_mode/capture_mode_metrics.h"
#include "ash/capture_mode/capture_mode_session.h"
#include "ash/capture_mode/capture_mode_session_focus_cycler.h"
#include "ash/capture_mode/capture_mode_types.h"
#include "ash/capture_mode/capture_mode_util.h"
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/style/color_provider.h"
@ -38,7 +39,7 @@ namespace ash {
namespace {
constexpr gfx::Size kSettingsSize{256, 248};
constexpr gfx::Size kSettingsSize{266, 248};
constexpr int kCornerRadius = 10;
constexpr gfx::RoundedCornersF kRoundedCorners{kCornerRadius};
@ -98,11 +99,29 @@ CaptureModeSettingsView::CaptureModeSettingsView(
}
if (!audio_capture_managed_by_policy) {
const bool audio_mixing_enabled =
features::IsCaptureModeAudioMixingEnabled();
if (audio_mixing_enabled) {
audio_input_menu_group_->AddOption(
/*option_icon=*/nullptr,
l10n_util::GetStringUTF16(
IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_SYSTEM),
kAudioSystem);
}
audio_input_menu_group_->AddOption(
/*option_icon=*/nullptr,
l10n_util::GetStringUTF16(
IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_MICROPHONE),
kAudioMicrophone);
if (audio_mixing_enabled) {
audio_input_menu_group_->AddOption(
/*option_icon=*/nullptr,
l10n_util::GetStringUTF16(
IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_SYSTEM_AND_MICROPHONE),
kAudioSystemAndMicrophone);
}
}
separator_1_ = AddChildView(std::make_unique<views::Separator>());
@ -258,10 +277,17 @@ void CaptureModeSettingsView::OnOptionSelected(int option_id) const {
auto* camera_controller = controller->camera_controller();
switch (option_id) {
case kAudioOff:
controller->EnableAudioRecording(false);
controller->SetAudioRecordingMode(AudioRecordingMode::kOff);
break;
case kAudioSystem:
controller->SetAudioRecordingMode(AudioRecordingMode::kSystem);
break;
case kAudioMicrophone:
controller->EnableAudioRecording(true);
controller->SetAudioRecordingMode(AudioRecordingMode::kMicrophone);
break;
case kAudioSystemAndMicrophone:
controller->SetAudioRecordingMode(
AudioRecordingMode::kSystemAndMicrophone);
break;
case kDownloadsFolder:
controller->SetUsesDefaultCaptureFolder(true);
@ -287,11 +313,17 @@ void CaptureModeSettingsView::OnOptionSelected(int option_id) const {
bool CaptureModeSettingsView::IsOptionChecked(int option_id) const {
auto* controller = CaptureModeController::Get();
auto* camera_controller = controller->camera_controller();
const auto effective_audio_mode =
controller->GetEffectiveAudioRecordingMode();
switch (option_id) {
case kAudioOff:
return !CaptureModeController::Get()->GetAudioRecordingEnabled();
return effective_audio_mode == AudioRecordingMode::kOff;
case kAudioSystem:
return effective_audio_mode == AudioRecordingMode::kSystem;
case kAudioMicrophone:
return CaptureModeController::Get()->GetAudioRecordingEnabled();
return effective_audio_mode == AudioRecordingMode::kMicrophone;
case kAudioSystemAndMicrophone:
return effective_audio_mode == AudioRecordingMode::kSystemAndMicrophone;
case kDownloadsFolder:
return GetCurrentCaptureFolder().is_default_downloads_folder ||
!is_custom_folder_available_.value_or(false);
@ -316,7 +348,9 @@ bool CaptureModeSettingsView::IsOptionEnabled(int option_id) const {
case kAudioOff:
return !audio_capture_managed_by_policy &&
!active_behavior_->IsAudioRecordingRequired();
case kAudioSystem:
case kAudioMicrophone:
case kAudioSystemAndMicrophone:
return !audio_capture_managed_by_policy;
case kCustomFolder:
return is_custom_folder_available_.value_or(false);

@ -31,7 +31,9 @@ class SystemShadow;
// All the options in the CaptureMode settings view.
enum CaptureSettingsOption {
kAudioOff = 0,
kAudioSystem,
kAudioMicrophone,
kAudioSystemAndMicrophone,
kDownloadsFolder,
kCustomFolder,
kCameraOff,

@ -13,6 +13,7 @@
#include "ash/capture_mode/capture_mode_session.h"
#include "ash/capture_mode/capture_mode_types.h"
#include "ash/capture_mode/video_recording_watcher.h"
#include "ash/constants/ash_features.h"
#include "base/auto_reset.h"
#include "base/check.h"
#include "base/run_loop.h"
@ -27,6 +28,18 @@ CaptureModeController* GetController() {
return controller;
}
// Returns true of the given audio recording `mode` is currently supported.
bool IsAudioRecordingModeSupported(AudioRecordingMode mode) {
switch (mode) {
case AudioRecordingMode::kOff:
case AudioRecordingMode::kMicrophone:
return true;
case AudioRecordingMode::kSystem:
case AudioRecordingMode::kSystemAndMicrophone:
return features::IsCaptureModeAudioMixingEnabled();
}
}
} // namespace
CaptureModeTestApi::CaptureModeTestApi() : controller_(GetController()) {}
@ -114,13 +127,14 @@ void CaptureModeTestApi::SetOnVideoRecordCountdownFinishedCallback(
controller_->on_countdown_finished_callback_for_test_ = std::move(callback);
}
void CaptureModeTestApi::SetAudioRecordingEnabled(bool enabled) {
void CaptureModeTestApi::SetAudioRecordingMode(AudioRecordingMode mode) {
DCHECK(!controller_->is_recording_in_progress());
controller_->enable_audio_recording_ = enabled;
DCHECK(IsAudioRecordingModeSupported(mode));
controller_->audio_recording_mode_ = mode;
}
bool CaptureModeTestApi::GetAudioRecordingEnabled() const {
return controller_->GetAudioRecordingEnabled();
AudioRecordingMode CaptureModeTestApi::GetEffectiveAudioRecordingMode() const {
return controller_->GetEffectiveAudioRecordingMode();
}
void CaptureModeTestApi::FlushRecordingServiceForTesting() {

@ -178,6 +178,12 @@ CaptureModeBarView* GetCaptureModeBarView() {
return CaptureModeSessionTestApi(session).GetCaptureModeBarView();
}
IconButton* GetSettingsButton() {
auto* controller = CaptureModeController::Get();
DCHECK(controller->IsActive());
return GetCaptureModeBarView()->settings_button();
}
IconButton* GetFullscreenToggleButton() {
auto* controller = CaptureModeController::Get();
DCHECK(controller->IsActive());

@ -101,6 +101,8 @@ void ClickOrTapView(const views::View* view,
CaptureModeBarView* GetCaptureModeBarView();
IconButton* GetSettingsButton();
IconButton* GetFullscreenToggleButton();
IconButton* GetRegionToggleButton();

@ -71,6 +71,14 @@ enum class RecordingType {
kGif,
};
// Defines the supported audio recording modes.
enum class AudioRecordingMode {
kOff,
kSystem,
kMicrophone,
kSystemAndMicrophone,
};
// Specifies the capture mode behavior types.
enum class BehaviorType {
kDefault,

@ -289,12 +289,6 @@ class CaptureModeTest : public AshTestBase {
->window_toggle_button();
}
IconButton* GetSettingsButton() const {
auto* controller = CaptureModeController::Get();
DCHECK(controller->IsActive());
return GetCaptureModeBarView()->settings_button();
}
IconButton* GetCloseButton() const {
auto* controller = CaptureModeController::Get();
DCHECK(controller->IsActive());
@ -5227,13 +5221,15 @@ TEST_F(ProjectorCaptureModeIntegrationTests, EntryPoint) {
controller->SetType(CaptureModeType::kImage);
// Also, audio recording is initially disabled. However, the projector flow
// forces it enabled.
EXPECT_FALSE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
StartProjectorModeSession();
EXPECT_TRUE(controller->IsActive());
auto* session = controller->capture_mode_session();
EXPECT_TRUE(session->is_in_projector_mode());
EXPECT_TRUE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kMicrophone,
controller->GetEffectiveAudioRecordingMode());
constexpr char kEntryPointHistogram[] =
"Ash.CaptureModeController.EntryPoint.ClamshellMode";
@ -5261,7 +5257,8 @@ TEST_F(ProjectorCaptureModeIntegrationTests, CaptureModeSettings) {
CaptureModeMenuGroup* audio_input_menu_group =
test_api.GetAudioInputMenuGroup();
EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
EXPECT_TRUE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kMicrophone,
controller->GetEffectiveAudioRecordingMode());
}
TEST_F(ProjectorCaptureModeIntegrationTests, AudioCaptureDisabledByPolicy) {
@ -5269,7 +5266,8 @@ TEST_F(ProjectorCaptureModeIntegrationTests, AudioCaptureDisabledByPolicy) {
auto* delegate =
static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
delegate->set_is_audio_capture_disabled_by_policy(true);
EXPECT_FALSE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
// A projector session is not allowed to start when audio recording is
// disabled by policy.
@ -5281,7 +5279,8 @@ TEST_F(ProjectorCaptureModeIntegrationTests,
auto* controller = CaptureModeController::Get();
auto* delegate =
static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
EXPECT_FALSE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
// At this point, a Projector session is allowed to begin.
EXPECT_TRUE(projector_helper_.CanStartProjectorSession());
@ -5443,14 +5442,16 @@ TEST_F(ProjectorCaptureModeIntegrationTests,
EXPECT_TRUE(controller->IsActive());
EXPECT_EQ(controller->type(), CaptureModeType::kVideo);
EXPECT_EQ(controller->source(), CaptureModeSource::kFullscreen);
EXPECT_TRUE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kMicrophone,
controller->GetEffectiveAudioRecordingMode());
// Stop the projector-initiated capture mode session and the original capture
// mode configurations will be restored.
controller->Stop();
EXPECT_EQ(controller->type(), CaptureModeType::kImage);
EXPECT_EQ(controller->source(), CaptureModeSource::kWindow);
EXPECT_FALSE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
// Start a new projector-initiated capture mode session and start the region
// recording.
@ -5472,7 +5473,8 @@ TEST_F(ProjectorCaptureModeIntegrationTests,
// session, the capture mode configurations will be restored as what has been
// set before the projector-initiated capture mode session.
EXPECT_EQ(controller->type(), CaptureModeType::kImage);
EXPECT_FALSE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
}
namespace {
@ -5689,7 +5691,8 @@ TEST_P(ProjectorCaptureModeIntegrationTests,
// and during video recording.
TEST_P(ProjectorCaptureModeIntegrationTests, ProjectorBehavior) {
CaptureModeController* controller = CaptureModeController::Get();
EXPECT_FALSE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
EXPECT_TRUE(projector_helper_.CanStartProjectorSession());
StartProjectorModeSession();
ASSERT_TRUE(controller->IsActive());
@ -6290,7 +6293,8 @@ TEST_F(CaptureModeSettingsTest, AudioInputSettingsMenu) {
// Test that the audio recording preference is defaulted to off.
ClickOnView(GetSettingsButton(), event_generator);
EXPECT_FALSE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
CaptureModeSettingsTestApi test_api;
CaptureModeMenuGroup* audio_input_menu_group =
@ -6304,13 +6308,15 @@ TEST_F(CaptureModeSettingsTest, AudioInputSettingsMenu) {
ClickOnView(microphone_option, event_generator);
EXPECT_TRUE(audio_input_menu_group->IsOptionChecked(kAudioMicrophone));
EXPECT_FALSE(audio_input_menu_group->IsOptionChecked(kAudioOff));
EXPECT_TRUE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kMicrophone,
controller->GetEffectiveAudioRecordingMode());
// Test that the user selected audio preference for audio recording is
// remembered between sessions.
SendKey(ui::VKEY_ESCAPE, event_generator);
StartImageRegionCapture();
EXPECT_TRUE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kMicrophone,
controller->GetEffectiveAudioRecordingMode());
}
TEST_F(CaptureModeSettingsTest, AudioCaptureDisabledByPolicy) {
@ -6318,11 +6324,12 @@ TEST_F(CaptureModeSettingsTest, AudioCaptureDisabledByPolicy) {
// Even if audio recording is set to enabled, the policy setting will
// overwrite it.
controller->EnableAudioRecording(true);
controller->SetAudioRecordingMode(AudioRecordingMode::kMicrophone);
auto* delegate =
static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
delegate->set_is_audio_capture_disabled_by_policy(true);
EXPECT_FALSE(controller->GetAudioRecordingEnabled());
EXPECT_EQ(AudioRecordingMode::kOff,
controller->GetEffectiveAudioRecordingMode());
StartImageRegionCapture();
@ -7128,7 +7135,7 @@ TEST_P(CaptureModeHistogramTest, VideoRecordingAudioVideoMetrics) {
// Perform a video recording with audio off. A false should be recorded.
StartSessionForVideo();
CaptureModeTestApi().SetAudioRecordingEnabled(false);
CaptureModeTestApi().SetAudioRecordingMode(AudioRecordingMode::kOff);
StartRecording();
histogram_tester.ExpectBucketCount(
GetCaptureModeHistogramName(kHistogramNameBase), false, 1);
@ -7146,9 +7153,10 @@ TEST_P(CaptureModeHistogramTest, VideoRecordingAudioVideoMetrics) {
"Ash.CaptureModeController.ScreenRecordingFileSize"),
/*expected_count=*/1);
// Perform a video recording with audio on. A true should be recorded.
// Perform a video recording with microphone audio recording on. A true should
// be recorded.
StartSessionForVideo();
CaptureModeTestApi().SetAudioRecordingEnabled(true);
CaptureModeTestApi().SetAudioRecordingMode(AudioRecordingMode::kMicrophone);
StartRecording();
histogram_tester.ExpectBucketCount(
GetCaptureModeHistogramName(kHistogramNameBase), false, 1);

@ -444,7 +444,7 @@ TEST_F(GifRecordingTest, RecordingTypeIsRespected) {
// Even though audio recording is enabled, when performing a GIF recording,
// the recording service should not be asked to connect to the audio streaming
// factory and should not be doing any audio recording.
controller->EnableAudioRecording(true);
controller->SetAudioRecordingMode(AudioRecordingMode::kMicrophone);
StartVideoRecordingImmediately();
// Test that the configuration histogram was reported correctly, and that the

@ -107,13 +107,13 @@ class ASH_EXPORT CaptureModeTestApi {
// finished.
void SetOnVideoRecordCountdownFinishedCallback(base::OnceClosure callback);
// Sets whether or not audio will be recorded when capturing a video. Should
// only be called before recording starts, otherwise it has no effect.
void SetAudioRecordingEnabled(bool enabled);
// Sets the audio recording mode when capturing a video. Should only be called
// before recording starts, otherwise it has no effect.
void SetAudioRecordingMode(AudioRecordingMode mode);
// Returns the effective enabled state of audio recording which takes into
// account the `AudioCaptureAllowed` policy.
bool GetAudioRecordingEnabled() const;
// Returns the effective mode of audio recording which takes into account the
// `AudioCaptureAllowed` policy.
AudioRecordingMode GetEffectiveAudioRecordingMode() const;
// Flushes the recording service pipe synchronously. Can only be called while
// recording is in progress.

@ -794,14 +794,17 @@ IN_PROC_BROWSER_TEST_F(CaptureModeSettingsBrowserTest,
IN_PROC_BROWSER_TEST_F(CaptureModeSettingsBrowserTest,
AudioCaptureDisabledByPolicy) {
ash::CaptureModeTestApi test_api;
test_api.SetAudioRecordingEnabled(true);
EXPECT_TRUE(test_api.GetAudioRecordingEnabled());
test_api.SetAudioRecordingMode(ash::AudioRecordingMode::kMicrophone);
EXPECT_EQ(ash::AudioRecordingMode::kMicrophone,
test_api.GetEffectiveAudioRecordingMode());
auto* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
prefs->SetBoolean(prefs::kAudioCaptureAllowed, false);
EXPECT_FALSE(test_api.GetAudioRecordingEnabled());
EXPECT_EQ(ash::AudioRecordingMode::kOff,
test_api.GetEffectiveAudioRecordingMode());
prefs->SetBoolean(prefs::kAudioCaptureAllowed, true);
EXPECT_TRUE(test_api.GetAudioRecordingEnabled());
EXPECT_EQ(ash::AudioRecordingMode::kMicrophone,
test_api.GetEffectiveAudioRecordingMode());
}
// This test fixture tests the chromeos-linux path of camera video frames coming

@ -5,6 +5,7 @@
#include <memory>
#include <string>
#include "ash/capture_mode/capture_mode_types.h"
#include "ash/public/cpp/capture_mode/capture_mode_test_api.h"
#include "ash/public/cpp/test/shell_test_api.h"
#include "base/check.h"
@ -150,7 +151,8 @@ class RecordingServiceBrowserTest : public InProcessBrowserTest {
// muxer to discard video frames if it expects audio frames but got none,
// which may cause the produced webm file to be empty. See issues
// https://crbug.com/1151167 and https://crbug.com/1151418.
ash::CaptureModeTestApi().SetAudioRecordingEnabled(false);
ash::CaptureModeTestApi().SetAudioRecordingMode(
ash::AudioRecordingMode::kOff);
}
aura::Window* GetBrowserWindow() const {