From a1b9dfeb459092e3400fc7e23dc9c9696872be38 Mon Sep 17 00:00:00 2001 From: "dalecurtis@chromium.org" Date: Sat, 31 May 2014 04:37:17 +0000 Subject: Don't background processes with active audio output. If a process is actively rendering audio, it should not be put into the background state. "Active" is determined by having any stream in the playing state as considered by AudioRendererHost. When a tab has active audio, it's already being woken up ~ every 10-20ms, so I expect the power impact of this change to be negligible. This should reduce glitching under load. BUG=362294 TEST=Ensure Windows playback under load no longer glitches. Review URL: https://codereview.chromium.org/298253004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274020 0039d316-1c4b-4281-b951-d872f2087c98 --- .../renderer_host/media/audio_renderer_host.cc | 25 ++++++++++++++++++++-- .../renderer_host/media/audio_renderer_host.h | 8 +++++++ .../renderer_host/render_process_host_impl.cc | 4 ++++ 3 files changed, 35 insertions(+), 2 deletions(-) (limited to 'content') diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc index fd6b474..9334d94 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_renderer_host.cc @@ -61,6 +61,9 @@ class AudioRendererHost::AudioEntry return reader_.get(); } + bool playing() const { return playing_; } + void set_playing(bool playing) { playing_ = playing; } + private: // media::AudioOutputController::EventHandler implementation. virtual void OnCreated() OVERRIDE; @@ -85,6 +88,8 @@ class AudioRendererHost::AudioEntry // The AudioOutputController that manages the audio stream. const scoped_refptr controller_; + + bool playing_; }; AudioRendererHost::AudioEntry::AudioEntry( @@ -106,7 +111,8 @@ AudioRendererHost::AudioEntry::AudioEntry( this, params, output_device_id, - reader_.get())) { + reader_.get())), + playing_(false) { DCHECK(controller_.get()); } @@ -127,7 +133,8 @@ AudioRendererHost::AudioRendererHost( mirroring_manager_(mirroring_manager), audio_log_(media_internals->CreateAudioLog( media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), - media_stream_manager_(media_stream_manager) { + media_stream_manager_(media_stream_manager), + num_playing_streams_(0) { DCHECK(audio_manager_); DCHECK(media_stream_manager_); } @@ -275,10 +282,18 @@ void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, entry->stream_id(), base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, entry->controller())); + if (!entry->playing()) { + entry->set_playing(true); + base::AtomicRefCountInc(&num_playing_streams_); + } } else { media_observer->OnAudioStreamStopped(render_process_id_, entry->render_frame_id(), entry->stream_id()); + if (entry->playing()) { + entry->set_playing(false); + base::AtomicRefCountDec(&num_playing_streams_); + } } } } @@ -458,6 +473,8 @@ void AudioRendererHost::DeleteEntry(scoped_ptr entry) { media_observer->OnAudioStreamStopped(render_process_id_, entry->render_frame_id(), entry->stream_id()); + if (entry->playing()) + base::AtomicRefCountDec(&num_playing_streams_); } } @@ -483,4 +500,8 @@ AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { return i != audio_entries_.end() ? i->second : NULL; } +bool AudioRendererHost::HasActiveAudio() { + return !base::AtomicRefCountIsZero(&num_playing_streams_); +} + } // namespace content diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h index 60556ee..38317ef 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.h +++ b/content/browser/renderer_host/media/audio_renderer_host.h @@ -39,6 +39,7 @@ #include +#include "base/atomic_ref_count.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -84,6 +85,10 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { virtual void OnDestruct() const OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + // Returns true if any streams managed by this host are actively playing. Can + // be called from any thread. + bool HasActiveAudio(); + private: friend class AudioRendererHostTest; friend class BrowserThread; @@ -165,6 +170,9 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { // A map of stream IDs to audio sources. AudioEntryMap audio_entries_; + // The number of streams in the playing state. + base::AtomicRefCount num_playing_streams_; + DISALLOW_COPY_AND_ASSIGN(AudioRendererHost); }; diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index ef0fea2..7a6506e 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -1960,6 +1960,10 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) { if (!child_process_launcher_.get() || child_process_launcher_->IsStarting()) return; + // Don't background processes which have active audio streams. + if (backgrounded_ && audio_renderer_host_->HasActiveAudio()) + return; + #if defined(OS_WIN) // The cbstext.dll loads as a global GetMessage hook in the browser process // and intercepts/unintercepts the kernel32 API SetPriorityClass in a -- cgit v1.1