blob: 166dfd742dca8120780779cbf1f58b5ead7e541e [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.
#ifndef CONTENT_BROWSER_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_IMPL_H_
#define CONTENT_BROWSER_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_IMPL_H_
#include <map>
#include <set>
#include "base/memory/weak_ptr.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "content/public/browser/media_player_id.h"
#include "content/public/browser/picture_in_picture_window_controller.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
namespace content {
class MediaWebContentsObserver;
class PictureInPictureSession;
class WebContents;
class WebContentsImpl;
// TODO(thakis,mlamouri): PictureInPictureWindowControllerImpl isn't
// CONTENT_EXPORT'd because it creates complicated build issues with
// WebContentsUserData being a non-exported template. As a result, the class
// uses CONTENT_EXPORT for methods that are being used from tests.
// CONTENT_EXPORT should be moved back to the class when the Windows build will
// work with it. https://crbug.com/589840.
class PictureInPictureWindowControllerImpl
: public PictureInPictureWindowController,
public WebContentsUserData<PictureInPictureWindowControllerImpl>,
public WebContentsObserver {
public:
// Gets a reference to the controller associated with |initiator| and creates
// one if it does not exist. The returned pointer is guaranteed to be
// non-null.
CONTENT_EXPORT static PictureInPictureWindowControllerImpl*
GetOrCreateForWebContents(WebContents* initiator);
~PictureInPictureWindowControllerImpl() override;
using PlayerSet = std::set<int>;
using MutedMediaPlayerMap = std::map<RenderFrameHost*, PlayerSet>;
// PictureInPictureWindowController:
CONTENT_EXPORT gfx::Size Show() override;
CONTENT_EXPORT void Close(bool should_pause_video) override;
CONTENT_EXPORT void CloseAndFocusInitiator() override;
CONTENT_EXPORT void OnWindowDestroyed() override;
CONTENT_EXPORT void EmbedSurface(const viz::SurfaceId& surface_id,
const gfx::Size& natural_size) override;
CONTENT_EXPORT OverlayWindow* GetWindowForTesting() override;
CONTENT_EXPORT void UpdateLayerBounds() override;
CONTENT_EXPORT bool IsPlayerActive() override;
CONTENT_EXPORT bool IsPlayerMuted() override;
CONTENT_EXPORT WebContents* GetInitiatorWebContents() override;
CONTENT_EXPORT bool TogglePlayPause() override;
CONTENT_EXPORT bool ToggleMute() override;
CONTENT_EXPORT void UpdatePlaybackState(bool is_playing,
bool reached_end_of_stream) override;
CONTENT_EXPORT void UpdateMutedState() override;
CONTENT_EXPORT void SetAlwaysHidePlayPauseButton(bool is_visible) override;
CONTENT_EXPORT void SetAlwaysHideMuteButton(bool is_visible) override;
CONTENT_EXPORT void SkipAd() override;
CONTENT_EXPORT void NextTrack() override;
CONTENT_EXPORT void PreviousTrack() override;
CONTENT_EXPORT void MediaSessionActionsChanged(
const std::set<media_session::mojom::MediaSessionAction>& actions);
// WebContentsObserver:
void MediaStartedPlaying(const MediaPlayerInfo&,
const MediaPlayerId&) override;
void MediaStoppedPlaying(const MediaPlayerInfo&,
const MediaPlayerId&,
WebContentsObserver::MediaStoppedReason) override;
void MediaMutedStatusChanged(const MediaPlayerId&, bool muted) override;
// TODO(mlamouri): temporary method used because of the media player id is
// stored in a different location from the one that is used to update the
// state of this object.
void UpdateMediaPlayerId();
// Sets the active Picture-in-Picture session associated with the controller.
// This is different from the service's active session as there is one
// controller per WebContents and one service per RenderFrameHost.
// The current session may be shut down as a side effect of this.
void SetActiveSession(PictureInPictureSession* session);
private:
friend class WebContentsUserData<PictureInPictureWindowControllerImpl>;
// Use PictureInPictureWindowControllerImpl::GetOrCreateForWebContents() to
// create an instance.
CONTENT_EXPORT explicit PictureInPictureWindowControllerImpl(
WebContents* initiator);
// Signal to the media player that |this| is leaving Picture-in-Picture mode.
void OnLeavingPictureInPicture(bool should_pause_video);
// Internal method to set the states after the window was closed, whether via
// the system or Chromium.
void CloseInternal(bool should_pause_video);
// Creates a new window if the previous one was destroyed. It can happen
// because of the system control of the window.
void EnsureWindow();
// Allow play/pause button to be visible if Media Session actions "play" and
// "pause" are both handled by the website or if
// always_hide_play_pause_button_ is false.
void UpdatePlayPauseButtonVisibility();
// Used to add/remove a muted player entry to |muted_players_|.
void AddMutedPlayerEntry(const MediaPlayerId& id);
bool RemoveMutedPlayerEntry(const MediaPlayerId& id);
std::unique_ptr<OverlayWindow> window_;
// TODO(929156): remove this as it should be accessible via `web_contents()`.
WebContentsImpl* const initiator_;
// Used to determine the state of the media player and route messages to
// the corresponding media player with id |media_player_id_|.
MediaWebContentsObserver* media_web_contents_observer_;
base::Optional<MediaPlayerId> media_player_id_;
viz::SurfaceId surface_id_;
// Used to track the muted state of all players.
MutedMediaPlayerMap muted_players_;
// Used to show/hide some actions in Picture-in-Picture window. These are set
// to true when website handles some Media Session actions.
bool media_session_action_play_handled_ = false;
bool media_session_action_pause_handled_ = false;
bool media_session_action_skip_ad_handled_ = false;
bool media_session_action_next_track_handled_ = false;
bool media_session_action_previous_track_handled_ = false;
// Used to hide play/pause button if video is a MediaStream or has infinite
// duration. Play/pause button visibility can be overridden by the Media
// Session API in UpdatePlayPauseButtonVisibility().
bool always_hide_play_pause_button_ = false;
// Used to hide mute button if video has no audio track or if MuteButton
// origin trial is disabled.
bool always_hide_mute_button_ = false;
// Session currently associated with the Picture-in-Picture window. The
// session object makes the bridge with the renderer process by handling
// requests and holding states such as the active player id.
// The session will be nullptr when there is no active session.
PictureInPictureSession* active_session_ = nullptr;
WEB_CONTENTS_USER_DATA_KEY_DECL();
DISALLOW_COPY_AND_ASSIGN(PictureInPictureWindowControllerImpl);
};
} // namespace content
#endif // CONTENT_BROWSER_PICTURE_IN_PICTURE_PICTURE_IN_PICTURE_WINDOW_CONTROLLER_IMPL_H_