| // Copyright 2014 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_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_H_ |
| #define CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_H_ |
| |
| #include <stdint.h> |
| |
| #include <map> |
| #include <memory> |
| |
| #include "base/containers/flat_map.h" |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/optional.h" |
| #include "build/build_config.h" |
| #include "content/browser/media/media_power_experiment_manager.h" |
| #include "content/browser/media/session/media_session_controllers_manager.h" |
| #include "content/common/content_export.h" |
| #include "content/public/browser/media_player_id.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "media/base/use_after_free_checker.h" |
| #include "media/mojo/mojom/media_player.mojom.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "services/device/public/mojom/wake_lock.mojom.h" |
| |
| #if defined(OS_ANDROID) |
| #include "ui/android/view_android.h" |
| #endif // OS_ANDROID |
| |
| namespace blink { |
| enum class WebFullscreenVideoStatus; |
| } // namespace blink |
| |
| namespace media { |
| enum class MediaContentType; |
| } // namespace media |
| |
| namespace media_session { |
| struct MediaPosition; |
| } // namespace media_session |
| |
| namespace gfx { |
| class Size; |
| } // namespace gfx |
| |
| namespace content { |
| |
| class AudibleMetrics; |
| class WebContentsImpl; |
| |
| // This class manages all RenderFrame based media related managers at the |
| // browser side. It receives IPC messages from media RenderFrameObservers and |
| // forwards them to the corresponding managers. The managers are responsible |
| // for sending IPCs back to the RenderFrameObservers at the render side. |
| class CONTENT_EXPORT MediaWebContentsObserver : public WebContentsObserver { |
| public: |
| explicit MediaWebContentsObserver(WebContentsImpl* web_contents); |
| ~MediaWebContentsObserver() override; |
| |
| // Called by WebContentsImpl when the audible state may have changed. |
| void MaybeUpdateAudibleState(); |
| |
| // Called by WebContentsImpl to know if an active player is effectively |
| // fullscreen. That means that the video is either fullscreen or it is the |
| // content of a fullscreen page (in other words, a fullscreen video with |
| // custom controls). |
| // It should only be called while the WebContents is fullscreen. |
| bool HasActiveEffectivelyFullscreenVideo() const; |
| |
| // Called by WebContentsImpl to know if Picture-in-Picture can be triggered |
| // for the current active effectively fullscreen player. |
| // It should only be called while the WebContents is fullscreen. |
| bool IsPictureInPictureAllowedForFullscreenVideo() const; |
| |
| // Gets the MediaPlayerId of the fullscreen video if it exists. |
| const base::Optional<MediaPlayerId>& GetFullscreenVideoMediaPlayerId() const; |
| |
| // WebContentsObserver implementation. |
| void WebContentsDestroyed() override; |
| void RenderFrameDeleted(RenderFrameHost* render_frame_host) override; |
| bool OnMessageReceived(const IPC::Message& message, |
| RenderFrameHost* render_frame_host) override; |
| void MediaPictureInPictureChanged(bool is_picture_in_picture) override; |
| void DidUpdateAudioMutingState(bool muted) override; |
| |
| // TODO(zqzhang): this method is temporarily in MediaWebContentsObserver as |
| // the effectively fullscreen video code is also here. We need to consider |
| // merging the logic of effectively fullscreen, hiding media controls and |
| // fullscreening video element to the same place. |
| void RequestPersistentVideo(bool value); |
| |
| // Returns whether or not the given player id is active. |
| bool IsPlayerActive(const MediaPlayerId& player_id) const; |
| |
| bool has_audio_wake_lock_for_testing() const { |
| return has_audio_wake_lock_for_testing_; |
| } |
| |
| void SetAudibleMetricsForTest(AudibleMetrics* audible_metrics) { |
| audible_metrics_ = audible_metrics; |
| } |
| |
| void OnReceivedTranslatedDeviceId(RenderFrameHost* render_frame_host, |
| int delegate_id, |
| const std::string& raw_device_id); |
| |
| // Return an already bound mojo Remote for the MediaPlayer mojo interface. It |
| // is an error to call this method if no MediaPlayer with |player_id| exists. |
| mojo::Remote<media::mojom::MediaPlayer>& GetMediaPlayerRemote( |
| const MediaPlayerId& player_id); |
| |
| // Creates a new MediaPlayerObserverHostImpl associated to |player_id| if |
| // needed, and then passes |player_receiver| to it to establish a |
| // communication channel. |
| void BindMediaPlayerHost( |
| RenderFrameHost* host, |
| mojo::PendingReceiver<media::mojom::MediaPlayerHost> player_receiver); |
| |
| // Communicates with the MediaSessionControllerManager to find or create (if |
| // needed) a MediaSessionController identified by |player_id|, in order to |
| // bind its mojo remote for media::mojom::MediaPlayer. |
| void OnMediaPlayerAdded( |
| mojo::PendingRemote<media::mojom::MediaPlayer> player_remote, |
| MediaPlayerId player_id); |
| |
| #if defined(OS_ANDROID) |
| // Called by the WebContents when a tab has been closed but may still be |
| // available for "undo" -- indicates that all media players (even audio only |
| // players typically allowed background audio) bound to this WebContents must |
| // be suspended. |
| void SuspendAllMediaPlayers(); |
| #endif // defined(OS_ANDROID) |
| protected: |
| MediaSessionControllersManager* session_controllers_manager() { |
| return &session_controllers_manager_; |
| } |
| |
| private: |
| class PlayerInfo; |
| friend class PlayerInfo; |
| |
| using PlayerInfoMap = |
| base::flat_map<MediaPlayerId, std::unique_ptr<PlayerInfo>>; |
| |
| // Helper class providing a per-RenderFrame object implementing the only |
| // method of the media::mojom::MediaPlayerHost mojo interface, to provide the |
| // renderer process with a way to notify the browser when a new MediaPlayer |
| // has been created, so that a communication channel can be established. |
| class MediaPlayerHostImpl : public media::mojom::MediaPlayerHost { |
| public: |
| MediaPlayerHostImpl(RenderFrameHost* render_frame_host, |
| MediaWebContentsObserver* media_web_contents_observer); |
| ~MediaPlayerHostImpl() override; |
| |
| // Used to bind the receiver via the BrowserInterfaceBroker. |
| void BindMediaPlayerHostReceiver( |
| mojo::PendingReceiver<media::mojom::MediaPlayerHost> receiver); |
| |
| // media::mojom::MediaPlayerHost implementation. |
| void OnMediaPlayerAdded( |
| mojo::PendingRemote<media::mojom::MediaPlayer> media_player, |
| int32_t player_id) override; |
| |
| private: |
| RenderFrameHost* render_frame_host_; |
| MediaWebContentsObserver* media_web_contents_observer_; |
| mojo::Receiver<media::mojom::MediaPlayerHost> receiver_{this}; |
| }; |
| |
| // Helper class providing a per-MediaPlayerId object implementing the |
| // media::mojom::MediaPlayerObserver mojo interface. |
| class MediaPlayerObserverHostImpl : public media::mojom::MediaPlayerObserver { |
| public: |
| MediaPlayerObserverHostImpl( |
| const MediaPlayerId& media_player_id, |
| MediaWebContentsObserver* media_web_contents_observer); |
| ~MediaPlayerObserverHostImpl() override; |
| |
| // Used to bind the receiver via the BrowserInterfaceBroker. |
| mojo::PendingRemote<media::mojom::MediaPlayerObserver> |
| BindMediaPlayerObserverReceiverAndPassRemote(); |
| |
| // media::mojom::MediaPlayerObserver implementation. |
| void OnMutedStatusChanged(bool muted) override; |
| void OnMediaPositionStateChanged( |
| const media_session::MediaPosition& media_position) override; |
| void OnMediaSizeChanged(const ::gfx::Size& size) override; |
| void OnPictureInPictureAvailabilityChanged(bool available) override; |
| void OnAudioOutputSinkChangingDisabled() override; |
| void OnBufferUnderflow() override; |
| void OnSeek() override; |
| |
| private: |
| MediaPlayerId media_player_id_; |
| MediaWebContentsObserver* media_web_contents_observer_; |
| mojo::Receiver<media::mojom::MediaPlayerObserver> |
| media_player_observer_receiver_{this}; |
| }; |
| |
| using MediaPlayerHostImplMap = |
| base::flat_map<RenderFrameHost*, std::unique_ptr<MediaPlayerHostImpl>>; |
| using MediaPlayerObserverHostImplMap = |
| base::flat_map<MediaPlayerId, |
| std::unique_ptr<MediaPlayerObserverHostImpl>>; |
| using MediaPlayerRemotesMap = |
| base::flat_map<MediaPlayerId, mojo::Remote<media::mojom::MediaPlayer>>; |
| |
| // Returns the PlayerInfo associated with |id|, or nullptr if no such |
| // PlayerInfo exists. |
| PlayerInfo* GetPlayerInfo(const MediaPlayerId& id) const; |
| |
| void OnMediaPaused(RenderFrameHost* render_frame_host, |
| int delegate_id, |
| bool reached_end_of_stream); |
| void OnMediaMetadataChanged(RenderFrameHost* render_frame_host, |
| int delegate_id, |
| bool has_video, |
| bool has_audio, |
| media::MediaContentType media_content_type); |
| void OnMediaPlaying(RenderFrameHost* render_frame_host, int delegate_id); |
| void OnMediaEffectivelyFullscreenChanged( |
| RenderFrameHost* render_frame_host, |
| int delegate_id, |
| blink::WebFullscreenVideoStatus fullscreen_status); |
| void OnAudioOutputSinkChanged(RenderFrameHost* render_frame_host, |
| int delegate_id, |
| std::string hashed_device_id); |
| |
| // Used to notify when the renderer -> browser mojo connection via the |
| // interface media::mojom::MediaPlayerHost gets disconnected. |
| void OnMediaPlayerHostDisconnected(RenderFrameHost* host); |
| |
| // Used to notify when the renderer -> browser mojo connection via the |
| // interface media::mojom::MediaPlayerObserver gets disconnected. |
| void OnMediaPlayerObserverDisconnected(const MediaPlayerId& player_id); |
| |
| device::mojom::WakeLock* GetAudioWakeLock(); |
| |
| // WakeLock related methods for audio and video. |
| void LockAudio(); |
| void CancelAudioLock(); |
| void UpdateVideoLock(); |
| |
| // Convenience method that casts web_contents() to a WebContentsImpl*. |
| WebContentsImpl* web_contents_impl() const; |
| |
| // Notify |id| about |is_starting|. Note that |id| might no longer be in the |
| // active players list, which is fine. |
| void OnExperimentStateChanged(MediaPlayerId id, bool is_starting); |
| |
| // Return a weak pointer to |this| that's local to |render_frame_host|, in the |
| // sense that we can cancel all of the ptrs to one frame without cancelling |
| // pointers for any of the others. |
| base::WeakPtr<MediaWebContentsObserver> GetWeakPtrForFrame( |
| RenderFrameHost* render_frame_host); |
| |
| // Helper class for recording audible metrics. |
| AudibleMetrics* audible_metrics_; |
| |
| // Tracking variables and associated wake locks for media playback. |
| PlayerInfoMap player_info_map_; |
| mojo::Remote<device::mojom::WakeLock> audio_wake_lock_; |
| base::Optional<MediaPlayerId> fullscreen_player_; |
| base::Optional<bool> picture_in_picture_allowed_in_fullscreen_; |
| bool has_audio_wake_lock_for_testing_ = false; |
| |
| MediaSessionControllersManager session_controllers_manager_; |
| MediaPowerExperimentManager* power_experiment_manager_ = nullptr; |
| |
| std::map<RenderFrameHost*, |
| std::unique_ptr<base::WeakPtrFactory<MediaWebContentsObserver>>> |
| per_frame_factory_; |
| |
| media::UseAfterFreeChecker use_after_free_checker_; |
| |
| MediaPlayerHostImplMap media_player_hosts_; |
| MediaPlayerObserverHostImplMap media_player_observer_hosts_; |
| |
| // Map of remote endpoints for the media::mojom::MediaPlayer mojo interface, |
| // indexed by MediaPlayerId. |
| MediaPlayerRemotesMap media_player_remotes_; |
| |
| base::WeakPtrFactory<MediaWebContentsObserver> weak_ptr_factory_{this}; |
| DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserver); |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_BROWSER_MEDIA_MEDIA_WEB_CONTENTS_OBSERVER_H_ |