0

GMC V2 Add mute button to media notification.

This CL adds SetMute to MediaSession so that we can change mute status
of the player from media session.

Bug: 1238990

Change-Id: Ida26834d006cfb76056c72934d4844f44c0f0a3e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2881119
Commit-Queue: Jazz Xu <jazzhsu@chromium.org>
Reviewed-by: Wez <wez@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Tao Wu <wutao@chromium.org>
Reviewed-by: François Beaufort <beaufort.francois@gmail.com>
Reviewed-by: Olga Sharonova <olka@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: Sean Topping <seantopping@chromium.org>
Cr-Commit-Position: refs/heads/main@{#913135}
This commit is contained in:
Jazz Xu
2021-08-18 20:26:38 +00:00
committed by Chromium LUCI CQ
parent c724a89f4b
commit 0f11c0f272
41 changed files with 141 additions and 17 deletions

@@ -134,6 +134,7 @@ const gfx::VectorIcon& GetVectorIconForMediaAction(MediaSessionAction action) {
case MediaSessionAction::kToggleCamera: case MediaSessionAction::kToggleCamera:
case MediaSessionAction::kHangUp: case MediaSessionAction::kHangUp:
case MediaSessionAction::kRaise: case MediaSessionAction::kRaise:
case MediaSessionAction::kSetMute:
NOTREACHED(); NOTREACHED();
break; break;
} }

@@ -90,6 +90,7 @@ const gfx::VectorIcon& GetVectorIconForMediaAction(MediaSessionAction action) {
case MediaSessionAction::kToggleCamera: case MediaSessionAction::kToggleCamera:
case MediaSessionAction::kHangUp: case MediaSessionAction::kHangUp:
case MediaSessionAction::kRaise: case MediaSessionAction::kRaise:
case MediaSessionAction::kSetMute:
NOTREACHED(); NOTREACHED();
break; break;
} }

@@ -68,6 +68,7 @@ void CastMediaSessionController::Send(
case media_session::mojom::MediaSessionAction::kToggleCamera: case media_session::mojom::MediaSessionAction::kToggleCamera:
case media_session::mojom::MediaSessionAction::kHangUp: case media_session::mojom::MediaSessionAction::kHangUp:
case media_session::mojom::MediaSessionAction::kRaise: case media_session::mojom::MediaSessionAction::kRaise:
case media_session::mojom::MediaSessionAction::kSetMute:
NOTREACHED(); NOTREACHED();
return; return;
} }

