| Index: content/renderer/media/renderer_webmediaplayer_delegate.cc
|
| diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
|
| index 9788a6545c0196358c3bab81003e492390fed4d6..edda2e288a5fb3bf3ed674a29f90c34f88dd4cdc 100644
|
| --- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
|
| +++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
|
| @@ -6,6 +6,7 @@
|
|
|
| #include <stdint.h>
|
|
|
| +#include "base/auto_reset.h"
|
| #include "content/common/media/media_player_delegate_messages.h"
|
| #include "content/public/renderer/render_frame.h"
|
| #include "third_party/WebKit/public/platform/WebMediaPlayer.h"
|
| @@ -14,17 +15,30 @@ namespace media {
|
|
|
| RendererWebMediaPlayerDelegate::RendererWebMediaPlayerDelegate(
|
| content::RenderFrame* render_frame)
|
| - : RenderFrameObserver(render_frame) {}
|
| + : RenderFrameObserver(render_frame),
|
| + default_tick_clock_(new base::DefaultTickClock()),
|
| + tick_clock_(default_tick_clock_.get()) {
|
| +#if defined(OS_ANDROID)
|
| + // On Android the idle cleanup timer is enabled by default.
|
| + // TODO(dalecurtis): Eventually this should be enabled on all platforms.
|
| + idle_cleanup_enabled_ = true;
|
| + idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5);
|
| + idle_timeout_ = base::TimeDelta::FromSeconds(15);
|
| +#endif
|
| +}
|
|
|
| RendererWebMediaPlayerDelegate::~RendererWebMediaPlayerDelegate() {}
|
|
|
| int RendererWebMediaPlayerDelegate::AddObserver(Observer* observer) {
|
| - return id_map_.Add(observer);
|
| + const int delegate_id = id_map_.Add(observer);
|
| + AddIdleDelegate(delegate_id);
|
| + return delegate_id;
|
| }
|
|
|
| void RendererWebMediaPlayerDelegate::RemoveObserver(int delegate_id) {
|
| DCHECK(id_map_.Lookup(delegate_id));
|
| id_map_.Remove(delegate_id);
|
| + RemoveIdleDelegate(delegate_id);
|
| }
|
|
|
| void RendererWebMediaPlayerDelegate::DidPlay(int delegate_id,
|
| @@ -34,6 +48,7 @@ void RendererWebMediaPlayerDelegate::DidPlay(int delegate_id,
|
| base::TimeDelta duration) {
|
| DCHECK(id_map_.Lookup(delegate_id));
|
| has_played_media_ = true;
|
| + RemoveIdleDelegate(delegate_id);
|
| Send(new MediaPlayerDelegateHostMsg_OnMediaPlaying(
|
| routing_id(), delegate_id, has_video, has_audio, is_remote, duration));
|
| }
|
| @@ -41,12 +56,14 @@ void RendererWebMediaPlayerDelegate::DidPlay(int delegate_id,
|
| void RendererWebMediaPlayerDelegate::DidPause(int delegate_id,
|
| bool reached_end_of_stream) {
|
| DCHECK(id_map_.Lookup(delegate_id));
|
| + AddIdleDelegate(delegate_id);
|
| Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), delegate_id,
|
| reached_end_of_stream));
|
| }
|
|
|
| void RendererWebMediaPlayerDelegate::PlayerGone(int delegate_id) {
|
| DCHECK(id_map_.Lookup(delegate_id));
|
| + RemoveIdleDelegate(delegate_id);
|
| Send(new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(),
|
| delegate_id));
|
| }
|
| @@ -69,17 +86,26 @@ bool RendererWebMediaPlayerDelegate::OnMessageReceived(
|
| const IPC::Message& msg) {
|
| bool handled = true;
|
| IPC_BEGIN_MESSAGE_MAP(RendererWebMediaPlayerDelegate, msg)
|
| - IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Pause, OnMediaDelegatePause)
|
| - IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Play, OnMediaDelegatePlay)
|
| - IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_SuspendAllMediaPlayers,
|
| - OnMediaDelegateSuspendAllMediaPlayers)
|
| - IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_UpdateVolumeMultiplier,
|
| - OnMediaDelegateVolumeMultiplierUpdate)
|
| - IPC_MESSAGE_UNHANDLED(handled = false)
|
| + IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Pause, OnMediaDelegatePause)
|
| + IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_Play, OnMediaDelegatePlay)
|
| + IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_SuspendAllMediaPlayers,
|
| + OnMediaDelegateSuspendAllMediaPlayers)
|
| + IPC_MESSAGE_HANDLER(MediaPlayerDelegateMsg_UpdateVolumeMultiplier,
|
| + OnMediaDelegateVolumeMultiplierUpdate)
|
| + IPC_MESSAGE_UNHANDLED(handled = false)
|
| IPC_END_MESSAGE_MAP()
|
| return handled;
|
| }
|
|
|
| +void RendererWebMediaPlayerDelegate::EnableInstantIdleCleanupForTesting(
|
| + base::TimeDelta idle_timeout,
|
| + base::TickClock* tick_clock) {
|
| + idle_cleanup_enabled_ = true;
|
| + idle_cleanup_interval_ = base::TimeDelta();
|
| + idle_timeout_ = idle_timeout;
|
| + tick_clock_ = tick_clock;
|
| +}
|
| +
|
| void RendererWebMediaPlayerDelegate::OnMediaDelegatePause(int delegate_id) {
|
| Observer* observer = id_map_.Lookup(delegate_id);
|
| if (observer)
|
| @@ -105,4 +131,56 @@ void RendererWebMediaPlayerDelegate::OnMediaDelegateVolumeMultiplierUpdate(
|
| observer->OnVolumeMultiplierUpdate(multiplier);
|
| }
|
|
|
| +void RendererWebMediaPlayerDelegate::AddIdleDelegate(int delegate_id) {
|
| + if (!idle_cleanup_enabled_)
|
| + return;
|
| +
|
| + idle_delegate_map_[delegate_id] = tick_clock_->NowTicks();
|
| + if (!idle_cleanup_timer_.IsRunning()) {
|
| + idle_cleanup_timer_.Start(
|
| + FROM_HERE, idle_cleanup_interval_, this,
|
| + &RendererWebMediaPlayerDelegate::CleanupIdleDelegates);
|
| + }
|
| +}
|
| +
|
| +void RendererWebMediaPlayerDelegate::RemoveIdleDelegate(int delegate_id) {
|
| + if (!idle_cleanup_enabled_)
|
| + return;
|
| +
|
| + // To avoid invalidating the iterator, just mark the delegate for deletion
|
| + // using a sentinel value of an empty TimeTicks.
|
| + if (idle_cleanup_running_) {
|
| + idle_delegate_map_[delegate_id] = base::TimeTicks();
|
| + return;
|
| + }
|
| +
|
| + idle_delegate_map_.erase(delegate_id);
|
| + if (idle_delegate_map_.empty())
|
| + idle_cleanup_timer_.Stop();
|
| +}
|
| +
|
| +void RendererWebMediaPlayerDelegate::CleanupIdleDelegates() {
|
| + // Iterate over the delegates and suspend the idle ones. Note: The call to
|
| + // OnHidden() can trigger calls into RemoveIdleDelegate(), so for iterator
|
| + // validity we set |idle_cleanup_running_| to true and defer deletions.
|
| + base::AutoReset<bool> scoper(&idle_cleanup_running_, true);
|
| + const base::TimeTicks now = tick_clock_->NowTicks();
|
| + for (const auto& kv : idle_delegate_map_) {
|
| + if (now - kv.second > idle_timeout_)
|
| + id_map_.Lookup(kv.first)->OnHidden(true);
|
| + }
|
| +
|
| + // Take care of any removals that happened during the above iteration.
|
| + for (auto it = idle_delegate_map_.begin(); it != idle_delegate_map_.end();) {
|
| + if (it->second.is_null())
|
| + it = idle_delegate_map_.erase(it);
|
| + else
|
| + ++it;
|
| + }
|
| +
|
| + // Shutdown the timer if no delegates are left.
|
| + if (idle_delegate_map_.empty())
|
| + idle_cleanup_timer_.Stop();
|
| +}
|
| +
|
| } // namespace media
|
|
|