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
parent 675c847d
...@@ -61,6 +61,9 @@ class AudioRendererHost::AudioEntry ...@@ -61,6 +61,9 @@ class AudioRendererHost::AudioEntry
return reader_.get(); return reader_.get();
} }
bool playing() const { return playing_; }
void set_playing(bool playing) { playing_ = playing; }
private: private:
// media::AudioOutputController::EventHandler implementation. // media::AudioOutputController::EventHandler implementation.
virtual void OnCreated() OVERRIDE; virtual void OnCreated() OVERRIDE;
...@@ -85,6 +88,8 @@ class AudioRendererHost::AudioEntry ...@@ -85,6 +88,8 @@ class AudioRendererHost::AudioEntry
// The AudioOutputController that manages the audio stream. // The AudioOutputController that manages the audio stream.
const scoped_refptr<media::AudioOutputController> controller_; const scoped_refptr<media::AudioOutputController> controller_;
bool playing_;
}; };
AudioRendererHost::AudioEntry::AudioEntry( AudioRendererHost::AudioEntry::AudioEntry(
...@@ -106,7 +111,8 @@ AudioRendererHost::AudioEntry::AudioEntry( ...@@ -106,7 +111,8 @@ AudioRendererHost::AudioEntry::AudioEntry(
this, this,
params, params,
output_device_id, output_device_id,
reader_.get())) { reader_.get())),
playing_(false) {
DCHECK(controller_.get()); DCHECK(controller_.get());
} }
...@@ -127,7 +133,8 @@ AudioRendererHost::AudioRendererHost( ...@@ -127,7 +133,8 @@ AudioRendererHost::AudioRendererHost(
mirroring_manager_(mirroring_manager), mirroring_manager_(mirroring_manager),
audio_log_(media_internals->CreateAudioLog( audio_log_(media_internals->CreateAudioLog(
media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), 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(audio_manager_);
DCHECK(media_stream_manager_); DCHECK(media_stream_manager_);
} }
...@@ -275,10 +282,18 @@ void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, ...@@ -275,10 +282,18 @@ void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
entry->stream_id(), entry->stream_id(),
base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip,
entry->controller())); entry->controller()));
if (!entry->playing()) {
entry->set_playing(true);
base::AtomicRefCountInc(&num_playing_streams_);
}
} else { } else {
media_observer->OnAudioStreamStopped(render_process_id_, media_observer->OnAudioStreamStopped(render_process_id_,
entry->render_frame_id(), entry->render_frame_id(),
entry->stream_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<AudioEntry> entry) { ...@@ -458,6 +473,8 @@ void AudioRendererHost::DeleteEntry(scoped_ptr<AudioEntry> entry) {
media_observer->OnAudioStreamStopped(render_process_id_, media_observer->OnAudioStreamStopped(render_process_id_,
entry->render_frame_id(), entry->render_frame_id(),
entry->stream_id()); entry->stream_id());
if (entry->playing())
base::AtomicRefCountDec(&num_playing_streams_);
} }
} }
...@@ -483,4 +500,8 @@ AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { ...@@ -483,4 +500,8 @@ AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
return i != audio_entries_.end() ? i->second : NULL; return i != audio_entries_.end() ? i->second : NULL;
} }
bool AudioRendererHost::HasActiveAudio() {
return !base::AtomicRefCountIsZero(&num_playing_streams_);
}
} // namespace content } // namespace content
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <map> #include <map>
#include "base/atomic_ref_count.h"
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
...@@ -84,6 +85,10 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { ...@@ -84,6 +85,10 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
virtual void OnDestruct() const OVERRIDE; virtual void OnDestruct() const OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message) 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: private:
friend class AudioRendererHostTest; friend class AudioRendererHostTest;
friend class BrowserThread; friend class BrowserThread;
...@@ -165,6 +170,9 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { ...@@ -165,6 +170,9 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter {
// A map of stream IDs to audio sources. // A map of stream IDs to audio sources.
AudioEntryMap audio_entries_; AudioEntryMap audio_entries_;
// The number of streams in the playing state.
base::AtomicRefCount num_playing_streams_;
DISALLOW_COPY_AND_ASSIGN(AudioRendererHost); DISALLOW_COPY_AND_ASSIGN(AudioRendererHost);
}; };
......
...@@ -1960,6 +1960,10 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) { ...@@ -1960,6 +1960,10 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) {
if (!child_process_launcher_.get() || child_process_launcher_->IsStarting()) if (!child_process_launcher_.get() || child_process_launcher_->IsStarting())
return; return;
// Don't background processes which have active audio streams.
if (backgrounded_ && audio_renderer_host_->HasActiveAudio())
return;
#if defined(OS_WIN) #if defined(OS_WIN)
// The cbstext.dll loads as a global GetMessage hook in the browser process // The cbstext.dll loads as a global GetMessage hook in the browser process
// and intercepts/unintercepts the kernel32 API SetPriorityClass in a // and intercepts/unintercepts the kernel32 API SetPriorityClass in a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment