diff options
author | davej@chromium.org <davej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-14 23:34:00 +0000 |
---|---|---|
committer | davej@chromium.org <davej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-14 23:34:00 +0000 |
commit | 4841a4bde07696cad73224a0c7e28ea9343c9e1c (patch) | |
tree | 5750fda34ee1ed66d1a17b5e78bed0cf0630ba22 /media/audio/audio_output_dispatcher.cc | |
parent | fb930c854c9d3d984411eb6be45242af793943b3 (diff) | |
download | chromium_src-4841a4bde07696cad73224a0c7e28ea9343c9e1c.zip chromium_src-4841a4bde07696cad73224a0c7e28ea9343c9e1c.tar.gz chromium_src-4841a4bde07696cad73224a0c7e28ea9343c9e1c.tar.bz2 |
Fix erratic HTML5 audio playback
This was affecting all platforms. The major issue was that he SetPlaybackRate(1) which is used to start playback was being done in the middle of the series of Seek operations. So doing Seek() followed by SetPlaybackRate(1) was done, the Seek could immediately stop the playback. To fix, Seek() was made atomic with regards to SetPlaybackRate() by delaying the execution of SetPlaybackRate until after the Seek sequence has completely finished.
To make things run even smoother, a short delay was added before recyclilng a used audio stream in the Dispatcher. This gives the stream time to 'power down' before being reused.
Tested on Linux, Chrome-OS (Cr48) and Mac with great results, making HTML5 audio much more usable for games.
BUG=73045,59369,59370,65618
TEST=Manual, Quickly playing/stopping HTML5 audio should play cleanly.
Review URL: http://codereview.chromium.org/6822019
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81670 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio/audio_output_dispatcher.cc')
-rw-r--r-- | media/audio/audio_output_dispatcher.cc | 53 |
1 files changed, 39 insertions, 14 deletions
diff --git a/media/audio/audio_output_dispatcher.cc b/media/audio/audio_output_dispatcher.cc index 3f9d848..c707069 100644 --- a/media/audio/audio_output_dispatcher.cc +++ b/media/audio/audio_output_dispatcher.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,7 @@ #include "base/compiler_specific.h" #include "base/message_loop.h" +#include "base/time.h" #include "media/audio/audio_io.h" AudioOutputDispatcher::AudioOutputDispatcher( @@ -14,6 +15,8 @@ AudioOutputDispatcher::AudioOutputDispatcher( : audio_manager_(audio_manager), message_loop_(audio_manager->GetMessageLoop()), params_(params), + pause_delay_milliseconds_(2 * params.samples_per_packet * + base::Time::kMillisecondsPerSecond / params.sample_rate), paused_proxies_(0), ALLOW_THIS_IN_INITIALIZER_LIST(close_timer_( base::TimeDelta::FromMilliseconds(close_delay_ms), @@ -28,7 +31,7 @@ bool AudioOutputDispatcher::StreamOpened() { paused_proxies_++; // Ensure that there is at least one open stream. - if (streams_.empty() && !CreateAndOpenStream()) { + if (idle_streams_.empty() && !CreateAndOpenStream()) { return false; } @@ -40,12 +43,12 @@ bool AudioOutputDispatcher::StreamOpened() { AudioOutputStream* AudioOutputDispatcher::StreamStarted() { DCHECK_EQ(MessageLoop::current(), message_loop_); - if (streams_.empty() && !CreateAndOpenStream()) { + if (idle_streams_.empty() && !CreateAndOpenStream()) { return NULL; } - AudioOutputStream* stream = streams_.back(); - streams_.pop_back(); + AudioOutputStream* stream = idle_streams_.back(); + idle_streams_.pop_back(); DCHECK_GT(paused_proxies_, 0u); paused_proxies_--; @@ -61,20 +64,41 @@ AudioOutputStream* AudioOutputDispatcher::StreamStarted() { void AudioOutputDispatcher::StreamStopped(AudioOutputStream* stream) { DCHECK_EQ(MessageLoop::current(), message_loop_); + paused_proxies_++; - streams_.push_back(stream); + + pausing_streams_.push_front(stream); close_timer_.Reset(); + + // Don't recycle stream until two buffers worth of time has elapsed. + message_loop_->PostDelayedTask( + FROM_HERE, + NewRunnableMethod(this, &AudioOutputDispatcher::StopStreamTask), + pause_delay_milliseconds_); +} + +void AudioOutputDispatcher::StopStreamTask() { + if (pausing_streams_.empty()) + return; + AudioOutputStream* stream = pausing_streams_.back(); + pausing_streams_.pop_back(); + idle_streams_.push_back(stream); } void AudioOutputDispatcher::StreamClosed() { DCHECK_EQ(MessageLoop::current(), message_loop_); + while (!pausing_streams_.empty()) { + idle_streams_.push_back(pausing_streams_.back()); + pausing_streams_.pop_back(); + } + DCHECK_GT(paused_proxies_, 0u); paused_proxies_--; - while (streams_.size() > paused_proxies_) { - streams_.back()->Close(); - streams_.pop_back(); + while (idle_streams_.size() > paused_proxies_) { + idle_streams_.back()->Close(); + idle_streams_.pop_back(); } } @@ -92,14 +116,15 @@ bool AudioOutputDispatcher::CreateAndOpenStream() { stream->Close(); return false; } - streams_.push_back(stream); + idle_streams_.push_back(stream); return true; } void AudioOutputDispatcher::OpenTask() { // Make sure that we have at least one stream allocated if there // are paused streams. - if (paused_proxies_ > 0 && streams_.empty()) { + if (paused_proxies_ > 0 && idle_streams_.empty() && + pausing_streams_.empty()) { CreateAndOpenStream(); } @@ -108,8 +133,8 @@ void AudioOutputDispatcher::OpenTask() { // This method is called by |close_timer_|. void AudioOutputDispatcher::ClosePendingStreams() { - while (!streams_.empty()) { - streams_.back()->Close(); - streams_.pop_back(); + while (!idle_streams_.empty()) { + idle_streams_.back()->Close(); + idle_streams_.pop_back(); } } |