summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/renderer_host/media/audio_sync_reader.cc32
-rw-r--r--content/browser/renderer_host/media/audio_sync_reader.h11
-rw-r--r--media/audio/audio_io.h4
-rw-r--r--media/audio/audio_low_latency_input_output_unittest.cc1
-rw-r--r--media/audio/audio_output_controller.cc91
-rw-r--r--media/audio/audio_output_controller.h47
-rw-r--r--media/audio/audio_output_controller_unittest.cc12
-rw-r--r--media/audio/audio_output_resampler.cc7
-rw-r--r--media/audio/linux/alsa_output.cc4
-rw-r--r--media/audio/pulse/pulse_input.cc3
-rw-r--r--media/audio/pulse/pulse_output.cc1
-rw-r--r--media/audio/pulse/pulse_unified.cc1
-rw-r--r--media/audio/virtual_audio_output_stream.cc4
-rw-r--r--media/audio/win/waveout_output_win.cc11
14 files changed, 73 insertions, 156 deletions
diff --git a/content/browser/renderer_host/media/audio_sync_reader.cc b/content/browser/renderer_host/media/audio_sync_reader.cc
index 9ebf5ed..39fc80d1 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.cc
+++ b/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -68,11 +68,15 @@ void AudioSyncReader::UpdatePendingBytes(uint32 bytes) {
}
}
-int AudioSyncReader::Read(AudioBus* source, AudioBus* dest) {
+int AudioSyncReader::Read(bool block, const AudioBus* source, AudioBus* dest) {
++renderer_callback_count_;
- if (!DataReady())
+ if (!DataReady()) {
++renderer_missed_callback_count_;
+ if (block)
+ WaitTillDataReady();
+ }
+
// Copy optional synchronized live audio input for consumption by renderer
// process.
if (source && input_bus_) {
@@ -162,4 +166,28 @@ bool AudioSyncReader::PrepareForeignSocketHandle(
}
#endif
+void AudioSyncReader::WaitTillDataReady() {
+ base::TimeTicks start = base::TimeTicks::Now();
+ const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(20);
+#if defined(OS_WIN)
+ // Sleep(0) on Windows lets the other threads run.
+ const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(0);
+#else
+ // We want to sleep for a bit here, as otherwise a backgrounded renderer won't
+ // get enough cpu to send the data and the high priority thread in the browser
+ // will use up a core causing even more skips.
+ const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(2);
+#endif
+ base::TimeDelta time_since_start;
+ do {
+ base::PlatformThread::Sleep(kSleep);
+ time_since_start = base::TimeTicks::Now() - start;
+ } while (!DataReady() && time_since_start < kMaxWait);
+ UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
+ time_since_start,
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMilliseconds(1000),
+ 50);
+}
+
} // namespace content
diff --git a/content/browser/renderer_host/media/audio_sync_reader.h b/content/browser/renderer_host/media/audio_sync_reader.h
index 1f07b20..80f7b62 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.h
+++ b/content/browser/renderer_host/media/audio_sync_reader.h
@@ -33,9 +33,10 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
// media::AudioOutputController::SyncReader implementations.
virtual void UpdatePendingBytes(uint32 bytes) OVERRIDE;
- virtual int Read(media::AudioBus* source, media::AudioBus* dest) OVERRIDE;
+ virtual int Read(bool block,
+ const media::AudioBus* source,
+ media::AudioBus* dest) OVERRIDE;
virtual void Close() OVERRIDE;
- virtual bool DataReady() OVERRIDE;
bool Init();
bool PrepareForeignSocketHandle(base::ProcessHandle process_handle,
@@ -46,6 +47,12 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
#endif
private:
+ // Indicates whether the renderer has data available for reading.
+ bool DataReady();
+
+ // Blocks until DataReady() is true or a timeout expires.
+ void WaitTillDataReady();
+
base::SharedMemory* shared_memory_;
// Number of input channels for synchronized I/O.
diff --git a/media/audio/audio_io.h b/media/audio/audio_io.h
index 0f3f673..473af0d 100644
--- a/media/audio/audio_io.h
+++ b/media/audio/audio_io.h
@@ -73,10 +73,6 @@ class MEDIA_EXPORT AudioOutputStream {
// playback will not continue.
virtual void OnError(AudioOutputStream* stream) = 0;
- // Will block until the client has written its audio data or 1.5 seconds
- // have elapsed.
- virtual void WaitTillDataReady() {}
-
protected:
virtual ~AudioSourceCallback() {}
};
diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc
index 4dd22ab..f4aeab4 100644
--- a/media/audio/audio_low_latency_input_output_unittest.cc
+++ b/media/audio/audio_low_latency_input_output_unittest.cc
@@ -258,7 +258,6 @@ class FullDuplexAudioSinkSource
}
virtual void OnError(AudioOutputStream* stream) OVERRIDE {}
- virtual void WaitTillDataReady() OVERRIDE {}
protected:
// Converts from bytes to milliseconds taking the sample rate and size
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
index 8e33c7f..aea6440 100644
--- a/media/audio/audio_output_controller.cc
+++ b/media/audio/audio_output_controller.cc
@@ -52,8 +52,7 @@ AudioOutputController::AudioOutputController(AudioManager* audio_manager,
num_allowed_io_(0),
sync_reader_(sync_reader),
message_loop_(audio_manager->GetMessageLoop()),
- number_polling_attempts_left_(0),
- weak_this_(this) {
+ number_polling_attempts_left_(0) {
DCHECK(audio_manager);
DCHECK(handler_);
DCHECK(sync_reader_);
@@ -149,52 +148,16 @@ void AudioOutputController::DoCreate(bool is_for_device_change) {
void AudioOutputController::DoPlay() {
DCHECK(message_loop_->BelongsToCurrentThread());
+ SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
// We can start from created or paused state.
if (state_ != kCreated && state_ != kPaused)
return;
- state_ = kStarting;
-
// Ask for first packet.
sync_reader_->UpdatePendingBytes(0);
- // Cannot start stream immediately, should give renderer some time
- // to deliver data.
- // TODO(vrk): The polling here and in WaitTillDataReady() is pretty clunky.
- // Refine the API such that polling is no longer needed. (crbug.com/112196)
- number_polling_attempts_left_ = kPollNumAttempts;
- DCHECK(!weak_this_.HasWeakPtrs());
- message_loop_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&AudioOutputController::PollAndStartIfDataReady,
- weak_this_.GetWeakPtr()),
- TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
-}
-
-void AudioOutputController::PollAndStartIfDataReady() {
- DCHECK(message_loop_->BelongsToCurrentThread());
- SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioOutputController.PlayTime");
-
- DCHECK_EQ(kStarting, state_);
-
- // If we are ready to start the stream, start it.
- if (--number_polling_attempts_left_ == 0 ||
- sync_reader_->DataReady()) {
- StartStream();
- } else {
- message_loop_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&AudioOutputController::PollAndStartIfDataReady,
- weak_this_.GetWeakPtr()),
- TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
- }
-}
-
-void AudioOutputController::StartStream() {
- DCHECK(message_loop_->BelongsToCurrentThread());
state_ = kPlaying;
-
silence_detector_.reset(new AudioSilenceDetector(
params_.sample_rate(),
TimeDelta::FromMilliseconds(kQuestionableSilencePeriodMillis),
@@ -214,11 +177,7 @@ void AudioOutputController::StartStream() {
void AudioOutputController::StopStream() {
DCHECK(message_loop_->BelongsToCurrentThread());
- if (state_ == kStarting) {
- // Cancel in-progress polling start.
- weak_this_.InvalidateWeakPtrs();
- state_ = kPaused;
- } else if (state_ == kPlaying) {
+ if (state_ == kPlaying) {
stream_->Stop();
DisallowEntryToOnMoreIOData();
silence_detector_->Stop(true);
@@ -262,7 +221,6 @@ void AudioOutputController::DoSetVolume(double volume) {
switch (state_) {
case kCreated:
- case kStarting:
case kPlaying:
case kPaused:
stream_->SetVolume(volume_);
@@ -291,15 +249,23 @@ int AudioOutputController::OnMoreIOData(AudioBus* source,
// The OS level audio APIs on Linux and Windows all have problems requesting
// data on a fixed interval. Sometimes they will issue calls back to back
- // which can cause glitching, so wait until the renderer is ready for Read().
+ // which can cause glitching, so wait until the renderer is ready.
+ //
+ // We also need to wait when diverting since the virtual stream will call this
+ // multiple times without waiting.
+ //
+ // NEVER wait on OSX unless a virtual stream is connected, otherwise we can
+ // end up hanging the entire OS.
//
// See many bugs for context behind this decision: http://crbug.com/170498,
// http://crbug.com/171651, http://crbug.com/174985, and more.
#if defined(OS_WIN) || defined(OS_LINUX)
- WaitTillDataReady();
+ const bool kShouldBlock = true;
+#else
+ const bool kShouldBlock = diverting_to_stream_ != NULL;
#endif
- const int frames = sync_reader_->Read(source, dest);
+ const int frames = sync_reader_->Read(kShouldBlock, source, dest);
DCHECK_LE(0, frames);
sync_reader_->UpdatePendingBytes(
buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
@@ -310,34 +276,6 @@ int AudioOutputController::OnMoreIOData(AudioBus* source,
return frames;
}
-void AudioOutputController::WaitTillDataReady() {
- // Most of the time the data is ready already.
- if (sync_reader_->DataReady())
- return;
-
- base::TimeTicks start = base::TimeTicks::Now();
- const base::TimeDelta kMaxWait = base::TimeDelta::FromMilliseconds(20);
-#if defined(OS_WIN)
- // Sleep(0) on windows lets the other threads run.
- const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(0);
-#else
- // We want to sleep for a bit here, as otherwise a backgrounded renderer won't
- // get enough cpu to send the data and the high priority thread in the browser
- // will use up a core causing even more skips.
- const base::TimeDelta kSleep = base::TimeDelta::FromMilliseconds(2);
-#endif
- base::TimeDelta time_since_start;
- do {
- base::PlatformThread::Sleep(kSleep);
- time_since_start = base::TimeTicks::Now() - start;
- } while (!sync_reader_->DataReady() && (time_since_start < kMaxWait));
- UMA_HISTOGRAM_CUSTOM_TIMES("Media.AudioOutputControllerDataNotReady",
- time_since_start,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMilliseconds(1000),
- 50);
-}
-
void AudioOutputController::OnError(AudioOutputStream* stream) {
// Handle error on the audio controller thread.
message_loop_->PostTask(FROM_HERE, base::Bind(
@@ -381,7 +319,6 @@ void AudioOutputController::OnDeviceChange() {
// Get us back to the original state or an equivalent state.
switch (original_state) {
- case kStarting:
case kPlaying:
DoPlay();
return;
diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h
index 1e56633..93acc27 100644
--- a/media/audio/audio_output_controller.h
+++ b/media/audio/audio_output_controller.h
@@ -9,9 +9,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
#include "base/timer.h"
-#include "media/audio/audio_buffers_state.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_manager.h"
#include "media/audio/audio_source_diverter.h"
@@ -28,14 +26,14 @@
//
// Here is a state transition diagram for the AudioOutputController:
//
-// *[ Empty ] --> [ Created ] --> [ Starting ] --> [ Playing ] --.
-// | | | ^ | |
-// | | | | | |
-// | | | | v |
-// | | | `--------- [ Paused ] |
-// | | | | |
-// | v v | |
-// `-----------> [ Closed ] <-------------------------'
+// *[ Empty ] --> [ Created ] --> [ Playing ] -------.
+// | | | ^ |
+// | | | | |
+// | | | | v
+// | | | `----- [ Paused ]
+// | | | |
+// | v v |
+// `-----------> [ Closed ] <-----------'
//
// * Initial state
//
@@ -51,9 +49,6 @@
// AudioSourceCallback interface. AudioOutputController uses the SyncReader
// passed to it via construction to synchronously fulfill this read request.
//
-// Since AudioOutputController uses AudioManager's message loop the controller
-// uses WeakPtr to allow safe cancellation of pending tasks.
-//
namespace media {
@@ -93,16 +88,14 @@ class MEDIA_EXPORT AudioOutputController
// prepare more data and perform synchronization.
virtual void UpdatePendingBytes(uint32 bytes) = 0;
- // Attempt to completely fill |dest|, return the actual number of
- // frames that could be read.
- // |source| may optionally be provided for input data.
- virtual int Read(AudioBus* source, AudioBus* dest) = 0;
+ // Attempt to completely fill |dest|, return the actual number of frames
+ // that could be read. |source| may optionally be provided for input data.
+ // If |block| is specified, the Read() will block until data is available
+ // or a timeout is reached.
+ virtual int Read(bool block, const AudioBus* source, AudioBus* dest) = 0;
// Close this synchronous reader.
virtual void Close() = 0;
-
- // Check if data is ready.
- virtual bool DataReady() = 0;
};
// Factory method for creating an AudioOutputController.
@@ -142,9 +135,6 @@ class MEDIA_EXPORT AudioOutputController
AudioBus* dest,
AudioBuffersState buffers_state) OVERRIDE;
virtual void OnError(AudioOutputStream* stream) OVERRIDE;
- // Deprecated: Currently only used for starting audio playback and for audio
- // mirroring.
- virtual void WaitTillDataReady() OVERRIDE;
// AudioDeviceListener implementation. When called AudioOutputController will
// shutdown the existing |stream_|, transition to the kRecreating state,
@@ -162,7 +152,6 @@ class MEDIA_EXPORT AudioOutputController
enum State {
kEmpty,
kCreated,
- kStarting,
kPlaying,
kPaused,
kClosed,
@@ -185,7 +174,6 @@ class MEDIA_EXPORT AudioOutputController
// The following methods are executed on the audio manager thread.
void DoCreate(bool is_for_device_change);
void DoPlay();
- void PollAndStartIfDataReady();
void DoPause();
void DoClose();
void DoSetVolume(double volume);
@@ -197,8 +185,7 @@ class MEDIA_EXPORT AudioOutputController
// silence and call EventHandler::OnAudible() when state changes occur.
void MaybeInvokeAudibleCallback();
- // Helper methods that start/stop physical stream.
- void StartStream();
+ // Helper method that stops the physical stream.
void StopStream();
// Helper method that stops, closes, and NULLs |*stream_|.
@@ -216,8 +203,6 @@ class MEDIA_EXPORT AudioOutputController
// Used by the unified IO to open the correct input device.
std::string input_device_id_;
- // Note: It's important to invalidate the weak pointers whenever stream_ is
- // changed. See comment for weak_this_.
AudioOutputStream* stream_;
// When non-NULL, audio is being diverted to this stream.
@@ -248,10 +233,6 @@ class MEDIA_EXPORT AudioOutputController
// Number of times left.
int number_polling_attempts_left_;
- // Used to auto-cancel the delayed tasks that are created to poll for data
- // (when starting-up a stream).
- base::WeakPtrFactory<AudioOutputController> weak_this_;
-
// Scans audio samples from OnMoreIOData() as input and causes
// EventHandler::OnAudbile() to be called whenever a transition to a period of
// silence or non-silence is detected.
diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc
index c2630b0..ab4f652 100644
--- a/media/audio/audio_output_controller_unittest.cc
+++ b/media/audio/audio_output_controller_unittest.cc
@@ -55,9 +55,8 @@ class MockAudioOutputControllerSyncReader
MockAudioOutputControllerSyncReader() {}
MOCK_METHOD1(UpdatePendingBytes, void(uint32 bytes));
- MOCK_METHOD2(Read, int(AudioBus* source, AudioBus* dest));
+ MOCK_METHOD3(Read, int(bool block, const AudioBus* source, AudioBus* dest));
MOCK_METHOD0(Close, void());
- MOCK_METHOD0(DataReady, bool());
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioOutputControllerSyncReader);
@@ -86,10 +85,10 @@ ACTION_P(SignalEvent, event) {
static const float kBufferNonZeroData = 1.0f;
ACTION(PopulateBuffer) {
- arg1->Zero();
+ arg2->Zero();
// Note: To confirm the buffer will be populated in these tests, it's
// sufficient that only the first float in channel 0 is set to the value.
- arg1->channel(0)[0] = kBufferNonZeroData;
+ arg2->channel(0)[0] = kBufferNonZeroData;
}
class AudioOutputControllerTest : public testing::Test {
@@ -142,13 +141,10 @@ class AudioOutputControllerTest : public testing::Test {
// sent from the render process.
EXPECT_CALL(mock_sync_reader_, UpdatePendingBytes(_))
.Times(AtLeast(1));
- EXPECT_CALL(mock_sync_reader_, Read(_, _))
+ EXPECT_CALL(mock_sync_reader_, Read(_, _, _))
.WillRepeatedly(DoAll(PopulateBuffer(),
SignalEvent(&read_event_),
Return(params_.frames_per_buffer())));
- EXPECT_CALL(mock_sync_reader_, DataReady())
- .WillRepeatedly(Return(true));
-
controller_->Play();
}
diff --git a/media/audio/audio_output_resampler.cc b/media/audio/audio_output_resampler.cc
index ea1848e..ad12d27 100644
--- a/media/audio/audio_output_resampler.cc
+++ b/media/audio/audio_output_resampler.cc
@@ -36,7 +36,6 @@ class OnMoreDataConverter
AudioBus* dest,
AudioBuffersState buffers_state) OVERRIDE;
virtual void OnError(AudioOutputStream* stream) OVERRIDE;
- virtual void WaitTillDataReady() OVERRIDE;
// Sets |source_callback_|. If this is not a new object, then Stop() must be
// called before Start().
@@ -393,10 +392,4 @@ void OnMoreDataConverter::OnError(AudioOutputStream* stream) {
source_callback_->OnError(stream);
}
-void OnMoreDataConverter::WaitTillDataReady() {
- base::AutoLock auto_lock(source_lock_);
- if (source_callback_)
- source_callback_->WaitTillDataReady();
-}
-
} // namespace media
diff --git a/media/audio/linux/alsa_output.cc b/media/audio/linux/alsa_output.cc
index 3c2520e..9058555 100644
--- a/media/audio/linux/alsa_output.cc
+++ b/media/audio/linux/alsa_output.cc
@@ -744,10 +744,8 @@ int AlsaPcmOutputStream::RunDataCallback(AudioBus* audio_bus,
AudioBuffersState buffers_state) {
TRACE_EVENT0("audio", "AlsaPcmOutputStream::RunDataCallback");
- if (source_callback_) {
- source_callback_->WaitTillDataReady();
+ if (source_callback_)
return source_callback_->OnMoreData(audio_bus, buffers_state);
- }
return 0;
}
diff --git a/media/audio/pulse/pulse_input.cc b/media/audio/pulse/pulse_input.cc
index c365c47..cc62085 100644
--- a/media/audio/pulse/pulse_input.cc
+++ b/media/audio/pulse/pulse_input.cc
@@ -278,8 +278,7 @@ void PulseAudioInputStream::ReadData() {
if (buffer_->forward_bytes() < packet_size)
break;
- // TODO(xians): improve the code by implementing a WaitTillDataReady on the
- // input side.
+ // TODO(xians): Remove once PPAPI is using circular buffers.
DVLOG(1) << "OnData is being called consecutively, sleep 5ms to "
<< "wait until render consumes the data";
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5));
diff --git a/media/audio/pulse/pulse_output.cc b/media/audio/pulse/pulse_output.cc
index 1734954..99ede3b 100644
--- a/media/audio/pulse/pulse_output.cc
+++ b/media/audio/pulse/pulse_output.cc
@@ -129,7 +129,6 @@ void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) {
uint32 hardware_delay = pulse::GetHardwareLatencyInBytes(
pa_stream_, params_.sample_rate(),
params_.GetBytesPerFrame());
- source_callback_->WaitTillDataReady();
frames_filled = source_callback_->OnMoreData(
audio_bus_.get(), AudioBuffersState(0, hardware_delay));
}
diff --git a/media/audio/pulse/pulse_unified.cc b/media/audio/pulse/pulse_unified.cc
index ee14341..cfa55a2 100644
--- a/media/audio/pulse/pulse_unified.cc
+++ b/media/audio/pulse/pulse_unified.cc
@@ -157,7 +157,6 @@ void PulseAudioUnifiedStream::WriteData(size_t requested_bytes) {
uint32 hardware_delay = pulse::GetHardwareLatencyInBytes(
output_stream_, params_.sample_rate(),
params_.GetBytesPerFrame());
- source_callback_->WaitTillDataReady();
fifo_->Read(input_data_buffer_.get(), requested_bytes);
input_bus_->FromInterleaved(
input_data_buffer_.get(), params_.frames_per_buffer(), 2);
diff --git a/media/audio/virtual_audio_output_stream.cc b/media/audio/virtual_audio_output_stream.cc
index 005fbc2..254a70a 100644
--- a/media/audio/virtual_audio_output_stream.cc
+++ b/media/audio/virtual_audio_output_stream.cc
@@ -74,10 +74,6 @@ double VirtualAudioOutputStream::ProvideInput(AudioBus* audio_bus,
DCHECK(message_loop_->BelongsToCurrentThread());
DCHECK(callback_);
- // A VirtualAudioInputStream with a larger buffer size may be calling this
- // multiple times without waiting, so we need to block and ensure the data is
- // ready to prevent glitching.
- callback_->WaitTillDataReady();
const int frames = callback_->OnMoreData(audio_bus, AudioBuffersState());
if (frames < audio_bus->frames())
audio_bus->ZeroFramesPartial(frames, audio_bus->frames() - frames);
diff --git a/media/audio/win/waveout_output_win.cc b/media/audio/win/waveout_output_win.cc
index 9b03c31..47d4fa6 100644
--- a/media/audio/win/waveout_output_win.cc
+++ b/media/audio/win/waveout_output_win.cc
@@ -204,10 +204,6 @@ void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) {
pending_bytes_ = 0;
for (int ix = 0; ix != num_buffers_; ++ix) {
WAVEHDR* buffer = GetBuffer(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;
}
@@ -343,13 +339,6 @@ void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) {
// return to us how many bytes were used.
// TODO(fbarchard): Handle used 0 by queueing more.
- // HACK: Yield if Read() is called too often. On older platforms which are
- // still using the WaveOut backend, we run into synchronization issues where
- // the renderer has not finished filling the shared memory when Read() is
- // called. Reading too early will lead to clicks and pops. See issues:
- // http://crbug.com/161307 and http://crbug.com/61022
- callback_->WaitTillDataReady();
-
// TODO(sergeyu): Specify correct hardware delay for AudioBuffersState.
int frames_filled = callback_->OnMoreData(
audio_bus_.get(), AudioBuffersState(pending_bytes_, 0));