Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / media / base / pipeline_unittest.cc
index 45cc73b..4eb84f6 100644 (file)
@@ -10,7 +10,6 @@
 #include "base/test/simple_test_tick_clock.h"
 #include "base/threading/simple_thread.h"
 #include "base/time/clock.h"
-#include "media/base/clock.h"
 #include "media/base/fake_text_track_stream.h"
 #include "media/base/gmock_callback_support.h"
 #include "media/base/media_log.h"
@@ -19,6 +18,7 @@
 #include "media/base/test_helpers.h"
 #include "media/base/text_renderer.h"
 #include "media/base/text_track_config.h"
+#include "media/base/time_delta_interpolator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/size.h"
 
@@ -51,6 +51,10 @@ ACTION_P2(SetError, pipeline, status) {
   pipeline->SetErrorForTesting(status);
 }
 
+ACTION_P2(SetBufferingState, cb, buffering_state) {
+  cb->Run(buffering_state);
+}
+
 // Used for setting expectations on pipeline callbacks.  Using a StrictMock
 // also lets us test for missing callbacks.
 class CallbackHelper {
@@ -64,7 +68,7 @@ class CallbackHelper {
   MOCK_METHOD0(OnEnded, void());
   MOCK_METHOD1(OnError, void(PipelineStatus));
   MOCK_METHOD1(OnMetadata, void(PipelineMetadata));
-  MOCK_METHOD0(OnPrerollCompleted, void());
+  MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
   MOCK_METHOD0(OnDurationChange, void());
 
  private:
@@ -83,14 +87,14 @@ class PipelineTest : public ::testing::Test {
       : pipeline_(new Pipeline(message_loop_.message_loop_proxy(),
                                new MediaLog())),
         filter_collection_(new FilterCollection()),
-        demuxer_(new MockDemuxer()) {
+        demuxer_(new StrictMock<MockDemuxer>()) {
     filter_collection_->SetDemuxer(demuxer_.get());
 
-    video_renderer_ = new MockVideoRenderer();
+    video_renderer_ = new StrictMock<MockVideoRenderer>();
     scoped_ptr<VideoRenderer> video_renderer(video_renderer_);
     filter_collection_->SetVideoRenderer(video_renderer.Pass());
 
-    audio_renderer_ = new MockAudioRenderer();
+    audio_renderer_ = new StrictMock<MockAudioRenderer>();
     scoped_ptr<AudioRenderer> audio_renderer(audio_renderer_);
     filter_collection_->SetAudioRenderer(audio_renderer.Pass());
 
@@ -101,15 +105,12 @@ class PipelineTest : public ::testing::Test {
     scoped_ptr<TextRenderer> text_renderer(text_renderer_);
     filter_collection_->SetTextRenderer(text_renderer.Pass());
 
-    // InitializeDemuxer() adds overriding expectations for expected non-NULL
-    // streams.
+    // SetDemuxerExpectations() adds overriding expectations for expected
+    // non-NULL streams.
     DemuxerStream* null_pointer = NULL;
     EXPECT_CALL(*demuxer_, GetStream(_))
         .WillRepeatedly(Return(null_pointer));
 
-    EXPECT_CALL(*demuxer_, GetStartTime())
-        .WillRepeatedly(Return(base::TimeDelta()));
-
     EXPECT_CALL(*demuxer_, GetTimelineOffset())
         .WillRepeatedly(Return(base::Time()));
 
@@ -121,7 +122,7 @@ class PipelineTest : public ::testing::Test {
     if (!pipeline_ || !pipeline_->IsRunning())
       return;
 
-    ExpectStop();
+    ExpectDemuxerStop();
 
     // The mock demuxer doesn't stop the fake text track stream,
     // so just stop it manually.
@@ -131,17 +132,23 @@ class PipelineTest : public ::testing::Test {
     }
 
     // Expect a stop callback if we were started.
-    EXPECT_CALL(callbacks_, OnStop());
+    ExpectPipelineStopAndDestroyPipeline();
     pipeline_->Stop(base::Bind(&CallbackHelper::OnStop,
                                base::Unretained(&callbacks_)));
     message_loop_.RunUntilIdle();
   }
 
+  void OnDemuxerError() {
+    // Cast because OnDemuxerError is private in Pipeline.
+    static_cast<DemuxerHost*>(pipeline_.get())
+        ->OnDemuxerError(PIPELINE_ERROR_ABORT);
+  }
+
  protected:
   // Sets up expectations to allow the demuxer to initialize.
   typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector;
-  void InitializeDemuxer(MockDemuxerStreamVector* streams,
-                         const base::TimeDelta& duration) {
+  void SetDemuxerExpectations(MockDemuxerStreamVector* streams,
+                              const base::TimeDelta& duration) {
     EXPECT_CALL(callbacks_, OnDurationChange());
     EXPECT_CALL(*demuxer_, Initialize(_, _, _))
         .WillOnce(DoAll(SetDemuxerProperties(duration),
@@ -155,9 +162,9 @@ class PipelineTest : public ::testing::Test {
     }
   }
 
-  void InitializeDemuxer(MockDemuxerStreamVector* streams) {
+  void SetDemuxerExpectations(MockDemuxerStreamVector* streams) {
     // Initialize with a default non-zero duration.
-    InitializeDemuxer(streams, base::TimeDelta::FromSeconds(10));
+    SetDemuxerExpectations(streams, base::TimeDelta::FromSeconds(10));
   }
 
   scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream(
@@ -168,22 +175,19 @@ class PipelineTest : public ::testing::Test {
   }
 
   // Sets up expectations to allow the video renderer to initialize.
-  void InitializeVideoRenderer(DemuxerStream* stream) {
-    EXPECT_CALL(*video_renderer_, Initialize(stream, _, _, _, _, _, _, _, _))
-        .WillOnce(RunCallback<2>(PIPELINE_OK));
-    EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
-
-    // Startup sequence.
-    EXPECT_CALL(*video_renderer_, Preroll(demuxer_->GetStartTime(), _))
-        .WillOnce(RunCallback<1>(PIPELINE_OK));
-    EXPECT_CALL(*video_renderer_, Play(_))
-        .WillOnce(RunClosure<0>());
+  void SetVideoRendererExpectations(DemuxerStream* stream) {
+    EXPECT_CALL(*video_renderer_, Initialize(stream, _, _, _, _, _, _, _, _, _))
+        .WillOnce(DoAll(SaveArg<5>(&video_buffering_state_cb_),
+                        SaveArg<6>(&video_ended_cb_),
+                        RunCallback<2>(PIPELINE_OK)));
   }
 
   // Sets up expectations to allow the audio renderer to initialize.
-  void InitializeAudioRenderer(DemuxerStream* stream) {
+  void SetAudioRendererExpectations(DemuxerStream* stream) {
     EXPECT_CALL(*audio_renderer_, Initialize(stream, _, _, _, _, _, _))
-        .WillOnce(DoAll(SaveArg<4>(&audio_time_cb_),
+        .WillOnce(DoAll(SaveArg<3>(&audio_time_cb_),
+                        SaveArg<4>(&audio_buffering_state_cb_),
+                        SaveArg<5>(&audio_ended_cb_),
                         RunCallback<1>(PIPELINE_OK)));
   }
 
@@ -194,24 +198,33 @@ class PipelineTest : public ::testing::Test {
                               TextTrackConfig(kTextSubtitles, "", "", ""));
   }
 
-  // Sets up expectations on the callback and initializes the pipeline.  Called
+  // Sets up expectations on the callback and initializes the pipeline. Called
   // after tests have set expectations any filters they wish to use.
-  void InitializePipeline(PipelineStatus start_status) {
+  void StartPipeline(PipelineStatus start_status) {
     EXPECT_CALL(callbacks_, OnStart(start_status));
 
     if (start_status == PIPELINE_OK) {
       EXPECT_CALL(callbacks_, OnMetadata(_)).WillOnce(SaveArg<0>(&metadata_));
 
       if (audio_stream_) {
-        EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
+        EXPECT_CALL(*audio_renderer_, GetTimeSource())
+            .WillOnce(Return(&time_source_));
+        EXPECT_CALL(time_source_, SetPlaybackRate(0.0f));
+        EXPECT_CALL(time_source_, SetMediaTime(base::TimeDelta()));
+        EXPECT_CALL(time_source_, StartTicking());
         EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
+        EXPECT_CALL(*audio_renderer_, StartPlaying())
+            .WillOnce(SetBufferingState(&audio_buffering_state_cb_,
+                                        BUFFERING_HAVE_ENOUGH));
+      }
 
-        // Startup sequence.
-        EXPECT_CALL(*audio_renderer_, Preroll(base::TimeDelta(), _))
-            .WillOnce(RunCallback<1>(PIPELINE_OK));
-        EXPECT_CALL(*audio_renderer_, StartRendering());
+      if (video_stream_) {
+        EXPECT_CALL(*video_renderer_, StartPlaying())
+            .WillOnce(SetBufferingState(&video_buffering_state_cb_,
+                                        BUFFERING_HAVE_ENOUGH));
       }
-      EXPECT_CALL(callbacks_, OnPrerollCompleted());
+
+      EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
     }
 
     pipeline_->Start(
@@ -220,7 +233,7 @@ class PipelineTest : public ::testing::Test {
         base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
-        base::Bind(&CallbackHelper::OnPrerollCompleted,
+        base::Bind(&CallbackHelper::OnBufferingStateChange,
                    base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnDurationChange,
                    base::Unretained(&callbacks_)));
@@ -254,36 +267,40 @@ class PipelineTest : public ::testing::Test {
     return text_stream_.get();
   }
 
-  void ExpectSeek(const base::TimeDelta& seek_time) {
+  void ExpectSeek(const base::TimeDelta& seek_time, bool underflowed) {
     // Every filter should receive a call to Seek().
     EXPECT_CALL(*demuxer_, Seek(seek_time, _))
         .WillOnce(RunCallback<1>(PIPELINE_OK));
 
     if (audio_stream_) {
-      EXPECT_CALL(*audio_renderer_, StopRendering());
+      if (!underflowed)
+        EXPECT_CALL(time_source_, StopTicking());
       EXPECT_CALL(*audio_renderer_, Flush(_))
-          .WillOnce(RunClosure<0>());
-      EXPECT_CALL(*audio_renderer_, Preroll(seek_time, _))
-          .WillOnce(RunCallback<1>(PIPELINE_OK));
-      EXPECT_CALL(*audio_renderer_, SetPlaybackRate(_));
+          .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_,
+                                            BUFFERING_HAVE_NOTHING),
+                          RunClosure<0>()));
+      EXPECT_CALL(time_source_, SetMediaTime(seek_time));
+      EXPECT_CALL(time_source_, SetPlaybackRate(_));
+      EXPECT_CALL(time_source_, StartTicking());
+      EXPECT_CALL(*audio_renderer_, StartPlaying())
+          .WillOnce(SetBufferingState(&audio_buffering_state_cb_,
+                                      BUFFERING_HAVE_ENOUGH));
       EXPECT_CALL(*audio_renderer_, SetVolume(_));
-      EXPECT_CALL(*audio_renderer_, StartRendering());
     }
 
     if (video_stream_) {
       EXPECT_CALL(*video_renderer_, Flush(_))
-          .WillOnce(RunClosure<0>());
-      EXPECT_CALL(*video_renderer_, Preroll(seek_time, _))
-          .WillOnce(RunCallback<1>(PIPELINE_OK));
-      EXPECT_CALL(*video_renderer_, SetPlaybackRate(_));
-      EXPECT_CALL(*video_renderer_, Play(_))
-          .WillOnce(RunClosure<0>());
+          .WillOnce(DoAll(SetBufferingState(&video_buffering_state_cb_,
+                                            BUFFERING_HAVE_NOTHING),
+                          RunClosure<0>()));
+      EXPECT_CALL(*video_renderer_, StartPlaying())
+          .WillOnce(SetBufferingState(&video_buffering_state_cb_,
+                                      BUFFERING_HAVE_ENOUGH));
     }
 
-    EXPECT_CALL(callbacks_, OnPrerollCompleted());
-
-    // We expect a successful seek callback.
+    // We expect a successful seek callback followed by a buffering update.
     EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
+    EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
   }
 
   void DoSeek(const base::TimeDelta& seek_time) {
@@ -297,15 +314,23 @@ class PipelineTest : public ::testing::Test {
     EXPECT_EQ(seek_time, pipeline_->GetMediaTime());
   }
 
-  void ExpectStop() {
+  void DestroyPipeline() {
+    // In real code Pipeline could be destroyed on a different thread. All weak
+    // pointers must have been invalidated before the stop callback returns.
+    DCHECK(!pipeline_->HasWeakPtrsForTesting());
+    pipeline_.reset();
+  }
+
+  void ExpectDemuxerStop() {
     if (demuxer_)
       EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
+  }
 
-    if (audio_stream_)
-      EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
-
-    if (video_stream_)
-      EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
+  void ExpectPipelineStopAndDestroyPipeline() {
+    // After the Pipeline is stopped, it could be destroyed any time. Always
+    // destroy the pipeline immediately after OnStop() to test this.
+    EXPECT_CALL(callbacks_, OnStop())
+        .WillOnce(Invoke(this, &PipelineTest::DestroyPipeline));
   }
 
   MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&,
@@ -324,15 +349,20 @@ class PipelineTest : public ::testing::Test {
   scoped_ptr<Pipeline> pipeline_;
 
   scoped_ptr<FilterCollection> filter_collection_;
-  scoped_ptr<MockDemuxer> demuxer_;
-  MockVideoRenderer* video_renderer_;
-  MockAudioRenderer* audio_renderer_;
+  scoped_ptr<StrictMock<MockDemuxer> > demuxer_;
+  StrictMock<MockVideoRenderer>* video_renderer_;
+  StrictMock<MockAudioRenderer>* audio_renderer_;
+  StrictMock<MockTimeSource> time_source_;
   StrictMock<CallbackHelper> text_renderer_callbacks_;
   TextRenderer* text_renderer_;
   scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
   scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
   scoped_ptr<FakeTextTrackStream> text_stream_;
   AudioRenderer::TimeCB audio_time_cb_;
+  BufferingStateCB audio_buffering_state_cb_;
+  BufferingStateCB video_buffering_state_cb_;
+  base::Closure audio_ended_cb_;
+  base::Closure video_ended_cb_;
   VideoDecoderConfig video_decoder_config_;
   PipelineMetadata metadata_;
 
@@ -379,13 +409,12 @@ TEST_F(PipelineTest, NeverInitializes) {
         base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
-        base::Bind(&CallbackHelper::OnPrerollCompleted,
+        base::Bind(&CallbackHelper::OnBufferingStateChange,
                    base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnDurationChange,
                    base::Unretained(&callbacks_)));
   message_loop_.RunUntilIdle();
 
-
   // Because our callback will get executed when the test tears down, we'll
   // verify that nothing has been called, then set our expectation for the call
   // made during tear down.
@@ -393,13 +422,66 @@ TEST_F(PipelineTest, NeverInitializes) {
   EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
 }
 
+TEST_F(PipelineTest, StopWithoutStart) {
+  ExpectPipelineStopAndDestroyPipeline();
+  pipeline_->Stop(
+      base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
+  message_loop_.RunUntilIdle();
+}
+
+TEST_F(PipelineTest, StartThenStopImmediately) {
+  EXPECT_CALL(*demuxer_, Initialize(_, _, _))
+      .WillOnce(RunCallback<1>(PIPELINE_OK));
+  EXPECT_CALL(*demuxer_, Stop(_))
+      .WillOnce(RunClosure<0>());
+
+  EXPECT_CALL(callbacks_, OnStart(_));
+
+  pipeline_->Start(
+      filter_collection_.Pass(),
+      base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
+      base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
+      base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
+      base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
+      base::Bind(&CallbackHelper::OnBufferingStateChange,
+                 base::Unretained(&callbacks_)),
+      base::Bind(&CallbackHelper::OnDurationChange,
+                 base::Unretained(&callbacks_)));
+
+  // Expect a stop callback if we were started.
+  ExpectPipelineStopAndDestroyPipeline();
+  pipeline_->Stop(
+      base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
+  message_loop_.RunUntilIdle();
+}
+
+TEST_F(PipelineTest, DemuxerErrorDuringStop) {
+  CreateAudioStream();
+  MockDemuxerStreamVector streams;
+  streams.push_back(audio_stream());
+
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+
+  StartPipeline(PIPELINE_OK);
+
+  EXPECT_CALL(*demuxer_, Stop(_))
+      .WillOnce(DoAll(InvokeWithoutArgs(this, &PipelineTest::OnDemuxerError),
+                      RunClosure<0>()));
+  ExpectPipelineStopAndDestroyPipeline();
+
+  pipeline_->Stop(
+      base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
+  message_loop_.RunUntilIdle();
+}
+
 TEST_F(PipelineTest, URLNotFound) {
   EXPECT_CALL(*demuxer_, Initialize(_, _, _))
       .WillOnce(RunCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND));
   EXPECT_CALL(*demuxer_, Stop(_))
       .WillOnce(RunClosure<0>());
 
-  InitializePipeline(PIPELINE_ERROR_URL_NOT_FOUND);
+  StartPipeline(PIPELINE_ERROR_URL_NOT_FOUND);
 }
 
 TEST_F(PipelineTest, NoStreams) {
@@ -408,7 +490,7 @@ TEST_F(PipelineTest, NoStreams) {
   EXPECT_CALL(*demuxer_, Stop(_))
       .WillOnce(RunClosure<0>());
 
-  InitializePipeline(PIPELINE_ERROR_COULD_NOT_RENDER);
+  StartPipeline(PIPELINE_ERROR_COULD_NOT_RENDER);
 }
 
 TEST_F(PipelineTest, AudioStream) {
@@ -416,10 +498,10 @@ TEST_F(PipelineTest, AudioStream) {
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeAudioRenderer(audio_stream());
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
 
-  InitializePipeline(PIPELINE_OK);
+  StartPipeline(PIPELINE_OK);
   EXPECT_TRUE(metadata_.has_audio);
   EXPECT_FALSE(metadata_.has_video);
 }
@@ -429,10 +511,10 @@ TEST_F(PipelineTest, VideoStream) {
   MockDemuxerStreamVector streams;
   streams.push_back(video_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeVideoRenderer(video_stream());
+  SetDemuxerExpectations(&streams);
+  SetVideoRendererExpectations(video_stream());
 
-  InitializePipeline(PIPELINE_OK);
+  StartPipeline(PIPELINE_OK);
   EXPECT_FALSE(metadata_.has_audio);
   EXPECT_TRUE(metadata_.has_video);
 }
@@ -444,11 +526,11 @@ TEST_F(PipelineTest, AudioVideoStream) {
   streams.push_back(audio_stream());
   streams.push_back(video_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeAudioRenderer(audio_stream());
-  InitializeVideoRenderer(video_stream());
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+  SetVideoRendererExpectations(video_stream());
 
-  InitializePipeline(PIPELINE_OK);
+  StartPipeline(PIPELINE_OK);
   EXPECT_TRUE(metadata_.has_audio);
   EXPECT_TRUE(metadata_.has_video);
 }
@@ -459,10 +541,10 @@ TEST_F(PipelineTest, VideoTextStream) {
   MockDemuxerStreamVector streams;
   streams.push_back(video_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeVideoRenderer(video_stream());
+  SetDemuxerExpectations(&streams);
+  SetVideoRendererExpectations(video_stream());
 
-  InitializePipeline(PIPELINE_OK);
+  StartPipeline(PIPELINE_OK);
   EXPECT_FALSE(metadata_.has_audio);
   EXPECT_TRUE(metadata_.has_video);
 
@@ -478,11 +560,11 @@ TEST_F(PipelineTest, VideoAudioTextStream) {
   streams.push_back(video_stream());
   streams.push_back(audio_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeVideoRenderer(video_stream());
-  InitializeAudioRenderer(audio_stream());
+  SetDemuxerExpectations(&streams);
+  SetVideoRendererExpectations(video_stream());
+  SetAudioRendererExpectations(audio_stream());
 
-  InitializePipeline(PIPELINE_OK);
+  StartPipeline(PIPELINE_OK);
   EXPECT_TRUE(metadata_.has_audio);
   EXPECT_TRUE(metadata_.has_video);
 
@@ -498,36 +580,58 @@ TEST_F(PipelineTest, Seek) {
   streams.push_back(audio_stream());
   streams.push_back(video_stream());
 
-  InitializeDemuxer(&streams, base::TimeDelta::FromSeconds(3000));
-  InitializeAudioRenderer(audio_stream());
-  InitializeVideoRenderer(video_stream());
+  SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
+  SetAudioRendererExpectations(audio_stream());
+  SetVideoRendererExpectations(video_stream());
 
   // Initialize then seek!
-  InitializePipeline(PIPELINE_OK);
-
-  AddTextStream();
-  message_loop_.RunUntilIdle();
+  StartPipeline(PIPELINE_OK);
 
   // Every filter should receive a call to Seek().
   base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
-  ExpectSeek(expected);
+  ExpectSeek(expected, false);
   DoSeek(expected);
 }
 
+TEST_F(PipelineTest, SeekAfterError) {
+  CreateAudioStream();
+  MockDemuxerStreamVector streams;
+  streams.push_back(audio_stream());
+
+  SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
+  SetAudioRendererExpectations(audio_stream());
+
+  // Initialize then seek!
+  StartPipeline(PIPELINE_OK);
+
+  EXPECT_CALL(*demuxer_, Stop(_))
+      .WillOnce(RunClosure<0>());
+  EXPECT_CALL(callbacks_, OnError(_));
+
+  static_cast<DemuxerHost*>(pipeline_.get())
+      ->OnDemuxerError(PIPELINE_ERROR_ABORT);
+  message_loop_.RunUntilIdle();
+
+  pipeline_->Seek(
+      base::TimeDelta::FromMilliseconds(100),
+      base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
+  message_loop_.RunUntilIdle();
+}
+
 TEST_F(PipelineTest, SetVolume) {
   CreateAudioStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeAudioRenderer(audio_stream());
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
 
   // The audio renderer should receive a call to SetVolume().
   float expected = 0.5f;
   EXPECT_CALL(*audio_renderer_, SetVolume(expected));
 
   // Initialize then set volume!
-  InitializePipeline(PIPELINE_OK);
+  StartPipeline(PIPELINE_OK);
   pipeline_->SetVolume(expected);
 }
 
@@ -537,10 +641,10 @@ TEST_F(PipelineTest, Properties) {
   streams.push_back(video_stream());
 
   const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
-  InitializeDemuxer(&streams, kDuration);
-  InitializeVideoRenderer(video_stream());
+  SetDemuxerExpectations(&streams, kDuration);
+  SetVideoRendererExpectations(video_stream());
 
-  InitializePipeline(PIPELINE_OK);
+  StartPipeline(PIPELINE_OK);
   EXPECT_EQ(kDuration.ToInternalValue(),
             pipeline_->GetMediaDuration().ToInternalValue());
   EXPECT_FALSE(pipeline_->DidLoadingProgress());
@@ -552,10 +656,10 @@ TEST_F(PipelineTest, GetBufferedTimeRanges) {
   streams.push_back(video_stream());
 
   const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
-  InitializeDemuxer(&streams, kDuration);
-  InitializeVideoRenderer(video_stream());
+  SetDemuxerExpectations(&streams, kDuration);
+  SetVideoRendererExpectations(video_stream());
 
-  InitializePipeline(PIPELINE_OK);
+  StartPipeline(PIPELINE_OK);
 
   EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
 
@@ -568,7 +672,7 @@ TEST_F(PipelineTest, GetBufferedTimeRanges) {
   EXPECT_EQ(kDuration / 8, pipeline_->GetBufferedTimeRanges().end(0));
 
   base::TimeDelta kSeekTime = kDuration / 2;
-  ExpectSeek(kSeekTime);
+  ExpectSeek(kSeekTime, false);
   DoSeek(kSeekTime);
 
   EXPECT_FALSE(pipeline_->DidLoadingProgress());
@@ -582,21 +686,21 @@ TEST_F(PipelineTest, EndedCallback) {
   streams.push_back(audio_stream());
   streams.push_back(video_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeAudioRenderer(audio_stream());
-  InitializeVideoRenderer(video_stream());
-  InitializePipeline(PIPELINE_OK);
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+  SetVideoRendererExpectations(video_stream());
+  StartPipeline(PIPELINE_OK);
 
   AddTextStream();
 
   // The ended callback shouldn't run until all renderers have ended.
-  pipeline_->OnAudioRendererEnded();
+  audio_ended_cb_.Run();
   message_loop_.RunUntilIdle();
 
-  pipeline_->OnVideoRendererEnded();
+  video_ended_cb_.Run();
   message_loop_.RunUntilIdle();
 
-  EXPECT_CALL(*audio_renderer_, StopRendering());
+  EXPECT_CALL(time_source_, StopTicking());
   EXPECT_CALL(callbacks_, OnEnded());
   text_stream()->SendEosNotification();
   message_loop_.RunUntilIdle();
@@ -611,20 +715,19 @@ TEST_F(PipelineTest, AudioStreamShorterThanVideo) {
   streams.push_back(audio_stream());
   streams.push_back(video_stream());
 
-  // Replace the clock so we can simulate wall clock time advancing w/o using
-  // Sleep().
-  pipeline_->SetClockForTesting(new Clock(&test_tick_clock_));
+  // Replace what's used for interpolating to simulate wall clock time.
+  pipeline_->SetTimeDeltaInterpolatorForTesting(
+      new TimeDeltaInterpolator(&test_tick_clock_));
 
-  InitializeDemuxer(&streams, duration);
-  InitializeAudioRenderer(audio_stream());
-  InitializeVideoRenderer(video_stream());
-  InitializePipeline(PIPELINE_OK);
+  SetDemuxerExpectations(&streams, duration);
+  SetAudioRendererExpectations(audio_stream());
+  SetVideoRendererExpectations(video_stream());
+  StartPipeline(PIPELINE_OK);
 
   EXPECT_EQ(0, pipeline_->GetMediaTime().ToInternalValue());
 
   float playback_rate = 1.0f;
-  EXPECT_CALL(*video_renderer_, SetPlaybackRate(playback_rate));
-  EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
+  EXPECT_CALL(time_source_, SetPlaybackRate(playback_rate));
   pipeline_->SetPlaybackRate(playback_rate);
   message_loop_.RunUntilIdle();
 
@@ -637,7 +740,7 @@ TEST_F(PipelineTest, AudioStreamShorterThanVideo) {
   EXPECT_EQ(pipeline_->GetMediaTime().ToInternalValue(), start_time);
 
   // Signal end of audio stream.
-  pipeline_->OnAudioRendererEnded();
+  audio_ended_cb_.Run();
   message_loop_.RunUntilIdle();
 
   // Verify that the clock advances.
@@ -646,9 +749,9 @@ TEST_F(PipelineTest, AudioStreamShorterThanVideo) {
   EXPECT_GT(pipeline_->GetMediaTime().ToInternalValue(), start_time);
 
   // Signal end of video stream and make sure OnEnded() callback occurs.
-  EXPECT_CALL(*audio_renderer_, StopRendering());
+  EXPECT_CALL(time_source_, StopTicking());
   EXPECT_CALL(callbacks_, OnEnded());
-  pipeline_->OnVideoRendererEnded();
+  video_ended_cb_.Run();
 }
 
 TEST_F(PipelineTest, ErrorDuringSeek) {
@@ -656,23 +759,23 @@ TEST_F(PipelineTest, ErrorDuringSeek) {
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeAudioRenderer(audio_stream());
-  InitializePipeline(PIPELINE_OK);
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+  StartPipeline(PIPELINE_OK);
 
   float playback_rate = 1.0f;
-  EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
+  EXPECT_CALL(time_source_, SetPlaybackRate(playback_rate));
   pipeline_->SetPlaybackRate(playback_rate);
   message_loop_.RunUntilIdle();
 
   base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
 
   // Preroll() isn't called as the demuxer errors out first.
-  EXPECT_CALL(*audio_renderer_, StopRendering());
+  EXPECT_CALL(time_source_, StopTicking());
   EXPECT_CALL(*audio_renderer_, Flush(_))
-      .WillOnce(RunClosure<0>());
-  EXPECT_CALL(*audio_renderer_, Stop(_))
-      .WillOnce(RunClosure<0>());
+      .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_,
+                                        BUFFERING_HAVE_NOTHING),
+                      RunClosure<0>()));
 
   EXPECT_CALL(*demuxer_, Seek(seek_time, _))
       .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
@@ -709,9 +812,9 @@ TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeAudioRenderer(audio_stream());
-  InitializePipeline(PIPELINE_OK);
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+  StartPipeline(PIPELINE_OK);
 
   // Trigger additional requests on the pipeline during tear down from error.
   base::Callback<void(PipelineStatus)> cb = base::Bind(
@@ -722,11 +825,11 @@ TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
   base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
 
   // Seek() isn't called as the demuxer errors out first.
-  EXPECT_CALL(*audio_renderer_, StopRendering());
+  EXPECT_CALL(time_source_, StopTicking());
   EXPECT_CALL(*audio_renderer_, Flush(_))
-      .WillOnce(RunClosure<0>());
-  EXPECT_CALL(*audio_renderer_, Stop(_))
-      .WillOnce(RunClosure<0>());
+      .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_,
+                                        BUFFERING_HAVE_NOTHING),
+                      RunClosure<0>()));
 
   EXPECT_CALL(*demuxer_, Seek(seek_time, _))
       .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
@@ -739,43 +842,6 @@ TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
   message_loop_.RunUntilIdle();
 }
 
-TEST_F(PipelineTest, StartTimeIsZero) {
-  CreateVideoStream();
-  MockDemuxerStreamVector streams;
-  streams.push_back(video_stream());
-
-  const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
-  InitializeDemuxer(&streams, kDuration);
-  InitializeVideoRenderer(video_stream());
-
-  InitializePipeline(PIPELINE_OK);
-  EXPECT_FALSE(metadata_.has_audio);
-  EXPECT_TRUE(metadata_.has_video);
-
-  EXPECT_EQ(base::TimeDelta(), pipeline_->GetMediaTime());
-}
-
-TEST_F(PipelineTest, StartTimeIsNonZero) {
-  const base::TimeDelta kStartTime = base::TimeDelta::FromSeconds(4);
-  const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
-
-  EXPECT_CALL(*demuxer_, GetStartTime())
-      .WillRepeatedly(Return(kStartTime));
-
-  CreateVideoStream();
-  MockDemuxerStreamVector streams;
-  streams.push_back(video_stream());
-
-  InitializeDemuxer(&streams, kDuration);
-  InitializeVideoRenderer(video_stream());
-
-  InitializePipeline(PIPELINE_OK);
-  EXPECT_FALSE(metadata_.has_audio);
-  EXPECT_TRUE(metadata_.has_video);
-
-  EXPECT_EQ(kStartTime, pipeline_->GetMediaTime());
-}
-
 static void RunTimeCB(const AudioRenderer::TimeCB& time_cb,
                        int time_in_ms,
                        int max_time_in_ms) {
@@ -788,12 +854,12 @@ TEST_F(PipelineTest, AudioTimeUpdateDuringSeek) {
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
 
-  InitializeDemuxer(&streams);
-  InitializeAudioRenderer(audio_stream());
-  InitializePipeline(PIPELINE_OK);
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+  StartPipeline(PIPELINE_OK);
 
   float playback_rate = 1.0f;
-  EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
+  EXPECT_CALL(time_source_, SetPlaybackRate(playback_rate));
   pipeline_->SetPlaybackRate(playback_rate);
   message_loop_.RunUntilIdle();
 
@@ -812,17 +878,21 @@ TEST_F(PipelineTest, AudioTimeUpdateDuringSeek) {
       .WillOnce(DoAll(InvokeWithoutArgs(&closure, &base::Closure::Run),
                       RunCallback<1>(PIPELINE_OK)));
 
-  EXPECT_CALL(*audio_renderer_, StopRendering());
+  EXPECT_CALL(time_source_, StopTicking());
   EXPECT_CALL(*audio_renderer_, Flush(_))
-      .WillOnce(RunClosure<0>());
-  EXPECT_CALL(*audio_renderer_, Preroll(seek_time, _))
-      .WillOnce(RunCallback<1>(PIPELINE_OK));
-  EXPECT_CALL(*audio_renderer_, SetPlaybackRate(_));
+      .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_,
+                                        BUFFERING_HAVE_NOTHING),
+                      RunClosure<0>()));
+  EXPECT_CALL(time_source_, SetMediaTime(seek_time));
+  EXPECT_CALL(time_source_, SetPlaybackRate(_));
+  EXPECT_CALL(time_source_, StartTicking());
+  EXPECT_CALL(*audio_renderer_, StartPlaying())
+      .WillOnce(SetBufferingState(&audio_buffering_state_cb_,
+                                  BUFFERING_HAVE_ENOUGH));
   EXPECT_CALL(*audio_renderer_, SetVolume(_));
-  EXPECT_CALL(*audio_renderer_, StartRendering());
 
-  EXPECT_CALL(callbacks_, OnPrerollCompleted());
   EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
+  EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
   DoSeek(seek_time);
 
   EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
@@ -835,22 +905,74 @@ TEST_F(PipelineTest, AudioTimeUpdateDuringSeek) {
   EXPECT_EQ(pipeline_->GetMediaTime(), new_time);
 }
 
-static void DeletePipeline(scoped_ptr<Pipeline> pipeline) {
-  // |pipeline| will go out of scope.
+TEST_F(PipelineTest, DestroyAfterStop) {
+  CreateAudioStream();
+  MockDemuxerStreamVector streams;
+  streams.push_back(audio_stream());
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+  StartPipeline(PIPELINE_OK);
+
+  ExpectDemuxerStop();
+
+  ExpectPipelineStopAndDestroyPipeline();
+  pipeline_->Stop(
+      base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
+  message_loop_.RunUntilIdle();
+}
+
+TEST_F(PipelineTest, Underflow) {
+  CreateAudioStream();
+  CreateVideoStream();
+  MockDemuxerStreamVector streams;
+  streams.push_back(audio_stream());
+  streams.push_back(video_stream());
+
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+  SetVideoRendererExpectations(video_stream());
+  StartPipeline(PIPELINE_OK);
+
+  // Simulate underflow.
+  EXPECT_CALL(time_source_, StopTicking());
+  audio_buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
+
+  // Seek while underflowed. We shouldn't call StopTicking() again.
+  base::TimeDelta expected = base::TimeDelta::FromSeconds(5);
+  ExpectSeek(expected, true);
+  DoSeek(expected);
+}
+
+static void PostTimeCB(base::MessageLoop* message_loop,
+                       const AudioRenderer::TimeCB& time_cb) {
+  base::TimeDelta new_time = base::TimeDelta::FromMilliseconds(100);
+  message_loop->PostTask(FROM_HERE, base::Bind(time_cb, new_time, new_time));
 }
 
-TEST_F(PipelineTest, DeleteAfterStop) {
+TEST_F(PipelineTest, TimeUpdateAfterStop) {
   CreateAudioStream();
+  CreateVideoStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
-  InitializeDemuxer(&streams);
-  InitializeAudioRenderer(audio_stream());
-  InitializePipeline(PIPELINE_OK);
+  streams.push_back(video_stream());
+
+  SetDemuxerExpectations(&streams);
+  SetAudioRendererExpectations(audio_stream());
+  SetVideoRendererExpectations(video_stream());
+  StartPipeline(PIPELINE_OK);
 
-  ExpectStop();
+  // Double post here! This is a hack to simulate the case where TimeCB is
+  // posted during ~AudioRenderer(), which is triggered in Pipeline::DoStop.
+  // Since we can't EXPECT_CALL the dtor and Pipeline::DoStop() is posted
+  // as well, we need to post twice here.
+  message_loop_.PostTask(
+      FROM_HERE, base::Bind(&PostTimeCB, &message_loop_, audio_time_cb_));
 
-  Pipeline* pipeline = pipeline_.get();
-  pipeline->Stop(base::Bind(&DeletePipeline, base::Passed(&pipeline_)));
+  EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
+
+  ExpectPipelineStopAndDestroyPipeline();
+  pipeline_->Stop(
+      base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
   message_loop_.RunUntilIdle();
 }
 
@@ -862,7 +984,6 @@ class PipelineTeardownTest : public PipelineTest {
     kInitVideoRenderer,
     kFlushing,
     kSeeking,
-    kPrerolling,
     kPlaying,
   };
 
@@ -885,7 +1006,6 @@ class PipelineTeardownTest : public PipelineTest {
 
       case kFlushing:
       case kSeeking:
-      case kPrerolling:
         DoInitialize(state, stop_or_error);
         DoSeek(state, stop_or_error);
         break;
@@ -912,7 +1032,7 @@ class PipelineTeardownTest : public PipelineTest {
         base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
-        base::Bind(&CallbackHelper::OnPrerollCompleted,
+        base::Bind(&CallbackHelper::OnBufferingStateChange,
                    base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnDurationChange,
                    base::Unretained(&callbacks_)));
@@ -930,7 +1050,7 @@ class PipelineTeardownTest : public PipelineTest {
         EXPECT_CALL(*demuxer_, Initialize(_, _, _))
             .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
                             RunCallback<1>(PIPELINE_OK)));
-        EXPECT_CALL(callbacks_, OnStop());
+        ExpectPipelineStopAndDestroyPipeline();
       } else {
         status = DEMUXER_ERROR_COULD_NOT_OPEN;
         EXPECT_CALL(*demuxer_, Initialize(_, _, _))
@@ -946,14 +1066,14 @@ class PipelineTeardownTest : public PipelineTest {
     MockDemuxerStreamVector streams;
     streams.push_back(audio_stream());
     streams.push_back(video_stream());
-    InitializeDemuxer(&streams, base::TimeDelta::FromSeconds(3000));
+    SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
 
     if (state == kInitAudioRenderer) {
       if (stop_or_error == kStop) {
         EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
             .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
                             RunCallback<1>(PIPELINE_OK)));
-        EXPECT_CALL(callbacks_, OnStop());
+        ExpectPipelineStopAndDestroyPipeline();
       } else {
         status = PIPELINE_ERROR_INITIALIZATION_FAILED;
         EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
@@ -961,52 +1081,51 @@ class PipelineTeardownTest : public PipelineTest {
       }
 
       EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
-      EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
       return status;
     }
 
     EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
-        .WillOnce(RunCallback<1>(PIPELINE_OK));
+        .WillOnce(DoAll(SaveArg<4>(&audio_buffering_state_cb_),
+                        RunCallback<1>(PIPELINE_OK)));
 
     if (state == kInitVideoRenderer) {
       if (stop_or_error == kStop) {
-        EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
+        EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _, _))
             .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
                             RunCallback<2>(PIPELINE_OK)));
-        EXPECT_CALL(callbacks_, OnStop());
+        ExpectPipelineStopAndDestroyPipeline();
       } else {
         status = PIPELINE_ERROR_INITIALIZATION_FAILED;
-        EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
+        EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _, _))
             .WillOnce(RunCallback<2>(status));
       }
 
       EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
-      EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
-      EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
       return status;
     }
 
-    EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
-        .WillOnce(RunCallback<2>(PIPELINE_OK));
+    EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _, _))
+        .WillOnce(DoAll(SaveArg<5>(&video_buffering_state_cb_),
+                        RunCallback<2>(PIPELINE_OK)));
 
     EXPECT_CALL(callbacks_, OnMetadata(_));
 
     // If we get here it's a successful initialization.
-    EXPECT_CALL(*audio_renderer_, Preroll(base::TimeDelta(), _))
-        .WillOnce(RunCallback<1>(PIPELINE_OK));
-    EXPECT_CALL(*video_renderer_, Preroll(base::TimeDelta(), _))
-        .WillOnce(RunCallback<1>(PIPELINE_OK));
-
-    EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
-    EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
+    EXPECT_CALL(*audio_renderer_, GetTimeSource())
+        .WillOnce(Return(&time_source_));
+    EXPECT_CALL(time_source_, SetMediaTime(base::TimeDelta()));
+    EXPECT_CALL(time_source_, SetPlaybackRate(0.0f));
+    EXPECT_CALL(time_source_, StartTicking());
     EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
-
-    EXPECT_CALL(*audio_renderer_, StartRendering());
-    EXPECT_CALL(*video_renderer_, Play(_))
-        .WillOnce(RunClosure<0>());
+    EXPECT_CALL(*audio_renderer_, StartPlaying())
+        .WillOnce(SetBufferingState(&audio_buffering_state_cb_,
+                                    BUFFERING_HAVE_ENOUGH));
+    EXPECT_CALL(*video_renderer_, StartPlaying())
+        .WillOnce(SetBufferingState(&video_buffering_state_cb_,
+                                    BUFFERING_HAVE_ENOUGH));
 
     if (status == PIPELINE_OK)
-      EXPECT_CALL(callbacks_, OnPrerollCompleted());
+      EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
 
     return status;
   }
@@ -1016,12 +1135,10 @@ class PipelineTeardownTest : public PipelineTest {
     PipelineStatus status = SetSeekExpectations(state, stop_or_error);
 
     EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
-    EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
-    EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
     EXPECT_CALL(callbacks_, OnSeek(status));
 
     if (status == PIPELINE_OK) {
-      EXPECT_CALL(callbacks_, OnStop());
+      ExpectPipelineStopAndDestroyPipeline();
     }
 
     pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
@@ -1035,23 +1152,35 @@ class PipelineTeardownTest : public PipelineTest {
     base::Closure stop_cb = base::Bind(
         &CallbackHelper::OnStop, base::Unretained(&callbacks_));
 
-    EXPECT_CALL(*audio_renderer_, StopRendering());
+    EXPECT_CALL(time_source_, StopTicking());
 
     if (state == kFlushing) {
       if (stop_or_error == kStop) {
         EXPECT_CALL(*audio_renderer_, Flush(_))
-            .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), RunClosure<0>()));
+            .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
+                            SetBufferingState(&audio_buffering_state_cb_,
+                                              BUFFERING_HAVE_NOTHING),
+                            RunClosure<0>()));
       } else {
         status = PIPELINE_ERROR_READ;
         EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(
-            DoAll(SetError(pipeline_.get(), status), RunClosure<0>()));
+            DoAll(SetError(pipeline_.get(), status),
+                  SetBufferingState(&audio_buffering_state_cb_,
+                                    BUFFERING_HAVE_NOTHING),
+                  RunClosure<0>()));
       }
 
       return status;
     }
 
-    EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(RunClosure<0>());
-    EXPECT_CALL(*video_renderer_, Flush(_)).WillOnce(RunClosure<0>());
+    EXPECT_CALL(*audio_renderer_, Flush(_))
+        .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_,
+                                          BUFFERING_HAVE_NOTHING),
+                        RunClosure<0>()));
+    EXPECT_CALL(*video_renderer_, Flush(_))
+        .WillOnce(DoAll(SetBufferingState(&video_buffering_state_cb_,
+                                          BUFFERING_HAVE_NOTHING),
+                        RunClosure<0>()));
 
     if (state == kSeeking) {
       if (stop_or_error == kStop) {
@@ -1067,33 +1196,6 @@ class PipelineTeardownTest : public PipelineTest {
       return status;
     }
 
-    EXPECT_CALL(*demuxer_, Seek(_, _))
-        .WillOnce(RunCallback<1>(PIPELINE_OK));
-
-    if (state == kPrerolling) {
-      if (stop_or_error == kStop) {
-        EXPECT_CALL(*audio_renderer_, Preroll(_, _))
-            .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
-                            RunCallback<1>(PIPELINE_OK)));
-      } else {
-        status = PIPELINE_ERROR_READ;
-        EXPECT_CALL(*audio_renderer_, Preroll(_, _))
-            .WillOnce(RunCallback<1>(status));
-      }
-
-      return status;
-    }
-
-    EXPECT_CALL(*audio_renderer_, Preroll(_, _))
-        .WillOnce(RunCallback<1>(PIPELINE_OK));
-    EXPECT_CALL(*video_renderer_, Preroll(_, _))
-        .WillOnce(RunCallback<1>(PIPELINE_OK));
-
-    // Playback rate and volume are updated prior to starting.
-    EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
-    EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
-    EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
-
     NOTREACHED() << "State not supported: " << state;
     return status;
   }
@@ -1102,12 +1204,10 @@ class PipelineTeardownTest : public PipelineTest {
     InSequence s;
 
     EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
-    EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
-    EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
 
     switch (stop_or_error) {
       case kStop:
-        EXPECT_CALL(callbacks_, OnStop());
+        ExpectPipelineStopAndDestroyPipeline();
         pipeline_->Stop(base::Bind(
             &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
         break;
@@ -1118,7 +1218,8 @@ class PipelineTeardownTest : public PipelineTest {
         break;
 
       case kErrorAndStop:
-        EXPECT_CALL(callbacks_, OnStop());
+        EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
+        ExpectPipelineStopAndDestroyPipeline();
         pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
         pipeline_->Stop(base::Bind(
             &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
@@ -1141,7 +1242,6 @@ INSTANTIATE_TEARDOWN_TEST(Stop, InitAudioRenderer);
 INSTANTIATE_TEARDOWN_TEST(Stop, InitVideoRenderer);
 INSTANTIATE_TEARDOWN_TEST(Stop, Flushing);
 INSTANTIATE_TEARDOWN_TEST(Stop, Seeking);
-INSTANTIATE_TEARDOWN_TEST(Stop, Prerolling);
 INSTANTIATE_TEARDOWN_TEST(Stop, Playing);
 
 INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer);
@@ -1149,7 +1249,6 @@ INSTANTIATE_TEARDOWN_TEST(Error, InitAudioRenderer);
 INSTANTIATE_TEARDOWN_TEST(Error, InitVideoRenderer);
 INSTANTIATE_TEARDOWN_TEST(Error, Flushing);
 INSTANTIATE_TEARDOWN_TEST(Error, Seeking);
-INSTANTIATE_TEARDOWN_TEST(Error, Prerolling);
 INSTANTIATE_TEARDOWN_TEST(Error, Playing);
 
 INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);