blob: dc3b70eb116729ea0e6045c655a044dabbb5dce8 [file] [log] [blame]
// 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 "content/browser/media/session/media_session_impl.h"
#include <memory>
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/media/session/media_session_player_observer.h"
#include "content/browser/media/session/mock_media_session_player_observer.h"
#include "content/browser/media/session/mock_media_session_service_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/media_session_service.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_renderer_host.h"
#include "content/test/test_web_contents.h"
#include "media/base/media_content_type.h"
#include "services/media_session/public/cpp/features.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/media_session.mojom.h"
using ::testing::_;
namespace content {
using media_session::mojom::AudioFocusType;
using media_session::mojom::MediaPlaybackState;
using media_session::mojom::MediaSessionInfo;
using media_session::mojom::MediaSessionInfoPtr;
using media_session::test::MockMediaSessionMojoObserver;
using media_session::test::TestAudioFocusObserver;
namespace {
class MockAudioFocusDelegate : public AudioFocusDelegate {
public:
MockAudioFocusDelegate() = default;
MockAudioFocusDelegate(const MockAudioFocusDelegate&) = delete;
MockAudioFocusDelegate& operator=(const MockAudioFocusDelegate&) = delete;
~MockAudioFocusDelegate() override = default;
void AbandonAudioFocus() override {}
AudioFocusResult RequestAudioFocus(AudioFocusType type) override {
request_audio_focus_count_++;
return AudioFocusResult::kSuccess;
}
absl::optional<AudioFocusType> GetCurrentFocusType() const override {
return AudioFocusType::kGain;
}
void MediaSessionInfoChanged(
const MediaSessionInfoPtr& session_info) override {
session_info_ = session_info.Clone();
}
MOCK_CONST_METHOD0(request_id, const base::UnguessableToken&());
MOCK_METHOD(void, ReleaseRequestId, (), (override));
MediaSessionInfo::SessionState GetState() const {
DCHECK(!session_info_.is_null());
return session_info_->state;
}
int request_audio_focus_count() const { return request_audio_focus_count_; }
private:
int request_audio_focus_count_ = 0;
MediaSessionInfoPtr session_info_;
};
// A mock WebContentsDelegate which listens to |ActivateContents()| calls.
class MockWebContentsDelegate : public content::WebContentsDelegate {
public:
// content::WebContentsDelegate:
MOCK_METHOD(void, ActivateContents, (content::WebContents*), (override));
};
} // anonymous namespace
class MediaSessionImplTest : public RenderViewHostTestHarness {
public:
MediaSessionImplTest()
: RenderViewHostTestHarness(
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
default_actions_.insert(media_session::mojom::MediaSessionAction::kPlay);
default_actions_.insert(media_session::mojom::MediaSessionAction::kPause);
default_actions_.insert(media_session::mojom::MediaSessionAction::kStop);
default_actions_.insert(media_session::mojom::MediaSessionAction::kSeekTo);
default_actions_.insert(media_session::mojom::MediaSessionAction::kScrubTo);
}
MediaSessionImplTest(const MediaSessionImplTest&) = delete;
MediaSessionImplTest& operator=(const MediaSessionImplTest&) = delete;
void SetUp() override {
scoped_feature_list_.InitWithFeatures(
{media_session::features::kMediaSessionService,
media_session::features::kAudioFocusEnforcement},
{});
RenderViewHostTestHarness::SetUp();
player_observer_ = std::make_unique<MockMediaSessionPlayerObserver>(
main_rfh(), media::MediaContentType::Persistent);
mock_media_session_service_ =
std::make_unique<testing::NiceMock<MockMediaSessionServiceImpl>>(
main_rfh());
// Connect to the Media Session service and bind |audio_focus_remote_| to
// it.
GetMediaSessionService().BindAudioFocusManager(
audio_focus_remote_.BindNewPipeAndPassReceiver());
}
void TearDown() override {
mock_media_session_service_.reset();
RenderViewHostTestHarness::TearDown();
}
void RequestAudioFocus(MediaSessionImpl* session,
AudioFocusType audio_focus_type) {
session->RequestSystemAudioFocus(audio_focus_type);
}
void AbandonAudioFocus(MediaSessionImpl* session) {
session->AbandonSystemAudioFocusIfNeeded();
}
bool GetForceDuck(MediaSessionImpl* session) {
return media_session::test::GetMediaSessionInfoSync(session)->force_duck;
}
MediaSessionInfo::SessionState GetState(MediaSessionImpl* session) {
return media_session::test::GetMediaSessionInfoSync(session)->state;
}
void ClearObservers(MediaSessionImpl* session) {
session->observers_.Clear();
}
bool HasObservers(MediaSessionImpl* session) {
return !session->observers_.empty();
}
void FlushForTesting(MediaSessionImpl* session) {
session->FlushForTesting();
}
std::unique_ptr<TestAudioFocusObserver> CreateAudioFocusObserver() {
std::unique_ptr<TestAudioFocusObserver> observer =
std::make_unique<TestAudioFocusObserver>();
audio_focus_remote_->AddObserver(observer->BindNewPipeAndPassRemote());
audio_focus_remote_.FlushForTesting();
return observer;
}
std::unique_ptr<MockMediaSessionPlayerObserver> player_observer_;
void SetDelegateForTests(MediaSessionImpl* session,
AudioFocusDelegate* delegate) {
session->SetDelegateForTests(base::WrapUnique(delegate));
}
MockMediaSessionServiceImpl& mock_media_session_service() const {
return *mock_media_session_service_.get();
}
MediaSessionImpl* GetMediaSession() {
return MediaSessionImpl::Get(web_contents());
}
void StartNewPlayer() {
GetMediaSession()->AddPlayer(player_observer_.get(),
player_observer_->StartNewPlayer());
}
const std::set<media_session::mojom::MediaSessionAction>& default_actions()
const {
return default_actions_;
}
private:
std::set<media_session::mojom::MediaSessionAction> default_actions_;
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<MockMediaSessionServiceImpl> mock_media_session_service_;
mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote_;
};
TEST_F(MediaSessionImplTest, SessionInfoState) {
EXPECT_EQ(MediaSessionInfo::SessionState::kInactive,
GetState(GetMediaSession()));
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain);
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
EXPECT_TRUE(observer.session_info().Equals(
media_session::test::GetMediaSessionInfoSync(GetMediaSession())));
}
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->StartDucking();
observer.WaitForState(MediaSessionInfo::SessionState::kDucking);
}
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->StopDucking();
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
EXPECT_TRUE(observer.session_info().Equals(
media_session::test::GetMediaSessionInfoSync(GetMediaSession())));
}
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
EXPECT_TRUE(observer.session_info().Equals(
media_session::test::GetMediaSessionInfoSync(GetMediaSession())));
}
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->Resume(MediaSession::SuspendType::kSystem);
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
EXPECT_TRUE(observer.session_info().Equals(
media_session::test::GetMediaSessionInfoSync(GetMediaSession())));
}
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
AbandonAudioFocus(GetMediaSession());
observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
EXPECT_TRUE(observer.session_info().Equals(
media_session::test::GetMediaSessionInfoSync(GetMediaSession())));
}
}
TEST_F(MediaSessionImplTest, NotifyDelegateOnStateChange) {
MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
SetDelegateForTests(GetMediaSession(), delegate);
RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(MediaSessionInfo::SessionState::kActive, delegate->GetState());
GetMediaSession()->StartDucking();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(MediaSessionInfo::SessionState::kDucking, delegate->GetState());
GetMediaSession()->StopDucking();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(MediaSessionInfo::SessionState::kActive, delegate->GetState());
GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(MediaSessionInfo::SessionState::kSuspended, delegate->GetState());
GetMediaSession()->Resume(MediaSession::SuspendType::kSystem);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(MediaSessionInfo::SessionState::kActive, delegate->GetState());
AbandonAudioFocus(GetMediaSession());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(MediaSessionInfo::SessionState::kInactive, delegate->GetState());
}
TEST_F(MediaSessionImplTest, PepperForcesDuckAndRequestsFocus) {
int player_id = player_observer_->StartNewPlayer();
{
player_observer_->SetMediaContentType(media::MediaContentType::Pepper);
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->AddPlayer(player_observer_.get(), player_id);
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
player_observer_->SetMediaContentType(media::MediaContentType::Persistent);
}
EXPECT_TRUE(GetForceDuck(GetMediaSession()));
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->RemovePlayer(player_observer_.get(), player_id);
observer.WaitForState(MediaSessionInfo::SessionState::kInactive);
}
EXPECT_FALSE(GetForceDuck(GetMediaSession()));
}
TEST_F(MediaSessionImplTest, RegisterObserver) {
// There is no way to get the number of mojo observers so we should just
// remove them all and check if the mojo observers interface ptr set is
// empty or not.
ClearObservers(GetMediaSession());
EXPECT_FALSE(HasObservers(GetMediaSession()));
MockMediaSessionMojoObserver observer(*GetMediaSession());
FlushForTesting(GetMediaSession());
EXPECT_TRUE(HasObservers(GetMediaSession()));
}
TEST_F(MediaSessionImplTest, SessionInfo_PlaybackState) {
EXPECT_EQ(MediaPlaybackState::kPaused,
media_session::test::GetMediaSessionInfoSync(GetMediaSession())
->playback_state);
int player_id = player_observer_->StartNewPlayer();
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->AddPlayer(player_observer_.get(), player_id);
observer.WaitForPlaybackState(MediaPlaybackState::kPlaying);
}
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->OnPlayerPaused(player_observer_.get(), player_id);
observer.WaitForPlaybackState(MediaPlaybackState::kPaused);
}
}
TEST_F(MediaSessionImplTest, SuspendUI) {
EXPECT_CALL(
mock_media_session_service().mock_client(),
DidReceiveAction(media_session::mojom::MediaSessionAction::kPause, _))
.Times(0);
StartNewPlayer();
GetMediaSession()->Suspend(MediaSession::SuspendType::kUI);
mock_media_session_service().FlushForTesting();
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(default_actions());
}
TEST_F(MediaSessionImplTest, SuspendContent_WithAction) {
EXPECT_CALL(
mock_media_session_service().mock_client(),
DidReceiveAction(media_session::mojom::MediaSessionAction::kPause, _))
.Times(0);
StartNewPlayer();
mock_media_session_service().EnableAction(
media_session::mojom::MediaSessionAction::kPause);
GetMediaSession()->Suspend(MediaSession::SuspendType::kContent);
mock_media_session_service().FlushForTesting();
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(default_actions());
}
TEST_F(MediaSessionImplTest, SuspendSystem_WithAction) {
EXPECT_CALL(
mock_media_session_service().mock_client(),
DidReceiveAction(media_session::mojom::MediaSessionAction::kPause, _))
.Times(0);
StartNewPlayer();
mock_media_session_service().EnableAction(
media_session::mojom::MediaSessionAction::kPause);
GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
mock_media_session_service().FlushForTesting();
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(default_actions());
}
TEST_F(MediaSessionImplTest, SuspendUI_WithAction) {
EXPECT_CALL(
mock_media_session_service().mock_client(),
DidReceiveAction(media_session::mojom::MediaSessionAction::kPause, _));
StartNewPlayer();
mock_media_session_service().EnableAction(
media_session::mojom::MediaSessionAction::kPause);
GetMediaSession()->Suspend(MediaSession::SuspendType::kUI);
mock_media_session_service().FlushForTesting();
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(default_actions());
}
TEST_F(MediaSessionImplTest, ResumeUI) {
EXPECT_CALL(
mock_media_session_service().mock_client(),
DidReceiveAction(media_session::mojom::MediaSessionAction::kPlay, _))
.Times(0);
StartNewPlayer();
GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
GetMediaSession()->Resume(MediaSession::SuspendType::kUI);
mock_media_session_service().FlushForTesting();
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(default_actions());
}
TEST_F(MediaSessionImplTest, ResumeContent_WithAction) {
EXPECT_CALL(
mock_media_session_service().mock_client(),
DidReceiveAction(media_session::mojom::MediaSessionAction::kPlay, _))
.Times(0);
StartNewPlayer();
mock_media_session_service().EnableAction(
media_session::mojom::MediaSessionAction::kPlay);
GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
GetMediaSession()->Resume(MediaSession::SuspendType::kContent);
mock_media_session_service().FlushForTesting();
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(default_actions());
}
TEST_F(MediaSessionImplTest, ResumeSystem_WithAction) {
EXPECT_CALL(
mock_media_session_service().mock_client(),
DidReceiveAction(media_session::mojom::MediaSessionAction::kPlay, _))
.Times(0);
StartNewPlayer();
mock_media_session_service().EnableAction(
media_session::mojom::MediaSessionAction::kPlay);
GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
GetMediaSession()->Resume(MediaSession::SuspendType::kSystem);
mock_media_session_service().FlushForTesting();
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(default_actions());
}
TEST_F(MediaSessionImplTest, ResumeUI_WithAction) {
EXPECT_CALL(
mock_media_session_service().mock_client(),
DidReceiveAction(media_session::mojom::MediaSessionAction::kPlay, _));
StartNewPlayer();
mock_media_session_service().EnableAction(
media_session::mojom::MediaSessionAction::kPlay);
GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
GetMediaSession()->Resume(MediaSession::SuspendType::kUI);
mock_media_session_service().FlushForTesting();
media_session::test::MockMediaSessionMojoObserver observer(
*GetMediaSession());
observer.WaitForExpectedActions(default_actions());
}
#if !BUILDFLAG(IS_ANDROID)
TEST_F(MediaSessionImplTest, WebContentsDestroyed_ReleasesFocus) {
std::unique_ptr<WebContents> web_contents(CreateTestWebContents());
MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
{
std::unique_ptr<TestAudioFocusObserver> observer =
CreateAudioFocusObserver();
RequestAudioFocus(media_session, AudioFocusType::kGain);
observer->WaitForGainedEvent();
}
{
MockMediaSessionMojoObserver observer(*media_session);
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
}
{
std::unique_ptr<TestAudioFocusObserver> observer =
CreateAudioFocusObserver();
web_contents.reset();
observer->WaitForLostEvent();
}
}
TEST_F(MediaSessionImplTest, WebContentsDestroyed_ReleasesTransients) {
std::unique_ptr<WebContents> web_contents(CreateTestWebContents());
MediaSessionImpl* media_session = MediaSessionImpl::Get(web_contents.get());
{
std::unique_ptr<TestAudioFocusObserver> observer =
CreateAudioFocusObserver();
RequestAudioFocus(media_session, AudioFocusType::kGainTransientMayDuck);
observer->WaitForGainedEvent();
}
{
MockMediaSessionMojoObserver observer(*media_session);
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
}
{
std::unique_ptr<TestAudioFocusObserver> observer =
CreateAudioFocusObserver();
web_contents.reset();
observer->WaitForLostEvent();
}
}
TEST_F(MediaSessionImplTest, WebContentsDestroyed_StopsDucking) {
std::unique_ptr<WebContents> web_contents_1(CreateTestWebContents());
MediaSessionImpl* media_session_1 =
MediaSessionImpl::Get(web_contents_1.get());
std::unique_ptr<WebContents> web_contents_2(CreateTestWebContents());
MediaSessionImpl* media_session_2 =
MediaSessionImpl::Get(web_contents_2.get());
{
std::unique_ptr<TestAudioFocusObserver> observer =
CreateAudioFocusObserver();
RequestAudioFocus(media_session_1, AudioFocusType::kGain);
observer->WaitForGainedEvent();
}
{
MockMediaSessionMojoObserver observer(*media_session_1);
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
}
{
std::unique_ptr<TestAudioFocusObserver> observer =
CreateAudioFocusObserver();
RequestAudioFocus(media_session_2, AudioFocusType::kGainTransientMayDuck);
observer->WaitForGainedEvent();
}
{
MockMediaSessionMojoObserver observer(*media_session_1);
observer.WaitForState(MediaSessionInfo::SessionState::kDucking);
}
{
std::unique_ptr<TestAudioFocusObserver> observer =
CreateAudioFocusObserver();
web_contents_2.reset();
observer->WaitForLostEvent();
}
{
MockMediaSessionMojoObserver observer(*media_session_1);
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
}
}
#if BUILDFLAG(IS_MAC)
TEST_F(MediaSessionImplTest, TabFocusDoesNotCauseAudioFocus) {
MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
SetDelegateForTests(GetMediaSession(), delegate);
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain);
FlushForTesting(GetMediaSession());
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
}
EXPECT_EQ(1, delegate->request_audio_focus_count());
GetMediaSession()->OnWebContentsFocused(nullptr);
EXPECT_EQ(1, delegate->request_audio_focus_count());
}
#else // BUILDFLAG(IS_MAC)
TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Active) {
MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
SetDelegateForTests(GetMediaSession(), delegate);
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain);
FlushForTesting(GetMediaSession());
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
}
EXPECT_EQ(1, delegate->request_audio_focus_count());
GetMediaSession()->OnWebContentsFocused(nullptr);
EXPECT_EQ(2, delegate->request_audio_focus_count());
}
TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Inactive) {
MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
SetDelegateForTests(GetMediaSession(), delegate);
EXPECT_EQ(MediaSessionInfo::SessionState::kInactive,
GetState(GetMediaSession()));
EXPECT_EQ(0, delegate->request_audio_focus_count());
GetMediaSession()->OnWebContentsFocused(nullptr);
EXPECT_EQ(0, delegate->request_audio_focus_count());
}
TEST_F(MediaSessionImplTest, RequestAudioFocus_OnFocus_Suspended) {
MockAudioFocusDelegate* delegate = new MockAudioFocusDelegate();
SetDelegateForTests(GetMediaSession(), delegate);
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
RequestAudioFocus(GetMediaSession(), AudioFocusType::kGain);
FlushForTesting(GetMediaSession());
observer.WaitForState(MediaSessionInfo::SessionState::kActive);
}
{
MockMediaSessionMojoObserver observer(*GetMediaSession());
GetMediaSession()->Suspend(MediaSession::SuspendType::kSystem);
observer.WaitForState(MediaSessionInfo::SessionState::kSuspended);
}
EXPECT_EQ(1, delegate->request_audio_focus_count());
GetMediaSession()->OnWebContentsFocused(nullptr);
EXPECT_EQ(1, delegate->request_audio_focus_count());
}
#endif // BUILDFLAG(IS_MAC)
#endif // !BUILDFLAG(IS_ANDROID)
TEST_F(MediaSessionImplTest, SourceId_SameBrowserContext) {
auto other_contents = TestWebContents::Create(browser_context(), nullptr);
MediaSessionImpl* other_session = MediaSessionImpl::Get(other_contents.get());
EXPECT_EQ(GetMediaSession()->GetSourceId(), other_session->GetSourceId());
}
TEST_F(MediaSessionImplTest, SourceId_DifferentBrowserContext) {
auto other_context = CreateBrowserContext();
auto other_contents = TestWebContents::Create(other_context.get(), nullptr);
MediaSessionImpl* other_session = MediaSessionImpl::Get(other_contents.get());
EXPECT_NE(GetMediaSession()->GetSourceId(), other_session->GetSourceId());
}
TEST_F(MediaSessionImplTest, SessionInfoSensitive) {
EXPECT_FALSE(browser_context()->IsOffTheRecord());
EXPECT_FALSE(media_session::test::GetMediaSessionInfoSync(GetMediaSession())
->is_sensitive);
}
TEST_F(MediaSessionImplTest, SessionInfoSensitive_OffTheRecord) {
auto other_context = std::make_unique<TestBrowserContext>();
other_context->set_is_off_the_record(true);
auto other_contents = TestWebContents::Create(other_context.get(), nullptr);
MediaSessionImpl* other_session = MediaSessionImpl::Get(other_contents.get());
EXPECT_TRUE(other_context->IsOffTheRecord());
EXPECT_TRUE(media_session::test::GetMediaSessionInfoSync(other_session)
->is_sensitive);
}
TEST_F(MediaSessionImplTest, SessionInfoPictureInPicture) {
WebContentsImpl* web_contents_impl =
static_cast<WebContentsImpl*>(web_contents());
EXPECT_EQ(
media_session::test::GetMediaSessionInfoSync(GetMediaSession())
->picture_in_picture_state,
media_session::mojom::MediaPictureInPictureState::kNotInPictureInPicture);
web_contents_impl->SetHasPictureInPictureVideo(true);
EXPECT_EQ(
media_session::test::GetMediaSessionInfoSync(GetMediaSession())
->picture_in_picture_state,
media_session::mojom::MediaPictureInPictureState::kInPictureInPicture);
web_contents_impl->SetHasPictureInPictureVideo(false);
EXPECT_EQ(
media_session::test::GetMediaSessionInfoSync(GetMediaSession())
->picture_in_picture_state,
media_session::mojom::MediaPictureInPictureState::kNotInPictureInPicture);
}
TEST_F(MediaSessionImplTest, SessionInfoAudioSink) {
// When the session is created it should be using the default audio device.
// When the default audio device is in use, the |audio_sink_id| attribute
// should be unset.
EXPECT_FALSE(media_session::test::GetMediaSessionInfoSync(GetMediaSession())
->audio_sink_id.has_value());
int player1 = player_observer_->StartNewPlayer();
int player2 = player_observer_->StartNewPlayer();
GetMediaSession()->AddPlayer(player_observer_.get(), player1);
GetMediaSession()->AddPlayer(player_observer_.get(), player2);
player_observer_->SetAudioSinkId(player1, "1");
player_observer_->SetAudioSinkId(player2, "1");
auto info = media_session::test::GetMediaSessionInfoSync(GetMediaSession());
ASSERT_TRUE(info->audio_sink_id.has_value());
EXPECT_EQ(info->audio_sink_id.value(), "1");
// If multiple audio devices are being used the audio sink id attribute should
// be unset.
player_observer_->SetAudioSinkId(player2, "2");
info = media_session::test::GetMediaSessionInfoSync(GetMediaSession());
EXPECT_FALSE(info->audio_sink_id.has_value());
}
TEST_F(MediaSessionImplTest, RaiseActivatesWebContents) {
MockWebContentsDelegate delegate;
web_contents()->SetDelegate(&delegate);
// When the WebContents has a delegate, |Raise()| should activate the
// WebContents.
EXPECT_CALL(delegate, ActivateContents(web_contents()));
GetMediaSession()->Raise();
testing::Mock::VerifyAndClearExpectations(&delegate);
// When the WebContents does not have a delegate, |Raise()| should not crash.
web_contents()->SetDelegate(nullptr);
GetMediaSession()->Raise();
}
// Tests for throttling duration updates.
// TODO (jazzhsu): Remove these tests once media session supports livestream.
class MediaSessionImplDurationThrottleTest : public MediaSessionImplTest {
public:
void SetUp() override {
MediaSessionImplTest::SetUp();
GetMediaSession()->SetShouldThrottleDurationUpdateForTest(true);
}
void FastForwardBy(base::TimeDelta delay) {
task_environment()->FastForwardBy(delay);
}
int GetDurationUpdateMaxAllowance() {
return MediaSessionImpl::kDurationUpdateMaxAllowance;
}
base::TimeDelta GetDurationUpdateAllowanceIncreaseInterval() {
return MediaSessionImpl::kDurationUpdateAllowanceIncreaseInterval;
}
};
TEST_F(MediaSessionImplDurationThrottleTest, ThrottleDurationUpdate) {
MockMediaSessionMojoObserver observer(*GetMediaSession());
int player_id = player_observer_->StartNewPlayer();
GetMediaSession()->AddPlayer(player_observer_.get(), player_id);
media_session::MediaPosition pos;
for (int duration = 0; duration <= GetDurationUpdateMaxAllowance();
++duration) {
pos = media_session::MediaPosition(
/*playback_rate=*/0.0,
/*duration=*/base::Seconds(duration),
/*position=*/base::TimeDelta(), /*end_of_media=*/false);
player_observer_->SetPosition(player_id, pos);
GetMediaSession()->RebuildAndNotifyMediaPositionChanged();
FlushForTesting(GetMediaSession());
if (duration == GetDurationUpdateMaxAllowance()) {
// Last update should be throttle and marked as +INF duration.
EXPECT_EQ(**observer.session_position(),
media_session::MediaPosition(
/*playback_rate=*/0.0,
/*duration=*/base::TimeDelta::Max(),
/*position=*/base::TimeDelta(), /*end_of_media=*/false));
} else {
EXPECT_EQ(**observer.session_position(), pos);
}
}
// Media session should send last throttled duration update after certain
// delay.
FastForwardBy(GetDurationUpdateAllowanceIncreaseInterval());
FlushForTesting(GetMediaSession());
EXPECT_EQ(**observer.session_position(), pos);
}
TEST_F(MediaSessionImplDurationThrottleTest, ThrottleResetOnPlayerChange) {
MockMediaSessionMojoObserver observer(*GetMediaSession());
// Duration updates caused by player switch should not be throttled.
media_session::MediaPosition pos;
for (int duration = 0; duration <= GetDurationUpdateMaxAllowance();
++duration) {
int player_id = player_observer_->StartNewPlayer();
GetMediaSession()->AddPlayer(player_observer_.get(), player_id);
pos = media_session::MediaPosition(
/*playback_rate=*/0.0,
/*duration=*/base::Seconds(duration),
/*position=*/base::TimeDelta(), /*end_of_media=*/false);
player_observer_->SetPosition(player_id, pos);
GetMediaSession()->RebuildAndNotifyMediaPositionChanged();
FlushForTesting(GetMediaSession());
EXPECT_EQ(**observer.session_position(), pos);
GetMediaSession()->RemovePlayer(player_observer_.get(), player_id);
}
}
} // namespace content