Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / media / android / browser_media_player_manager.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/media/android/browser_media_player_manager.h"
6
7 #include "base/android/scoped_java_ref.h"
8 #include "base/command_line.h"
9 #include "content/browser/android/content_view_core_impl.h"
10 #include "content/browser/media/android/browser_demuxer_android.h"
11 #include "content/browser/media/android/media_resource_getter_impl.h"
12 #include "content/browser/renderer_host/render_view_host_impl.h"
13 #include "content/browser/web_contents/web_contents_view_android.h"
14 #include "content/common/media/cdm_messages.h"
15 #include "content/common/media/media_player_messages_android.h"
16 #include "content/public/browser/android/content_view_core.h"
17 #include "content/public/browser/android/external_video_surface_container.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/content_browser_client.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/storage_partition.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_contents_delegate.h"
25 #include "content/public/common/content_client.h"
26 #include "content/public/common/content_switches.h"
27 #include "media/base/android/media_drm_bridge.h"
28 #include "media/base/android/media_player_bridge.h"
29 #include "media/base/android/media_source_player.h"
30 #include "media/base/media_switches.h"
31
32 using media::MediaDrmBridge;
33 using media::MediaPlayerAndroid;
34 using media::MediaPlayerBridge;
35 using media::MediaPlayerManager;
36 using media::MediaSourcePlayer;
37
38 namespace content {
39
40 // Threshold on the number of media players per renderer before we start
41 // attempting to release inactive media players.
42 const int kMediaPlayerThreshold = 1;
43
44 // Maximum lengths for various EME API parameters. These are checks to
45 // prevent unnecessarily large parameters from being passed around, and the
46 // lengths are somewhat arbitrary as the EME spec doesn't specify any limits.
47 const size_t kMaxInitDataLength = 64 * 1024;  // 64 KB
48 const size_t kMaxSessionResponseLength = 64 * 1024;  // 64 KB
49 const size_t kMaxKeySystemLength = 256;
50
51 static BrowserMediaPlayerManager::Factory g_factory = NULL;
52
53 // static
54 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
55   g_factory = factory;
56 }
57
58 // static
59 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
60     RenderViewHost* rvh) {
61   if (g_factory)
62     return g_factory(rvh);
63   return new BrowserMediaPlayerManager(rvh);
64 }
65
66 ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
67   return ContentViewCoreImpl::FromWebContents(web_contents());
68 }
69
70 MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
71     MediaPlayerHostMsg_Initialize_Type type,
72     int player_id,
73     const GURL& url,
74     const GURL& first_party_for_cookies,
75     int demuxer_client_id,
76     bool hide_url_log,
77     MediaPlayerManager* manager,
78     BrowserDemuxerAndroid* demuxer) {
79   switch (type) {
80     case MEDIA_PLAYER_TYPE_URL: {
81       const std::string user_agent = GetContentClient()->GetUserAgent();
82       MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
83           player_id,
84           url,
85           first_party_for_cookies,
86           user_agent,
87           hide_url_log,
88           manager,
89           base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
90                      weak_ptr_factory_.GetWeakPtr()),
91           base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
92                      weak_ptr_factory_.GetWeakPtr()));
93       BrowserMediaPlayerManager* browser_media_player_manager =
94           static_cast<BrowserMediaPlayerManager*>(manager);
95       ContentViewCoreImpl* content_view_core_impl =
96           static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents(
97               browser_media_player_manager->web_contents_));
98       if (!content_view_core_impl) {
99         // May reach here due to prerendering. Don't extract the metadata
100         // since it is expensive.
101         // TODO(qinmin): extract the metadata once the user decided to load
102         // the page.
103         browser_media_player_manager->OnMediaMetadataChanged(
104             player_id, base::TimeDelta(), 0, 0, false);
105       } else if (!content_view_core_impl->ShouldBlockMediaRequest(url)) {
106         media_player_bridge->Initialize();
107       }
108       return media_player_bridge;
109     }
110
111     case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
112       return new MediaSourcePlayer(
113           player_id,
114           manager,
115           base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
116                      weak_ptr_factory_.GetWeakPtr()),
117           base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,
118                      weak_ptr_factory_.GetWeakPtr()),
119           demuxer->CreateDemuxer(demuxer_client_id));
120     }
121   }
122
123   NOTREACHED();
124   return NULL;
125 }
126
127 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
128     RenderViewHost* render_view_host)
129     : WebContentsObserver(WebContents::FromRenderViewHost(render_view_host)),
130       fullscreen_player_id_(-1),
131       fullscreen_player_is_released_(false),
132       web_contents_(WebContents::FromRenderViewHost(render_view_host)),
133       weak_ptr_factory_(this) {
134 }
135
136 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {}
137
138 bool BrowserMediaPlayerManager::OnMessageReceived(const IPC::Message& msg) {
139   bool handled = true;
140   IPC_BEGIN_MESSAGE_MAP(BrowserMediaPlayerManager, msg)
141     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_EnterFullscreen, OnEnterFullscreen)
142     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_ExitFullscreen, OnExitFullscreen)
143     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Initialize, OnInitialize)
144     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Start, OnStart)
145     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Seek, OnSeek)
146     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Pause, OnPause)
147     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetVolume, OnSetVolume)
148     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetPoster, OnSetPoster)
149     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_Release, OnReleaseResources)
150     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DestroyMediaPlayer, OnDestroyPlayer)
151     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DestroyAllMediaPlayers,
152                         DestroyAllMediaPlayers)
153     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_SetCdm, OnSetCdm)
154     IPC_MESSAGE_HANDLER(CdmHostMsg_InitializeCdm, OnInitializeCdm)
155     IPC_MESSAGE_HANDLER(CdmHostMsg_CreateSession, OnCreateSession)
156     IPC_MESSAGE_HANDLER(CdmHostMsg_UpdateSession, OnUpdateSession)
157     IPC_MESSAGE_HANDLER(CdmHostMsg_ReleaseSession, OnReleaseSession)
158     IPC_MESSAGE_HANDLER(CdmHostMsg_DestroyCdm, OnDestroyCdm)
159 #if defined(VIDEO_HOLE)
160     IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_NotifyExternalSurface,
161                         OnNotifyExternalSurface)
162 #endif  // defined(VIDEO_HOLE)
163     IPC_MESSAGE_UNHANDLED(handled = false)
164   IPC_END_MESSAGE_MAP()
165   return handled;
166 }
167
168 void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
169   MediaPlayerAndroid* player = GetFullscreenPlayer();
170   if (player) {
171     if (fullscreen_player_is_released_) {
172       video_view_->OpenVideo();
173       fullscreen_player_is_released_ = false;
174     }
175     player->Start();
176     Send(new MediaPlayerMsg_DidMediaPlayerPlay(
177         routing_id(), fullscreen_player_id_));
178   }
179 }
180
181 void BrowserMediaPlayerManager::FullscreenPlayerPause() {
182   MediaPlayerAndroid* player = GetFullscreenPlayer();
183   if (player) {
184     player->Pause(true);
185     Send(new MediaPlayerMsg_DidMediaPlayerPause(
186         routing_id(), fullscreen_player_id_));
187   }
188 }
189
190 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
191   MediaPlayerAndroid* player = GetFullscreenPlayer();
192   if (player) {
193     // TODO(kbalazs): if |fullscreen_player_is_released_| is true
194     // at this point, player->GetCurrentTime() will be wrong until
195     // FullscreenPlayerPlay (http://crbug.com/322798).
196     OnSeekRequest(fullscreen_player_id_,
197                   base::TimeDelta::FromMilliseconds(msec));
198   }
199 }
200
201 void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
202   if (!CommandLine::ForCurrentProcess()->HasSwitch(
203       switches::kDisableOverlayFullscreenVideoSubtitle)) {
204     if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
205       delegate->ToggleFullscreenModeForTab(web_contents_, false);
206     if (RenderWidgetHostViewAndroid* view_android =
207         static_cast<RenderWidgetHostViewAndroid*>(
208             web_contents_->GetRenderWidgetHostView())) {
209       view_android->SetOverlayVideoMode(false);
210     }
211   }
212
213   Send(new MediaPlayerMsg_DidExitFullscreen(
214       routing_id(), fullscreen_player_id_));
215   video_view_.reset();
216   MediaPlayerAndroid* player = GetFullscreenPlayer();
217   fullscreen_player_id_ = -1;
218   if (!player)
219     return;
220   if (release_media_player)
221     ReleaseFullscreenPlayer(player);
222   else
223     player->SetVideoSurface(gfx::ScopedJavaSurface());
224 }
225
226 void BrowserMediaPlayerManager::OnTimeUpdate(int player_id,
227                                              base::TimeDelta current_time) {
228   Send(new MediaPlayerMsg_MediaTimeUpdate(
229       routing_id(), player_id, current_time));
230 }
231
232 void BrowserMediaPlayerManager::SetVideoSurface(
233     gfx::ScopedJavaSurface surface) {
234   MediaPlayerAndroid* player = GetFullscreenPlayer();
235   if (!player)
236     return;
237
238   bool empty_surface = surface.IsEmpty();
239   player->SetVideoSurface(surface.Pass());
240   if (empty_surface)
241     return;
242
243   Send(new MediaPlayerMsg_DidEnterFullscreen(routing_id(),
244                                              player->player_id()));
245   if (CommandLine::ForCurrentProcess()->HasSwitch(
246       switches::kDisableOverlayFullscreenVideoSubtitle)) {
247     return;
248   }
249   if (RenderWidgetHostViewAndroid* view_android =
250       static_cast<RenderWidgetHostViewAndroid*>(
251           web_contents_->GetRenderWidgetHostView())) {
252     view_android->SetOverlayVideoMode(true);
253   }
254   if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
255     delegate->ToggleFullscreenModeForTab(web_contents_, true);
256 }
257
258 void BrowserMediaPlayerManager::OnMediaMetadataChanged(
259     int player_id, base::TimeDelta duration, int width, int height,
260     bool success) {
261   Send(new MediaPlayerMsg_MediaMetadataChanged(
262       routing_id(), player_id, duration, width, height, success));
263   if (fullscreen_player_id_ == player_id)
264     video_view_->UpdateMediaMetadata();
265 }
266
267 void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
268   Send(new MediaPlayerMsg_MediaPlaybackCompleted(routing_id(), player_id));
269   if (fullscreen_player_id_ == player_id)
270     video_view_->OnPlaybackComplete();
271 }
272
273 void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
274   // Tell WebKit that the audio should be paused, then release all resources
275   Send(new MediaPlayerMsg_MediaPlayerReleased(routing_id(), player_id));
276   OnReleaseResources(player_id);
277 }
278
279 void BrowserMediaPlayerManager::OnBufferingUpdate(
280     int player_id, int percentage) {
281   Send(new MediaPlayerMsg_MediaBufferingUpdate(
282       routing_id(), player_id, percentage));
283   if (fullscreen_player_id_ == player_id)
284     video_view_->OnBufferingUpdate(percentage);
285 }
286
287 void BrowserMediaPlayerManager::OnSeekRequest(
288     int player_id,
289     const base::TimeDelta& time_to_seek) {
290   Send(new MediaPlayerMsg_SeekRequest(routing_id(), player_id, time_to_seek));
291 }
292
293 void BrowserMediaPlayerManager::OnSeekComplete(
294     int player_id,
295     const base::TimeDelta& current_time) {
296   Send(new MediaPlayerMsg_SeekCompleted(routing_id(), player_id, current_time));
297 }
298
299 void BrowserMediaPlayerManager::OnError(int player_id, int error) {
300   Send(new MediaPlayerMsg_MediaError(routing_id(), player_id, error));
301   if (fullscreen_player_id_ == player_id)
302     video_view_->OnMediaPlayerError(error);
303 }
304
305 void BrowserMediaPlayerManager::OnVideoSizeChanged(
306     int player_id, int width, int height) {
307   Send(new MediaPlayerMsg_MediaVideoSizeChanged(routing_id(), player_id,
308       width, height));
309   if (fullscreen_player_id_ == player_id)
310     video_view_->OnVideoSizeChanged(width, height);
311 }
312
313 media::MediaResourceGetter*
314 BrowserMediaPlayerManager::GetMediaResourceGetter() {
315   if (!media_resource_getter_.get()) {
316     RenderProcessHost* host = web_contents()->GetRenderProcessHost();
317     BrowserContext* context = host->GetBrowserContext();
318     StoragePartition* partition = host->GetStoragePartition();
319     fileapi::FileSystemContext* file_system_context =
320         partition ? partition->GetFileSystemContext() : NULL;
321     // Eventually this needs to be fixed to pass the correct frame rather
322     // than just using the main frame.
323     media_resource_getter_.reset(new MediaResourceGetterImpl(
324         context,
325         file_system_context,
326         host->GetID(),
327         web_contents()->GetMainFrame()->GetRoutingID()));
328   }
329   return media_resource_getter_.get();
330 }
331
332 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
333   return GetPlayer(fullscreen_player_id_);
334 }
335
336 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
337   for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
338       it != players_.end(); ++it) {
339     if ((*it)->player_id() == player_id)
340       return *it;
341   }
342   return NULL;
343 }
344
345 MediaDrmBridge* BrowserMediaPlayerManager::GetDrmBridge(int cdm_id) {
346   for (ScopedVector<MediaDrmBridge>::iterator it = drm_bridges_.begin();
347       it != drm_bridges_.end(); ++it) {
348     if ((*it)->cdm_id() == cdm_id)
349       return *it;
350   }
351   return NULL;
352 }
353
354 void BrowserMediaPlayerManager::DestroyAllMediaPlayers() {
355   players_.clear();
356   drm_bridges_.clear();
357   if (fullscreen_player_id_ != -1) {
358     video_view_.reset();
359     fullscreen_player_id_ = -1;
360   }
361 }
362
363 void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
364   if (fullscreen_player_id_ == player_id)
365     return;
366
367   if (fullscreen_player_id_ != -1) {
368     // TODO(qinmin): Determine the correct error code we should report to WMPA.
369     OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
370     return;
371   }
372
373   // Send an IPC to the render process to request the video element to enter
374   // fullscreen. OnEnterFullscreen() will be called later on success.
375   // This guarantees the fullscreen video will be rendered correctly.
376   // TODO(qinmin): make this flag default on android.
377   if (CommandLine::ForCurrentProcess()->HasSwitch(
378       switches::kDisableGestureRequirementForMediaFullscreen)) {
379     Send(new MediaPlayerMsg_RequestFullscreen(routing_id(), player_id));
380   }
381 }
382
383 // The following 5 functions are EME MediaKeySession events.
384
385 void BrowserMediaPlayerManager::OnSessionCreated(
386     int cdm_id,
387     uint32 session_id,
388     const std::string& web_session_id) {
389   Send(new CdmMsg_SessionCreated(
390       routing_id(), cdm_id, session_id, web_session_id));
391 }
392
393 void BrowserMediaPlayerManager::OnSessionMessage(
394     int cdm_id,
395     uint32 session_id,
396     const std::vector<uint8>& message,
397     const GURL& destination_url) {
398   Send(new CdmMsg_SessionMessage(
399       routing_id(), cdm_id, session_id, message, destination_url));
400 }
401
402 void BrowserMediaPlayerManager::OnSessionReady(int cdm_id, uint32 session_id) {
403   Send(new CdmMsg_SessionReady(routing_id(), cdm_id, session_id));
404 }
405
406 void BrowserMediaPlayerManager::OnSessionClosed(int cdm_id, uint32 session_id) {
407   Send(new CdmMsg_SessionClosed(routing_id(), cdm_id, session_id));
408 }
409
410 void BrowserMediaPlayerManager::OnSessionError(
411     int cdm_id,
412     uint32 session_id,
413     media::MediaKeys::KeyError error_code,
414     uint32 system_code) {
415   Send(new CdmMsg_SessionError(
416       routing_id(), cdm_id, session_id, error_code, system_code));
417 }
418
419 #if defined(VIDEO_HOLE)
420 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
421                                                            jobject surface) {
422   MediaPlayerAndroid* player = GetPlayer(player_id);
423   if (player) {
424     player->SetVideoSurface(
425         gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
426   }
427 }
428
429 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
430   MediaPlayerAndroid* player = GetPlayer(player_id);
431   if (player)
432     player->SetVideoSurface(gfx::ScopedJavaSurface());
433 }
434
435 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
436   if (external_video_surface_container_)
437     external_video_surface_container_->OnFrameInfoUpdated();
438 }
439
440 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
441     int player_id, bool is_request, const gfx::RectF& rect) {
442   if (!web_contents_)
443     return;
444
445   if (is_request) {
446     OnRequestExternalSurface(player_id, rect);
447   }
448   if (external_video_surface_container_) {
449     external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
450         player_id, rect);
451   }
452 }
453
454 void BrowserMediaPlayerManager::OnRequestExternalSurface(
455     int player_id, const gfx::RectF& rect) {
456   if (!external_video_surface_container_) {
457     ContentBrowserClient* client = GetContentClient()->browser();
458     external_video_surface_container_.reset(
459         client->OverrideCreateExternalVideoSurfaceContainer(web_contents_));
460   }
461   // It's safe to use base::Unretained(this), because the callbacks will not
462   // be called after running ReleaseExternalVideoSurface().
463   if (external_video_surface_container_) {
464     external_video_surface_container_->RequestExternalVideoSurface(
465         player_id,
466         base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
467                    base::Unretained(this)),
468         base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
469                    base::Unretained(this)));
470   }
471 }
472 #endif  // defined(VIDEO_HOLE)
473
474 void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
475   DCHECK_EQ(fullscreen_player_id_, -1);
476 #if defined(VIDEO_HOLE)
477   if (external_video_surface_container_)
478     external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
479 #endif  // defined(VIDEO_HOLE)
480   if (video_view_.get()) {
481     fullscreen_player_id_ = player_id;
482     video_view_->OpenVideo();
483     return;
484   } else if (!ContentVideoView::GetInstance()) {
485     // In Android WebView, two ContentViewCores could both try to enter
486     // fullscreen video, we just ignore the second one.
487     video_view_.reset(new ContentVideoView(this));
488     base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
489         video_view_->GetJavaObject(base::android::AttachCurrentThread());
490     if (!j_content_video_view.is_null()) {
491       fullscreen_player_id_ = player_id;
492       return;
493     }
494   }
495
496   // Force the second video to exit fullscreen.
497   // TODO(qinmin): There is no need to send DidEnterFullscreen message.
498   // However, if we don't send the message, page layers will not be
499   // correctly restored. http:crbug.com/367346.
500   Send(new MediaPlayerMsg_DidEnterFullscreen(routing_id(), player_id));
501   Send(new MediaPlayerMsg_DidExitFullscreen(routing_id(), player_id));
502   video_view_.reset();
503 }
504
505 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) {
506   if (fullscreen_player_id_ == player_id) {
507     MediaPlayerAndroid* player = GetPlayer(player_id);
508     if (player)
509       player->SetVideoSurface(gfx::ScopedJavaSurface());
510     video_view_->OnExitFullscreen();
511   }
512 }
513
514 void BrowserMediaPlayerManager::OnInitialize(
515     MediaPlayerHostMsg_Initialize_Type type,
516     int player_id,
517     const GURL& url,
518     const GURL& first_party_for_cookies,
519     int demuxer_client_id) {
520   DCHECK(type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE || demuxer_client_id > 0)
521       << "Media source players must have positive demuxer client IDs: "
522       << demuxer_client_id;
523
524   RemovePlayer(player_id);
525
526   RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
527       web_contents()->GetRenderProcessHost());
528   MediaPlayerAndroid* player = CreateMediaPlayer(
529       type, player_id, url, first_party_for_cookies, demuxer_client_id,
530       host->GetBrowserContext()->IsOffTheRecord(), this,
531       host->browser_demuxer_android());
532   if (!player)
533     return;
534
535   AddPlayer(player);
536 }
537
538 void BrowserMediaPlayerManager::OnStart(int player_id) {
539   MediaPlayerAndroid* player = GetPlayer(player_id);
540   if (!player)
541     return;
542   player->Start();
543   if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
544     video_view_->OpenVideo();
545     fullscreen_player_is_released_ = false;
546   }
547 }
548
549 void BrowserMediaPlayerManager::OnSeek(
550     int player_id,
551     const base::TimeDelta& time) {
552   MediaPlayerAndroid* player = GetPlayer(player_id);
553   if (player)
554     player->SeekTo(time);
555 }
556
557 void BrowserMediaPlayerManager::OnPause(
558     int player_id,
559     bool is_media_related_action) {
560   MediaPlayerAndroid* player = GetPlayer(player_id);
561   if (player)
562     player->Pause(is_media_related_action);
563 }
564
565 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
566   MediaPlayerAndroid* player = GetPlayer(player_id);
567   if (player)
568     player->SetVolume(volume);
569 }
570
571 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
572   // To be overridden by subclasses.
573 }
574
575 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
576   MediaPlayerAndroid* player = GetPlayer(player_id);
577   if (player)
578     player->Release();
579   if (player_id == fullscreen_player_id_)
580     fullscreen_player_is_released_ = true;
581 }
582
583 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
584   RemovePlayer(player_id);
585   if (fullscreen_player_id_ == player_id)
586     fullscreen_player_id_ = -1;
587 }
588
589 void BrowserMediaPlayerManager::OnInitializeCdm(int cdm_id,
590                                                 const std::string& key_system,
591                                                 const GURL& security_origin) {
592   if (key_system.size() > kMaxKeySystemLength) {
593     // This failure will be discovered and reported by OnCreateSession()
594     // as GetDrmBridge() will return null.
595     NOTREACHED() << "Invalid key system: " << key_system;
596     return;
597   }
598
599   if (!MediaDrmBridge::IsKeySystemSupported(key_system)) {
600     NOTREACHED() << "Unsupported key system: " << key_system;
601     return;
602   }
603
604   AddDrmBridge(cdm_id, key_system, security_origin);
605 }
606
607 void BrowserMediaPlayerManager::OnCreateSession(
608     int cdm_id,
609     uint32 session_id,
610     CdmHostMsg_CreateSession_ContentType content_type,
611     const std::vector<uint8>& init_data) {
612   if (init_data.size() > kMaxInitDataLength) {
613     LOG(WARNING) << "InitData for ID: " << cdm_id
614                  << " too long: " << init_data.size();
615     OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
616     return;
617   }
618
619   // Convert the session content type into a MIME type. "audio" and "video"
620   // don't matter, so using "video" for the MIME type.
621   // Ref:
622   // https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-createsession
623   std::string mime_type;
624   switch (content_type) {
625     case CREATE_SESSION_TYPE_WEBM:
626       mime_type = "video/webm";
627       break;
628     case CREATE_SESSION_TYPE_MP4:
629       mime_type = "video/mp4";
630       break;
631     default:
632       NOTREACHED();
633       return;
634   }
635
636   if (CommandLine::ForCurrentProcess()
637       ->HasSwitch(switches::kDisableInfobarForProtectedMediaIdentifier)) {
638     CreateSessionIfPermitted(cdm_id, session_id, mime_type, init_data, true);
639     return;
640   }
641
642   MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
643   if (!drm_bridge) {
644     DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
645     OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
646     return;
647   }
648
649   BrowserContext* context =
650       web_contents()->GetRenderProcessHost()->GetBrowserContext();
651
652   context->RequestProtectedMediaIdentifierPermission(
653       web_contents()->GetRenderProcessHost()->GetID(),
654       web_contents()->GetRenderViewHost()->GetRoutingID(),
655       static_cast<int>(session_id),
656       cdm_id,
657       drm_bridge->security_origin(),
658       base::Bind(&BrowserMediaPlayerManager::CreateSessionIfPermitted,
659                  weak_ptr_factory_.GetWeakPtr(),
660                  cdm_id,
661                  session_id,
662                  mime_type,
663                  init_data));
664 }
665
666 void BrowserMediaPlayerManager::OnUpdateSession(
667     int cdm_id,
668     uint32 session_id,
669     const std::vector<uint8>& response) {
670   MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
671   if (!drm_bridge) {
672     DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
673     OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
674     return;
675   }
676
677   if (response.size() > kMaxSessionResponseLength) {
678     LOG(WARNING) << "Response for ID: " << cdm_id
679                  << " too long: " << response.size();
680     OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
681     return;
682   }
683
684   drm_bridge->UpdateSession(session_id, &response[0], response.size());
685
686   DrmBridgePlayerMap::const_iterator iter = drm_bridge_player_map_.find(cdm_id);
687   if (iter == drm_bridge_player_map_.end())
688     return;
689
690   int player_id = iter->second;
691   MediaPlayerAndroid* player = GetPlayer(player_id);
692   if (player)
693     player->OnKeyAdded();
694 }
695
696 void BrowserMediaPlayerManager::OnReleaseSession(int cdm_id,
697                                                  uint32 session_id) {
698   MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
699   if (!drm_bridge) {
700     DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
701     OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
702     return;
703   }
704
705   drm_bridge->ReleaseSession(session_id);
706 }
707
708 void BrowserMediaPlayerManager::OnDestroyCdm(int cdm_id) {
709   MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
710   if (!drm_bridge) return;
711
712   CancelAllPendingSessionCreations(cdm_id);
713   RemoveDrmBridge(cdm_id);
714 }
715
716 void BrowserMediaPlayerManager::CancelAllPendingSessionCreations(int cdm_id) {
717   BrowserContext* context =
718       web_contents()->GetRenderProcessHost()->GetBrowserContext();
719   context->CancelProtectedMediaIdentifierPermissionRequests(cdm_id);
720 }
721
722 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
723   DCHECK(!GetPlayer(player->player_id()));
724   players_.push_back(player);
725 }
726
727 void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
728   for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
729       it != players_.end(); ++it) {
730     MediaPlayerAndroid* player = *it;
731     if (player->player_id() == player_id) {
732       players_.erase(it);
733       break;
734     }
735   }
736
737   for (DrmBridgePlayerMap::iterator it = drm_bridge_player_map_.begin();
738        it != drm_bridge_player_map_.end(); ++it) {
739     if (it->second == player_id) {
740       drm_bridge_player_map_.erase(it);
741       break;
742     }
743   }
744 }
745
746 scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
747       int player_id, media::MediaPlayerAndroid* player) {
748   media::MediaPlayerAndroid* previous_player = NULL;
749   for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
750       it != players_.end(); ++it) {
751     if ((*it)->player_id() == player_id) {
752       previous_player = *it;
753       players_.weak_erase(it);
754       players_.push_back(player);
755       break;
756     }
757   }
758   return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
759 }
760
761 void BrowserMediaPlayerManager::AddDrmBridge(int cdm_id,
762                                              const std::string& key_system,
763                                              const GURL& security_origin) {
764   DCHECK(!GetDrmBridge(cdm_id));
765
766   scoped_ptr<MediaDrmBridge> drm_bridge(
767       MediaDrmBridge::Create(cdm_id, key_system, security_origin, this));
768   if (!drm_bridge) {
769     // This failure will be discovered and reported by OnCreateSession()
770     // as GetDrmBridge() will return null.
771     DVLOG(1) << "failed to create drm bridge.";
772     return;
773   }
774
775   // TODO(xhwang/ddorwin): Pass the security level from key system.
776   MediaDrmBridge::SecurityLevel security_level =
777       MediaDrmBridge::SECURITY_LEVEL_3;
778   if (CommandLine::ForCurrentProcess()
779           ->HasSwitch(switches::kMediaDrmEnableNonCompositing)) {
780     security_level = MediaDrmBridge::SECURITY_LEVEL_1;
781   }
782   if (!drm_bridge->SetSecurityLevel(security_level)) {
783     DVLOG(1) << "failed to set security level " << security_level;
784     return;
785   }
786
787   drm_bridges_.push_back(drm_bridge.release());
788 }
789
790 void BrowserMediaPlayerManager::RemoveDrmBridge(int cdm_id) {
791   // TODO(xhwang): Detach DrmBridge from the player it's set to. In prefixed
792   // EME implementation the current code is fine because we always destroy the
793   // player before we destroy the DrmBridge. This will not always be the case
794   // in unprefixed EME implementation.
795   for (ScopedVector<MediaDrmBridge>::iterator it = drm_bridges_.begin();
796       it != drm_bridges_.end(); ++it) {
797     if ((*it)->cdm_id() == cdm_id) {
798       drm_bridges_.erase(it);
799       drm_bridge_player_map_.erase(cdm_id);
800       break;
801     }
802   }
803 }
804
805 void BrowserMediaPlayerManager::OnSetCdm(int player_id, int cdm_id) {
806   MediaPlayerAndroid* player = GetPlayer(player_id);
807   MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
808   if (!drm_bridge || !player) {
809     DVLOG(1) << "Cannot set CDM on the specified player.";
810     return;
811   }
812
813   // TODO(qinmin): add the logic to decide whether we should create the
814   // fullscreen surface for EME lv1.
815   player->SetDrmBridge(drm_bridge);
816   // Do now support setting one CDM on multiple players.
817   DCHECK(drm_bridge_player_map_.find(cdm_id) == drm_bridge_player_map_.end());
818   drm_bridge_player_map_[cdm_id] = player_id;
819 }
820
821 void BrowserMediaPlayerManager::CreateSessionIfPermitted(
822     int cdm_id,
823     uint32 session_id,
824     const std::string& content_type,
825     const std::vector<uint8>& init_data,
826     bool permitted) {
827   if (!permitted) {
828     OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
829     return;
830   }
831
832   MediaDrmBridge* drm_bridge = GetDrmBridge(cdm_id);
833   if (!drm_bridge) {
834     DLOG(WARNING) << "No MediaDrmBridge for ID: " << cdm_id << " found";
835     OnSessionError(cdm_id, session_id, media::MediaKeys::kUnknownError, 0);
836     return;
837   }
838
839   // This could fail, in which case a SessionError will be fired.
840   drm_bridge->CreateSession(
841       session_id, content_type, &init_data[0], init_data.size());
842 }
843
844 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
845     MediaPlayerAndroid* player) {
846     player->Release();
847 }
848
849 void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
850   int num_active_player = 0;
851   ScopedVector<MediaPlayerAndroid>::iterator it;
852   for (it = players_.begin(); it != players_.end(); ++it) {
853     if (!(*it)->IsPlayerReady())
854       continue;
855
856     // The player is already active, ignore it.
857     if ((*it)->player_id() == player_id)
858       return;
859     else
860       num_active_player++;
861   }
862
863   // Number of active players are less than the threshold, do nothing.
864   if (num_active_player < kMediaPlayerThreshold)
865     return;
866
867   for (it = players_.begin(); it != players_.end(); ++it) {
868     if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
869         fullscreen_player_id_ != (*it)->player_id()) {
870       (*it)->Release();
871       Send(new MediaPlayerMsg_MediaPlayerReleased(
872           routing_id(), (*it)->player_id()));
873     }
874   }
875 }
876
877 void BrowserMediaPlayerManager::OnMediaResourcesReleased(int player_id) {
878 #if defined(VIDEO_HOLE)
879   MediaPlayerAndroid* player = GetPlayer(player_id);
880   if (player && player->IsSurfaceInUse())
881     return;
882   if (external_video_surface_container_)
883     external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
884 #endif  // defined(VIDEO_HOLE)
885 }
886
887 }  // namespace content