summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authortommycli <tommycli@chromium.org>2015-03-20 10:48:19 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-20 17:49:14 +0000
commit43d8cc4ccbb9dacf346bc6d6fe0f407b3a1e9c59 (patch)
tree1ea1d9ee71ff97b5f057397a09330b4acf83315d /content
parent283ecc53bba9214e19f67bba6234e0a2742f560c (diff)
downloadchromium_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.h4
-rw-r--r--content/renderer/pepper/plugin_instance_throttler_impl.cc32
-rw-r--r--content/renderer/pepper/plugin_instance_throttler_impl.h13
-rw-r--r--content/renderer/pepper/ppb_audio_impl.cc61
-rw-r--r--content/renderer/pepper/ppb_audio_impl.h13
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);
};