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:

committed by
Chromium LUCI CQ

parent
604865633f
commit
3073e19ff7
ash
BUILD.gnash_strings.grd
ash_strings_grd
IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_SYSTEM.png.sha1IDS_ASH_SCREEN_CAPTURE_AUDIO_INPUT_SYSTEM_AND_MICROPHONE.png.sha1
capture_mode
camera_video_frame_handler.hcapture_audio_mixing_unittests.cccapture_mode_camera_unittests.cccapture_mode_controller.cccapture_mode_controller.hcapture_mode_session.cccapture_mode_settings_test_api.cccapture_mode_settings_test_api.hcapture_mode_settings_view.cccapture_mode_settings_view.hcapture_mode_test_api.cccapture_mode_test_util.cccapture_mode_test_util.hcapture_mode_types.hcapture_mode_unittests.ccgif_recording_unittests.cc
public
cpp
capture_mode
chrome/browser/ui/ash/capture_mode
@ -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 {
|
||||
|
Reference in New Issue
Block a user