Home | History | Annotate | Download | only in android
      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/media_player_messages_android.h"
     15 #include "content/public/browser/android/content_view_core.h"
     16 #include "content/public/browser/android/external_video_surface_container.h"
     17 #include "content/public/browser/browser_context.h"
     18 #include "content/public/browser/content_browser_client.h"
     19 #include "content/public/browser/render_frame_host.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_player_bridge.h"
     28 #include "media/base/android/media_source_player.h"
     29 #include "media/base/android/media_url_interceptor.h"
     30 #include "media/base/media_switches.h"
     31 
     32 using media::MediaPlayerAndroid;
     33 using media::MediaPlayerBridge;
     34 using media::MediaPlayerManager;
     35 using media::MediaSourcePlayer;
     36 
     37 namespace content {
     38 
     39 // Threshold on the number of media players per renderer before we start
     40 // attempting to release inactive media players.
     41 const int kMediaPlayerThreshold = 1;
     42 
     43 static BrowserMediaPlayerManager::Factory g_factory = NULL;
     44 static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
     45 
     46 // static
     47 void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
     48   g_factory = factory;
     49 }
     50 
     51 // static
     52 void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
     53     media::MediaUrlInterceptor* media_url_interceptor) {
     54   media_url_interceptor_ = media_url_interceptor;
     55 }
     56 
     57 // static
     58 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
     59     RenderFrameHost* rfh) {
     60   if (g_factory)
     61     return g_factory(rfh);
     62   return new BrowserMediaPlayerManager(rfh);
     63 }
     64 
     65 ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
     66   return ContentViewCoreImpl::FromWebContents(web_contents());
     67 }
     68 
     69 MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
     70     const MediaPlayerHostMsg_Initialize_Params& media_player_params,
     71     bool hide_url_log,
     72     MediaPlayerManager* manager,
     73     BrowserDemuxerAndroid* demuxer) {
     74   switch (media_player_params.type) {
     75     case MEDIA_PLAYER_TYPE_URL: {
     76       const std::string user_agent = GetContentClient()->GetUserAgent();
     77       MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
     78           media_player_params.player_id,
     79           media_player_params.url,
     80           media_player_params.first_party_for_cookies,
     81           user_agent,
     82           hide_url_log,
     83           manager,
     84           base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
     85                      weak_ptr_factory_.GetWeakPtr()),
     86           media_player_params.frame_url,
     87           media_player_params.allow_credentials);
     88       BrowserMediaPlayerManager* browser_media_player_manager =
     89           static_cast<BrowserMediaPlayerManager*>(manager);
     90       ContentViewCoreImpl* content_view_core_impl =
     91           static_cast<ContentViewCoreImpl*>(ContentViewCore::FromWebContents(
     92               browser_media_player_manager->web_contents_));
     93       if (!content_view_core_impl) {
     94         // May reach here due to prerendering. Don't extract the metadata
     95         // since it is expensive.
     96         // TODO(qinmin): extract the metadata once the user decided to load
     97         // the page.
     98         browser_media_player_manager->OnMediaMetadataChanged(
     99             media_player_params.player_id, base::TimeDelta(), 0, 0, false);
    100       } else if (!content_view_core_impl->ShouldBlockMediaRequest(
    101             media_player_params.url)) {
    102         media_player_bridge->Initialize();
    103       }
    104       return media_player_bridge;
    105     }
    106 
    107     case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
    108       return new MediaSourcePlayer(
    109           media_player_params.player_id,
    110           manager,
    111           base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,
    112                      weak_ptr_factory_.GetWeakPtr()),
    113           demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
    114           media_player_params.frame_url);
    115     }
    116   }
    117 
    118   NOTREACHED();
    119   return NULL;
    120 }
    121 
    122 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
    123     RenderFrameHost* render_frame_host)
    124     : render_frame_host_(render_frame_host),
    125       fullscreen_player_id_(-1),
    126       fullscreen_player_is_released_(false),
    127       web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
    128       weak_ptr_factory_(this) {
    129 }
    130 
    131 BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
    132   // During the tear down process, OnDestroyPlayer() may or may not be called
    133   // (e.g. the WebContents may be destroyed before the render process). So
    134   // we cannot DCHECK(players_.empty()) here. Instead, all media players in
    135   // |players_| will be destroyed here because |player_| is a ScopedVector.
    136 }
    137 
    138 void BrowserMediaPlayerManager::FullscreenPlayerPlay() {
    139   MediaPlayerAndroid* player = GetFullscreenPlayer();
    140   if (player) {
    141     if (fullscreen_player_is_released_) {
    142       video_view_->OpenVideo();
    143       fullscreen_player_is_released_ = false;
    144     }
    145     player->Start();
    146     Send(new MediaPlayerMsg_DidMediaPlayerPlay(RoutingID(),
    147                                                fullscreen_player_id_));
    148   }
    149 }
    150 
    151 void BrowserMediaPlayerManager::FullscreenPlayerPause() {
    152   MediaPlayerAndroid* player = GetFullscreenPlayer();
    153   if (player) {
    154     player->Pause(true);
    155     Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(),
    156                                                 fullscreen_player_id_));
    157   }
    158 }
    159 
    160 void BrowserMediaPlayerManager::FullscreenPlayerSeek(int msec) {
    161   MediaPlayerAndroid* player = GetFullscreenPlayer();
    162   if (player) {
    163     // TODO(kbalazs): if |fullscreen_player_is_released_| is true
    164     // at this point, player->GetCurrentTime() will be wrong until
    165     // FullscreenPlayerPlay (http://crbug.com/322798).
    166     OnSeekRequest(fullscreen_player_id_,
    167                   base::TimeDelta::FromMilliseconds(msec));
    168   }
    169 }
    170 
    171 void BrowserMediaPlayerManager::ExitFullscreen(bool release_media_player) {
    172   if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
    173     delegate->ToggleFullscreenModeForTab(web_contents_, false);
    174   if (RenderWidgetHostViewAndroid* view_android =
    175       static_cast<RenderWidgetHostViewAndroid*>(
    176           web_contents_->GetRenderWidgetHostView())) {
    177     view_android->SetOverlayVideoMode(false);
    178   }
    179 
    180   Send(
    181       new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_));
    182   video_view_.reset();
    183   MediaPlayerAndroid* player = GetFullscreenPlayer();
    184   fullscreen_player_id_ = -1;
    185   if (!player)
    186     return;
    187   if (release_media_player)
    188     ReleaseFullscreenPlayer(player);
    189   else
    190     player->SetVideoSurface(gfx::ScopedJavaSurface());
    191 }
    192 
    193 void BrowserMediaPlayerManager::OnTimeUpdate(
    194     int player_id,
    195     base::TimeDelta current_timestamp,
    196     base::TimeTicks current_time_ticks) {
    197   Send(new MediaPlayerMsg_MediaTimeUpdate(
    198       RoutingID(), player_id, current_timestamp, current_time_ticks));
    199 }
    200 
    201 void BrowserMediaPlayerManager::SetVideoSurface(
    202     gfx::ScopedJavaSurface surface) {
    203   MediaPlayerAndroid* player = GetFullscreenPlayer();
    204   if (!player)
    205     return;
    206 
    207   bool empty_surface = surface.IsEmpty();
    208   player->SetVideoSurface(surface.Pass());
    209   if (empty_surface)
    210     return;
    211 
    212   Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player->player_id()));
    213   if (RenderWidgetHostViewAndroid* view_android =
    214       static_cast<RenderWidgetHostViewAndroid*>(
    215           web_contents_->GetRenderWidgetHostView())) {
    216     view_android->SetOverlayVideoMode(true);
    217   }
    218 }
    219 
    220 void BrowserMediaPlayerManager::OnMediaMetadataChanged(
    221     int player_id, base::TimeDelta duration, int width, int height,
    222     bool success) {
    223   Send(new MediaPlayerMsg_MediaMetadataChanged(
    224       RoutingID(), player_id, duration, width, height, success));
    225   if (fullscreen_player_id_ == player_id)
    226     video_view_->UpdateMediaMetadata();
    227 }
    228 
    229 void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
    230   Send(new MediaPlayerMsg_MediaPlaybackCompleted(RoutingID(), player_id));
    231   if (fullscreen_player_id_ == player_id)
    232     video_view_->OnPlaybackComplete();
    233 }
    234 
    235 void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
    236   // Tell WebKit that the audio should be paused, then release all resources
    237   Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), player_id));
    238   OnReleaseResources(player_id);
    239 }
    240 
    241 void BrowserMediaPlayerManager::OnBufferingUpdate(
    242     int player_id, int percentage) {
    243   Send(new MediaPlayerMsg_MediaBufferingUpdate(
    244       RoutingID(), player_id, percentage));
    245   if (fullscreen_player_id_ == player_id)
    246     video_view_->OnBufferingUpdate(percentage);
    247 }
    248 
    249 void BrowserMediaPlayerManager::OnSeekRequest(
    250     int player_id,
    251     const base::TimeDelta& time_to_seek) {
    252   Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
    253 }
    254 
    255 void BrowserMediaPlayerManager::ReleaseAllMediaPlayers() {
    256   for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
    257       it != players_.end(); ++it) {
    258     if ((*it)->player_id() == fullscreen_player_id_)
    259       fullscreen_player_is_released_ = true;
    260     (*it)->Release();
    261   }
    262 }
    263 
    264 void BrowserMediaPlayerManager::OnSeekComplete(
    265     int player_id,
    266     const base::TimeDelta& current_time) {
    267   Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time));
    268 }
    269 
    270 void BrowserMediaPlayerManager::OnError(int player_id, int error) {
    271   Send(new MediaPlayerMsg_MediaError(RoutingID(), player_id, error));
    272   if (fullscreen_player_id_ == player_id)
    273     video_view_->OnMediaPlayerError(error);
    274 }
    275 
    276 void BrowserMediaPlayerManager::OnVideoSizeChanged(
    277     int player_id, int width, int height) {
    278   Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id,
    279       width, height));
    280   if (fullscreen_player_id_ == player_id)
    281     video_view_->OnVideoSizeChanged(width, height);
    282 }
    283 
    284 media::MediaResourceGetter*
    285 BrowserMediaPlayerManager::GetMediaResourceGetter() {
    286   if (!media_resource_getter_.get()) {
    287     RenderProcessHost* host = web_contents()->GetRenderProcessHost();
    288     BrowserContext* context = host->GetBrowserContext();
    289     StoragePartition* partition = host->GetStoragePartition();
    290     storage::FileSystemContext* file_system_context =
    291         partition ? partition->GetFileSystemContext() : NULL;
    292     // Eventually this needs to be fixed to pass the correct frame rather
    293     // than just using the main frame.
    294     media_resource_getter_.reset(new MediaResourceGetterImpl(
    295         context,
    296         file_system_context,
    297         host->GetID(),
    298         web_contents()->GetMainFrame()->GetRoutingID()));
    299   }
    300   return media_resource_getter_.get();
    301 }
    302 
    303 media::MediaUrlInterceptor*
    304 BrowserMediaPlayerManager::GetMediaUrlInterceptor() {
    305   return media_url_interceptor_;
    306 }
    307 
    308 MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
    309   return GetPlayer(fullscreen_player_id_);
    310 }
    311 
    312 MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
    313   for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
    314       it != players_.end(); ++it) {
    315     if ((*it)->player_id() == player_id)
    316       return *it;
    317   }
    318   return NULL;
    319 }
    320 
    321 void BrowserMediaPlayerManager::RequestFullScreen(int player_id) {
    322   if (fullscreen_player_id_ == player_id)
    323     return;
    324 
    325   if (fullscreen_player_id_ != -1) {
    326     // TODO(qinmin): Determine the correct error code we should report to WMPA.
    327     OnError(player_id, MediaPlayerAndroid::MEDIA_ERROR_DECODE);
    328     return;
    329   }
    330 
    331   Send(new MediaPlayerMsg_RequestFullscreen(RoutingID(), player_id));
    332 }
    333 
    334 #if defined(VIDEO_HOLE)
    335 bool
    336 BrowserMediaPlayerManager::ShouldUseVideoOverlayForEmbeddedEncryptedVideo() {
    337   RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
    338   return prefs->use_video_overlay_for_embedded_encrypted_video;
    339 }
    340 
    341 void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
    342                                                            jobject surface) {
    343   MediaPlayerAndroid* player = GetPlayer(player_id);
    344   if (player) {
    345     player->SetVideoSurface(
    346         gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
    347   }
    348 }
    349 
    350 void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
    351   MediaPlayerAndroid* player = GetPlayer(player_id);
    352   if (player)
    353     player->SetVideoSurface(gfx::ScopedJavaSurface());
    354 }
    355 
    356 void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
    357   if (external_video_surface_container_)
    358     external_video_surface_container_->OnFrameInfoUpdated();
    359 }
    360 
    361 void BrowserMediaPlayerManager::OnNotifyExternalSurface(
    362     int player_id, bool is_request, const gfx::RectF& rect) {
    363   if (!web_contents_)
    364     return;
    365 
    366   if (is_request) {
    367     OnRequestExternalSurface(player_id, rect);
    368   }
    369   if (external_video_surface_container_) {
    370     external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
    371         player_id, rect);
    372   }
    373 }
    374 
    375 void BrowserMediaPlayerManager::OnRequestExternalSurface(
    376     int player_id, const gfx::RectF& rect) {
    377   if (!external_video_surface_container_) {
    378     ContentBrowserClient* client = GetContentClient()->browser();
    379     external_video_surface_container_.reset(
    380         client->OverrideCreateExternalVideoSurfaceContainer(web_contents_));
    381   }
    382   // It's safe to use base::Unretained(this), because the callbacks will not
    383   // be called after running ReleaseExternalVideoSurface().
    384   if (external_video_surface_container_) {
    385     external_video_surface_container_->RequestExternalVideoSurface(
    386         player_id,
    387         base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
    388                    base::Unretained(this)),
    389         base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
    390                    base::Unretained(this)));
    391   }
    392 }
    393 #endif  // defined(VIDEO_HOLE)
    394 
    395 void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
    396   DCHECK_EQ(fullscreen_player_id_, -1);
    397 #if defined(VIDEO_HOLE)
    398   if (external_video_surface_container_)
    399     external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
    400 #endif  // defined(VIDEO_HOLE)
    401   if (video_view_.get()) {
    402     fullscreen_player_id_ = player_id;
    403     video_view_->OpenVideo();
    404     return;
    405   } else if (!ContentVideoView::GetInstance()) {
    406     // In Android WebView, two ContentViewCores could both try to enter
    407     // fullscreen video, we just ignore the second one.
    408     video_view_.reset(new ContentVideoView(this));
    409     base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
    410         video_view_->GetJavaObject(base::android::AttachCurrentThread());
    411     if (!j_content_video_view.is_null()) {
    412       fullscreen_player_id_ = player_id;
    413       return;
    414     }
    415   }
    416 
    417   // Force the second video to exit fullscreen.
    418   // TODO(qinmin): There is no need to send DidEnterFullscreen message.
    419   // However, if we don't send the message, page layers will not be
    420   // correctly restored. http:crbug.com/367346.
    421   Send(new MediaPlayerMsg_DidEnterFullscreen(RoutingID(), player_id));
    422   Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
    423   video_view_.reset();
    424 }
    425 
    426 void BrowserMediaPlayerManager::OnExitFullscreen(int player_id) {
    427   if (fullscreen_player_id_ == player_id) {
    428     MediaPlayerAndroid* player = GetPlayer(player_id);
    429     if (player)
    430       player->SetVideoSurface(gfx::ScopedJavaSurface());
    431     video_view_->OnExitFullscreen();
    432   }
    433 }
    434 
    435 void BrowserMediaPlayerManager::OnInitialize(
    436     const MediaPlayerHostMsg_Initialize_Params& media_player_params) {
    437   DCHECK(media_player_params.type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE ||
    438       media_player_params.demuxer_client_id > 0)
    439       << "Media source players must have positive demuxer client IDs: "
    440       << media_player_params.demuxer_client_id;
    441 
    442   RemovePlayer(media_player_params.player_id);
    443 
    444   RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
    445       web_contents()->GetRenderProcessHost());
    446   MediaPlayerAndroid* player = CreateMediaPlayer(
    447       media_player_params,
    448 
    449       host->GetBrowserContext()->IsOffTheRecord(), this,
    450       host->browser_demuxer_android());
    451 
    452   if (!player)
    453     return;
    454 
    455   AddPlayer(player);
    456 }
    457 
    458 void BrowserMediaPlayerManager::OnStart(int player_id) {
    459   MediaPlayerAndroid* player = GetPlayer(player_id);
    460   if (!player)
    461     return;
    462   player->Start();
    463   if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
    464     video_view_->OpenVideo();
    465     fullscreen_player_is_released_ = false;
    466   }
    467 }
    468 
    469 void BrowserMediaPlayerManager::OnSeek(
    470     int player_id,
    471     const base::TimeDelta& time) {
    472   MediaPlayerAndroid* player = GetPlayer(player_id);
    473   if (player)
    474     player->SeekTo(time);
    475 }
    476 
    477 void BrowserMediaPlayerManager::OnPause(
    478     int player_id,
    479     bool is_media_related_action) {
    480   MediaPlayerAndroid* player = GetPlayer(player_id);
    481   if (player)
    482     player->Pause(is_media_related_action);
    483 }
    484 
    485 void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
    486   MediaPlayerAndroid* player = GetPlayer(player_id);
    487   if (player)
    488     player->SetVolume(volume);
    489 }
    490 
    491 void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
    492   // To be overridden by subclasses.
    493 }
    494 
    495 void BrowserMediaPlayerManager::OnReleaseResources(int player_id) {
    496   MediaPlayerAndroid* player = GetPlayer(player_id);
    497   if (player)
    498     ReleasePlayer(player);
    499   if (player_id == fullscreen_player_id_)
    500     fullscreen_player_is_released_ = true;
    501 }
    502 
    503 void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
    504   RemovePlayer(player_id);
    505   if (fullscreen_player_id_ == player_id)
    506     fullscreen_player_id_ = -1;
    507 }
    508 
    509 void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) {
    510   // Does nothing if we don't have a remote player
    511 }
    512 
    513 void BrowserMediaPlayerManager::OnRequestRemotePlaybackControl(
    514     int /* player_id */) {
    515   // Does nothing if we don't have a remote player
    516 }
    517 
    518 void BrowserMediaPlayerManager::AddPlayer(MediaPlayerAndroid* player) {
    519   DCHECK(!GetPlayer(player->player_id()));
    520   players_.push_back(player);
    521 }
    522 
    523 void BrowserMediaPlayerManager::RemovePlayer(int player_id) {
    524   for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
    525       it != players_.end(); ++it) {
    526     if ((*it)->player_id() == player_id) {
    527       ReleaseMediaResources(player_id);
    528       players_.erase(it);
    529       break;
    530     }
    531   }
    532 }
    533 
    534 scoped_ptr<media::MediaPlayerAndroid> BrowserMediaPlayerManager::SwapPlayer(
    535       int player_id, media::MediaPlayerAndroid* player) {
    536   media::MediaPlayerAndroid* previous_player = NULL;
    537   for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
    538       it != players_.end(); ++it) {
    539     if ((*it)->player_id() == player_id) {
    540       previous_player = *it;
    541       ReleaseMediaResources(player_id);
    542       players_.weak_erase(it);
    543       players_.push_back(player);
    544       break;
    545     }
    546   }
    547   return scoped_ptr<media::MediaPlayerAndroid>(previous_player);
    548 }
    549 
    550 int BrowserMediaPlayerManager::RoutingID() {
    551   return render_frame_host_->GetRoutingID();
    552 }
    553 
    554 bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
    555   return render_frame_host_->Send(msg);
    556 }
    557 
    558 void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
    559     MediaPlayerAndroid* player) {
    560   ReleasePlayer(player);
    561 }
    562 
    563 void BrowserMediaPlayerManager::OnMediaResourcesRequested(int player_id) {
    564   int num_active_player = 0;
    565   ScopedVector<MediaPlayerAndroid>::iterator it;
    566   for (it = players_.begin(); it != players_.end(); ++it) {
    567     if (!(*it)->IsPlayerReady())
    568       continue;
    569 
    570     // The player is already active, ignore it.
    571     if ((*it)->player_id() == player_id)
    572       return;
    573     else
    574       num_active_player++;
    575   }
    576 
    577   // Number of active players are less than the threshold, do nothing.
    578   if (num_active_player < kMediaPlayerThreshold)
    579     return;
    580 
    581   for (it = players_.begin(); it != players_.end(); ++it) {
    582     if ((*it)->IsPlayerReady() && !(*it)->IsPlaying() &&
    583         fullscreen_player_id_ != (*it)->player_id()) {
    584       ReleasePlayer(*it);
    585       Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
    586                                                   (*it)->player_id()));
    587     }
    588   }
    589 }
    590 
    591 void BrowserMediaPlayerManager::ReleaseMediaResources(int player_id) {
    592 #if defined(VIDEO_HOLE)
    593   if (external_video_surface_container_)
    594     external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
    595 #endif  // defined(VIDEO_HOLE)
    596 }
    597 
    598 void BrowserMediaPlayerManager::ReleasePlayer(MediaPlayerAndroid* player) {
    599   player->Release();
    600   ReleaseMediaResources(player->player_id());
    601 }
    602 
    603 }  // namespace content
    604