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
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<media::AudioOutputController> 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<AudioEntry> 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
......@@ -39,6 +39,7 @@
#include <map>
#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);
};
......
......@@ -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
......
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