diff options
author | tommycli <tommycli@chromium.org> | 2015-03-20 10:48:19 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-20 17:49:14 +0000 |
commit | 43d8cc4ccbb9dacf346bc6d6fe0f407b3a1e9c59 (patch) | |
tree | 1ea1d9ee71ff97b5f057397a09330b4acf83315d /content | |
parent | 283ecc53bba9214e19f67bba6234e0a2742f560c (diff) | |
download | chromium_src-43d8cc4ccbb9dacf346bc6d6fe0f407b3a1e9c59.zip chromium_src-43d8cc4ccbb9dacf346bc6d6fe0f407b3a1e9c59.tar.gz chromium_src-43d8cc4ccbb9dacf346bc6d6fe0f407b3a1e9c59.tar.bz2 |
Plugin Power Saver: Mute throttled plugins.
BUG=452215, 403800
Review URL: https://codereview.chromium.org/879403002
Cr-Commit-Position: refs/heads/master@{#321593}
Diffstat (limited to 'content')
-rw-r--r-- | content/public/renderer/plugin_instance_throttler.h | 4 | ||||
-rw-r--r-- | content/renderer/pepper/plugin_instance_throttler_impl.cc | 32 | ||||
-rw-r--r-- | content/renderer/pepper/plugin_instance_throttler_impl.h | 13 | ||||
-rw-r--r-- | content/renderer/pepper/ppb_audio_impl.cc | 61 | ||||
-rw-r--r-- | content/renderer/pepper/ppb_audio_impl.h | 13 |
5 files changed, 113 insertions, 10 deletions
diff --git a/content/public/renderer/plugin_instance_throttler.h b/content/public/renderer/plugin_instance_throttler.h index d20f525..f9c5b92 100644 --- a/content/public/renderer/plugin_instance_throttler.h +++ b/content/public/renderer/plugin_instance_throttler.h @@ -84,6 +84,10 @@ class CONTENT_EXPORT PluginInstanceThrottler { virtual blink::WebPlugin* GetWebPlugin() const = 0; + // Throttler needs to know when the plugin audio is throttled, as this may + // prevent the plugin from generating new frames. + virtual void NotifyAudioThrottled() = 0; + protected: PluginInstanceThrottler() {} diff --git a/content/renderer/pepper/plugin_instance_throttler_impl.cc b/content/renderer/pepper/plugin_instance_throttler_impl.cc index 097480d..6a48a4d 100644 --- a/content/renderer/pepper/plugin_instance_throttler_impl.cc +++ b/content/renderer/pepper/plugin_instance_throttler_impl.cc @@ -26,6 +26,11 @@ const double kAcceptableFrameMaximumBoringness = 0.94; const int kMinimumConsecutiveInterestingFrames = 4; +// When plugin audio is throttled, the plugin will sometimes stop generating +// video frames. We use this timeout to prevent waiting forever for a good +// poster image. Chosen arbitrarily. +const int kAudioThrottledFrameTimeoutMilliseconds = 500; + } // namespace // static @@ -53,6 +58,13 @@ PluginInstanceThrottlerImpl::PluginInstanceThrottlerImpl( web_plugin_(nullptr), consecutive_interesting_frames_(0), frames_examined_(0), + audio_throttled_(false), + audio_throttled_frame_timeout_( + FROM_HERE, + base::TimeDelta::FromMilliseconds( + kAudioThrottledFrameTimeoutMilliseconds), + this, + &PluginInstanceThrottlerImpl::EngageThrottle), weak_factory_(this) { } @@ -101,6 +113,11 @@ blink::WebPlugin* PluginInstanceThrottlerImpl::GetWebPlugin() const { return web_plugin_; } +void PluginInstanceThrottlerImpl::NotifyAudioThrottled() { + audio_throttled_ = true; + audio_throttled_frame_timeout_.Reset(); +} + void PluginInstanceThrottlerImpl::SetWebPlugin(blink::WebPlugin* web_plugin) { DCHECK(!web_plugin_); web_plugin_ = web_plugin; @@ -148,9 +165,14 @@ void PluginInstanceThrottlerImpl::OnImageFlush(const SkBitmap* bitmap) { else consecutive_interesting_frames_ = 0; + // Does not make a copy, just takes a reference to the underlying pixel data. + last_received_frame_ = *bitmap; + + if (audio_throttled_) + audio_throttled_frame_timeout_.Reset(); + if (frames_examined_ >= kMaximumFramesToExamine || consecutive_interesting_frames_ >= kMinimumConsecutiveInterestingFrames) { - FOR_EACH_OBSERVER(Observer, observer_list_, OnKeyframeExtracted(bitmap)); EngageThrottle(); } } @@ -179,6 +201,14 @@ void PluginInstanceThrottlerImpl::EngageThrottle() { if (state_ != THROTTLER_STATE_AWAITING_KEYFRAME) return; + if (!last_received_frame_.empty()) { + FOR_EACH_OBSERVER(Observer, observer_list_, + OnKeyframeExtracted(&last_received_frame_)); + + // Release our reference to the underlying pixel data. + last_received_frame_.reset(); + } + state_ = THROTTLER_STATE_PLUGIN_THROTTLED; FOR_EACH_OBSERVER(Observer, observer_list_, OnThrottleStateChange()); } diff --git a/content/renderer/pepper/plugin_instance_throttler_impl.h b/content/renderer/pepper/plugin_instance_throttler_impl.h index b223cd2..0bcad2f 100644 --- a/content/renderer/pepper/plugin_instance_throttler_impl.h +++ b/content/renderer/pepper/plugin_instance_throttler_impl.h @@ -8,9 +8,11 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/timer/timer.h" #include "content/common/content_export.h" #include "content/public/renderer/plugin_instance_throttler.h" #include "ppapi/shared_impl/ppb_view_shared.h" +#include "third_party/skia/include/core/SkBitmap.h" namespace blink { class WebInputEvent; @@ -36,6 +38,7 @@ class CONTENT_EXPORT PluginInstanceThrottlerImpl void MarkPluginEssential(PowerSaverUnthrottleMethod method) override; void SetHiddenForPlaceholder(bool hidden) override; blink::WebPlugin* GetWebPlugin() const override; + void NotifyAudioThrottled() override; void SetWebPlugin(blink::WebPlugin* web_plugin); @@ -80,6 +83,7 @@ class CONTENT_EXPORT PluginInstanceThrottlerImpl // simply suspend the plugin where it's at. Chosen arbitrarily. static const int kMaximumFramesToExamine; + void AudioThrottledFrameTimeout(); void EngageThrottle(); ThrottlerState state_; @@ -88,12 +92,21 @@ class CONTENT_EXPORT PluginInstanceThrottlerImpl blink::WebPlugin* web_plugin_; + // Holds a reference to the last received frame. This doesn't actually copy + // the pixel data, but rather increments the reference count to the pixels. + SkBitmap last_received_frame_; + // Number of consecutive interesting frames we've encountered. int consecutive_interesting_frames_; // Number of frames we've examined to find a keyframe. int frames_examined_; + // Video plugins with throttled audio often stop generating frames. + // This timer is so we don't wait forever for candidate poster frames. + bool audio_throttled_; + base::DelayTimer<PluginInstanceThrottlerImpl> audio_throttled_frame_timeout_; + ObserverList<Observer> observer_list_; base::WeakPtrFactory<PluginInstanceThrottlerImpl> weak_factory_; diff --git a/content/renderer/pepper/ppb_audio_impl.cc b/content/renderer/pepper/ppb_audio_impl.cc index b7fcf0d..7a5ead9 100644 --- a/content/renderer/pepper/ppb_audio_impl.cc +++ b/content/renderer/pepper/ppb_audio_impl.cc @@ -30,9 +30,24 @@ namespace content { // PPB_Audio_Impl -------------------------------------------------------------- PPB_Audio_Impl::PPB_Audio_Impl(PP_Instance instance) - : Resource(ppapi::OBJECT_IS_IMPL, instance), audio_(NULL) {} + : Resource(ppapi::OBJECT_IS_IMPL, instance), + audio_(NULL), + playback_throttled_(false) { + PepperPluginInstanceImpl* plugin_instance = + static_cast<PepperPluginInstanceImpl*>( + PepperPluginInstance::Get(pp_instance())); + if (plugin_instance && plugin_instance->throttler()) { + plugin_instance->throttler()->AddObserver(this); + } +} PPB_Audio_Impl::~PPB_Audio_Impl() { + PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>( + PepperPluginInstance::Get(pp_instance())); + if (instance && instance->throttler()) { + instance->throttler()->RemoveObserver(this); + } + // Calling ShutDown() makes sure StreamCreated cannot be called anymore and // releases the audio data associated with the pointer. Note however, that // until ShutDown returns, StreamCreated may still be called. This will be @@ -57,6 +72,17 @@ PP_Bool PPB_Audio_Impl::StartPlayback() { return PP_FALSE; if (playing()) return PP_TRUE; + + // If plugin is in power saver mode, defer audio IPC communication. + PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>( + PepperPluginInstance::Get(pp_instance())); + if (instance && instance->throttler() && + instance->throttler()->power_saver_enabled()) { + instance->throttler()->NotifyAudioThrottled(); + playback_throttled_ = true; + return PP_TRUE; + } + SetStartPlaybackState(); return PP_FromBool(audio_->StartPlayback()); } @@ -64,11 +90,19 @@ PP_Bool PPB_Audio_Impl::StartPlayback() { PP_Bool PPB_Audio_Impl::StopPlayback() { if (!audio_) return PP_FALSE; + + if (playback_throttled_) { + // If a start playback request is still deferred, we must fulfill it first + // to shut down the audio thread correctly. + StartDeferredPlayback(); + } + if (!playing()) return PP_TRUE; if (!audio_->StopPlayback()) return PP_FALSE; SetStopPlaybackState(); + return PP_TRUE; } @@ -85,13 +119,6 @@ int32_t PPB_Audio_Impl::Open(PP_Resource config, if (!instance) return PP_ERROR_FAILED; - // Prevent any throttling since we are playing audio. This stopgap prevents - // video from appearing 'frozen' while the audio track plays. - if (instance->throttler() && instance->throttler()->power_saver_enabled()) { - instance->throttler()->MarkPluginEssential( - PluginInstanceThrottler::UNTHROTTLE_METHOD_BY_AUDIO); - } - // When the stream is created, we'll get called back on StreamCreated(). DCHECK(!audio_); audio_ = PepperPlatformAudioOutput::Create( @@ -132,4 +159,22 @@ void PPB_Audio_Impl::OnSetStreamInfo( enter.object()->GetSampleFrameCount()); } +void PPB_Audio_Impl::OnThrottleStateChange() { + PepperPluginInstanceImpl* instance = static_cast<PepperPluginInstanceImpl*>( + PepperPluginInstance::Get(pp_instance())); + if (playback_throttled_ && instance && instance->throttler() && + !instance->throttler()->power_saver_enabled()) { + // If we have become unthrottled, and we have a pending playback, start it. + StartDeferredPlayback(); + } +} + +void PPB_Audio_Impl::StartDeferredPlayback() { + DCHECK(playback_throttled_); + playback_throttled_ = false; + + SetStartPlaybackState(); + audio_->StartPlayback(); +} + } // namespace content diff --git a/content/renderer/pepper/ppb_audio_impl.h b/content/renderer/pepper/ppb_audio_impl.h index 3348527..6c0af8f 100644 --- a/content/renderer/pepper/ppb_audio_impl.h +++ b/content/renderer/pepper/ppb_audio_impl.h @@ -9,6 +9,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/shared_memory.h" #include "base/sync_socket.h" +#include "content/public/renderer/plugin_instance_throttler.h" #include "content/renderer/pepper/audio_helper.h" #include "ppapi/c/pp_completion_callback.h" #include "ppapi/c/ppb_audio.h" @@ -28,7 +29,8 @@ class PepperPlatformAudioOutput; // to look more like typical HostResource implementations. class PPB_Audio_Impl : public ppapi::Resource, public ppapi::PPB_Audio_Shared, - public AudioHelper { + public AudioHelper, + public PluginInstanceThrottler::Observer { public: explicit PPB_Audio_Impl(PP_Instance instance); @@ -52,6 +54,12 @@ class PPB_Audio_Impl : public ppapi::Resource, size_t shared_memory_size_, base::SyncSocket::Handle socket) override; + // PluginInstanceThrottler::Observer implementation. + void OnThrottleStateChange() override; + + // Starts the deferred playback and unsubscribes from the throttler. + void StartDeferredPlayback(); + // AudioConfig used for creating this Audio object. We own a ref. ppapi::ScopedPPResource config_; @@ -59,6 +67,9 @@ class PPB_Audio_Impl : public ppapi::Resource, // own this pointer but are responsible for calling Shutdown on it. PepperPlatformAudioOutput* audio_; + // Stream is playing, but throttled due to Plugin Power Saver. + bool playback_throttled_; + DISALLOW_COPY_AND_ASSIGN(PPB_Audio_Impl); }; |