diff options
author | enal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-09 01:46:04 +0000 |
---|---|---|
committer | enal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-09 01:46:04 +0000 |
commit | 552a01e6eef2a1344c0c80285732bcd0661d9868 (patch) | |
tree | 70b010f747cd6d85583a428ff2f821a7168b4d9c | |
parent | bef1ee3f79388f87c3c88ac1a726522a2b65ca36 (diff) | |
download | chromium_src-552a01e6eef2a1344c0c80285732bcd0661d9868.zip chromium_src-552a01e6eef2a1344c0c80285732bcd0661d9868.tar.gz chromium_src-552a01e6eef2a1344c0c80285732bcd0661d9868.tar.bz2 |
Implement polling for data becoming ready when starting audio stream.
Before the change we had polling for 1st buffer but not for subsequent ones. Do it in simplest possible way -- poll and sleep in the loop. It is probably not the best approach, but simplest and most reliable. We had lot of problems adding polling for 1st buffer in the existing message loop, do not want to introduce new message loop where we had not such loop before. In any case loop usually is not executed, otherwise we would have more audible glitches when starting the stream.
Windows and Mac only change, we have only single buffer on Linux.
TEST=Start playing HTML5 audio on extremely busy Win/MAC
TEST=system with single core. Before the change you will
TEST=almost always here the glitch in the beginning.
TEST=That should become much more rare now.
Review URL: http://codereview.chromium.org/8496022
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109162 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/audio/audio_io.h | 10 | ||||
-rw-r--r-- | media/audio/audio_output_controller.cc | 17 | ||||
-rw-r--r-- | media/audio/audio_output_controller.h | 9 | ||||
-rw-r--r-- | media/audio/mac/audio_output_mac.cc | 7 | ||||
-rw-r--r-- | media/audio/win/waveout_output_win.cc | 4 |
5 files changed, 44 insertions, 3 deletions
diff --git a/media/audio/audio_io.h b/media/audio/audio_io.h index 3069eaa..173f4f5 100644 --- a/media/audio/audio_io.h +++ b/media/audio/audio_io.h @@ -72,6 +72,16 @@ class MEDIA_EXPORT AudioOutputStream { // playback will not continue. |code| is an error code that is platform // specific. virtual void OnError(AudioOutputStream* stream, int code) = 0; + + // Waits till data becomes available. Used when buffering data starting + // new audio stream. + // Polling is not the best approach, but incorporating messaging loop + // with delayed tasks into guts of complex code is even worse, as it is + // very error-prone. We cannot easily add synchronization, interface is + // already cut in stone because of need of backward compatibility with + // plugins. In any case, data is usually immediately available, + // so there would be no delay. + virtual void WaitTillDataReady() {} }; virtual ~AudioOutputStream() {} diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index adad10a..b83aa61 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -7,6 +7,10 @@ #include "base/bind.h" #include "base/debug/trace_event.h" #include "base/message_loop.h" +#include "base/threading/platform_thread.h" +#include "base/time.h" + +using base::Time; namespace media { @@ -359,6 +363,19 @@ uint32 AudioOutputController::OnMoreData( return size; } +void AudioOutputController::WaitTillDataReady() { + if (LowLatencyMode() && !sync_reader_->DataReady()) { + // In the different place we use different mechanism to poll, get max + // polling delay from constants used there. + const int kMaxPollingDelayMs = kPollNumAttempts * kPollPauseInMilliseconds; + Time start_time = Time::Now(); + do { + base::PlatformThread::Sleep(1); + } while (!sync_reader_->DataReady() && + (Time::Now() - start_time).InMilliseconds() < kMaxPollingDelayMs); + } +} + void AudioOutputController::OnError(AudioOutputStream* stream, int code) { // Handle error on the audio controller thread. message_loop_->PostTask(FROM_HERE, base::Bind( diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h index ea8f27a..d60af07 100644 --- a/media/audio/audio_output_controller.h +++ b/media/audio/audio_output_controller.h @@ -161,9 +161,12 @@ class MEDIA_EXPORT AudioOutputController /////////////////////////////////////////////////////////////////////////// // AudioSourceCallback methods. - virtual uint32 OnMoreData(AudioOutputStream* stream, uint8* dest, - uint32 max_size, AudioBuffersState buffers_state); - virtual void OnError(AudioOutputStream* stream, int code); + virtual uint32 OnMoreData(AudioOutputStream* stream, + uint8* dest, + uint32 max_size, + AudioBuffersState buffers_state) OVERRIDE; + virtual void OnError(AudioOutputStream* stream, int code) OVERRIDE; + virtual void WaitTillDataReady() OVERRIDE; protected: // Internal state of the source. diff --git a/media/audio/mac/audio_output_mac.cc b/media/audio/mac/audio_output_mac.cc index 02e8c63..7fbed99 100644 --- a/media/audio/mac/audio_output_mac.cc +++ b/media/audio/mac/audio_output_mac.cc @@ -485,6 +485,13 @@ void PCMQueueOutAudioOutputStream::Start(AudioSourceCallback* callback) { // Ask the source to pre-fill all our buffers before playing. for (uint32 ix = 0; ix != kNumBuffers; ++ix) { buffer_[ix]->mAudioDataByteSize = 0; + // Caller waits for 1st packet to become available, but not for others, + // so we wait for them here. + if (ix != 0) { + AudioSourceCallback* source = GetSource(); + if (source) + source->WaitTillDataReady(); + } RenderCallback(this, NULL, buffer_[ix]); } diff --git a/media/audio/win/waveout_output_win.cc b/media/audio/win/waveout_output_win.cc index 288c026..f8446cb 100644 --- a/media/audio/win/waveout_output_win.cc +++ b/media/audio/win/waveout_output_win.cc @@ -185,6 +185,10 @@ void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) { pending_bytes_ = 0; WAVEHDR* buffer = buffer_; for (int ix = 0; ix != num_buffers_; ++ix) { + // Caller waits for 1st packet to become available, but not for others, + // so we wait for them here. + if (ix != 0) + callback_->WaitTillDataReady(); QueueNextPacket(buffer); // Read more data. pending_bytes_ += buffer->dwBufferLength; buffer = GetNextBuffer(buffer); |