@@ -71,8 +71,10 @@ void MediaSessionNotificationItem::MediaSessionInfoChanged(
MaybeUnfreeze(); MaybeUnfreeze();
MaybeHideOrShowNotification(); MaybeHideOrShowNotification();
if (view_ && !frozen_) if (view_ && !frozen_) {
view_->UpdateWithMediaSessionInfo(session_info_); view_->UpdateWithMediaSessionInfo(session_info_);
view_->UpdateWithMuteStatus(session_info_->muted);
}
} }
void MediaSessionNotificationItem::MediaSessionMetadataChanged( void MediaSessionNotificationItem::MediaSessionMetadataChanged(
@@ -153,6 +155,7 @@ void MediaSessionNotificationItem::SetView(
view_->UpdateWithMediaSessionInfo(session_info_); view_->UpdateWithMediaSessionInfo(session_info_);
view_->UpdateWithMediaMetadata(session_metadata_); view_->UpdateWithMediaMetadata(session_metadata_);
view_->UpdateWithMediaActions(session_actions_); view_->UpdateWithMediaActions(session_actions_);
view_->UpdateWithMuteStatus(session_info_->muted);
if (session_position_.has_value()) if (session_position_.has_value())
view_->UpdateWithMediaPosition(*session_position_); view_->UpdateWithMediaPosition(*session_position_);
@@ -196,6 +199,11 @@ void MediaSessionNotificationItem::Raise() {
media_controller_remote_->Raise(); media_controller_remote_->Raise();
} }
void MediaSessionNotificationItem::SetMute(bool mute) {
if (!frozen_)
media_controller_remote_->SetMute(mute);
}
void MediaSessionNotificationItem::SetController( void MediaSessionNotificationItem::SetController(
mojo::Remote<media_session::mojom::MediaController> controller, mojo::Remote<media_session::mojom::MediaController> controller,
media_session::mojom::MediaSessionInfoPtr session_info) { media_session::mojom::MediaSessionInfoPtr session_info) {
@@ -310,6 +318,7 @@ void MediaSessionNotificationItem::Unfreeze() {
view_->UpdateWithMediaSessionInfo(session_info_); view_->UpdateWithMediaSessionInfo(session_info_);
view_->UpdateWithMediaMetadata(session_metadata_); view_->UpdateWithMediaMetadata(session_metadata_);
view_->UpdateWithMediaActions(session_actions_); view_->UpdateWithMediaActions(session_actions_);
view_->UpdateWithMuteStatus(session_info_->muted);
if (session_position_.has_value()) if (session_position_.has_value())
view_->UpdateWithMediaPosition(*session_position_); view_->UpdateWithMediaPosition(*session_position_);

@@ -92,7 +92,7 @@ class MediaSessionNotificationItem
void Dismiss() override; void Dismiss() override;
media_message_center::SourceType SourceType() override; media_message_center::SourceType SourceType() override;
void SetVolume(float volume) override {} void SetVolume(float volume) override {}
void SetMute(bool mute) override {} void SetMute(bool mute) override;
// Calls |Raise()| on the underlying MediaSession, which will focus the // Calls |Raise()| on the underlying MediaSession, which will focus the
// WebContents if the MediaSession is associated with one. // WebContents if the MediaSession is associated with one.

@@ -61,6 +61,7 @@ class MockMediaSession : public content::MediaSession {
MOCK_METHOD0(ToggleCamera, void()); MOCK_METHOD0(ToggleCamera, void());
MOCK_METHOD0(HangUp, void()); MOCK_METHOD0(HangUp, void());
MOCK_METHOD0(Raise, void()); MOCK_METHOD0(Raise, void());
MOCK_METHOD1(SetMute, void(bool));
private: private:
DISALLOW_COPY_AND_ASSIGN(MockMediaSession); DISALLOW_COPY_AND_ASSIGN(MockMediaSession);

@@ -100,6 +100,7 @@ class MediaControllerMock : public media_session::mojom::MediaController {
MOCK_METHOD(void, ToggleCamera, ()); MOCK_METHOD(void, ToggleCamera, ());
MOCK_METHOD(void, HangUp, ()); MOCK_METHOD(void, HangUp, ());
MOCK_METHOD(void, Raise, ()); MOCK_METHOD(void, Raise, ());
MOCK_METHOD(void, SetMute, (bool mute));
void AddObserver( void AddObserver(
mojo::PendingRemote<media_session::mojom::MediaControllerObserver> remote) mojo::PendingRemote<media_session::mojom::MediaControllerObserver> remote)
override { override {

@@ -58,6 +58,7 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE) AssistantMediaSession
void ToggleCamera() override {} void ToggleCamera() override {}
void HangUp() override {} void HangUp() override {}
void Raise() override {} void Raise() override {}
void SetMute(bool mute) override {}
// Requests/abandons audio focus to the AudioFocusManager. // Requests/abandons audio focus to the AudioFocusManager.
void RequestAudioFocus(media_session::mojom::AudioFocusType audio_focus_type); void RequestAudioFocus(media_session::mojom::AudioFocusType audio_focus_type);

@@ -104,6 +104,7 @@ const gfx::VectorIcon* GetVectorIconForMediaAction(MediaSessionAction action) {
case MediaSessionAction::kToggleCamera: case MediaSessionAction::kToggleCamera:
case MediaSessionAction::kHangUp: case MediaSessionAction::kHangUp:
case MediaSessionAction::kRaise: case MediaSessionAction::kRaise:
case MediaSessionAction::kSetMute:
NOTREACHED(); NOTREACHED();
break; break;
} }

@@ -111,6 +111,7 @@ const gfx::VectorIcon* GetVectorIconForMediaAction(MediaSessionAction action) {
case MediaSessionAction::kToggleCamera: case MediaSessionAction::kToggleCamera:
case MediaSessionAction::kHangUp: case MediaSessionAction::kHangUp:
case MediaSessionAction::kRaise: case MediaSessionAction::kRaise:
case MediaSessionAction::kSetMute:
NOTREACHED(); NOTREACHED();
break; break;
} }
@@ -154,6 +155,7 @@ const std::u16string GetAccessibleNameForMediaAction(
case MediaSessionAction::kToggleCamera: case MediaSessionAction::kToggleCamera:
case MediaSessionAction::kHangUp: case MediaSessionAction::kHangUp:
case MediaSessionAction::kRaise: case MediaSessionAction::kRaise:
case MediaSessionAction::kSetMute:
NOTREACHED(); NOTREACHED();
break; break;
} }
@@ -439,20 +441,19 @@ MediaNotificationViewModernImpl::MediaNotificationViewModernImpl(
volume_slider->SetPreferredSize(kVolumeSliderSize); volume_slider->SetPreferredSize(kVolumeSliderSize);
volume_slider_ = volume_slider_ =
util_buttons_container->AddChildView(std::move(volume_slider)); util_buttons_container->AddChildView(std::move(volume_slider));
auto mute_button =
std::make_unique<views::ToggleImageButton>(base::BindRepeating(
&MediaNotificationViewModernImpl::OnMuteButtonClicked,
base::Unretained(this)));
mute_button->SetPreferredSize(kMuteButtonSize);
mute_button->SetImageHorizontalAlignment(
views::ImageButton::HorizontalAlignment::ALIGN_CENTER);
mute_button->SetImageVerticalAlignment(
views::ImageButton::VerticalAlignment::ALIGN_MIDDLE);
mute_button_ =
util_buttons_container->AddChildView(std::move(mute_button));
} }
auto mute_button =
std::make_unique<views::ToggleImageButton>(base::BindRepeating(
&MediaNotificationViewModernImpl::OnMuteButtonClicked,
base::Unretained(this)));
mute_button->SetPreferredSize(kMuteButtonSize);
mute_button->SetImageHorizontalAlignment(
views::ImageButton::HorizontalAlignment::ALIGN_CENTER);
mute_button->SetImageVerticalAlignment(
views::ImageButton::VerticalAlignment::ALIGN_MIDDLE);
mute_button_ = util_buttons_container->AddChildView(std::move(mute_button));
AddChildView(std::move(util_buttons_container)); AddChildView(std::move(util_buttons_container));
} }

@@ -199,6 +199,7 @@ void ActiveMediaSessionController::PerformAction(MediaSessionAction action) {
case MediaSessionAction::kToggleCamera: case MediaSessionAction::kToggleCamera:
case MediaSessionAction::kHangUp: case MediaSessionAction::kHangUp:
case MediaSessionAction::kRaise: case MediaSessionAction::kRaise:
case MediaSessionAction::kSetMute:
NOTREACHED(); NOTREACHED();
return; return;
} }
@@ -251,6 +252,7 @@ ActiveMediaSessionController::MediaSessionActionToKeyCode(
case MediaSessionAction::kToggleCamera: case MediaSessionAction::kToggleCamera:
case MediaSessionAction::kHangUp: case MediaSessionAction::kHangUp:
case MediaSessionAction::kRaise: case MediaSessionAction::kRaise:
case MediaSessionAction::kSetMute:
return absl::nullopt; return absl::nullopt;
} }
} }

