blob: 684020f456459f0749c3467f2e89415bb2bee7ce [file] [log] [blame]
// Copyright 2013 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.
#include "content/browser/media/android/browser_media_player_manager.h"
#include <utility>
#include "base/android/scoped_java_ref.h"
#include "base/memory/singleton.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/media/android/browser_demuxer_android.h"
#include "content/browser/media/android/media_resource_getter_impl.h"
#include "content/browser/media/android/media_throttler.h"
#include "content/browser/media/android/media_web_contents_observer_android.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/media/media_player_messages_android.h"
#include "content/public/browser/android/external_video_surface_container.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "gpu/ipc/common/android/surface_texture_peer.h"
#include "media/base/android/media_codec_player.h"
#include "media/base/android/media_player_bridge.h"
#include "media/base/android/media_source_player.h"
#include "media/base/android/media_task_runner.h"
#include "media/base/android/media_url_interceptor.h"
#if !defined(USE_AURA)
#include "content/browser/android/content_view_core_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#endif
using media::MediaCodecPlayer;
using media::MediaPlayerAndroid;
using media::MediaPlayerBridge;
using media::MediaPlayerManager;
using media::MediaSourcePlayer;
namespace content {
namespace {
class BrowserSurfaceTexturePeer : public gpu::SurfaceTexturePeer {
public:
static BrowserSurfaceTexturePeer* GetInstance();
private:
friend struct base::DefaultSingletonTraits<BrowserSurfaceTexturePeer>;
BrowserSurfaceTexturePeer();
~BrowserSurfaceTexturePeer() override;
void EstablishSurfaceTexturePeer(
base::ProcessHandle render_process_handle,
scoped_refptr<gfx::SurfaceTexture> surface_texture,
int render_frame_id,
int player_id) override;
DISALLOW_COPY_AND_ASSIGN(BrowserSurfaceTexturePeer);
};
// static
BrowserSurfaceTexturePeer* BrowserSurfaceTexturePeer::GetInstance() {
return base::Singleton<
BrowserSurfaceTexturePeer,
base::LeakySingletonTraits<BrowserSurfaceTexturePeer>>::get();
}
BrowserSurfaceTexturePeer::BrowserSurfaceTexturePeer() {
gpu::SurfaceTexturePeer::InitInstance(this);
}
BrowserSurfaceTexturePeer::~BrowserSurfaceTexturePeer() {
gpu::SurfaceTexturePeer::InitInstance(nullptr);
}
void BrowserSurfaceTexturePeer::EstablishSurfaceTexturePeer(
base::ProcessHandle render_process_handle,
scoped_refptr<gfx::SurfaceTexture> surface_texture,
int render_frame_id,
int player_id) {
if (!surface_texture.get())
return;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&BrowserMediaPlayerManager::SetSurfacePeer, surface_texture,
render_process_handle, render_frame_id, player_id));
}
} // namespace
// Threshold on the number of media players per renderer before we start
// attempting to release inactive media players.
const int kMediaPlayerThreshold = 1;
const int kInvalidMediaPlayerId = -1;
static BrowserMediaPlayerManager::Factory g_factory = NULL;
static media::MediaUrlInterceptor* media_url_interceptor_ = NULL;
// static
void BrowserMediaPlayerManager::RegisterFactory(Factory factory) {
// TODO(aberent) nullptr test is a temporary fix to simplify upstreaming Cast.
// Until Cast is fully upstreamed we want the downstream factory to take
// priority over the upstream factory. The downstream call happens first,
// so this will ensure that it does.
if (g_factory == nullptr)
g_factory = factory;
}
// static
void BrowserMediaPlayerManager::RegisterMediaUrlInterceptor(
media::MediaUrlInterceptor* media_url_interceptor) {
media_url_interceptor_ = media_url_interceptor;
}
// static
void BrowserMediaPlayerManager::InitSurfaceTexturePeer() {
BrowserSurfaceTexturePeer::GetInstance();
}
// static
void BrowserMediaPlayerManager::SetSurfacePeer(
scoped_refptr<gfx::SurfaceTexture> surface_texture,
base::ProcessHandle render_process_handle,
int render_frame_id,
int player_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
int render_process_id = 0;
RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
while (!it.IsAtEnd()) {
if (it.GetCurrentValue()->GetHandle() == render_process_handle) {
render_process_id = it.GetCurrentValue()->GetID();
break;
}
it.Advance();
}
if (!render_process_id) {
DVLOG(1) << "Cannot find render process for render_process_handle "
<< render_process_handle;
return;
}
RenderFrameHostImpl* frame =
RenderFrameHostImpl::FromID(render_process_id, render_frame_id);
if (!frame) {
DVLOG(1) << "Cannot find frame for render_frame_id " << render_frame_id;
return;
}
BrowserMediaPlayerManager* player_manager =
MediaWebContentsObserverAndroid::FromWebContents(
WebContents::FromRenderFrameHost(frame))
->GetMediaPlayerManager(frame);
if (!player_manager) {
DVLOG(1) << "Cannot find the media player manager for frame " << frame;
return;
}
media::MediaPlayerAndroid* player = player_manager->GetPlayer(player_id);
if (!player) {
DVLOG(1) << "Cannot find media player for player_id " << player_id;
return;
}
if (player != player_manager->GetFullscreenPlayer()) {
gfx::ScopedJavaSurface scoped_surface(surface_texture.get());
player->SetVideoSurface(std::move(scoped_surface));
}
}
// static
BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
RenderFrameHost* rfh) {
if (g_factory)
return g_factory(rfh);
return new BrowserMediaPlayerManager(rfh);
}
#if !defined(USE_AURA)
ContentViewCore* BrowserMediaPlayerManager::GetContentViewCore() const {
return ContentViewCoreImpl::FromWebContents(web_contents());
}
#endif
MediaPlayerAndroid* BrowserMediaPlayerManager::CreateMediaPlayer(
const MediaPlayerHostMsg_Initialize_Params& media_player_params,
bool hide_url_log,
BrowserDemuxerAndroid* demuxer) {
switch (media_player_params.type) {
case MEDIA_PLAYER_TYPE_REMOTE_ONLY:
case MEDIA_PLAYER_TYPE_URL: {
const std::string user_agent = GetContentClient()->GetUserAgent();
MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge(
media_player_params.player_id, media_player_params.url,
media_player_params.first_party_for_cookies, user_agent, hide_url_log,
this,
base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
weak_ptr_factory_.GetWeakPtr()),
media_player_params.frame_url, media_player_params.allow_credentials,
media_player_params.media_session_id);
if (media_player_params.type == MEDIA_PLAYER_TYPE_REMOTE_ONLY)
return media_player_bridge;
bool should_block = false;
bool extract_metadata =
// Initialize the player will cause MediaMetadataExtractor to decode
// small chunks of data.
RequestDecoderResources(media_player_params.player_id, true);
#if !defined(USE_AURA)
ContentViewCoreImpl* content_view_core_impl =
static_cast<ContentViewCoreImpl*>(
ContentViewCore::FromWebContents(web_contents_));
if (!content_view_core_impl) {
extract_metadata = false;
} else {
should_block = content_view_core_impl->ShouldBlockMediaRequest(
media_player_params.url);
}
#endif
if (!extract_metadata) {
// May reach here due to prerendering or throttling. Don't extract the
// metadata since it is expensive.
// TODO(qinmin): extract the metadata once the user decided to load
// the page.
OnMediaMetadataChanged(media_player_params.player_id, base::TimeDelta(),
0, 0, false);
} else if (!should_block) {
media_player_bridge->Initialize();
}
return media_player_bridge;
}
case MEDIA_PLAYER_TYPE_MEDIA_SOURCE: {
if (media::UseMediaThreadForMediaPlayback()) {
return new MediaCodecPlayer(
media_player_params.player_id, weak_ptr_factory_.GetWeakPtr(),
base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
weak_ptr_factory_.GetWeakPtr()),
demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
media_player_params.frame_url,
media_player_params.media_session_id);
} else {
return new MediaSourcePlayer(
media_player_params.player_id, this,
base::Bind(&BrowserMediaPlayerManager::OnDecoderResourcesReleased,
weak_ptr_factory_.GetWeakPtr()),
demuxer->CreateDemuxer(media_player_params.demuxer_client_id),
media_player_params.frame_url,
media_player_params.media_session_id);
}
}
}
NOTREACHED();
return NULL;
}
BrowserMediaPlayerManager::BrowserMediaPlayerManager(
RenderFrameHost* render_frame_host)
: render_frame_host_(render_frame_host),
fullscreen_player_id_(kInvalidMediaPlayerId),
fullscreen_player_is_released_(false),
web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
weak_ptr_factory_(this) {
}
BrowserMediaPlayerManager::~BrowserMediaPlayerManager() {
// During the tear down process, OnDestroyPlayer() may or may not be called
// (e.g. the WebContents may be destroyed before the render process). So
// we cannot DCHECK(players_.empty()) here. Instead, all media players in
// |players_| will be destroyed here because |player_| is a ScopedVector.
for (MediaPlayerAndroid* player : players_)
player->DeleteOnCorrectThread();
players_.weak_clear();
}
void BrowserMediaPlayerManager::DidExitFullscreen(bool release_media_player) {
#if defined(USE_AURA)
// TODO(crbug.com/548024)
NOTIMPLEMENTED();
#else
if (WebContentsDelegate* delegate = web_contents_->GetDelegate())
delegate->ExitFullscreenModeForTab(web_contents_);
if (RenderWidgetHostViewAndroid* view_android =
static_cast<RenderWidgetHostViewAndroid*>(
web_contents_->GetRenderWidgetHostView())) {
view_android->SetOverlayVideoMode(false);
}
Send(
new MediaPlayerMsg_DidExitFullscreen(RoutingID(), fullscreen_player_id_));
video_view_.reset();
MediaPlayerAndroid* player = GetFullscreenPlayer();
fullscreen_player_id_ = kInvalidMediaPlayerId;
if (!player)
return;
#if defined(VIDEO_HOLE)
if (external_video_surface_container_)
external_video_surface_container_->OnFrameInfoUpdated();
#endif // defined(VIDEO_HOLE)
if (release_media_player)
ReleaseFullscreenPlayer(player);
else
player->SetVideoSurface(gfx::ScopedJavaSurface());
#endif // defined(USE_AURA)
}
void BrowserMediaPlayerManager::OnTimeUpdate(
int player_id,
base::TimeDelta current_timestamp,
base::TimeTicks current_time_ticks) {
Send(new MediaPlayerMsg_MediaTimeUpdate(
RoutingID(), player_id, current_timestamp, current_time_ticks));
}
void BrowserMediaPlayerManager::SetVideoSurface(
gfx::ScopedJavaSurface surface) {
MediaPlayerAndroid* player = GetFullscreenPlayer();
if (!player)
return;
bool empty_surface = surface.IsEmpty();
player->SetVideoSurface(std::move(surface));
if (empty_surface)
return;
// If we already know the size, set it now. Otherwise it will be set when the
// player gets it.
if (player->IsPlayerReady()) {
video_view_->OnVideoSizeChanged(player->GetVideoWidth(),
player->GetVideoHeight());
}
#if !defined(USE_AURA)
if (RenderWidgetHostViewAndroid* view_android =
static_cast<RenderWidgetHostViewAndroid*>(
web_contents_->GetRenderWidgetHostView())) {
view_android->SetOverlayVideoMode(true);
}
#endif
}
void BrowserMediaPlayerManager::OnMediaMetadataChanged(
int player_id, base::TimeDelta duration, int width, int height,
bool success) {
Send(new MediaPlayerMsg_MediaMetadataChanged(
RoutingID(), player_id, duration, width, height, success));
if (fullscreen_player_id_ == player_id)
video_view_->OnVideoSizeChanged(width, height);
}
void BrowserMediaPlayerManager::OnPlaybackComplete(int player_id) {
Send(new MediaPlayerMsg_MediaPlaybackCompleted(RoutingID(), player_id));
}
void BrowserMediaPlayerManager::OnMediaInterrupted(int player_id) {
// Tell WebKit that the audio should be paused, then release all resources
Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(), player_id));
ReleaseResources(player_id);
}
void BrowserMediaPlayerManager::OnBufferingUpdate(int player_id,
int percentage) {
Send(new MediaPlayerMsg_MediaBufferingUpdate(RoutingID(), player_id,
percentage));
}
void BrowserMediaPlayerManager::OnSeekRequest(
int player_id,
const base::TimeDelta& time_to_seek) {
Send(new MediaPlayerMsg_SeekRequest(RoutingID(), player_id, time_to_seek));
}
void BrowserMediaPlayerManager::OnSeekComplete(
int player_id,
const base::TimeDelta& current_time) {
Send(new MediaPlayerMsg_SeekCompleted(RoutingID(), player_id, current_time));
}
void BrowserMediaPlayerManager::OnError(int player_id, int error) {
Send(new MediaPlayerMsg_MediaError(RoutingID(), player_id, error));
if (fullscreen_player_id_ == player_id &&
error != MediaPlayerAndroid::MEDIA_ERROR_INVALID_CODE) {
video_view_->OnMediaPlayerError(error);
}
}
void BrowserMediaPlayerManager::OnVideoSizeChanged(
int player_id, int width, int height) {
Send(new MediaPlayerMsg_MediaVideoSizeChanged(RoutingID(), player_id,
width, height));
if (fullscreen_player_id_ == player_id)
video_view_->OnVideoSizeChanged(width, height);
}
void BrowserMediaPlayerManager::OnWaitingForDecryptionKey(int player_id) {
Send(new MediaPlayerMsg_WaitingForDecryptionKey(RoutingID(), player_id));
}
media::MediaResourceGetter*
BrowserMediaPlayerManager::GetMediaResourceGetter() {
if (!media_resource_getter_.get()) {
RenderProcessHost* host = web_contents()->GetRenderProcessHost();
BrowserContext* context = host->GetBrowserContext();
StoragePartition* partition = host->GetStoragePartition();
storage::FileSystemContext* file_system_context =
partition ? partition->GetFileSystemContext() : NULL;
// Eventually this needs to be fixed to pass the correct frame rather
// than just using the main frame.
media_resource_getter_.reset(new MediaResourceGetterImpl(
context,
file_system_context,
host->GetID(),
web_contents()->GetMainFrame()->GetRoutingID()));
}
return media_resource_getter_.get();
}
media::MediaUrlInterceptor*
BrowserMediaPlayerManager::GetMediaUrlInterceptor() {
return media_url_interceptor_;
}
MediaPlayerAndroid* BrowserMediaPlayerManager::GetFullscreenPlayer() {
return GetPlayer(fullscreen_player_id_);
}
MediaPlayerAndroid* BrowserMediaPlayerManager::GetPlayer(int player_id) {
for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
it != players_.end(); ++it) {
if ((*it)->player_id() == player_id)
return *it;
}
return NULL;
}
bool BrowserMediaPlayerManager::RequestPlay(int player_id,
base::TimeDelta duration,
bool has_audio) {
DCHECK(player_id_to_delegate_id_map_.find(player_id) !=
player_id_to_delegate_id_map_.end());
return MediaWebContentsObserverAndroid::FromWebContents(web_contents_)
->RequestPlay(render_frame_host_,
player_id_to_delegate_id_map_[player_id], has_audio,
IsPlayingRemotely(player_id), duration);
}
#if defined(VIDEO_HOLE)
void BrowserMediaPlayerManager::AttachExternalVideoSurface(int player_id,
jobject surface) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (player) {
player->SetVideoSurface(
gfx::ScopedJavaSurface::AcquireExternalSurface(surface));
}
}
void BrowserMediaPlayerManager::DetachExternalVideoSurface(int player_id) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (player)
player->SetVideoSurface(gfx::ScopedJavaSurface());
}
void BrowserMediaPlayerManager::OnFrameInfoUpdated() {
if (fullscreen_player_id_ != kInvalidMediaPlayerId)
return;
if (external_video_surface_container_)
external_video_surface_container_->OnFrameInfoUpdated();
}
void BrowserMediaPlayerManager::OnNotifyExternalSurface(
int player_id, bool is_request, const gfx::RectF& rect) {
if (!web_contents_)
return;
if (is_request) {
OnRequestExternalSurface(player_id, rect);
}
if (external_video_surface_container_) {
external_video_surface_container_->OnExternalVideoSurfacePositionChanged(
player_id, rect);
}
}
void BrowserMediaPlayerManager::ReleasePlayerOfExternalVideoSurfaceIfNeeded(
int future_player) {
int current_player = ExternalVideoSurfaceContainer::kInvalidPlayerId;
if (external_video_surface_container_)
current_player = external_video_surface_container_->GetCurrentPlayerId();
if (current_player == ExternalVideoSurfaceContainer::kInvalidPlayerId)
return;
if (current_player != future_player)
OnMediaInterrupted(current_player);
}
void BrowserMediaPlayerManager::OnRequestExternalSurface(
int player_id, const gfx::RectF& rect) {
if (!external_video_surface_container_) {
ContentBrowserClient* client = GetContentClient()->browser();
external_video_surface_container_.reset(
client->OverrideCreateExternalVideoSurfaceContainer(web_contents_));
}
// It's safe to use base::Unretained(this), because the callbacks will not
// be called after running ReleaseExternalVideoSurface().
if (external_video_surface_container_) {
// In case we're stealing the external surface from another player.
ReleasePlayerOfExternalVideoSurfaceIfNeeded(player_id);
external_video_surface_container_->RequestExternalVideoSurface(
player_id,
base::Bind(&BrowserMediaPlayerManager::AttachExternalVideoSurface,
base::Unretained(this)),
base::Bind(&BrowserMediaPlayerManager::DetachExternalVideoSurface,
base::Unretained(this)));
}
}
void BrowserMediaPlayerManager::ReleaseExternalSurface(int player_id) {
if (external_video_surface_container_)
external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
}
#endif // defined(VIDEO_HOLE)
void BrowserMediaPlayerManager::OnEnterFullscreen(int player_id) {
#if defined(USE_AURA)
// TODO(crbug.com/548024)
NOTIMPLEMENTED();
#else
DCHECK_EQ(fullscreen_player_id_, kInvalidMediaPlayerId);
#if defined(VIDEO_HOLE)
// If this fullscreen player is started when another player
// uses the external surface, release that other player.
ReleasePlayerOfExternalVideoSurfaceIfNeeded(player_id);
if (external_video_surface_container_)
external_video_surface_container_->ReleaseExternalVideoSurface(player_id);
#endif // defined(VIDEO_HOLE)
if (video_view_) {
fullscreen_player_id_ = player_id;
video_view_->OpenVideo();
return;
}
if (ContentVideoView::GetInstance()) {
// In Android WebView, two ContentViewCores could both try to enter
// fullscreen video, we just ignore the second one.
Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
return;
}
// There's no ContentVideoView instance so create one.
video_view_.reset(new ContentVideoView(this, GetContentViewCore()));
base::android::ScopedJavaLocalRef<jobject> j_content_video_view =
video_view_->GetJavaObject(base::android::AttachCurrentThread());
if (!j_content_video_view.is_null()) {
fullscreen_player_id_ = player_id;
} else {
Send(new MediaPlayerMsg_DidExitFullscreen(RoutingID(), player_id));
video_view_.reset();
}
#endif // defined(USE_AURA)
}
void BrowserMediaPlayerManager::OnInitialize(
const MediaPlayerHostMsg_Initialize_Params& media_player_params) {
DCHECK(media_player_params.type != MEDIA_PLAYER_TYPE_MEDIA_SOURCE ||
media_player_params.demuxer_client_id > 0)
<< "Media source players must have positive demuxer client IDs: "
<< media_player_params.demuxer_client_id;
DestroyPlayer(media_player_params.player_id);
RenderProcessHostImpl* host = static_cast<RenderProcessHostImpl*>(
web_contents()->GetRenderProcessHost());
MediaPlayerAndroid* player =
CreateMediaPlayer(media_player_params,
host->GetBrowserContext()->IsOffTheRecord(),
host->browser_demuxer_android().get());
if (!player)
return;
AddPlayer(player, media_player_params.delegate_id);
}
void BrowserMediaPlayerManager::OnStart(int player_id) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (!player)
return;
if (RequestDecoderResources(player_id, false)) {
StartInternal(player_id);
} else if (WebContentsDelegate* delegate = web_contents_->GetDelegate()){
delegate->RequestMediaDecodePermission(
web_contents_,
base::Bind(&BrowserMediaPlayerManager::OnPlaybackPermissionGranted,
weak_ptr_factory_.GetWeakPtr(), player_id));
}
}
void BrowserMediaPlayerManager::OnSeek(
int player_id,
const base::TimeDelta& time) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (player)
player->SeekTo(time);
}
void BrowserMediaPlayerManager::OnPause(
int player_id,
bool is_media_related_action) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (player)
player->Pause(is_media_related_action);
}
void BrowserMediaPlayerManager::OnSetVolume(int player_id, double volume) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (player)
player->SetVolume(volume);
}
void BrowserMediaPlayerManager::OnSetPoster(int player_id, const GURL& url) {
// To be overridden by subclasses.
}
void BrowserMediaPlayerManager::OnSuspendAndReleaseResources(int player_id) {
ReleaseResources(player_id);
}
void BrowserMediaPlayerManager::OnDestroyPlayer(int player_id) {
DestroyPlayer(player_id);
if (fullscreen_player_id_ == player_id)
fullscreen_player_id_ = kInvalidMediaPlayerId;
}
void BrowserMediaPlayerManager::OnRequestRemotePlayback(int /* player_id */) {
// Does nothing if we don't have a remote player
}
void BrowserMediaPlayerManager::OnRequestRemotePlaybackControl(
int /* player_id */) {
// Does nothing if we don't have a remote player
}
bool BrowserMediaPlayerManager::IsPlayingRemotely(int player_id) {
return false;
}
void BrowserMediaPlayerManager::AddPlayer(
MediaPlayerAndroid* player, int delegate_id) {
DCHECK(!GetPlayer(player->player_id()));
players_.push_back(player);
player_id_to_delegate_id_map_[player->player_id()] =
delegate_id;
}
void BrowserMediaPlayerManager::DestroyPlayer(int player_id) {
for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
it != players_.end(); ++it) {
if ((*it)->player_id() == player_id) {
#if defined(VIDEO_HOLE)
ReleaseExternalSurface(player_id);
#endif
(*it)->DeleteOnCorrectThread();
players_.weak_erase(it);
break;
}
}
active_players_.erase(player_id);
player_id_to_delegate_id_map_.erase(player_id);
}
void BrowserMediaPlayerManager::ReleaseResources(int player_id) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (player)
ReleasePlayer(player);
if (player_id == fullscreen_player_id_)
fullscreen_player_is_released_ = true;
}
std::unique_ptr<media::MediaPlayerAndroid>
BrowserMediaPlayerManager::SwapPlayer(int player_id,
media::MediaPlayerAndroid* player) {
media::MediaPlayerAndroid* previous_player = NULL;
for (ScopedVector<MediaPlayerAndroid>::iterator it = players_.begin();
it != players_.end(); ++it) {
if ((*it)->player_id() == player_id) {
previous_player = *it;
#if defined(VIDEO_HOLE)
ReleaseExternalSurface(player_id);
#endif
MediaWebContentsObserverAndroid::FromWebContents(web_contents_)
->DisconnectMediaSession(render_frame_host_,
player_id_to_delegate_id_map_[player_id]);
players_.weak_erase(it);
players_.push_back(player);
break;
}
}
return std::unique_ptr<media::MediaPlayerAndroid>(previous_player);
}
bool BrowserMediaPlayerManager::RequestDecoderResources(
int player_id, bool temporary) {
if (!MediaThrottler::GetInstance()->RequestDecoderResources())
return false;
ActivePlayerMap::iterator it;
// The player is already active, ignore it. A long running player should not
// request temporary permissions.
if ((it = active_players_.find(player_id)) != active_players_.end()) {
DCHECK(!temporary || it->second);
return true;
}
if (!temporary) {
int long_running_player = 0;
for (it = active_players_.begin(); it != active_players_.end(); ++it) {
if (!it->second)
long_running_player++;
}
// Number of active players are less than the threshold, do nothing.
if (long_running_player < kMediaPlayerThreshold)
return true;
for (it = active_players_.begin(); it != active_players_.end(); ++it) {
if (!it->second && !GetPlayer(it->first)->IsPlaying() &&
fullscreen_player_id_ != it->first) {
ReleasePlayer(GetPlayer(it->first));
Send(new MediaPlayerMsg_MediaPlayerReleased(RoutingID(),
(it->first)));
}
}
}
active_players_[player_id] = temporary;
return true;
}
void BrowserMediaPlayerManager::OnDecoderResourcesReleased(int player_id) {
if (active_players_.find(player_id) == active_players_.end())
return;
active_players_.erase(player_id);
MediaThrottler::GetInstance()->OnDecodeRequestFinished();
}
int BrowserMediaPlayerManager::RoutingID() {
return render_frame_host_->GetRoutingID();
}
bool BrowserMediaPlayerManager::Send(IPC::Message* msg) {
return render_frame_host_->Send(msg);
}
void BrowserMediaPlayerManager::ReleaseFullscreenPlayer(
MediaPlayerAndroid* player) {
ReleasePlayer(player);
}
void BrowserMediaPlayerManager::ReleasePlayer(MediaPlayerAndroid* player) {
player->Release();
#if defined(VIDEO_HOLE)
ReleaseExternalSurface(player->player_id());
#endif
}
void BrowserMediaPlayerManager::OnPlaybackPermissionGranted(
int player_id, bool granted) {
if (!granted)
return;
MediaThrottler::GetInstance()->Reset();
StartInternal(player_id);
}
void BrowserMediaPlayerManager::StartInternal(int player_id) {
MediaPlayerAndroid* player = GetPlayer(player_id);
if (!player)
return;
player->Start();
if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
video_view_->OpenVideo();
fullscreen_player_is_released_ = false;
}
}
} // namespace content