Skip to content

Commit

Permalink
Scale audio delay information in AudioRendererMixer.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
dalecurtis@chromium.org committed Oct 22, 2012
1 parent 86c6531 commit 3167a14
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 12 deletions.
28 changes: 18 additions & 10 deletions media/base/audio_renderer_mixer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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))));
}

Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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() {
Expand Down
4 changes: 4 additions & 0 deletions media/base/audio_renderer_mixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

Expand Down
22 changes: 21 additions & 1 deletion media/base/audio_renderer_mixer_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion media/base/fake_audio_render_callback.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ namespace media {

FakeAudioRenderCallback::FakeAudioRenderCallback(double step)
: half_fill_(false),
step_(step) {
step_(step),
last_audio_delay_milliseconds_(-1) {
reset();
}

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;
Expand Down
5 changes: 5 additions & 0 deletions media/base/fake_audio_render_callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down

0 comments on commit 3167a14

Please sign in to comment.