Chromium Code Reviews| Index: content/browser/media/android/media_web_contents_observer_android.cc |
| diff --git a/content/browser/media/android/media_web_contents_observer_android.cc b/content/browser/media/android/media_web_contents_observer_android.cc |
| index 2bd332681c614786dc1d33fa59fd8669995b2221..5e1ea718b447cdc393d2c93c8e0825120d607ddd 100644 |
| --- a/content/browser/media/android/media_web_contents_observer_android.cc |
| +++ b/content/browser/media/android/media_web_contents_observer_android.cc |
| @@ -8,6 +8,7 @@ |
| #include "base/stl_util.h" |
| #include "content/browser/media/android/browser_media_player_manager.h" |
| #include "content/browser/media/android/browser_media_session_manager.h" |
| +#include "content/browser/media/android/media_session.h" |
| #include "content/browser/media/android/media_session_observer.h" |
| #include "content/browser/media/cdm/browser_cdm_manager.h" |
| #include "content/browser/web_contents/web_contents_impl.h" |
| @@ -21,11 +22,81 @@ |
| namespace content { |
| +class MediaSessionController : public MediaSessionObserver { |
|
mlamouri (slow - plz ping)
2016/01/14 15:43:08
Maybe this could be in a separate file?
DaleCurtis
2016/01/14 18:21:18
Yeah, I was thinking the same since it ended up la
|
| + public: |
| + MediaSessionController(const WebContentsObserver::MediaPlayerId& id, |
| + MediaWebContentsObserver* media_web_contents_observer) |
| + : id_(id), media_web_contents_observer_(media_web_contents_observer) {} |
| + |
| + // Clients must call this after construction and destroy the controller if it |
| + // returns false. |
| + bool Initialize(bool has_video, bool has_audio, base::TimeDelta duration) { |
| + // These objects are only created on the UI thread, so this is safe. |
| + static uint32_t player_id = 0; |
| + player_id_ = static_cast<int>(player_id++); |
| + |
| + // Minimal duration of a player in order to be considered as Content type. |
| + const base::TimeDelta kMinimumDurationForContent = |
| + base::TimeDelta::FromSeconds(5); |
| + |
| + const MediaSession::Type media_session_type = |
| + duration == base::TimeDelta() || duration > kMinimumDurationForContent |
| + ? MediaSession::Type::Content |
| + : MediaSession::Type::Transient; |
| + |
| + // If a session can't be created, force a pause immediately. |
| + if (!MediaSession::Get(media_web_contents_observer_->web_contents()) |
| + ->AddPlayer(this, player_id_, media_session_type)) { |
| + OnSuspend(player_id_); |
| + return false; |
| + } |
| + |
| + return true; |
| + } |
| + |
| + ~MediaSessionController() { |
| + MediaSession::Get(media_web_contents_observer_->web_contents()) |
| + ->RemovePlayer(this, player_id_); |
| + } |
| + |
| + void OnSuspend(int player_id) { |
| + DCHECK_EQ(player_id_, player_id); |
| + media_web_contents_observer_->Send( |
| + new FrameMsg_MediaDelegatePause(id_.first->GetRoutingID(), id_.second)); |
| + } |
| + |
| + void OnResume(int player_id) { |
| + DCHECK_EQ(player_id_, player_id); |
| + media_web_contents_observer_->Send( |
| + new FrameMsg_MediaDelegatePlay(id_.first->GetRoutingID(), id_.second)); |
| + } |
| + |
| + void PausePlayback() { |
| + MediaSession* session = |
| + MediaSession::Get(media_web_contents_observer_->web_contents()); |
| + // TODO(dalecurtis, mlamouri): This seems odd, if we don't check suspend of |
| + // the entire session, notifying a pause will DCHECK in mediasession.cc:146. |
| + if (!session->IsSuspended()) |
|
mlamouri (slow - plz ping)
2016/01/14 15:43:08
How do you end up with a suspended session that pa
DaleCurtis
2016/01/14 18:21:18
This is due to the delegate sending a "pause" ack
mlamouri (slow - plz ping)
2016/01/19 16:59:11
zqzhang@ has been working on issues related to tha
|
| + session->OnPlayerPaused(this, player_id_); |
| + } |
| + |
| + private: |
| + const WebContentsObserver::MediaPlayerId id_; |
| + MediaWebContentsObserver* const media_web_contents_observer_; |
| + int player_id_ = 0; |
| + bool initialize_failed_ = false; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MediaSessionController); |
| +}; |
| + |
| MediaWebContentsObserverAndroid::MediaWebContentsObserverAndroid( |
| WebContents* web_contents) |
| : MediaWebContentsObserver(web_contents) {} |
| -MediaWebContentsObserverAndroid::~MediaWebContentsObserverAndroid() {} |
| +MediaWebContentsObserverAndroid::~MediaWebContentsObserverAndroid() { |
| + // Clear active sessions before destructing the observer. |
| + media_session_map_.clear(); |
| +} |
| // static |
| MediaWebContentsObserverAndroid* |
| @@ -93,6 +164,10 @@ void MediaWebContentsObserverAndroid::RenderFrameDeleted( |
| bool MediaWebContentsObserverAndroid::OnMessageReceived( |
| const IPC::Message& msg, |
| RenderFrameHost* render_frame_host) { |
| + // Receive play/pause/destroyed messages, but don't mark as processed so they |
| + // are also handled by MediaWebContentsObserver. |
| + OnMediaPlayerDelegateMessageReceived(msg, render_frame_host); |
| + |
| if (MediaWebContentsObserver::OnMessageReceived(msg, render_frame_host)) |
| return true; |
| @@ -105,6 +180,21 @@ bool MediaWebContentsObserverAndroid::OnMessageReceived( |
| return false; |
| } |
| +void MediaWebContentsObserverAndroid::OnMediaPlayerDelegateMessageReceived( |
| + const IPC::Message& msg, |
| + RenderFrameHost* render_frame_host) { |
| + // TODO(dalecurtis): These should no longer be FrameHostMsg. |
| + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MediaWebContentsObserverAndroid, msg, |
| + render_frame_host) |
| + IPC_MESSAGE_HANDLER(FrameHostMsg_MediaDestroyedNotification, |
| + OnMediaDestroyedNotification) |
| + IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPlayingNotification, |
| + OnMediaPlayingNotification) |
| + IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification, |
| + OnMediaPausedNotification) |
| + IPC_END_MESSAGE_MAP() |
| +} |
| + |
| bool MediaWebContentsObserverAndroid::OnMediaPlayerMessageReceived( |
| const IPC::Message& msg, |
| RenderFrameHost* render_frame_host) { |
| @@ -203,4 +293,51 @@ void MediaWebContentsObserverAndroid::OnSetCdm( |
| media_player->SetCdm(cdm); |
| } |
| +void MediaWebContentsObserverAndroid::OnMediaDestroyedNotification( |
|
mlamouri (slow - plz ping)
2016/01/14 15:43:08
Do we destroy the media as soon as it reached the
DaleCurtis
2016/01/14 18:21:18
No, this is only called when the WMP is being dest
|
| + RenderFrameHost* render_frame_host, |
| + int64_t player_cookie) { |
| + media_session_map_.erase(MediaPlayerId(render_frame_host, player_cookie)); |
| +} |
| + |
| +void MediaWebContentsObserverAndroid::OnMediaPlayingNotification( |
|
mlamouri (slow - plz ping)
2016/01/14 15:43:08
Are we going to call this when the media _starts_
DaleCurtis
2016/01/14 18:21:18
This is only called when status changes to play.
mlamouri (slow - plz ping)
2016/01/19 16:59:11
Does that match the 'playing' event?
DaleCurtis
2016/01/20 00:43:58
Yes
|
| + RenderFrameHost* render_frame_host, |
| + int64_t player_cookie, |
| + bool has_video, |
| + bool has_audio, |
| + bool is_remote, |
| + base::TimeDelta duration) { |
| + // Don't setup a media session for remote playback instances. |
| + if (is_remote) |
| + return; |
| + |
| + const MediaPlayerId id(render_frame_host, player_cookie); |
| + scoped_ptr<MediaSessionController> controller( |
| + new MediaSessionController(id, this)); |
| + |
| + // If initialize fails, the controller should be destroyed and a new one |
| + // attempted later after another playback attempt occurs. |
| + if (!controller->Initialize(has_video, has_audio, duration)) |
| + return; |
| + |
| + media_session_map_[id] = std::move(controller); |
| +} |
| + |
| +void MediaWebContentsObserverAndroid::OnMediaPausedNotification( |
| + RenderFrameHost* render_frame_host, |
| + int64_t player_cookie, |
| + bool reached_end_of_stream) { |
| + // Drop the session if playback completes normally. |
| + if (reached_end_of_stream) { |
| + OnMediaDestroyedNotification(render_frame_host, player_cookie); |
| + return; |
| + } |
| + |
| + auto it = |
| + media_session_map_.find(MediaPlayerId(render_frame_host, player_cookie)); |
| + if (it == media_session_map_.end()) |
| + return; |
| + |
| + it->second->PausePlayback(); |
| +} |
| + |
| } // namespace content |