summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-22 23:21:14 +0000
committerdalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-22 23:21:14 +0000
commit3167a14f5a2a73afa9774b92faf4016b633f6366 (patch)
tree7eb39bb4f6f64a93df8977271b37e1295e5319a2
parent86c65310708e4de9c4b552302d665427a6a53d3f (diff)
downloadchromium_src-3167a14f5a2a73afa9774b92faf4016b633f6366.zip
chromium_src-3167a14f5a2a73afa9774b92faf4016b633f6366.tar.gz
chromium_src-3167a14f5a2a73afa9774b92faf4016b633f6366.tar.bz2
Scale audio delay information in AudioRendererMixer.
Converts the audio delay information into the scale expected by the underlying audio renderer mixer input. Similar to what is already done in AudioOutputResampler. bytes_per_ms = channels * bytes_per_channel * frames_per_second / 1000; bytes_per_buffer = channels * bytes_per_channel * frames_per_buffer; delay_ms = bytes_per_buffer / bytes_per_ms ... delay_ms = frames_per_buffer * 1000 / frames_per_second Which means we just want to include the sample rate in the scaling. BUG=133637 TEST=playback is in sync, tests work fine. Review URL: https://chromiumcodereview.appspot.com/11231031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@163435 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/base/audio_renderer_mixer.cc28
-rw-r--r--media/base/audio_renderer_mixer.h4
-rw-r--r--media/base/audio_renderer_mixer_unittest.cc22
-rw-r--r--media/base/fake_audio_render_callback.cc4
-rw-r--r--media/base/fake_audio_render_callback.h5
5 files changed, 51 insertions, 12 deletions
diff --git a/media/base/audio_renderer_mixer.cc b/media/base/audio_renderer_mixer.cc
index e48b171..4df2eea 100644
--- a/media/base/audio_renderer_mixer.cc
+++ b/media/base/audio_renderer_mixer.cc
@@ -17,19 +17,23 @@ AudioRendererMixer::AudioRendererMixer(
const AudioParameters& input_params, const AudioParameters& output_params,
const scoped_refptr<AudioRendererSink>& sink)
: audio_sink_(sink),
- current_audio_delay_milliseconds_(0) {
- // Sanity check sample rates.
- DCHECK_LE(input_params.sample_rate(), limits::kMaxSampleRate);
- DCHECK_GE(input_params.sample_rate(), limits::kMinSampleRate);
- DCHECK_LE(output_params.sample_rate(), limits::kMaxSampleRate);
- DCHECK_GE(output_params.sample_rate(), limits::kMinSampleRate);
+ current_audio_delay_milliseconds_(0),
+ io_ratio_(1),
+ input_ms_per_frame_(
+ static_cast<double>(base::Time::kMillisecondsPerSecond) /
+ input_params.sample_rate()) {
+ DCHECK(input_params.IsValid());
+ DCHECK(output_params.IsValid());
+
+ // Channel mixing is handled by the browser side currently.
+ DCHECK_EQ(input_params.channels(), output_params.channels());
// Only resample if necessary since it's expensive.
if (input_params.sample_rate() != output_params.sample_rate()) {
+ io_ratio_ = input_params.sample_rate() /
+ static_cast<double>(output_params.sample_rate());
resampler_.reset(new MultiChannelResampler(
- output_params.channels(),
- input_params.sample_rate() / static_cast<double>(
- output_params.sample_rate()),
+ output_params.channels(), io_ratio_,
base::Bind(&AudioRendererMixer::ProvideInput, base::Unretained(this))));
}
@@ -60,7 +64,7 @@ void AudioRendererMixer::RemoveMixerInput(
int AudioRendererMixer::Render(AudioBus* audio_bus,
int audio_delay_milliseconds) {
- current_audio_delay_milliseconds_ = audio_delay_milliseconds;
+ current_audio_delay_milliseconds_ = audio_delay_milliseconds / io_ratio_;
if (resampler_.get())
resampler_->Resample(audio_bus, audio_bus->frames());
@@ -117,6 +121,10 @@ void AudioRendererMixer::ProvideInput(AudioBus* audio_bus) {
audio_bus->channel(i));
}
}
+
+ // Update the delay estimate.
+ current_audio_delay_milliseconds_ +=
+ audio_bus->frames() * input_ms_per_frame_;
}
void AudioRendererMixer::OnRenderError() {
diff --git a/media/base/audio_renderer_mixer.h b/media/base/audio_renderer_mixer.h
index c595c0d..7bb85af 100644
--- a/media/base/audio_renderer_mixer.h
+++ b/media/base/audio_renderer_mixer.h
@@ -61,6 +61,10 @@ class MEDIA_EXPORT AudioRendererMixer
// The audio delay in milliseconds received by the last Render() call.
int current_audio_delay_milliseconds_;
+ // Ratio of input data to output data. Used to scale audio delay information.
+ double io_ratio_;
+ double input_ms_per_frame_;
+
DISALLOW_COPY_AND_ASSIGN(AudioRendererMixer);
};
diff --git a/media/base/audio_renderer_mixer_unittest.cc b/media/base/audio_renderer_mixer_unittest.cc
index a37cd69..09fe8d4 100644
--- a/media/base/audio_renderer_mixer_unittest.cc
+++ b/media/base/audio_renderer_mixer_unittest.cc
@@ -24,7 +24,7 @@ static const int kMixerInputs = 8;
static const int kMixerCycles = 3;
// Parameters used for testing.
-static const int kBitsPerChannel = 16;
+static const int kBitsPerChannel = 32;
static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
static const int kHighLatencyBufferSize = 8192;
static const int kLowLatencyBufferSize = 256;
@@ -388,6 +388,26 @@ TEST_P(AudioRendererMixerTest, OnRenderError) {
mixer_inputs_[i]->Stop();
}
+// Verify that audio delay information is scaled to the input parameters.
+TEST_P(AudioRendererMixerTest, DelayTest) {
+ InitializeInputs(1);
+ static const int kAudioDelayMilliseconds = 100;
+ ASSERT_EQ(mixer_inputs_.size(), 1u);
+
+ // Start the input and issue a single render callback.
+ mixer_inputs_[0]->Start();
+ mixer_inputs_[0]->Play();
+ mixer_callback_->Render(audio_bus_.get(), kAudioDelayMilliseconds);
+
+ // The input to output ratio should only include the sample rate difference.
+ double io_ratio = input_parameters_.sample_rate() /
+ static_cast<double>(output_parameters_.sample_rate());
+
+ EXPECT_EQ(static_cast<int>(kAudioDelayMilliseconds / io_ratio),
+ fake_callbacks_[0]->last_audio_delay_milliseconds());
+ mixer_inputs_[0]->Stop();
+}
+
INSTANTIATE_TEST_CASE_P(
AudioRendererMixerTest, AudioRendererMixerTest, testing::Values(
// No resampling.
diff --git a/media/base/fake_audio_render_callback.cc b/media/base/fake_audio_render_callback.cc
index 6adf569..65b6ac9 100644
--- a/media/base/fake_audio_render_callback.cc
+++ b/media/base/fake_audio_render_callback.cc
@@ -13,7 +13,8 @@ namespace media {
FakeAudioRenderCallback::FakeAudioRenderCallback(double step)
: half_fill_(false),
- step_(step) {
+ step_(step),
+ last_audio_delay_milliseconds_(-1) {
reset();
}
@@ -21,6 +22,7 @@ FakeAudioRenderCallback::~FakeAudioRenderCallback() {}
int FakeAudioRenderCallback::Render(AudioBus* audio_bus,
int audio_delay_milliseconds) {
+ last_audio_delay_milliseconds_ = audio_delay_milliseconds;
int number_of_frames = audio_bus->frames();
if (half_fill_)
number_of_frames /= 2;
diff --git a/media/base/fake_audio_render_callback.h b/media/base/fake_audio_render_callback.h
index f6ce104..760e39d 100644
--- a/media/base/fake_audio_render_callback.h
+++ b/media/base/fake_audio_render_callback.h
@@ -31,10 +31,15 @@ class FakeAudioRenderCallback : public AudioRendererSink::RenderCallback {
// Reset the sine state to initial value.
void reset() { x_ = 0; }
+ // Returns the last |audio_delay_milliseconds| provided to Render() or -1 if
+ // no Render() call occurred.
+ int last_audio_delay_milliseconds() { return last_audio_delay_milliseconds_; }
+
private:
bool half_fill_;
double x_;
double step_;
+ int last_audio_delay_milliseconds_;
DISALLOW_COPY_AND_ASSIGN(FakeAudioRenderCallback);
};