summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/renderer_host/media/audio_sync_reader.cc21
-rw-r--r--content/browser/renderer_host/media/audio_sync_reader.h1
-rw-r--r--media/audio/audio_io.h12
-rw-r--r--media/audio/audio_output_controller.cc25
-rw-r--r--media/audio/audio_output_controller.h6
-rw-r--r--media/audio/audio_output_resampler.cc26
-rw-r--r--media/audio/win/waveout_output_win.cc8
7 files changed, 52 insertions, 47 deletions
diff --git a/content/browser/renderer_host/media/audio_sync_reader.cc b/content/browser/renderer_host/media/audio_sync_reader.cc
index 037f568..0730ec2 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.cc
+++ b/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -8,15 +8,10 @@
#include "base/process_util.h"
#include "base/shared_memory.h"
-#include "base/threading/platform_thread.h"
#include "media/audio/audio_buffers_state.h"
#include "media/audio/audio_parameters.h"
#include "media/audio/shared_memory_util.h"
-#if defined(OS_WIN)
-const int kMinIntervalBetweenReadCallsInMs = 10;
-#endif
-
using media::AudioBus;
namespace content {
@@ -62,22 +57,6 @@ void AudioSyncReader::UpdatePendingBytes(uint32 bytes) {
}
int AudioSyncReader::Read(AudioBus* source, AudioBus* dest) {
-#if defined(OS_WIN)
- // HACK: yield if reader is called too often.
- // Problem is lack of synchronization between host and renderer. We cannot be
- // sure if renderer already filled the buffer, and due to all the plugins we
- // cannot change the API, so we yield if previous call was too recent.
- // Optimization: if renderer is "new" one that writes length of data we can
- // stop yielding the moment length is written -- not ideal solution,
- // but better than nothing.
- while (!DataReady() &&
- ((base::Time::Now() - previous_call_time_).InMilliseconds() <
- kMinIntervalBetweenReadCallsInMs)) {
- base::PlatformThread::YieldCurrentThread();
- }
- previous_call_time_ = base::Time::Now();
-#endif
-
// Copy optional synchronized live audio input for consumption by renderer
// process.
if (source && input_bus_.get()) {
diff --git a/content/browser/renderer_host/media/audio_sync_reader.h b/content/browser/renderer_host/media/audio_sync_reader.h
index 5cb5e8f..b2c3b1f 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.h
+++ b/content/browser/renderer_host/media/audio_sync_reader.h
@@ -47,7 +47,6 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
private:
base::SharedMemory* shared_memory_;
- base::Time previous_call_time_;
// Number of input channels for synchronized I/O.
int input_channels_;
diff --git a/media/audio/audio_io.h b/media/audio/audio_io.h
index cfc71bd..e7b9a36 100644
--- a/media/audio/audio_io.h
+++ b/media/audio/audio_io.h
@@ -74,14 +74,10 @@ class MEDIA_EXPORT AudioOutputStream {
// 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.
+ // Deprecated. DO NOT USE. Waits until data becomes available. Used only
+ // by Windows' WaveOut clients which may be extremely laggy. Will yield the
+ // current thread until the renderer client has written its audio data or
+ // 1.5 seconds have elapsed.
virtual void WaitTillDataReady() {}
protected:
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
index f21da8f..50850c9 100644
--- a/media/audio/audio_output_controller.cc
+++ b/media/audio/audio_output_controller.cc
@@ -11,6 +11,7 @@
#include "base/threading/platform_thread.h"
#include "base/threading/thread_restrictions.h"
#include "base/time.h"
+#include "build/build_config.h"
#include "media/audio/shared_memory_util.h"
using base::Time;
@@ -319,17 +320,21 @@ int AudioOutputController::OnMoreIOData(AudioBus* source,
}
void AudioOutputController::WaitTillDataReady() {
- if (!sync_reader_->DataReady()) {
- // In the different place we use different mechanism to poll, get max
- // polling delay from constants used there.
- const base::TimeDelta kMaxPollingDelay = TimeDelta::FromMilliseconds(
- kPollNumAttempts * kPollPauseInMilliseconds);
- Time start_time = Time::Now();
- do {
- base::PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
- } while (!sync_reader_->DataReady() &&
- Time::Now() - start_time < kMaxPollingDelay);
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ base::Time start = base::Time::Now();
+ // Wait for up to 1.5 seconds for DataReady(). 1.5 seconds was chosen because
+ // it's larger than the playback time of the WaveOut buffer size using the
+ // minimum supported sample rate: 4096 / 3000 = ~1.4 seconds. Even a client
+ // expecting real time playout should be able to fill in this time.
+ const base::TimeDelta max_wait = base::TimeDelta::FromMilliseconds(1500);
+ while (!sync_reader_->DataReady() &&
+ ((base::Time::Now() - start) < max_wait)) {
+ base::PlatformThread::YieldCurrentThread();
}
+#else
+ // WaitTillDataReady() is deprecated and should not be used.
+ CHECK(false);
+#endif
}
void AudioOutputController::OnError(AudioOutputStream* stream, int code) {
diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h
index 3dae719..762a948 100644
--- a/media/audio/audio_output_controller.h
+++ b/media/audio/audio_output_controller.h
@@ -102,11 +102,7 @@ class MEDIA_EXPORT AudioOutputController
// Close this synchronous reader.
virtual void Close() = 0;
- // Poll if data is ready.
- // Not reliable, as there is no guarantee that renderer is "new-style"
- // renderer that writes metadata into buffer. After several unsuccessful
- // attempts caller should assume the data is ready even if that function
- // returns false.
+ // Check if data is ready.
virtual bool DataReady() = 0;
};
diff --git a/media/audio/audio_output_resampler.cc b/media/audio/audio_output_resampler.cc
index baad88a..4734e40 100644
--- a/media/audio/audio_output_resampler.cc
+++ b/media/audio/audio_output_resampler.cc
@@ -11,6 +11,7 @@
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/time.h"
+#include "build/build_config.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_output_dispatcher_impl.h"
#include "media/audio/audio_output_proxy.h"
@@ -20,6 +21,10 @@
#include "media/base/limits.h"
#include "media/base/media_switches.h"
+#if defined(OS_WIN)
+#include "media/audio/win/core_audio_util_win.h"
+#endif
+
namespace media {
class OnMoreDataConverter
@@ -72,6 +77,10 @@ class OnMoreDataConverter
// parameters.
AudioConverter audio_converter_;
+ // If we're using WaveOut on Windows' we always have to wait for DataReady()
+ // before calling |source_callback_|.
+ bool waveout_wait_hack_;
+
DISALLOW_COPY_AND_ASSIGN(OnMoreDataConverter);
};
@@ -278,10 +287,22 @@ OnMoreDataConverter::OnMoreDataConverter(const AudioParameters& input_params,
: source_callback_(NULL),
source_bus_(NULL),
input_bytes_per_second_(input_params.GetBytesPerSecond()),
- audio_converter_(input_params, output_params, false) {
+ audio_converter_(input_params, output_params, false),
+ waveout_wait_hack_(false) {
io_ratio_ =
static_cast<double>(input_params.GetBytesPerSecond()) /
output_params.GetBytesPerSecond();
+
+ // TODO(dalecurtis): We should require all render side clients to use a
+ // buffer size that's a multiple of the hardware buffer size scaled by the
+ // request_sample_rate / hw_sample_rate. Doing so ensures each hardware
+ // request for audio data results in only a single render side callback and
+ // would allow us to remove this hack. See http://crbug.com/162207.
+#if defined(OS_WIN)
+ waveout_wait_hack_ =
+ output_params.format() == AudioParameters::AUDIO_PCM_LINEAR ||
+ !CoreAudioUtil::IsSupported();
+#endif
}
OnMoreDataConverter::~OnMoreDataConverter() {}
@@ -340,6 +361,9 @@ double OnMoreDataConverter::ProvideInput(AudioBus* dest,
io_ratio_ * (current_buffers_state_.total_bytes() +
buffer_delay.InSecondsF() * input_bytes_per_second_);
+ if (waveout_wait_hack_)
+ source_callback_->WaitTillDataReady();
+
// Retrieve data from the original callback.
int frames = source_callback_->OnMoreIOData(
source_bus_, dest, new_buffers_state);
diff --git a/media/audio/win/waveout_output_win.cc b/media/audio/win/waveout_output_win.cc
index 5e56169..f18b2fa 100644
--- a/media/audio/win/waveout_output_win.cc
+++ b/media/audio/win/waveout_output_win.cc
@@ -76,7 +76,6 @@ inline WAVEHDR* PCMWaveOutAudioOutputStream::GetBuffer(int n) const {
return reinterpret_cast<WAVEHDR*>(&buffers_[n * BufferSize()]);
}
-
PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream(
AudioManagerWin* manager, const AudioParameters& params, int num_buffers,
UINT device_id)
@@ -342,6 +341,13 @@ 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));