summaryrefslogtreecommitdiffstats
path: root/media/filters
diff options
context:
space:
mode:
authordalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-23 04:27:27 +0000
committerdalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-23 04:27:27 +0000
commit98e55e8c3281fbf5a18e99b48a1bd67428a0a8e5 (patch)
treea5034e244f5e232f23356a0d8a217bc1f6da7f9b /media/filters
parent302f319da5df35548bc967d3dd491e65caaaf10e (diff)
downloadchromium_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.cc15
-rw-r--r--media/filters/audio_renderer_impl_unittest.cc33
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