| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/media_session/audio_focus_manager.h" |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/run_loop.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "build/build_config.h" |
| #include "mojo/public/cpp/bindings/binding_set.h" |
| #include "mojo/public/cpp/bindings/interface_request.h" |
| #include "services/media_session/audio_focus_manager_metrics_helper.h" |
| #include "services/media_session/media_session_service.h" |
| #include "services/media_session/public/cpp/test/audio_focus_test_util.h" |
| #include "services/media_session/public/cpp/test/mock_media_session.h" |
| #include "services/media_session/public/mojom/audio_focus.mojom.h" |
| #include "services/media_session/public/mojom/constants.mojom.h" |
| #include "services/service_manager/public/cpp/test/test_connector_factory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace media_session { |
| |
| namespace { |
| |
| const char kExampleSourceName[] = "test"; |
| const char kExampleSourceName2[] = "test2"; |
| |
| } // anonymous namespace |
| |
| // This tests the Audio Focus Manager API. The parameter determines whether |
| // audio focus is enabled or not. If it is not enabled it should track the media |
| // sessions but not enforce single session focus. |
| class AudioFocusManagerTest |
| : public testing::TestWithParam<mojom::EnforcementMode> { |
| public: |
| AudioFocusManagerTest() = default; |
| |
| void SetUp() override { |
| // Create an instance of the MediaSessionService. |
| service_ = std::make_unique<MediaSessionService>( |
| connector_factory_.RegisterInstance(mojom::kServiceName)); |
| connector_factory_.GetDefaultConnector()->BindInterface(mojom::kServiceName, |
| &audio_focus_ptr_); |
| connector_factory_.GetDefaultConnector()->BindInterface( |
| mojom::kServiceName, &audio_focus_debug_ptr_); |
| |
| audio_focus_ptr_->SetEnforcementMode(GetParam()); |
| audio_focus_ptr_.FlushForTesting(); |
| } |
| |
| void TearDown() override { |
| // Run pending tasks. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| AudioFocusManager::RequestId GetAudioFocusedSession() { |
| const auto audio_focus_requests = GetRequests(); |
| for (auto iter = audio_focus_requests.rbegin(); |
| iter != audio_focus_requests.rend(); ++iter) { |
| if ((*iter)->audio_focus_type == mojom::AudioFocusType::kGain) |
| return (*iter)->request_id.value(); |
| } |
| return base::UnguessableToken::Null(); |
| } |
| |
| int GetTransientCount() { |
| return GetCountForType(mojom::AudioFocusType::kGainTransient); |
| } |
| |
| int GetTransientMaybeDuckCount() { |
| return GetCountForType(mojom::AudioFocusType::kGainTransientMayDuck); |
| } |
| |
| void AbandonAudioFocusNoReset(test::MockMediaSession* session) { |
| session->audio_focus_request()->AbandonAudioFocus(); |
| session->FlushForTesting(); |
| audio_focus_ptr_.FlushForTesting(); |
| } |
| |
| AudioFocusManager::RequestId RequestAudioFocus( |
| test::MockMediaSession* session, |
| mojom::AudioFocusType audio_focus_type) { |
| return session->RequestAudioFocusFromService(audio_focus_ptr_, |
| audio_focus_type); |
| } |
| |
| AudioFocusManager::RequestId RequestGroupedAudioFocus( |
| test::MockMediaSession* session, |
| mojom::AudioFocusType audio_focus_type, |
| const base::UnguessableToken& group_id) { |
| return session->RequestGroupedAudioFocusFromService( |
| audio_focus_ptr_, audio_focus_type, group_id); |
| } |
| |
| mojom::MediaSessionDebugInfoPtr GetDebugInfo( |
| AudioFocusManager::RequestId request_id) { |
| mojom::MediaSessionDebugInfoPtr result; |
| base::OnceCallback<void(mojom::MediaSessionDebugInfoPtr)> callback = |
| base::BindOnce( |
| [](mojom::MediaSessionDebugInfoPtr* out_result, |
| mojom::MediaSessionDebugInfoPtr result) { |
| *out_result = std::move(result); |
| }, |
| &result); |
| |
| GetDebugService()->GetDebugInfoForRequest(request_id, std::move(callback)); |
| |
| audio_focus_ptr_.FlushForTesting(); |
| audio_focus_debug_ptr_.FlushForTesting(); |
| |
| return result; |
| } |
| |
| mojom::MediaSessionInfo::SessionState GetState( |
| test::MockMediaSession* session) { |
| mojom::MediaSessionInfo::SessionState state = session->GetState(); |
| |
| if (!IsEnforcementEnabled()) { |
| // If audio focus enforcement is disabled then we should never see these |
| // states in the tests. |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kSuspended, state); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, state); |
| } |
| |
| return state; |
| } |
| |
| std::unique_ptr<test::TestAudioFocusObserver> CreateObserver() { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = |
| std::make_unique<test::TestAudioFocusObserver>(); |
| |
| mojom::AudioFocusObserverPtr observer_ptr; |
| observer->BindToMojoRequest(mojo::MakeRequest(&observer_ptr)); |
| GetService()->AddObserver(std::move(observer_ptr)); |
| |
| audio_focus_ptr_.FlushForTesting(); |
| return observer; |
| } |
| |
| mojom::MediaSessionInfo::SessionState GetStateFromParam( |
| mojom::MediaSessionInfo::SessionState state) { |
| // If enforcement is enabled then returns the provided state, otherwise |
| // returns kActive because without enforcement we did not change state. |
| if (IsEnforcementEnabled()) |
| return state; |
| return mojom::MediaSessionInfo::SessionState::kActive; |
| } |
| |
| void SetSourceName(const std::string& name) { |
| GetService()->SetSourceName(name); |
| audio_focus_ptr_.FlushForTesting(); |
| } |
| |
| mojom::AudioFocusManagerPtr CreateAudioFocusManagerPtr() { |
| mojom::AudioFocusManagerPtr ptr; |
| connector_factory_.GetDefaultConnector()->BindInterface( |
| mojom::kServiceName, mojo::MakeRequest(&ptr)); |
| return ptr; |
| } |
| |
| const std::string GetSourceNameForLastRequest() { |
| std::vector<mojom::AudioFocusRequestStatePtr> requests = GetRequests(); |
| EXPECT_TRUE(requests.back()); |
| return requests.back()->source_name.value(); |
| } |
| |
| std::unique_ptr<base::HistogramSamples> GetHistogramSamplesSinceTestStart( |
| const std::string& name) { |
| return histogram_tester_.GetHistogramSamplesSinceCreation(name); |
| } |
| |
| int GetAudioFocusHistogramCount() { |
| return histogram_tester_ |
| .GetTotalCountsForPrefix("Media.Session.AudioFocus.") |
| .size(); |
| } |
| |
| bool IsEnforcementEnabled() const { |
| #if defined(OS_CHROMEOS) |
| // Enforcement is enabled by default on Chrome OS. |
| if (GetParam() == mojom::EnforcementMode::kDefault) |
| return true; |
| #endif |
| |
| return GetParam() == mojom::EnforcementMode::kSingleSession || |
| GetParam() == mojom::EnforcementMode::kSingleGroup; |
| } |
| |
| bool IsGroupingEnabled() const { |
| return GetParam() != mojom::EnforcementMode::kSingleSession; |
| } |
| |
| private: |
| int GetCountForType(mojom::AudioFocusType type) { |
| const auto audio_focus_requests = GetRequests(); |
| return std::count_if(audio_focus_requests.begin(), |
| audio_focus_requests.end(), |
| [type](const auto& session) { |
| return session->audio_focus_type == type; |
| }); |
| } |
| |
| std::vector<mojom::AudioFocusRequestStatePtr> GetRequests() { |
| std::vector<mojom::AudioFocusRequestStatePtr> result; |
| |
| GetService()->GetFocusRequests(base::BindOnce( |
| [](std::vector<mojom::AudioFocusRequestStatePtr>* out, |
| std::vector<mojom::AudioFocusRequestStatePtr> requests) { |
| for (auto& request : requests) |
| out->push_back(request.Clone()); |
| }, |
| &result)); |
| |
| audio_focus_ptr_.FlushForTesting(); |
| return result; |
| } |
| |
| mojom::AudioFocusManager* GetService() const { |
| return audio_focus_ptr_.get(); |
| } |
| |
| mojom::AudioFocusManagerDebug* GetDebugService() const { |
| return audio_focus_debug_ptr_.get(); |
| } |
| |
| void FlushForTestingIfEnabled() { |
| if (!IsEnforcementEnabled()) |
| return; |
| |
| audio_focus_ptr_.FlushForTesting(); |
| } |
| |
| base::test::ScopedTaskEnvironment task_environment_; |
| base::HistogramTester histogram_tester_; |
| |
| service_manager::TestConnectorFactory connector_factory_; |
| std::unique_ptr<MediaSessionService> service_; |
| |
| mojom::AudioFocusManagerPtr audio_focus_ptr_; |
| mojom::AudioFocusManagerDebugPtr audio_focus_debug_ptr_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AudioFocusManagerTest); |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P( |
| , |
| AudioFocusManagerTest, |
| testing::Values(mojom::EnforcementMode::kDefault, |
| mojom::EnforcementMode::kNone, |
| mojom::EnforcementMode::kSingleGroup, |
| mojom::EnforcementMode::kSingleSession)); |
| |
| TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_ReplaceFocusedEntry) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| test::MockMediaSession media_session_3; |
| |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kInactive, |
| GetState(&media_session_1)); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kInactive, |
| GetState(&media_session_2)); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kInactive, |
| GetState(&media_session_3)); |
| |
| AudioFocusManager::RequestId request_id_1 = |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id_1, GetAudioFocusedSession()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| AudioFocusManager::RequestId request_id_2 = |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id_2, GetAudioFocusedSession()); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_1)); |
| |
| AudioFocusManager::RequestId request_id_3 = |
| RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id_3, GetAudioFocusedSession()); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_2)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_Duplicate) { |
| test::MockMediaSession media_session; |
| |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| |
| AudioFocusManager::RequestId request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_FromTransient) { |
| test::MockMediaSession media_session; |
| |
| AudioFocusManager::RequestId request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| EXPECT_EQ(1, GetTransientCount()); |
| |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| EXPECT_EQ(0, GetTransientCount()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_FromTransientMayDuck) { |
| test::MockMediaSession media_session; |
| |
| AudioFocusManager::RequestId request_id = RequestAudioFocus( |
| &media_session, mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RequestAudioFocusTransient_FromGain) { |
| test::MockMediaSession media_session; |
| |
| AudioFocusManager::RequestId request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| EXPECT_EQ(0, GetTransientCount()); |
| |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| EXPECT_EQ(1, GetTransientCount()); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kSuspended, |
| GetState(&media_session)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RequestAudioFocusTransientMayDuck_FromGain) { |
| test::MockMediaSession media_session; |
| |
| AudioFocusManager::RequestId request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| |
| RequestAudioFocus(&media_session, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RequestAudioFocusTransient_FromGainWhileDucking) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(0, GetTransientCount()); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(1, GetTransientCount()); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, |
| RequestAudioFocusTransientMayDuck_FromGainWhileDucking) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_1, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(2, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AbandonAudioFocus_RemovesFocusedEntry) { |
| test::MockMediaSession media_session; |
| |
| AudioFocusManager::RequestId request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| |
| media_session.AbandonAudioFocusFromClient(); |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AbandonAudioFocus_MultipleCalls) { |
| test::MockMediaSession media_session; |
| |
| AudioFocusManager::RequestId request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| |
| AbandonAudioFocusNoReset(&media_session); |
| |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| media_session.AbandonAudioFocusFromClient(); |
| |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| EXPECT_TRUE(observer->focus_lost_session().is_null()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientMayDuckEntry) { |
| test::MockMediaSession media_session; |
| |
| RequestAudioFocus(&media_session, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| media_session.AbandonAudioFocusFromClient(); |
| |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_TRUE(observer->focus_lost_session()->session_info.Equals( |
| test::GetMediaSessionInfoSync(&media_session))); |
| } |
| } |
| |
| TEST_P(AudioFocusManagerTest, AbandonAudioFocus_RemovesTransientEntry) { |
| test::MockMediaSession media_session; |
| |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(1, GetTransientCount()); |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| media_session.AbandonAudioFocusFromClient(); |
| |
| EXPECT_EQ(0, GetTransientCount()); |
| EXPECT_TRUE(observer->focus_lost_session()->session_info.Equals( |
| test::GetMediaSessionInfoSync(&media_session))); |
| } |
| } |
| |
| TEST_P(AudioFocusManagerTest, AbandonAudioFocus_WhileDuckingThenResume) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| |
| media_session_1.AbandonAudioFocusFromClient(); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| |
| media_session_2.AbandonAudioFocusFromClient(); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AbandonAudioFocus_StopsDucking) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| |
| media_session_2.AbandonAudioFocusFromClient(); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AbandonAudioFocus_ResumesPlayback) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(1, GetTransientCount()); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_1)); |
| |
| media_session_2.AbandonAudioFocusFromClient(); |
| EXPECT_EQ(0, GetTransientCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, DuckWhilePlaying) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, GainSuspendsTransient) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_2)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, GainSuspendsTransientMayDuck) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_2)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, DuckWithMultipleTransientMayDucks) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| test::MockMediaSession media_session_3; |
| test::MockMediaSession media_session_4; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_2)); |
| |
| RequestAudioFocus(&media_session_3, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_2)); |
| |
| RequestAudioFocus(&media_session_4, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_2)); |
| |
| media_session_3.AbandonAudioFocusFromClient(); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_2)); |
| |
| media_session_4.AbandonAudioFocusFromClient(); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_1)); |
| EXPECT_NE(mojom::MediaSessionInfo::SessionState::kDucking, |
| GetState(&media_session_2)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesFocus) { |
| { |
| test::MockMediaSession media_session; |
| |
| AudioFocusManager::RequestId request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| } |
| |
| // If the media session is destroyed without abandoning audio focus we do not |
| // know until we next interact with the manager. |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(base::UnguessableToken::Null(), GetAudioFocusedSession()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransient) { |
| { |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(1, GetTransientCount()); |
| } |
| |
| // If the media session is destroyed without abandoning audio focus we do not |
| // know until we next interact with the manager. |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientCount()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, MediaSessionDestroyed_ReleasesTransientMayDucks) { |
| { |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| } |
| |
| // If the media session is destroyed without abandoning audio focus we do not |
| // know until we next interact with the manager. |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, GainDucksForceDuck) { |
| test::MockMediaSession media_session_1(true /* force_duck */); |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| |
| AudioFocusManager::RequestId request_id_2 = |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); |
| |
| EXPECT_EQ(request_id_2, GetAudioFocusedSession()); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, |
| AbandoningGainFocusRevokesTopMostForceDuckSession) { |
| test::MockMediaSession media_session_1(true /* force_duck */); |
| test::MockMediaSession media_session_2; |
| test::MockMediaSession media_session_3; |
| |
| AudioFocusManager::RequestId request_id_1 = |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| AudioFocusManager::RequestId request_id_2 = |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); |
| |
| AudioFocusManager::RequestId request_id_3 = |
| RequestAudioFocus(&media_session_3, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id_3, GetAudioFocusedSession()); |
| |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_2)); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| |
| media_session_3.AbandonAudioFocusFromClient(); |
| EXPECT_EQ(IsEnforcementEnabled() ? request_id_1 : request_id_2, |
| GetAudioFocusedSession()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) { |
| test::MockMediaSession media_session; |
| AudioFocusManager::RequestId request_id; |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| EXPECT_EQ(mojom::AudioFocusType::kGain, |
| observer->focus_gained_session()->audio_focus_type); |
| } |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| |
| EXPECT_EQ(request_id, GetAudioFocusedSession()); |
| EXPECT_TRUE(observer->focus_gained_session().is_null()); |
| } |
| } |
| |
| TEST_P(AudioFocusManagerTest, AudioFocusObserver_TransientMayDuck) { |
| test::MockMediaSession media_session; |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| RequestAudioFocus(&media_session, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::AudioFocusType::kGainTransientMayDuck, |
| observer->focus_gained_session()->audio_focus_type); |
| } |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| media_session.AbandonAudioFocusFromClient(); |
| |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_TRUE(observer->focus_lost_session()->session_info.Equals( |
| test::GetMediaSessionInfoSync(&media_session))); |
| } |
| } |
| |
| TEST_P(AudioFocusManagerTest, GetDebugInfo) { |
| test::MockMediaSession media_session; |
| AudioFocusManager::RequestId request_id = |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| |
| mojom::MediaSessionDebugInfoPtr debug_info = GetDebugInfo(request_id); |
| EXPECT_FALSE(debug_info->name.empty()); |
| EXPECT_FALSE(debug_info->owner.empty()); |
| EXPECT_FALSE(debug_info->state.empty()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, GetDebugInfo_BadRequestId) { |
| mojom::MediaSessionDebugInfoPtr debug_info = |
| GetDebugInfo(base::UnguessableToken::Create()); |
| EXPECT_TRUE(debug_info->name.empty()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, |
| RequestAudioFocusTransient_FromGainWhileSuspended) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(1, GetTransientCount()); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(2, GetTransientCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, |
| RequestAudioFocusTransientMayDuck_FromGainWhileSuspended) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientCount()); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ(1, GetTransientCount()); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_1, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(1, GetTransientCount()); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, SourceName_AssociatedWithBinding) { |
| SetSourceName(kExampleSourceName); |
| |
| mojom::AudioFocusManagerPtr new_ptr = CreateAudioFocusManagerPtr(); |
| new_ptr->SetSourceName(kExampleSourceName2); |
| new_ptr.FlushForTesting(); |
| |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, SourceName_Empty) { |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_TRUE(GetSourceNameForLastRequest().empty()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, SourceName_Updated) { |
| SetSourceName(kExampleSourceName); |
| |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest()); |
| |
| SetSourceName(kExampleSourceName2); |
| EXPECT_EQ(kExampleSourceName, GetSourceNameForLastRequest()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RecordUmaMetrics) { |
| EXPECT_EQ(0, GetAudioFocusHistogramCount()); |
| |
| SetSourceName(kExampleSourceName); |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGainTransient); |
| |
| { |
| std::unique_ptr<base::HistogramSamples> samples( |
| GetHistogramSamplesSinceTestStart( |
| "Media.Session.AudioFocus.Request.Test")); |
| EXPECT_EQ(1, samples->TotalCount()); |
| EXPECT_EQ(1, samples->GetCount(static_cast<base::HistogramBase::Sample>( |
| AudioFocusManagerMetricsHelper::AudioFocusRequestSource:: |
| kInitial))); |
| } |
| |
| { |
| std::unique_ptr<base::HistogramSamples> samples( |
| GetHistogramSamplesSinceTestStart( |
| "Media.Session.AudioFocus.Type.Test")); |
| EXPECT_EQ(1, samples->TotalCount()); |
| EXPECT_EQ( |
| 1, |
| samples->GetCount(static_cast<base::HistogramBase::Sample>( |
| AudioFocusManagerMetricsHelper::AudioFocusType::kGainTransient))); |
| } |
| |
| EXPECT_EQ(2, GetAudioFocusHistogramCount()); |
| |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| |
| { |
| std::unique_ptr<base::HistogramSamples> samples( |
| GetHistogramSamplesSinceTestStart( |
| "Media.Session.AudioFocus.Request.Test")); |
| EXPECT_EQ(2, samples->TotalCount()); |
| EXPECT_EQ( |
| 1, |
| samples->GetCount(static_cast<base::HistogramBase::Sample>( |
| AudioFocusManagerMetricsHelper::AudioFocusRequestSource::kUpdate))); |
| } |
| |
| { |
| std::unique_ptr<base::HistogramSamples> samples( |
| GetHistogramSamplesSinceTestStart( |
| "Media.Session.AudioFocus.Type.Test")); |
| EXPECT_EQ(2, samples->TotalCount()); |
| EXPECT_EQ(1, samples->GetCount(static_cast<base::HistogramBase::Sample>( |
| AudioFocusManagerMetricsHelper::AudioFocusType::kGain))); |
| } |
| |
| EXPECT_EQ(2, GetAudioFocusHistogramCount()); |
| |
| media_session.AbandonAudioFocusFromClient(); |
| |
| { |
| std::unique_ptr<base::HistogramSamples> samples( |
| GetHistogramSamplesSinceTestStart( |
| "Media.Session.AudioFocus.Abandon.Test")); |
| EXPECT_EQ(1, samples->TotalCount()); |
| EXPECT_EQ( |
| 1, samples->GetCount(static_cast<base::HistogramBase::Sample>( |
| AudioFocusManagerMetricsHelper::AudioFocusAbandonSource::kAPI))); |
| } |
| |
| EXPECT_EQ(3, GetAudioFocusHistogramCount()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RecordUmaMetrics_ConnectionError) { |
| SetSourceName(kExampleSourceName); |
| |
| { |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| } |
| |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| |
| { |
| std::unique_ptr<base::HistogramSamples> samples( |
| GetHistogramSamplesSinceTestStart( |
| "Media.Session.AudioFocus.Abandon.Test")); |
| EXPECT_EQ(1, samples->TotalCount()); |
| EXPECT_EQ(1, samples->GetCount(static_cast<base::HistogramBase::Sample>( |
| AudioFocusManagerMetricsHelper::AudioFocusAbandonSource:: |
| kConnectionError))); |
| } |
| } |
| |
| TEST_P(AudioFocusManagerTest, RecordUmaMetrics_NoSourceName) { |
| test::MockMediaSession media_session; |
| RequestAudioFocus(&media_session, mojom::AudioFocusType::kGain); |
| |
| EXPECT_EQ(0, GetAudioFocusHistogramCount()); |
| } |
| |
| TEST_P(AudioFocusManagerTest, |
| AbandonAudioFocus_ObserverFocusGain_NoTopSession) { |
| test::MockMediaSession media_session; |
| |
| RequestAudioFocus(&media_session, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session)); |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| media_session.AbandonAudioFocusFromClient(); |
| |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_TRUE(observer->focus_lost_session()->session_info.Equals( |
| test::GetMediaSessionInfoSync(&media_session))); |
| EXPECT_TRUE(observer->focus_gained_session().is_null()); |
| |
| auto notifications = observer->notifications(); |
| EXPECT_EQ(1u, notifications.size()); |
| EXPECT_EQ(test::TestAudioFocusObserver::NotificationType::kFocusLost, |
| notifications[0]); |
| } |
| } |
| |
| TEST_P(AudioFocusManagerTest, |
| AbandonAudioFocus_ObserverFocusGain_NewTopSession) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(1, GetTransientMaybeDuckCount()); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| |
| mojom::MediaSessionInfoPtr media_session_1_info = |
| test::GetMediaSessionInfoSync(&media_session_1); |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| media_session_2.AbandonAudioFocusFromClient(); |
| |
| EXPECT_EQ(0, GetTransientMaybeDuckCount()); |
| EXPECT_TRUE(observer->focus_lost_session()->session_info.Equals( |
| test::GetMediaSessionInfoSync(&media_session_2))); |
| EXPECT_TRUE(observer->focus_gained_session()->session_info.Equals( |
| media_session_1_info)); |
| |
| // FocusLost should always come before FocusGained so observers always know |
| // the current session that has focus. |
| auto notifications = observer->notifications(); |
| EXPECT_EQ(2u, notifications.size()); |
| EXPECT_EQ(test::TestAudioFocusObserver::NotificationType::kFocusLost, |
| notifications[0]); |
| EXPECT_EQ(test::TestAudioFocusObserver::NotificationType::kFocusGained, |
| notifications[1]); |
| } |
| } |
| |
| TEST_P(AudioFocusManagerTest, ObserverActiveSessionChanged) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| media_session_1.SetIsControllable(true); |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| EXPECT_EQ(media_session_1.GetRequestIdFromClient(), |
| observer->active_session()->request_id); |
| } |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_2)); |
| |
| EXPECT_NE( |
| test::TestAudioFocusObserver::NotificationType::kActiveSessionChanged, |
| observer->notifications().back()); |
| EXPECT_TRUE(observer->active_session().is_null()); |
| } |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| media_session_2.AbandonAudioFocusFromClient(); |
| |
| EXPECT_NE( |
| test::TestAudioFocusObserver::NotificationType::kActiveSessionChanged, |
| observer->notifications().back()); |
| EXPECT_TRUE(observer->active_session().is_null()); |
| } |
| |
| { |
| std::unique_ptr<test::TestAudioFocusObserver> observer = CreateObserver(); |
| media_session_1.AbandonAudioFocusFromClient(); |
| |
| // TODO(https://crbug.com/916177): This should wait on a more precise |
| // condition than RunLoop idling, but it's not clear exactly what that |
| // should be. |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ( |
| test::TestAudioFocusObserver::NotificationType::kActiveSessionChanged, |
| observer->notifications().back()); |
| EXPECT_TRUE(observer->active_session().is_null()); |
| } |
| } |
| |
| TEST_P(AudioFocusManagerTest, AudioFocusGrouping_AllowDucking) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| test::MockMediaSession media_session_3; |
| |
| base::UnguessableToken group_id = base::UnguessableToken::Create(); |
| |
| RequestGroupedAudioFocus(&media_session_1, mojom::AudioFocusType::kGain, |
| group_id); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransientMayDuck); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| |
| RequestGroupedAudioFocus(&media_session_3, mojom::AudioFocusType::kGain, |
| group_id); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_3)); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AudioFocusGrouping_TransientResume) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| test::MockMediaSession media_session_3; |
| test::MockMediaSession media_session_4; |
| |
| base::UnguessableToken group_id = base::UnguessableToken::Create(); |
| |
| RequestGroupedAudioFocus(&media_session_1, mojom::AudioFocusType::kGain, |
| group_id); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_2)); |
| |
| RequestGroupedAudioFocus(&media_session_3, mojom::AudioFocusType::kGain, |
| group_id); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_3)); |
| |
| RequestAudioFocus(&media_session_4, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_1)); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_2)); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_3)); |
| |
| media_session_4.AbandonAudioFocusFromClient(); |
| |
| // TODO(https://crbug.com/916177): This should wait on a more precise |
| // condition than RunLoop idling, but it's not clear exactly what that |
| // should be. |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(IsGroupingEnabled() |
| ? mojom::MediaSessionInfo::SessionState::kActive |
| : mojom::MediaSessionInfo::SessionState::kSuspended, |
| GetState(&media_session_1)); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_2)); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_3)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AudioFocusGrouping_DoNotSuspendSameGroup) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| base::UnguessableToken group_id = base::UnguessableToken::Create(); |
| |
| RequestGroupedAudioFocus(&media_session_1, mojom::AudioFocusType::kGain, |
| group_id); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestGroupedAudioFocus(&media_session_2, mojom::AudioFocusType::kGain, |
| group_id); |
| EXPECT_EQ(IsGroupingEnabled() |
| ? mojom::MediaSessionInfo::SessionState::kActive |
| : mojom::MediaSessionInfo::SessionState::kSuspended, |
| GetState(&media_session_1)); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_2)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AudioFocusGrouping_DuckSameGroup) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| base::UnguessableToken group_id = base::UnguessableToken::Create(); |
| |
| RequestGroupedAudioFocus(&media_session_1, mojom::AudioFocusType::kGain, |
| group_id); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestGroupedAudioFocus( |
| &media_session_2, mojom::AudioFocusType::kGainTransientMayDuck, group_id); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kDucking), |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, AudioFocusGrouping_TransientSameGroup) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| base::UnguessableToken group_id = base::UnguessableToken::Create(); |
| |
| RequestGroupedAudioFocus(&media_session_1, mojom::AudioFocusType::kGain, |
| group_id); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestGroupedAudioFocus(&media_session_2, |
| mojom::AudioFocusType::kGainTransient, group_id); |
| EXPECT_EQ(IsGroupingEnabled() |
| ? mojom::MediaSessionInfo::SessionState::kActive |
| : mojom::MediaSessionInfo::SessionState::kSuspended, |
| GetState(&media_session_1)); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_2)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, RequestAudioFocus_PreferStop_LossToGain) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| media_session_1.SetPreferStop(true); |
| |
| AudioFocusManager::RequestId request_id_1 = |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id_1, GetAudioFocusedSession()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| AudioFocusManager::RequestId request_id_2 = |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id_2, GetAudioFocusedSession()); |
| EXPECT_EQ(GetStateFromParam(mojom::MediaSessionInfo::SessionState::kInactive), |
| GetState(&media_session_1)); |
| } |
| |
| TEST_P(AudioFocusManagerTest, |
| RequestAudioFocus_PreferStop_LossToGainTransient) { |
| test::MockMediaSession media_session_1; |
| test::MockMediaSession media_session_2; |
| |
| media_session_1.SetPreferStop(true); |
| |
| AudioFocusManager::RequestId request_id_1 = |
| RequestAudioFocus(&media_session_1, mojom::AudioFocusType::kGain); |
| EXPECT_EQ(request_id_1, GetAudioFocusedSession()); |
| EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, |
| GetState(&media_session_1)); |
| |
| RequestAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient); |
| EXPECT_EQ( |
| GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), |
| GetState(&media_session_1)); |
| } |
| |
| } // namespace media_session |