diff options
author | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-23 04:27:27 +0000 |
---|---|---|
committer | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-23 04:27:27 +0000 |
commit | 98e55e8c3281fbf5a18e99b48a1bd67428a0a8e5 (patch) | |
tree | a5034e244f5e232f23356a0d8a217bc1f6da7f9b /media/filters | |
parent | 302f319da5df35548bc967d3dd491e65caaaf10e (diff) | |
download | chromium_src-98e55e8c3281fbf5a18e99b48a1bd67428a0a8e5.zip chromium_src-98e55e8c3281fbf5a18e99b48a1bd67428a0a8e5.tar.gz chromium_src-98e55e8c3281fbf5a18e99b48a1bd67428a0a8e5.tar.bz2 |
Update current time and pipeline of time update on first audio buffer.
Previously we always waited until the 2nd audio buffer before
firing Pipeline::OnAudioTimeUpdate(). This causes the first time
update to be delayed according to the audio buffer size, which is
awkward.
Instead, notify the pipeline on the first audio buffer to avoid the
extra latency incurred while waiting for the next buffer.
BUG=365470
TEST=new unittest.
Review URL: https://codereview.chromium.org/245963002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@265538 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/filters')
-rw-r--r-- | media/filters/audio_renderer_impl.cc | 15 | ||||
-rw-r--r-- | media/filters/audio_renderer_impl_unittest.cc | 33 |
2 files changed, 42 insertions, 6 deletions
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc index dd88527..4f71d3d 100644 --- a/media/filters/audio_renderer_impl.cc +++ b/media/filters/audio_renderer_impl.cc @@ -601,6 +601,7 @@ int AudioRendererImpl::Render(AudioBus* audio_bus, // 3) We are in the kPlaying state // // Otherwise the buffer has data we can send to the device. + const base::TimeDelta time_before_filling = algorithm_->GetTime(); frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); if (frames_written == 0) { const base::TimeTicks now = now_cb_.Run(); @@ -626,16 +627,15 @@ int AudioRendererImpl::Render(AudioBus* audio_bus, weak_factory_.GetWeakPtr())); } + // Adjust the delay according to playback rate. + base::TimeDelta adjusted_playback_delay = base::TimeDelta::FromMicroseconds( + ceil(playback_delay.InMicroseconds() * playback_rate)); + // The |audio_time_buffered_| is the ending timestamp of the last frame // buffered at the audio device. |playback_delay| is the amount of time // buffered at the audio device. The current time can be computed by their // difference. if (audio_time_buffered_ != kNoTimestamp()) { - // Adjust the delay according to playback rate. - base::TimeDelta adjusted_playback_delay = - base::TimeDelta::FromMicroseconds(ceil( - playback_delay.InMicroseconds() * playback_rate)); - base::TimeDelta previous_time = current_time_; current_time_ = audio_time_buffered_ - adjusted_playback_delay; @@ -656,6 +656,11 @@ int AudioRendererImpl::Render(AudioBus* audio_bus, if (current_time_ > previous_time && !rendered_end_of_stream_) { current_time = current_time_; } + } else if (frames_written > 0) { + // Nothing has been buffered yet, so use the first buffer's timestamp. + DCHECK(time_before_filling != kNoTimestamp()); + current_time_ = current_time = + time_before_filling - adjusted_playback_delay; } // The call to FillBuffer() on |algorithm_| has increased the amount of diff --git a/media/filters/audio_renderer_impl_unittest.cc b/media/filters/audio_renderer_impl_unittest.cc index 208e6e8..1ae27e3 100644 --- a/media/filters/audio_renderer_impl_unittest.cc +++ b/media/filters/audio_renderer_impl_unittest.cc @@ -60,7 +60,8 @@ class AudioRendererImplTest : public ::testing::Test { : hardware_config_(AudioParameters(), AudioParameters()), needs_stop_(true), demuxer_stream_(DemuxerStream::AUDIO), - decoder_(new MockAudioDecoder()) { + decoder_(new MockAudioDecoder()), + last_time_update_(kNoTimestamp()) { AudioDecoderConfig audio_config(kCodec, kSampleFormat, kChannelLayout, @@ -122,6 +123,7 @@ class AudioRendererImplTest : public ::testing::Test { void OnAudioTimeCallback(TimeDelta current_time, TimeDelta max_time) { CHECK(current_time <= max_time); + last_time_update_ = current_time; } void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) { @@ -432,6 +434,10 @@ class AudioRendererImplTest : public ::testing::Test { return renderer_->splicer_->HasNextBuffer(); } + base::TimeDelta last_time_update() const { + return last_time_update_; + } + // Fixture members. base::MessageLoop message_loop_; scoped_ptr<AudioRendererImpl> renderer_; @@ -500,6 +506,7 @@ class AudioRendererImplTest : public ::testing::Test { base::Closure stop_decoder_cb_; PipelineStatusCB init_decoder_cb_; + base::TimeDelta last_time_update_; DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest); }; @@ -949,4 +956,28 @@ TEST_F(AudioRendererImplTest, ConfigChangeDrainsConverter) { EXPECT_EQ(0, converter_input_frames_left()); } +TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) { + Initialize(); + Preroll(); + Play(); + + AudioTimestampHelper timestamp_helper(kOutputSamplesPerSecond); + EXPECT_EQ(kNoTimestamp(), last_time_update()); + + // Preroll() should be buffered some data, consume half of it now. + const int kFramesToConsume = frames_buffered() / 2; + EXPECT_TRUE(ConsumeBufferedData(kFramesToConsume, NULL)); + WaitForPendingRead(); + + // Ensure we received a time update for the first buffer and it's zero. + timestamp_helper.SetBaseTimestamp(base::TimeDelta()); + EXPECT_EQ(timestamp_helper.base_timestamp(), last_time_update()); + timestamp_helper.AddFrames(kFramesToConsume); + + // ConsumeBufferedData() uses an audio delay of zero, so the next buffer + // should have a timestamp equal to the duration of |kFramesToConsume|. + EXPECT_TRUE(ConsumeBufferedData(frames_buffered(), NULL)); + EXPECT_EQ(timestamp_helper.GetTimestamp(), last_time_update()); +} + } // namespace media |