| // Copyright 2023 The Chromium Authors |
| // 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/capture_mode/test_capture_mode_delegate.h" |
| #include "ash/constants/ash_features.h" |
| #include "ash/public/cpp/capture_mode/capture_mode_test_api.h" |
| #include "ash/style/icon_button.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/test/ash_test_util.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| |
| namespace ash { |
| |
| class CaptureAudioMixingTest : public AshTestBase { |
| public: |
| CaptureAudioMixingTest() |
| : scoped_feature_list_(features::kCaptureModeAudioMixing) {} |
| CaptureAudioMixingTest(const CaptureAudioMixingTest&) = delete; |
| 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, 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()); |
| } |
| |
| TEST_F(CaptureAudioMixingTest, ServiceWillRecordAudio) { |
| constexpr char kHistogramNameBase[] = "AudioRecordingMode"; |
| const std::string histogram_name = BuildHistogramName( |
| kHistogramNameBase, /*behavior=*/nullptr, /*append_ui_mode_suffix=*/true); |
| |
| struct { |
| const char* const scope_name; |
| AudioRecordingMode audio_mode; |
| int expected_number_of_audio_capturers; |
| } kTestCases[] = { |
| {"Off", AudioRecordingMode::kOff, |
| /*expected_number_of_audio_capturers=*/0}, |
| {"Microphone", AudioRecordingMode::kMicrophone, |
| /*expected_number_of_audio_capturers=*/1}, |
| {"System audio", AudioRecordingMode::kSystem, |
| /*expected_number_of_audio_capturers=*/1}, |
| {"System and microphone audio", AudioRecordingMode::kSystemAndMicrophone, |
| /*expected_number_of_audio_capturers=*/2}, |
| }; |
| |
| for (const auto& test_case : kTestCases) { |
| SCOPED_TRACE(test_case.scope_name); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(histogram_name, test_case.audio_mode, 0); |
| |
| auto* controller = StartSession(); |
| controller->SetAudioRecordingMode(test_case.audio_mode); |
| |
| StartVideoRecordingImmediately(); |
| |
| EXPECT_TRUE(controller->is_recording_in_progress()); |
| auto* test_delegate = static_cast<TestCaptureModeDelegate*>( |
| controller->delegate_for_testing()); |
| CaptureModeTestApi().FlushRecordingServiceForTesting(); |
| EXPECT_EQ(test_case.expected_number_of_audio_capturers, |
| test_delegate->GetNumberOfAudioCapturers()); |
| controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton); |
| |
| WaitForCaptureFileToBeSaved(); |
| |
| histogram_tester.ExpectBucketCount(histogram_name, test_case.audio_mode, 1); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // ProjectorAudioMixingTest: |
| |
| class ProjectorAudioMixingTest : public CaptureAudioMixingTest { |
| public: |
| ProjectorAudioMixingTest() = default; |
| ~ProjectorAudioMixingTest() override = default; |
| |
| // CaptureAudioMixingTest: |
| void SetUp() override { |
| CaptureAudioMixingTest::SetUp(); |
| projector_helper_.SetUp(); |
| } |
| |
| void StartProjectorModeSession() { |
| projector_helper_.StartProjectorModeSession(); |
| } |
| |
| private: |
| ProjectorCaptureModeIntegrationHelper projector_helper_; |
| }; |
| |
| TEST_F(ProjectorAudioMixingTest, AudioSettingsMenu) { |
| constexpr char kHistogramNameBase[] = "AudioRecordingMode"; |
| const std::string histogram_name = BuildHistogramName( |
| kHistogramNameBase, |
| CaptureModeTestApi().GetBehavior(BehaviorType::kProjector), |
| /*append_ui_mode_suffix=*/true); |
| base::HistogramTester histogram_tester; |
| |
| StartProjectorModeSession(); |
| auto* event_generator = GetEventGenerator(); |
| |
| // Open the settings menu, and check that only microphone and |
| // system+microphone options are available. |
| ClickOnView(GetSettingsButton(), event_generator); |
| |
| CaptureModeSettingsTestApi test_api; |
| views::View* off_option = test_api.GetAudioOffOption(); |
| views::View* microphone_option = test_api.GetMicrophoneOption(); |
| views::View* system_option = test_api.GetSystemAudioOption(); |
| views::View* system_and_microphone_option = |
| test_api.GetSystemAndMicrophoneAudioOption(); |
| |
| EXPECT_FALSE(off_option); |
| EXPECT_FALSE(system_option); |
| EXPECT_TRUE(microphone_option); |
| EXPECT_TRUE(system_and_microphone_option); |
| |
| // Microphone should still be selected by default. |
| EXPECT_TRUE(IsAudioOptionChecked(kAudioMicrophone)); |
| EXPECT_FALSE(IsAudioOptionChecked(kAudioSystemAndMicrophone)); |
| |
| // End the session and expect the correct audio mode was recorded. |
| auto* controller = CaptureModeController::Get(); |
| controller->Stop(); |
| histogram_tester.ExpectBucketCount(histogram_name, |
| AudioRecordingMode::kMicrophone, 1); |
| histogram_tester.ExpectBucketCount( |
| histogram_name, AudioRecordingMode::kSystemAndMicrophone, 0); |
| |
| // Start a new session and select `kSystemAndMicrophone`, and expect the |
| // correct metrics will be recorded when the session ends. |
| StartProjectorModeSession(); |
| controller->SetAudioRecordingMode(AudioRecordingMode::kSystemAndMicrophone); |
| controller->Stop(); |
| |
| histogram_tester.ExpectBucketCount(histogram_name, |
| AudioRecordingMode::kMicrophone, 1); |
| histogram_tester.ExpectBucketCount( |
| histogram_name, AudioRecordingMode::kSystemAndMicrophone, 1); |
| } |
| |
| } // namespace ash |