@@ -337,6 +337,9 @@ void MediaWebContentsObserver::MediaPlayerObserverHostImpl::
media_web_contents_observer_->web_contents_impl()->MediaMutedStatusChanged( media_web_contents_observer_->web_contents_impl()->MediaMutedStatusChanged(
media_player_id_, muted); media_player_id_, muted);
media_web_contents_observer_->session_controllers_manager()
->OnMediaMutedStatusChanged(media_player_id_, muted);
PlayerInfo* player_info = GetPlayerInfo(); PlayerInfo* player_info = GetPlayerInfo();
if (!player_info) if (!player_info)
return; return;

@@ -141,6 +141,14 @@ void MediaSessionController::OnSetAudioSinkId(
->SetAudioSinkId(hashed_sink_id); ->SetAudioSinkId(hashed_sink_id);
} }
void MediaSessionController::OnSetMute(int player_id, bool mute) {
DCHECK_EQ(player_id_, player_id);
web_contents_->media_web_contents_observer()
->GetMediaPlayerRemote(id_)
->RequestMute(mute);
}
RenderFrameHost* MediaSessionController::render_frame_host() const { RenderFrameHost* MediaSessionController::render_frame_host() const {
return RenderFrameHost::FromID(id_.frame_routing_id); return RenderFrameHost::FromID(id_.frame_routing_id);
} }
@@ -185,6 +193,10 @@ void MediaSessionController::OnMediaPositionStateChanged(
media_session_->RebuildAndNotifyMediaPositionChanged(); media_session_->RebuildAndNotifyMediaPositionChanged();
} }
void MediaSessionController::OnMediaMutedStatusChanged(bool mute) {
media_session_->OnMediaMutedStatusChanged(mute);
}
void MediaSessionController::OnPictureInPictureAvailabilityChanged( void MediaSessionController::OnPictureInPictureAvailabilityChanged(
bool available) { bool available) {
is_picture_in_picture_available_ = available; is_picture_in_picture_available_ = available;

@@ -60,6 +60,7 @@ class CONTENT_EXPORT MediaSessionController
void OnExitPictureInPicture(int player_id) override; void OnExitPictureInPicture(int player_id) override;
void OnSetAudioSinkId(int player_id, void OnSetAudioSinkId(int player_id,
const std::string& raw_device_id) override; const std::string& raw_device_id) override;
void OnSetMute(int player_id, bool mute) override;
RenderFrameHost* render_frame_host() const override; RenderFrameHost* render_frame_host() const override;
absl::optional<media_session::MediaPosition> GetPosition( absl::optional<media_session::MediaPosition> GetPosition(
int player_id) const override; int player_id) const override;
@@ -82,6 +83,8 @@ class CONTENT_EXPORT MediaSessionController
void OnMediaPositionStateChanged( void OnMediaPositionStateChanged(
const media_session::MediaPosition& position); const media_session::MediaPosition& position);
void OnMediaMutedStatusChanged(bool mute);
// Called when the media picture-in-picture availability has changed. // Called when the media picture-in-picture availability has changed.
void OnPictureInPictureAvailabilityChanged(bool available); void OnPictureInPictureAvailabilityChanged(bool available);

@@ -138,6 +138,8 @@ class TestMediaPlayer : public media::mojom::MediaPlayer {
void RequestExitPictureInPicture() override {} void RequestExitPictureInPicture() override {}
void RequestMute(bool mute) override {}
void SetVolumeMultiplier(double multiplier) override { void SetVolumeMultiplier(double multiplier) override {
received_volume_multiplier_ = multiplier; received_volume_multiplier_ = multiplier;
if (run_loop_for_volume_) if (run_loop_for_volume_)

@@ -104,6 +104,16 @@ void MediaSessionControllersManager::WebContentsMutedStateChanged(bool muted) {
entry.second->WebContentsMutedStateChanged(muted); entry.second->WebContentsMutedStateChanged(muted);
} }
void MediaSessionControllersManager::OnMediaMutedStatusChanged(
const MediaPlayerId& id,
bool mute) {
if (!IsMediaSessionEnabled())
return;
MediaSessionController* const controller = FindOrCreateController(id);
controller->OnMediaMutedStatusChanged(mute);
}
void MediaSessionControllersManager::OnPictureInPictureAvailabilityChanged( void MediaSessionControllersManager::OnPictureInPictureAvailabilityChanged(
const MediaPlayerId& id, const MediaPlayerId& id,
bool available) { bool available) {

@@ -67,6 +67,9 @@ class CONTENT_EXPORT MediaSessionControllersManager {
// Called when the WebContents was muted or unmuted. // Called when the WebContents was muted or unmuted.
void WebContentsMutedStateChanged(bool muted); void WebContentsMutedStateChanged(bool muted);
// Called when the player's mute status changed.
void OnMediaMutedStatusChanged(const MediaPlayerId& id, bool mute);
// Called when picture-in-picture availability for the player |id| has // Called when picture-in-picture availability for the player |id| has
// changed. // changed.
void OnPictureInPictureAvailabilityChanged(const MediaPlayerId& id, void OnPictureInPictureAvailabilityChanged(const MediaPlayerId& id,

@@ -149,6 +149,8 @@ MediaSessionUserAction MediaSessionActionToUserAction(
return MediaSessionUserAction::kHangUp; return MediaSessionUserAction::kHangUp;
case media_session::mojom::MediaSessionAction::kRaise: case media_session::mojom::MediaSessionAction::kRaise:
return MediaSessionUserAction::kRaise; return MediaSessionUserAction::kRaise;
case media_session::mojom::MediaSessionAction::kSetMute:
return MediaSessionUserAction::kSetMute;
} }
NOTREACHED(); NOTREACHED();
return MediaSessionUserAction::kPlay; return MediaSessionUserAction::kPlay;
@@ -1013,6 +1015,8 @@ MediaSessionImpl::GetMediaSessionInfoSync() {
info->camera_state = media_session::mojom::CameraState::kUnknown; info->camera_state = media_session::mojom::CameraState::kUnknown;
} }
info->muted = is_muted_;
return info; return info;
} }
@@ -1173,6 +1177,12 @@ void MediaSessionImpl::Raise() {
delegate->ActivateContents(web_contents()); delegate->ActivateContents(web_contents());
} }
void MediaSessionImpl::SetMute(bool mute) {
DCHECK_EQ(normal_players_.size(), 1u);
normal_players_.begin()->first.observer->OnSetMute(
normal_players_.begin()->first.player_id, mute);
}
void MediaSessionImpl::GetMediaImageBitmap( void MediaSessionImpl::GetMediaImageBitmap(
const media_session::MediaImage& image, const media_session::MediaImage& image,
int minimum_size_px, int minimum_size_px,
@@ -1481,6 +1491,11 @@ MediaSessionServiceImpl* MediaSessionImpl::ComputeServiceForRouting() {
return best_frame ? services_[best_frame->GetGlobalId()] : nullptr; return best_frame ? services_[best_frame->GetGlobalId()] : nullptr;
} }
void MediaSessionImpl::OnMediaMutedStatusChanged(bool mute) {
is_muted_ = mute;
RebuildAndNotifyMediaSessionInfoChanged();
}
void MediaSessionImpl::OnPictureInPictureAvailabilityChanged() { void MediaSessionImpl::OnPictureInPictureAvailabilityChanged() {
if (normal_players_.size() != 1) if (normal_players_.size() != 1)
return; return;

@@ -279,6 +279,9 @@ class MediaSessionImpl : public MediaSession,
// Brings the associated tab into focus. // Brings the associated tab into focus.
void Raise() override; void Raise() override;
// Mute or unmute the media player.
void SetMute(bool mute) override;
// Downloads the bitmap version of a MediaImage at least |minimum_size_px| // Downloads the bitmap version of a MediaImage at least |minimum_size_px|
// and closest to |desired_size_px|. If the download failed, was too small or // and closest to |desired_size_px|. If the download failed, was too small or
// the image did not come from the media session then returns a null image. // the image did not come from the media session then returns a null image.
@@ -292,6 +295,8 @@ class MediaSessionImpl : public MediaSession,
return audio_focus_group_id_; return audio_focus_group_id_;
} }
void OnMediaMutedStatusChanged(bool mute);
void OnPictureInPictureAvailabilityChanged(); void OnPictureInPictureAvailabilityChanged();
// Called when any of the normal players have switched to a different audio // Called when any of the normal players have switched to a different audio
@@ -481,6 +486,8 @@ class MediaSessionImpl : public MediaSession,
// True if the WebContents associated with this MediaSessionImpl is focused. // True if the WebContents associated with this MediaSessionImpl is focused.
bool focused_ = false; bool focused_ = false;
bool is_muted_ = false;
// Used to persist audio device selection between navigations on the same // Used to persist audio device selection between navigations on the same
// origin. // origin.
url::Origin origin_; url::Origin origin_;

@@ -58,6 +58,7 @@ class MockMediaSessionPlayerObserver : public MediaSessionPlayerObserver {
MOCK_METHOD1(OnExitPictureInPicture, void(int player_id)); MOCK_METHOD1(OnExitPictureInPicture, void(int player_id));
MOCK_METHOD2(OnSetAudioSinkId, MOCK_METHOD2(OnSetAudioSinkId,
void(int player_id, const std::string& raw_device_id)); void(int player_id, const std::string& raw_device_id));
MOCK_METHOD2(OnSetMute, void(int player_id, bool mute));
absl::optional<media_session::MediaPosition> GetPosition( absl::optional<media_session::MediaPosition> GetPosition(
int player_id) const override { int player_id) const override {

@@ -44,6 +44,7 @@ class MockMediaSessionPlayerObserver : public MediaSessionPlayerObserver {
void OnExitPictureInPicture(int player_id) override {} void OnExitPictureInPicture(int player_id) override {}
void OnSetAudioSinkId(int player_id, void OnSetAudioSinkId(int player_id,
const std::string& raw_device_id) override {} const std::string& raw_device_id) override {}
void OnSetMute(int player_id, bool mute) override {}
absl::optional<media_session::MediaPosition> GetPosition( absl::optional<media_session::MediaPosition> GetPosition(
int player_id) const override { int player_id) const override {

@@ -52,6 +52,9 @@ class MediaSessionPlayerObserver {
virtual void OnSetAudioSinkId(int player_id, virtual void OnSetAudioSinkId(int player_id,
const std::string& raw_device_id) = 0; const std::string& raw_device_id) = 0;
// The given |player_id| has been requested to mute or unmute.
virtual void OnSetMute(int player_id, bool mute) = 0;
// Returns the position for |player_id|. // Returns the position for |player_id|.
virtual absl::optional<media_session::MediaPosition> GetPosition( virtual absl::optional<media_session::MediaPosition> GetPosition(
int player_id) const = 0; int player_id) const = 0;

@@ -61,6 +61,7 @@ class MockMediaSessionPlayerObserver : public MediaSessionPlayerObserver {
void OnExitPictureInPicture(int player_id) override {} void OnExitPictureInPicture(int player_id) override {}
void OnSetAudioSinkId(int player_id, void OnSetAudioSinkId(int player_id,
const std::string& raw_device_id) override {} const std::string& raw_device_id) override {}
void OnSetMute(int player_id, bool mute) override {}
absl::optional<media_session::MediaPosition> GetPosition( absl::optional<media_session::MediaPosition> GetPosition(
int player_id) const override { int player_id) const override {

@@ -50,7 +50,8 @@ class CONTENT_EXPORT MediaSessionUmaHelper {
kToggleCamera = 17, kToggleCamera = 17,
kHangUp = 18, kHangUp = 18,
kRaise = 19, kRaise = 19,
kMaxValue = kRaise, kSetMute = 20,
kMaxValue = kSetMute,
}; };
MediaSessionUmaHelper(); MediaSessionUmaHelper();

@@ -89,6 +89,11 @@ void MockMediaSessionPlayerObserver::OnSetAudioSinkId(
players_[player_id].audio_sink_id_ = raw_device_id; players_[player_id].audio_sink_id_ = raw_device_id;
} }
void MockMediaSessionPlayerObserver::OnSetMute(int player_id, bool mute) {
EXPECT_GE(player_id, 0);
EXPECT_GT(players_.size(), static_cast<size_t>(player_id));
}
absl::optional<media_session::MediaPosition> absl::optional<media_session::MediaPosition>
MockMediaSessionPlayerObserver::GetPosition(int player_id) const { MockMediaSessionPlayerObserver::GetPosition(int player_id) const {
EXPECT_GE(player_id, 0); EXPECT_GE(player_id, 0);

@@ -34,6 +34,7 @@ class MockMediaSessionPlayerObserver : public MediaSessionPlayerObserver {
void OnExitPictureInPicture(int player_id) override; void OnExitPictureInPicture(int player_id) override;
void OnSetAudioSinkId(int player_id, void OnSetAudioSinkId(int player_id,
const std::string& raw_device_id) override; const std::string& raw_device_id) override;
void OnSetMute(int player_id, bool mute) override;
absl::optional<media_session::MediaPosition> GetPosition( absl::optional<media_session::MediaPosition> GetPosition(
int player_id) const override; int player_id) const override;
bool IsPictureInPictureAvailable(int player_id) const override; bool IsPictureInPictureAvailable(int player_id) const override;

@@ -80,6 +80,8 @@ void PepperPlayerDelegate::OnSetAudioSinkId(int player_id,
NOTREACHED(); NOTREACHED();
} }
void PepperPlayerDelegate::OnSetMute(int player_id, bool mute) {}
absl::optional<media_session::MediaPosition> PepperPlayerDelegate::GetPosition( absl::optional<media_session::MediaPosition> PepperPlayerDelegate::GetPosition(
int player_id) const { int player_id) const {
// Pepper does not support position data. // Pepper does not support position data.

@@ -34,6 +34,7 @@ class PepperPlayerDelegate : public MediaSessionPlayerObserver {
void OnExitPictureInPicture(int player_id) override; void OnExitPictureInPicture(int player_id) override;
void OnSetAudioSinkId(int player_id, void OnSetAudioSinkId(int player_id,
const std::string& raw_device_id) override; const std::string& raw_device_id) override;
void OnSetMute(int player_id, bool mute) override;
absl::optional<media_session::MediaPosition> GetPosition( absl::optional<media_session::MediaPosition> GetPosition(
int player_id) const override; int player_id) const override;
bool IsPictureInPictureAvailable(int player_id) const override; bool IsPictureInPictureAvailable(int player_id) const override;

@@ -130,6 +130,7 @@ class PictureInPictureMediaPlayerReceiver : public media::mojom::MediaPlayer {
void RequestSeekTo(base::TimeDelta seek_time) override {} void RequestSeekTo(base::TimeDelta seek_time) override {}
void RequestEnterPictureInPicture() override {} void RequestEnterPictureInPicture() override {}
void RequestExitPictureInPicture() override {} void RequestExitPictureInPicture() override {}
void RequestMute(bool mute) override {}
void SetVolumeMultiplier(double multiplier) override {} void SetVolumeMultiplier(double multiplier) override {}
void SetPersistentState(bool persistent) override {} void SetPersistentState(bool persistent) override {}
void SetPowerExperimentState(bool enabled) override {} void SetPowerExperimentState(bool enabled) override {}

@@ -55,6 +55,8 @@ fuchsia::media::sessions2::PlayerCapabilityFlags ActionToCapabilityFlag(
return {}; // PlayerControl does not support hanging up. return {}; // PlayerControl does not support hanging up.
case MediaSessionAction::kRaise: case MediaSessionAction::kRaise:
return {}; // PlayerControl does not support raising. return {}; // PlayerControl does not support raising.
case MediaSessionAction::kSetMute:
return {}; // TODO(crbug.com/1240811): implement set mute.
} }
} }

@@ -41,6 +41,7 @@ class FakeMediaSession : public content::MediaSession {
MOCK_METHOD0(ToggleCamera, void()); MOCK_METHOD0(ToggleCamera, void());
MOCK_METHOD0(HangUp, void()); MOCK_METHOD0(HangUp, void());
MOCK_METHOD0(Raise, void()); MOCK_METHOD0(Raise, void());
MOCK_METHOD1(SetMute, void(bool));
// content::MediaSession APIs faked to implement testing behaviour. // content::MediaSession APIs faked to implement testing behaviour.
MOCK_METHOD1(DidReceiveAction, MOCK_METHOD1(DidReceiveAction,

@@ -9,7 +9,8 @@ import "mojo/public/mojom/base/time.mojom";
import "services/media_session/public/mojom/media_session.mojom"; import "services/media_session/public/mojom/media_session.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom"; import "ui/gfx/geometry/mojom/geometry.mojom";
// Implemented by HTMLMediaElement in the renderer process. // Implemented by HTMLMediaElement in the renderer process to allow the
// browser to control media playback.
interface MediaPlayer { interface MediaPlayer {
// Requests the media player to start or resume media playback. // Requests the media player to start or resume media playback.
RequestPlay(); RequestPlay();
@@ -32,6 +33,9 @@ interface MediaPlayer {
// Requests the media player to exit the Picture-in-Picture mode. // Requests the media player to exit the Picture-in-Picture mode.
RequestExitPictureInPicture(); RequestExitPictureInPicture();
// Requests the media player to mute or unmute.
RequestMute(bool mute);
// Set the volume multiplier to control audio ducking. // Set the volume multiplier to control audio ducking.
// Output volume should be set to |player_volume| * |multiplier|. The range // Output volume should be set to |player_volume| * |multiplier|. The range
// of |multiplier| is [0, 1], where 1 indicates normal (non-ducked) playback. // of |multiplier| is [0, 1], where 1 indicates normal (non-ducked) playback.

@@ -328,6 +328,13 @@ void MediaController::Raise() {
session_->ipc()->Raise(); session_->ipc()->Raise();
} }
void MediaController::SetMute(bool mute) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (session_)
session_->ipc()->SetMute(mute);
}
void MediaController::SetMediaSession(AudioFocusRequest* session) { void MediaController::SetMediaSession(AudioFocusRequest* session) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

@@ -57,6 +57,7 @@ class MediaController : public mojom::MediaController,
void ToggleCamera() override; void ToggleCamera() override;
void HangUp() override; void HangUp() override;
void Raise() override; void Raise() override;
void SetMute(bool mute) override;
// mojom::MediaSessionObserver overrides. // mojom::MediaSessionObserver overrides.
void MediaSessionInfoChanged( void MediaSessionInfoChanged(

@@ -168,6 +168,7 @@ class COMPONENT_EXPORT(MEDIA_SESSION_TEST_SUPPORT_CPP) MockMediaSession
void ToggleCamera() override {} void ToggleCamera() override {}
void HangUp() override {} void HangUp() override {}
void Raise() override {} void Raise() override {}
void SetMute(bool mute) override {}
void SetIsControllable(bool value); void SetIsControllable(bool value);
void SetPreferStop(bool value) { prefer_stop_ = value; } void SetPreferStop(bool value) { prefer_stop_ = value; }

@@ -160,6 +160,7 @@ class COMPONENT_EXPORT(MEDIA_SESSION_TEST_SUPPORT_CPP) TestMediaController
void ToggleCamera() override {} void ToggleCamera() override {}
void HangUp() override {} void HangUp() override {}
void Raise() override {} void Raise() override {}
void SetMute(bool mute) override {}
int toggle_suspend_resume_count() const { int toggle_suspend_resume_count() const {
return toggle_suspend_resume_count_; return toggle_suspend_resume_count_;

@@ -58,6 +58,7 @@ void PerformMediaSessionAction(
case mojom::MediaSessionAction::kRaise: case mojom::MediaSessionAction::kRaise:
media_controller_remote->Raise(); media_controller_remote->Raise();
break; break;
case mojom::MediaSessionAction::kSetMute:
case mojom::MediaSessionAction::kSkipAd: case mojom::MediaSessionAction::kSkipAd:
case mojom::MediaSessionAction::kSeekTo: case mojom::MediaSessionAction::kSeekTo:
case mojom::MediaSessionAction::kScrubTo: case mojom::MediaSessionAction::kScrubTo:

@@ -33,7 +33,7 @@ interface MediaControllerManager {
// session, otherwise media sessions will be associated with a particular media // session, otherwise media sessions will be associated with a particular media
// session provided to the service when creating the media controller. If the // session provided to the service when creating the media controller. If the
// media session is not controllable then the commands will be no-ops. // media session is not controllable then the commands will be no-ops.
// Next Method ID: 18 // Next Method ID: 19
[Stable] [Stable]
interface MediaController { interface MediaController {
// Suspend the media session. // Suspend the media session.
@@ -109,6 +109,9 @@ interface MediaController {
// Display the source of the MediaSession (e.g. show the tab or the // Display the source of the MediaSession (e.g. show the tab or the
// application). // application).
[MinVersion=2] Raise@17(); [MinVersion=2] Raise@17();
// Mute or unmute the media player.
[MinVersion=3] SetMute@18(bool mute);
}; };
// The observer for observing media controller events. This is different to a // The observer for observing media controller events. This is different to a

@@ -36,6 +36,7 @@ enum MediaSessionAction {
[MinVersion=11] kToggleCamera, [MinVersion=11] kToggleCamera,
[MinVersion=11] kHangUp, [MinVersion=11] kHangUp,
[MinVersion=12] kRaise, [MinVersion=12] kRaise,
[MinVersion=13] kSetMute,
}; };
[Stable, Extensible] [Stable, Extensible]
@@ -189,6 +190,9 @@ struct MediaSessionInfo {
// Tracks whether the camera is turned on in WebRTC sessions. // Tracks whether the camera is turned on in WebRTC sessions.
[MinVersion=11] CameraState camera_state; [MinVersion=11] CameraState camera_state;
// Tracks whether the media player is muted.
[MinVersion=12] bool muted;
}; };
// Contains debugging information about a MediaSession. This will be displayed // Contains debugging information about a MediaSession. This will be displayed
@@ -331,4 +335,7 @@ interface MediaSession {
// Display the source of the MediaSession (e.g. show the tab or the // Display the source of the MediaSession (e.g. show the tab or the
// application). // application).
[MinVersion=12] Raise@21(); [MinVersion=12] Raise@21();
// Mute or unmute the media player.
[MinVersion=13] SetMute@22(bool mute);
}; };

@@ -4644,6 +4644,10 @@ void HTMLMediaElement::RequestSeekTo(base::TimeDelta seek_time) {
setCurrentTime(seek_time.InSecondsF()); setCurrentTime(seek_time.InSecondsF());
} }
void HTMLMediaElement::RequestMute(bool mute) {
setMuted(mute);
}
void HTMLMediaElement::SetVolumeMultiplier(double multiplier) { void HTMLMediaElement::SetVolumeMultiplier(double multiplier) {
if (web_media_player_) if (web_media_player_)
web_media_player_->SetVolumeMultiplier(multiplier); web_media_player_->SetVolumeMultiplier(multiplier);

@@ -518,6 +518,7 @@ class CORE_EXPORT HTMLMediaElement
void RequestSeekTo(base::TimeDelta seek_time) override; void RequestSeekTo(base::TimeDelta seek_time) override;
void RequestEnterPictureInPicture() override {} void RequestEnterPictureInPicture() override {}
void RequestExitPictureInPicture() override {} void RequestExitPictureInPicture() override {}
void RequestMute(bool mute) override;
void SetVolumeMultiplier(double multiplier) override; void SetVolumeMultiplier(double multiplier) override;
void SetPersistentState(bool persistent) override {} void SetPersistentState(bool persistent) override {}
void SetPowerExperimentState(bool enabled) override; void SetPowerExperimentState(bool enabled) override;