Commit 8ee18d31 authored by Becca Hughes's avatar Becca Hughes Committed by Commit Bot

[Media Controller] Add playback state

Add playback state to MediaSessionInfo. This reflects
the actual playback state of the media. This is used
because the audio focus state may not line up with
whether there is media playing (e.g. apps commonly
hold audio focus when they are paused).

BUG=893296

Change-Id: I025856fe007c08e61e85cb1417b472aecd5a3ccb
Reviewed-on: https://chromium-review.googlesource.com/c/1282026
Commit-Queue: Becca Hughes <beccahughes@chromium.org>
Reviewed-by: default avatarMounir Lamouri <mlamouri@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#602534}
parent badfb87f
...@@ -357,9 +357,9 @@ void AudioFocusManager::DidChangeFocus() { ...@@ -357,9 +357,9 @@ void AudioFocusManager::DidChangeFocus() {
if (audio_focus_stack_.empty()) { if (audio_focus_stack_.empty()) {
active_media_controller_.ClearMediaSession(); active_media_controller_.ClearMediaSession();
} else { } else {
active_media_controller_.SetMediaSession( StackRow* row = audio_focus_stack_.back().get();
audio_focus_stack_.back()->session(), active_media_controller_.SetMediaSession(row->session(),
audio_focus_stack_.back()->info()->state); row->info()->playback_state);
} }
} }
......
...@@ -29,30 +29,27 @@ void MediaController::Resume() { ...@@ -29,30 +29,27 @@ void MediaController::Resume() {
void MediaController::ToggleSuspendResume() { void MediaController::ToggleSuspendResume() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (state_) { switch (playback_state_) {
case mojom::MediaSessionInfo::SessionState::kInactive: case mojom::MediaPlaybackState::kPlaying:
case mojom::MediaSessionInfo::SessionState::kSuspended:
Resume();
break;
case mojom::MediaSessionInfo::SessionState::kDucking:
case mojom::MediaSessionInfo::SessionState::kActive:
Suspend(); Suspend();
break; break;
case mojom::MediaPlaybackState::kPaused:
Resume();
break;
} }
} }
void MediaController::SetMediaSession( void MediaController::SetMediaSession(mojom::MediaSession* session,
mojom::MediaSession* session, mojom::MediaPlaybackState state) {
mojom::MediaSessionInfo::SessionState state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
session_ = session; session_ = session;
state_ = state; playback_state_ = state;
} }
void MediaController::ClearMediaSession() { void MediaController::ClearMediaSession() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
session_ = nullptr; session_ = nullptr;
state_ = mojom::MediaSessionInfo::SessionState::kInactive; playback_state_ = mojom::MediaPlaybackState::kPaused;
} }
void MediaController::BindToInterface(mojom::MediaControllerRequest request) { void MediaController::BindToInterface(mojom::MediaControllerRequest request) {
......
...@@ -27,8 +27,7 @@ class MediaController : public mojom::MediaController { ...@@ -27,8 +27,7 @@ class MediaController : public mojom::MediaController {
void Resume() override; void Resume() override;
void ToggleSuspendResume() override; void ToggleSuspendResume() override;
void SetMediaSession(mojom::MediaSession*, void SetMediaSession(mojom::MediaSession*, mojom::MediaPlaybackState);
mojom::MediaSessionInfo::SessionState);
void ClearMediaSession(); void ClearMediaSession();
void BindToInterface(mojom::MediaControllerRequest); void BindToInterface(mojom::MediaControllerRequest);
...@@ -38,9 +37,9 @@ class MediaController : public mojom::MediaController { ...@@ -38,9 +37,9 @@ class MediaController : public mojom::MediaController {
// Holds mojo bindings for mojom::MediaController. // Holds mojo bindings for mojom::MediaController.
mojo::BindingSet<mojom::MediaController> bindings_; mojo::BindingSet<mojom::MediaController> bindings_;
// The current state of the |session_|. // The current playback state of the |session_|.
mojom::MediaSessionInfo::SessionState state_ = mojom::MediaPlaybackState playback_state_ =
mojom::MediaSessionInfo::SessionState::kInactive; mojom::MediaPlaybackState::kPaused;
// Raw pointer to the local proxy. This is used for sending control events to // Raw pointer to the local proxy. This is used for sending control events to
// the underlying MediaSession. // the underlying MediaSession.
......
...@@ -64,13 +64,13 @@ TEST_F(MediaControllerTest, ActiveController_Suspend) { ...@@ -64,13 +64,13 @@ TEST_F(MediaControllerTest, ActiveController_Suspend) {
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session); RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
controller()->Suspend(); controller()->Suspend();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPaused);
} }
} }
...@@ -80,7 +80,7 @@ TEST_F(MediaControllerTest, ActiveController_Suspend_Multiple) { ...@@ -80,7 +80,7 @@ TEST_F(MediaControllerTest, ActiveController_Suspend_Multiple) {
{ {
test::MockMediaSessionMojoObserver observer(media_session_1); test::MockMediaSessionMojoObserver observer(media_session_1);
RequestAudioFocus(media_session_1); RequestAudioFocus(media_session_1);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
test::MockMediaSession media_session_2; test::MockMediaSession media_session_2;
...@@ -91,26 +91,26 @@ TEST_F(MediaControllerTest, ActiveController_Suspend_Multiple) { ...@@ -91,26 +91,26 @@ TEST_F(MediaControllerTest, ActiveController_Suspend_Multiple) {
RequestAudioFocus(media_session_2); RequestAudioFocus(media_session_2);
observer_1.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended); observer_1.WaitForPlaybackState(mojom::MediaPlaybackState::kPaused);
observer_2.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer_2.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session_2); test::MockMediaSessionMojoObserver observer(media_session_2);
controller()->Suspend(); controller()->Suspend();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPaused);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session_1); test::MockMediaSessionMojoObserver observer(media_session_1);
media_session_2.AbandonAudioFocusFromClient(); media_session_2.AbandonAudioFocusFromClient();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session_1); test::MockMediaSessionMojoObserver observer(media_session_1);
controller()->Suspend(); controller()->Suspend();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPaused);
} }
} }
...@@ -124,7 +124,7 @@ TEST_F(MediaControllerTest, ActiveController_Suspend_Noop_Abandoned) { ...@@ -124,7 +124,7 @@ TEST_F(MediaControllerTest, ActiveController_Suspend_Noop_Abandoned) {
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session); RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
media_session.AbandonAudioFocusFromClient(); media_session.AbandonAudioFocusFromClient();
...@@ -134,7 +134,7 @@ TEST_F(MediaControllerTest, ActiveController_Suspend_Noop_Abandoned) { ...@@ -134,7 +134,7 @@ TEST_F(MediaControllerTest, ActiveController_Suspend_Noop_Abandoned) {
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session); RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
} }
...@@ -144,35 +144,35 @@ TEST_F(MediaControllerTest, ActiveController_SuspendResume) { ...@@ -144,35 +144,35 @@ TEST_F(MediaControllerTest, ActiveController_SuspendResume) {
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session); RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
controller()->Suspend(); controller()->Suspend();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPaused);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
controller()->Resume(); controller()->Resume();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
} }
TEST_F(MediaControllerTest, ActiveController_ToggleSuspendResume_Active) { TEST_F(MediaControllerTest, ActiveController_ToggleSuspendResume_Playing) {
test::MockMediaSession media_session; test::MockMediaSession media_session;
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session); RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
controller()->ToggleSuspendResume(); controller()->ToggleSuspendResume();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPaused);
} }
} }
...@@ -182,20 +182,19 @@ TEST_F(MediaControllerTest, ActiveController_ToggleSuspendResume_Ducked) { ...@@ -182,20 +182,19 @@ TEST_F(MediaControllerTest, ActiveController_ToggleSuspendResume_Ducked) {
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session); RequestAudioFocus(media_session);
media_session.StartDucking(); observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kDucking);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
controller()->ToggleSuspendResume(); media_session.StartDucking();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kDucking); observer.WaitForState(mojom::MediaSessionInfo::SessionState::kDucking);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
media_session.StopDucking(); controller()->ToggleSuspendResume();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPaused);
} }
} }
...@@ -212,29 +211,29 @@ TEST_F(MediaControllerTest, ActiveController_ToggleSuspendResume_Inactive) { ...@@ -212,29 +211,29 @@ TEST_F(MediaControllerTest, ActiveController_ToggleSuspendResume_Inactive) {
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
controller()->ToggleSuspendResume(); controller()->ToggleSuspendResume();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
} }
TEST_F(MediaControllerTest, ActiveController_ToggleSuspendResume_Suspended) { TEST_F(MediaControllerTest, ActiveController_ToggleSuspendResume_Paused) {
test::MockMediaSession media_session; test::MockMediaSession media_session;
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
RequestAudioFocus(media_session); RequestAudioFocus(media_session);
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
controller()->Suspend(); controller()->Suspend();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kSuspended); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPaused);
} }
{ {
test::MockMediaSessionMojoObserver observer(media_session); test::MockMediaSessionMojoObserver observer(media_session);
controller()->ToggleSuspendResume(); controller()->ToggleSuspendResume();
observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); observer.WaitForPlaybackState(mojom::MediaPlaybackState::kPlaying);
} }
} }
......
...@@ -25,8 +25,10 @@ void MockMediaSessionMojoObserver::MediaSessionInfoChanged( ...@@ -25,8 +25,10 @@ void MockMediaSessionMojoObserver::MediaSessionInfoChanged(
mojom::MediaSessionInfoPtr session) { mojom::MediaSessionInfoPtr session) {
session_info_ = std::move(session); session_info_ = std::move(session);
if (wanted_state_ == session_info_->state) if (wanted_state_ == session_info_->state ||
session_info_->playback_state == wanted_playback_state_) {
run_loop_.Quit(); run_loop_.Quit();
}
} }
void MockMediaSessionMojoObserver::WaitForState( void MockMediaSessionMojoObserver::WaitForState(
...@@ -38,6 +40,15 @@ void MockMediaSessionMojoObserver::WaitForState( ...@@ -38,6 +40,15 @@ void MockMediaSessionMojoObserver::WaitForState(
run_loop_.Run(); run_loop_.Run();
} }
void MockMediaSessionMojoObserver::WaitForPlaybackState(
mojom::MediaPlaybackState wanted_state) {
if (session_info_ && session_info_->playback_state == wanted_state)
return;
wanted_playback_state_ = wanted_state;
run_loop_.Run();
}
MockMediaSession::MockMediaSession() = default; MockMediaSession::MockMediaSession() = default;
MockMediaSession::MockMediaSession(bool force_duck) : force_duck_(force_duck) {} MockMediaSession::MockMediaSession(bool force_duck) : force_duck_(force_duck) {}
...@@ -170,6 +181,11 @@ mojom::MediaSessionInfoPtr MockMediaSession::GetMediaSessionInfoSync() const { ...@@ -170,6 +181,11 @@ mojom::MediaSessionInfoPtr MockMediaSession::GetMediaSessionInfoSync() const {
info->state = state_; info->state = state_;
if (is_ducking_) if (is_ducking_)
info->state = mojom::MediaSessionInfo::SessionState::kDucking; info->state = mojom::MediaSessionInfo::SessionState::kDucking;
info->playback_state = mojom::MediaPlaybackState::kPaused;
if (state_ == mojom::MediaSessionInfo::SessionState::kActive)
info->playback_state = mojom::MediaPlaybackState::kPlaying;
return info; return info;
} }
......
...@@ -30,10 +30,12 @@ class MockMediaSessionMojoObserver : public mojom::MediaSessionObserver { ...@@ -30,10 +30,12 @@ class MockMediaSessionMojoObserver : public mojom::MediaSessionObserver {
void MediaSessionInfoChanged(mojom::MediaSessionInfoPtr session) override; void MediaSessionInfoChanged(mojom::MediaSessionInfoPtr session) override;
void WaitForState(mojom::MediaSessionInfo::SessionState wanted_state); void WaitForState(mojom::MediaSessionInfo::SessionState wanted_state);
void WaitForPlaybackState(mojom::MediaPlaybackState wanted_state);
private: private:
mojom::MediaSessionInfoPtr session_info_; mojom::MediaSessionInfoPtr session_info_;
base::Optional<mojom::MediaSessionInfo::SessionState> wanted_state_; base::Optional<mojom::MediaSessionInfo::SessionState> wanted_state_;
base::Optional<mojom::MediaPlaybackState> wanted_playback_state_;
base::RunLoop run_loop_; base::RunLoop run_loop_;
mojo::Binding<mojom::MediaSessionObserver> binding_; mojo::Binding<mojom::MediaSessionObserver> binding_;
......
...@@ -4,7 +4,13 @@ ...@@ -4,7 +4,13 @@
module media_session.mojom; module media_session.mojom;
// Next MinVersion: 1 // Next MinVersion: 2
[Extensible]
enum MediaPlaybackState {
kPaused,
kPlaying,
};
// Contains state information about a MediaSession. // Contains state information about a MediaSession.
struct MediaSessionInfo { struct MediaSessionInfo {
...@@ -23,11 +29,16 @@ struct MediaSessionInfo { ...@@ -23,11 +29,16 @@ struct MediaSessionInfo {
kInactive, kInactive,
}; };
// The current state of the MediaSession. // The current audio focus state of the MediaSession.
SessionState state; SessionState state;
// If true then we will always duck this MediaSession instead of suspending. // If true then we will always duck this MediaSession instead of suspending.
bool force_duck; bool force_duck;
// The playback state tells the client whether the audio is playing. This is
// different from the audio focus state as it is common for a media session
// to hold audio focus sometimes even though it is not actually playing.
[MinVersion=1] MediaPlaybackState playback_state;
}; };
// Contains debugging information about a MediaSession. This will be displayed // Contains debugging information about a MediaSession. This will be displayed
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment