OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/media/android/media_web_contents_observer_android.h" | 5 #include "content/browser/media/android/media_web_contents_observer_android.h" |
6 | 6 |
7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "content/browser/media/android/browser_media_player_manager.h" | 9 #include "content/browser/media/android/browser_media_player_manager.h" |
10 #include "content/browser/media/android/browser_media_session_manager.h" | 10 #include "content/browser/media/android/browser_media_session_manager.h" |
11 #include "content/browser/media/android/media_session.h" | |
11 #include "content/browser/media/android/media_session_observer.h" | 12 #include "content/browser/media/android/media_session_observer.h" |
12 #include "content/browser/media/cdm/browser_cdm_manager.h" | 13 #include "content/browser/media/cdm/browser_cdm_manager.h" |
13 #include "content/browser/web_contents/web_contents_impl.h" | 14 #include "content/browser/web_contents/web_contents_impl.h" |
14 #include "content/common/frame_messages.h" | 15 #include "content/common/frame_messages.h" |
15 #include "content/common/media/media_player_messages_android.h" | 16 #include "content/common/media/media_player_messages_android.h" |
16 #include "content/common/media/media_session_messages_android.h" | 17 #include "content/common/media/media_session_messages_android.h" |
17 #include "content/public/browser/render_frame_host.h" | 18 #include "content/public/browser/render_frame_host.h" |
18 #include "content/public/browser/web_contents.h" | 19 #include "content/public/browser/web_contents.h" |
19 #include "ipc/ipc_message_macros.h" | 20 #include "ipc/ipc_message_macros.h" |
20 #include "media/base/android/media_player_android.h" | 21 #include "media/base/android/media_player_android.h" |
21 | 22 |
22 namespace content { | 23 namespace content { |
23 | 24 |
25 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
| |
26 public: | |
27 MediaSessionController(const WebContentsObserver::MediaPlayerId& id, | |
28 MediaWebContentsObserver* media_web_contents_observer) | |
29 : id_(id), media_web_contents_observer_(media_web_contents_observer) {} | |
30 | |
31 // Clients must call this after construction and destroy the controller if it | |
32 // returns false. | |
33 bool Initialize(bool has_video, bool has_audio, base::TimeDelta duration) { | |
34 // These objects are only created on the UI thread, so this is safe. | |
35 static uint32_t player_id = 0; | |
36 player_id_ = static_cast<int>(player_id++); | |
37 | |
38 // Minimal duration of a player in order to be considered as Content type. | |
39 const base::TimeDelta kMinimumDurationForContent = | |
40 base::TimeDelta::FromSeconds(5); | |
41 | |
42 const MediaSession::Type media_session_type = | |
43 duration == base::TimeDelta() || duration > kMinimumDurationForContent | |
44 ? MediaSession::Type::Content | |
45 : MediaSession::Type::Transient; | |
46 | |
47 // If a session can't be created, force a pause immediately. | |
48 if (!MediaSession::Get(media_web_contents_observer_->web_contents()) | |
49 ->AddPlayer(this, player_id_, media_session_type)) { | |
50 OnSuspend(player_id_); | |
51 return false; | |
52 } | |
53 | |
54 return true; | |
55 } | |
56 | |
57 ~MediaSessionController() { | |
58 MediaSession::Get(media_web_contents_observer_->web_contents()) | |
59 ->RemovePlayer(this, player_id_); | |
60 } | |
61 | |
62 void OnSuspend(int player_id) { | |
63 DCHECK_EQ(player_id_, player_id); | |
64 media_web_contents_observer_->Send( | |
65 new FrameMsg_MediaDelegatePause(id_.first->GetRoutingID(), id_.second)); | |
66 } | |
67 | |
68 void OnResume(int player_id) { | |
69 DCHECK_EQ(player_id_, player_id); | |
70 media_web_contents_observer_->Send( | |
71 new FrameMsg_MediaDelegatePlay(id_.first->GetRoutingID(), id_.second)); | |
72 } | |
73 | |
74 void PausePlayback() { | |
75 MediaSession* session = | |
76 MediaSession::Get(media_web_contents_observer_->web_contents()); | |
77 // TODO(dalecurtis, mlamouri): This seems odd, if we don't check suspend of | |
78 // the entire session, notifying a pause will DCHECK in mediasession.cc:146. | |
79 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
| |
80 session->OnPlayerPaused(this, player_id_); | |
81 } | |
82 | |
83 private: | |
84 const WebContentsObserver::MediaPlayerId id_; | |
85 MediaWebContentsObserver* const media_web_contents_observer_; | |
86 int player_id_ = 0; | |
87 bool initialize_failed_ = false; | |
88 | |
89 DISALLOW_COPY_AND_ASSIGN(MediaSessionController); | |
90 }; | |
91 | |
24 MediaWebContentsObserverAndroid::MediaWebContentsObserverAndroid( | 92 MediaWebContentsObserverAndroid::MediaWebContentsObserverAndroid( |
25 WebContents* web_contents) | 93 WebContents* web_contents) |
26 : MediaWebContentsObserver(web_contents) {} | 94 : MediaWebContentsObserver(web_contents) {} |
27 | 95 |
28 MediaWebContentsObserverAndroid::~MediaWebContentsObserverAndroid() {} | 96 MediaWebContentsObserverAndroid::~MediaWebContentsObserverAndroid() { |
97 // Clear active sessions before destructing the observer. | |
98 media_session_map_.clear(); | |
99 } | |
29 | 100 |
30 // static | 101 // static |
31 MediaWebContentsObserverAndroid* | 102 MediaWebContentsObserverAndroid* |
32 MediaWebContentsObserverAndroid::FromWebContents(WebContents* web_contents) { | 103 MediaWebContentsObserverAndroid::FromWebContents(WebContents* web_contents) { |
33 return static_cast<MediaWebContentsObserverAndroid*>( | 104 return static_cast<MediaWebContentsObserverAndroid*>( |
34 static_cast<WebContentsImpl*>(web_contents) | 105 static_cast<WebContentsImpl*>(web_contents) |
35 ->media_web_contents_observer()); | 106 ->media_web_contents_observer()); |
36 } | 107 } |
37 | 108 |
38 BrowserMediaPlayerManager* | 109 BrowserMediaPlayerManager* |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 // BrowserCdmManager run on a different thread. | 157 // BrowserCdmManager run on a different thread. |
87 BrowserCdmManager* browser_cdm_manager = | 158 BrowserCdmManager* browser_cdm_manager = |
88 BrowserCdmManager::FromProcess(render_frame_host->GetProcess()->GetID()); | 159 BrowserCdmManager::FromProcess(render_frame_host->GetProcess()->GetID()); |
89 if (browser_cdm_manager) | 160 if (browser_cdm_manager) |
90 browser_cdm_manager->RenderFrameDeleted(render_frame_host->GetRoutingID()); | 161 browser_cdm_manager->RenderFrameDeleted(render_frame_host->GetRoutingID()); |
91 } | 162 } |
92 | 163 |
93 bool MediaWebContentsObserverAndroid::OnMessageReceived( | 164 bool MediaWebContentsObserverAndroid::OnMessageReceived( |
94 const IPC::Message& msg, | 165 const IPC::Message& msg, |
95 RenderFrameHost* render_frame_host) { | 166 RenderFrameHost* render_frame_host) { |
167 // Receive play/pause/destroyed messages, but don't mark as processed so they | |
168 // are also handled by MediaWebContentsObserver. | |
169 OnMediaPlayerDelegateMessageReceived(msg, render_frame_host); | |
170 | |
96 if (MediaWebContentsObserver::OnMessageReceived(msg, render_frame_host)) | 171 if (MediaWebContentsObserver::OnMessageReceived(msg, render_frame_host)) |
97 return true; | 172 return true; |
98 | 173 |
99 if (OnMediaPlayerMessageReceived(msg, render_frame_host)) | 174 if (OnMediaPlayerMessageReceived(msg, render_frame_host)) |
100 return true; | 175 return true; |
101 | 176 |
102 if (OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host)) | 177 if (OnMediaPlayerSetCdmMessageReceived(msg, render_frame_host)) |
103 return true; | 178 return true; |
104 | 179 |
105 return false; | 180 return false; |
106 } | 181 } |
107 | 182 |
183 void MediaWebContentsObserverAndroid::OnMediaPlayerDelegateMessageReceived( | |
184 const IPC::Message& msg, | |
185 RenderFrameHost* render_frame_host) { | |
186 // TODO(dalecurtis): These should no longer be FrameHostMsg. | |
187 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MediaWebContentsObserverAndroid, msg, | |
188 render_frame_host) | |
189 IPC_MESSAGE_HANDLER(FrameHostMsg_MediaDestroyedNotification, | |
190 OnMediaDestroyedNotification) | |
191 IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPlayingNotification, | |
192 OnMediaPlayingNotification) | |
193 IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification, | |
194 OnMediaPausedNotification) | |
195 IPC_END_MESSAGE_MAP() | |
196 } | |
197 | |
108 bool MediaWebContentsObserverAndroid::OnMediaPlayerMessageReceived( | 198 bool MediaWebContentsObserverAndroid::OnMediaPlayerMessageReceived( |
109 const IPC::Message& msg, | 199 const IPC::Message& msg, |
110 RenderFrameHost* render_frame_host) { | 200 RenderFrameHost* render_frame_host) { |
111 bool handled = true; | 201 bool handled = true; |
112 IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserverAndroid, msg) | 202 IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserverAndroid, msg) |
113 IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_EnterFullscreen, | 203 IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_EnterFullscreen, |
114 GetMediaPlayerManager(render_frame_host), | 204 GetMediaPlayerManager(render_frame_host), |
115 BrowserMediaPlayerManager::OnEnterFullscreen) | 205 BrowserMediaPlayerManager::OnEnterFullscreen) |
116 IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize, | 206 IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize, |
117 GetMediaPlayerManager(render_frame_host), | 207 GetMediaPlayerManager(render_frame_host), |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
196 if (!cdm) { | 286 if (!cdm) { |
197 NOTREACHED() << "OnSetCdm: CDM not found for " << cdm_id; | 287 NOTREACHED() << "OnSetCdm: CDM not found for " << cdm_id; |
198 return; | 288 return; |
199 } | 289 } |
200 | 290 |
201 // TODO(xhwang): This could possibly fail. In that case we should reject the | 291 // TODO(xhwang): This could possibly fail. In that case we should reject the |
202 // promise. | 292 // promise. |
203 media_player->SetCdm(cdm); | 293 media_player->SetCdm(cdm); |
204 } | 294 } |
205 | 295 |
296 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
| |
297 RenderFrameHost* render_frame_host, | |
298 int64_t player_cookie) { | |
299 media_session_map_.erase(MediaPlayerId(render_frame_host, player_cookie)); | |
300 } | |
301 | |
302 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
| |
303 RenderFrameHost* render_frame_host, | |
304 int64_t player_cookie, | |
305 bool has_video, | |
306 bool has_audio, | |
307 bool is_remote, | |
308 base::TimeDelta duration) { | |
309 // Don't setup a media session for remote playback instances. | |
310 if (is_remote) | |
311 return; | |
312 | |
313 const MediaPlayerId id(render_frame_host, player_cookie); | |
314 scoped_ptr<MediaSessionController> controller( | |
315 new MediaSessionController(id, this)); | |
316 | |
317 // If initialize fails, the controller should be destroyed and a new one | |
318 // attempted later after another playback attempt occurs. | |
319 if (!controller->Initialize(has_video, has_audio, duration)) | |
320 return; | |
321 | |
322 media_session_map_[id] = std::move(controller); | |
323 } | |
324 | |
325 void MediaWebContentsObserverAndroid::OnMediaPausedNotification( | |
326 RenderFrameHost* render_frame_host, | |
327 int64_t player_cookie, | |
328 bool reached_end_of_stream) { | |
329 // Drop the session if playback completes normally. | |
330 if (reached_end_of_stream) { | |
331 OnMediaDestroyedNotification(render_frame_host, player_cookie); | |
332 return; | |
333 } | |
334 | |
335 auto it = | |
336 media_session_map_.find(MediaPlayerId(render_frame_host, player_cookie)); | |
337 if (it == media_session_map_.end()) | |
338 return; | |
339 | |
340 it->second->PausePlayback(); | |
341 } | |
342 | |
206 } // namespace content | 343 } // namespace content |
OLD | NEW |