[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / media / base / pipeline_unittest.cc
blob147e744dd0a6319ac9942080da775430f409c499
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <vector>
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/stl_util.h"
10 #include "base/test/simple_test_tick_clock.h"
11 #include "base/threading/simple_thread.h"
12 #include "base/time/clock.h"
13 #include "media/base/fake_text_track_stream.h"
14 #include "media/base/gmock_callback_support.h"
15 #include "media/base/media_log.h"
16 #include "media/base/mock_filters.h"
17 #include "media/base/pipeline.h"
18 #include "media/base/test_helpers.h"
19 #include "media/base/text_renderer.h"
20 #include "media/base/text_track_config.h"
21 #include "media/base/time_delta_interpolator.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "ui/gfx/geometry/size.h"
25 using ::testing::_;
26 using ::testing::AnyNumber;
27 using ::testing::DeleteArg;
28 using ::testing::DoAll;
29 // TODO(scherkus): Remove InSequence after refactoring Pipeline.
30 using ::testing::InSequence;
31 using ::testing::Invoke;
32 using ::testing::InvokeWithoutArgs;
33 using ::testing::Mock;
34 using ::testing::NotNull;
35 using ::testing::Return;
36 using ::testing::SaveArg;
37 using ::testing::StrictMock;
38 using ::testing::WithArg;
40 namespace media {
42 ACTION_P(SetDemuxerProperties, duration) {
43 arg0->SetDuration(duration);
46 ACTION_P2(Stop, pipeline, stop_cb) {
47 pipeline->Stop(stop_cb);
50 ACTION_P2(SetError, pipeline, status) {
51 pipeline->SetErrorForTesting(status);
54 ACTION_P2(SetBufferingState, cb, buffering_state) {
55 cb->Run(buffering_state);
58 ACTION_TEMPLATE(PostCallback,
59 HAS_1_TEMPLATE_PARAMS(int, k),
60 AND_1_VALUE_PARAMS(p0)) {
61 return base::MessageLoop::current()->PostTask(
62 FROM_HERE, base::Bind(::std::tr1::get<k>(args), p0));
65 // TODO(scherkus): even though some filters are initialized on separate
66 // threads these test aren't flaky... why? It's because filters' Initialize()
67 // is executed on |message_loop_| and the mock filters instantly call
68 // InitializationComplete(), which keeps the pipeline humming along. If
69 // either filters don't call InitializationComplete() immediately or filter
70 // initialization is moved to a separate thread this test will become flaky.
71 class PipelineTest : public ::testing::Test {
72 public:
73 // Used for setting expectations on pipeline callbacks. Using a StrictMock
74 // also lets us test for missing callbacks.
75 class CallbackHelper {
76 public:
77 CallbackHelper() {}
78 virtual ~CallbackHelper() {}
80 MOCK_METHOD1(OnStart, void(PipelineStatus));
81 MOCK_METHOD1(OnSeek, void(PipelineStatus));
82 MOCK_METHOD0(OnStop, void());
83 MOCK_METHOD0(OnEnded, void());
84 MOCK_METHOD1(OnError, void(PipelineStatus));
85 MOCK_METHOD1(OnMetadata, void(PipelineMetadata));
86 MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
87 MOCK_METHOD1(OnVideoFramePaint, void(const scoped_refptr<VideoFrame>&));
88 MOCK_METHOD0(OnDurationChange, void());
90 private:
91 DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
94 PipelineTest()
95 : pipeline_(new Pipeline(message_loop_.message_loop_proxy(),
96 new MediaLog())),
97 demuxer_(new StrictMock<MockDemuxer>()),
98 scoped_renderer_(new StrictMock<MockRenderer>()),
99 renderer_(scoped_renderer_.get()) {
100 // SetDemuxerExpectations() adds overriding expectations for expected
101 // non-NULL streams.
102 DemuxerStream* null_pointer = NULL;
103 EXPECT_CALL(*demuxer_, GetStream(_))
104 .WillRepeatedly(Return(null_pointer));
106 EXPECT_CALL(*demuxer_, GetTimelineOffset())
107 .WillRepeatedly(Return(base::Time()));
109 EXPECT_CALL(*renderer_, GetMediaTime())
110 .WillRepeatedly(Return(base::TimeDelta()));
112 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
115 virtual ~PipelineTest() {
116 if (!pipeline_ || !pipeline_->IsRunning())
117 return;
119 ExpectDemuxerStop();
121 // The mock demuxer doesn't stop the fake text track stream,
122 // so just stop it manually.
123 if (text_stream_) {
124 text_stream_->Stop();
125 message_loop_.RunUntilIdle();
128 // Expect a stop callback if we were started.
129 ExpectPipelineStopAndDestroyPipeline();
130 pipeline_->Stop(base::Bind(&CallbackHelper::OnStop,
131 base::Unretained(&callbacks_)));
132 message_loop_.RunUntilIdle();
135 void OnDemuxerError() {
136 // Cast because OnDemuxerError is private in Pipeline.
137 static_cast<DemuxerHost*>(pipeline_.get())
138 ->OnDemuxerError(PIPELINE_ERROR_ABORT);
141 protected:
142 // Sets up expectations to allow the demuxer to initialize.
143 typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector;
144 void SetDemuxerExpectations(MockDemuxerStreamVector* streams,
145 const base::TimeDelta& duration) {
146 EXPECT_CALL(callbacks_, OnDurationChange());
147 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
148 .WillOnce(DoAll(SetDemuxerProperties(duration),
149 PostCallback<1>(PIPELINE_OK)));
151 // Configure the demuxer to return the streams.
152 for (size_t i = 0; i < streams->size(); ++i) {
153 DemuxerStream* stream = (*streams)[i];
154 EXPECT_CALL(*demuxer_, GetStream(stream->type()))
155 .WillRepeatedly(Return(stream));
159 void SetDemuxerExpectations(MockDemuxerStreamVector* streams) {
160 // Initialize with a default non-zero duration.
161 SetDemuxerExpectations(streams, base::TimeDelta::FromSeconds(10));
164 scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream(
165 DemuxerStream::Type type) {
166 scoped_ptr<StrictMock<MockDemuxerStream> > stream(
167 new StrictMock<MockDemuxerStream>(type));
168 return stream.Pass();
171 // Sets up expectations to allow the video renderer to initialize.
172 void SetRendererExpectations() {
173 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _))
174 .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_),
175 SaveArg<5>(&ended_cb_),
176 PostCallback<1>(PIPELINE_OK)));
177 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(audio_stream()));
178 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(video_stream()));
181 void AddTextStream() {
182 EXPECT_CALL(*this, OnAddTextTrack(_,_))
183 .WillOnce(Invoke(this, &PipelineTest::DoOnAddTextTrack));
184 static_cast<DemuxerHost*>(pipeline_.get())->AddTextStream(text_stream(),
185 TextTrackConfig(kTextSubtitles, "", "", ""));
186 message_loop_.RunUntilIdle();
189 void StartPipeline() {
190 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
191 pipeline_->Start(
192 demuxer_.get(), scoped_renderer_.Pass(),
193 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
194 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
195 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
196 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
197 base::Bind(&CallbackHelper::OnBufferingStateChange,
198 base::Unretained(&callbacks_)),
199 base::Bind(&CallbackHelper::OnVideoFramePaint,
200 base::Unretained(&callbacks_)),
201 base::Bind(&CallbackHelper::OnDurationChange,
202 base::Unretained(&callbacks_)),
203 base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this)),
204 base::Bind(&PipelineTest::OnWaitingForDecryptionKey,
205 base::Unretained(this)));
208 // Sets up expectations on the callback and initializes the pipeline. Called
209 // after tests have set expectations any filters they wish to use.
210 void StartPipelineAndExpect(PipelineStatus start_status) {
211 EXPECT_CALL(callbacks_, OnStart(start_status));
213 if (start_status == PIPELINE_OK) {
214 EXPECT_CALL(callbacks_, OnMetadata(_)).WillOnce(SaveArg<0>(&metadata_));
215 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0f));
216 EXPECT_CALL(*renderer_, SetVolume(1.0f));
217 EXPECT_CALL(*renderer_, StartPlayingFrom(start_time_))
218 .WillOnce(SetBufferingState(&buffering_state_cb_,
219 BUFFERING_HAVE_ENOUGH));
220 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
223 StartPipeline();
224 message_loop_.RunUntilIdle();
227 void CreateAudioStream() {
228 audio_stream_ = CreateStream(DemuxerStream::AUDIO);
231 void CreateVideoStream() {
232 video_stream_ = CreateStream(DemuxerStream::VIDEO);
233 video_stream_->set_video_decoder_config(video_decoder_config_);
236 void CreateTextStream() {
237 scoped_ptr<FakeTextTrackStream> text_stream(new FakeTextTrackStream());
238 EXPECT_CALL(*text_stream, OnRead()).Times(AnyNumber());
239 text_stream_ = text_stream.Pass();
242 MockDemuxerStream* audio_stream() {
243 return audio_stream_.get();
246 MockDemuxerStream* video_stream() {
247 return video_stream_.get();
250 FakeTextTrackStream* text_stream() {
251 return text_stream_.get();
254 void ExpectSeek(const base::TimeDelta& seek_time, bool underflowed) {
255 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
256 .WillOnce(RunCallback<1>(PIPELINE_OK));
258 EXPECT_CALL(*renderer_, Flush(_))
259 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
260 BUFFERING_HAVE_NOTHING),
261 RunClosure<0>()));
262 EXPECT_CALL(*renderer_, SetPlaybackRate(_));
263 EXPECT_CALL(*renderer_, SetVolume(_));
264 EXPECT_CALL(*renderer_, StartPlayingFrom(seek_time))
265 .WillOnce(SetBufferingState(&buffering_state_cb_,
266 BUFFERING_HAVE_ENOUGH));
267 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
269 // We expect a successful seek callback followed by a buffering update.
270 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
271 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
274 void DoSeek(const base::TimeDelta& seek_time) {
275 pipeline_->Seek(seek_time,
276 base::Bind(&CallbackHelper::OnSeek,
277 base::Unretained(&callbacks_)));
278 message_loop_.RunUntilIdle();
281 void DestroyPipeline() {
282 // In real code Pipeline could be destroyed on a different thread. All weak
283 // pointers must have been invalidated before the stop callback returns.
284 DCHECK(!pipeline_->HasWeakPtrsForTesting());
285 pipeline_.reset();
288 void ExpectDemuxerStop() {
289 if (demuxer_)
290 EXPECT_CALL(*demuxer_, Stop());
293 void ExpectPipelineStopAndDestroyPipeline() {
294 // After the Pipeline is stopped, it could be destroyed any time. Always
295 // destroy the pipeline immediately after OnStop() to test this.
296 EXPECT_CALL(callbacks_, OnStop())
297 .WillOnce(Invoke(this, &PipelineTest::DestroyPipeline));
300 MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&,
301 const AddTextTrackDoneCB&));
302 MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
304 void DoOnAddTextTrack(const TextTrackConfig& config,
305 const AddTextTrackDoneCB& done_cb) {
306 scoped_ptr<TextTrack> text_track(new MockTextTrack);
307 done_cb.Run(text_track.Pass());
310 // Fixture members.
311 StrictMock<CallbackHelper> callbacks_;
312 base::SimpleTestTickClock test_tick_clock_;
313 base::MessageLoop message_loop_;
314 scoped_ptr<Pipeline> pipeline_;
316 scoped_ptr<StrictMock<MockDemuxer> > demuxer_;
317 scoped_ptr<StrictMock<MockRenderer> > scoped_renderer_;
318 StrictMock<MockRenderer>* renderer_;
319 StrictMock<CallbackHelper> text_renderer_callbacks_;
320 TextRenderer* text_renderer_;
321 scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
322 scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
323 scoped_ptr<FakeTextTrackStream> text_stream_;
324 BufferingStateCB buffering_state_cb_;
325 base::Closure ended_cb_;
326 VideoDecoderConfig video_decoder_config_;
327 PipelineMetadata metadata_;
328 base::TimeDelta start_time_;
330 private:
331 DISALLOW_COPY_AND_ASSIGN(PipelineTest);
334 // Test that playback controls methods no-op when the pipeline hasn't been
335 // started.
336 TEST_F(PipelineTest, NotStarted) {
337 const base::TimeDelta kZero;
339 EXPECT_FALSE(pipeline_->IsRunning());
341 // Setting should still work.
342 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
343 pipeline_->SetPlaybackRate(-1.0f);
344 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
345 pipeline_->SetPlaybackRate(1.0f);
346 EXPECT_EQ(1.0f, pipeline_->GetPlaybackRate());
348 // Setting should still work.
349 EXPECT_EQ(1.0f, pipeline_->GetVolume());
350 pipeline_->SetVolume(-1.0f);
351 EXPECT_EQ(1.0f, pipeline_->GetVolume());
352 pipeline_->SetVolume(0.0f);
353 EXPECT_EQ(0.0f, pipeline_->GetVolume());
355 EXPECT_TRUE(kZero == pipeline_->GetMediaTime());
356 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
357 EXPECT_TRUE(kZero == pipeline_->GetMediaDuration());
360 TEST_F(PipelineTest, NeverInitializes) {
361 // Don't execute the callback passed into Initialize().
362 EXPECT_CALL(*demuxer_, Initialize(_, _, _));
364 // This test hangs during initialization by never calling
365 // InitializationComplete(). StrictMock<> will ensure that the callback is
366 // never executed.
367 StartPipeline();
368 message_loop_.RunUntilIdle();
370 // Because our callback will get executed when the test tears down, we'll
371 // verify that nothing has been called, then set our expectation for the call
372 // made during tear down.
373 Mock::VerifyAndClear(&callbacks_);
374 EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
377 TEST_F(PipelineTest, StopWithoutStart) {
378 ExpectPipelineStopAndDestroyPipeline();
379 pipeline_->Stop(
380 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
381 message_loop_.RunUntilIdle();
384 TEST_F(PipelineTest, StartThenStopImmediately) {
385 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
386 .WillOnce(PostCallback<1>(PIPELINE_OK));
387 EXPECT_CALL(*demuxer_, Stop());
389 EXPECT_CALL(callbacks_, OnStart(_));
390 StartPipeline();
392 // Expect a stop callback if we were started.
393 ExpectPipelineStopAndDestroyPipeline();
394 pipeline_->Stop(
395 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
396 message_loop_.RunUntilIdle();
399 TEST_F(PipelineTest, DemuxerErrorDuringStop) {
400 CreateAudioStream();
401 MockDemuxerStreamVector streams;
402 streams.push_back(audio_stream());
404 SetDemuxerExpectations(&streams);
405 SetRendererExpectations();
407 StartPipelineAndExpect(PIPELINE_OK);
409 EXPECT_CALL(*demuxer_, Stop())
410 .WillOnce(InvokeWithoutArgs(this, &PipelineTest::OnDemuxerError));
411 ExpectPipelineStopAndDestroyPipeline();
413 pipeline_->Stop(
414 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
415 message_loop_.RunUntilIdle();
418 TEST_F(PipelineTest, URLNotFound) {
419 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
420 .WillOnce(PostCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND));
421 EXPECT_CALL(*demuxer_, Stop());
423 StartPipelineAndExpect(PIPELINE_ERROR_URL_NOT_FOUND);
426 TEST_F(PipelineTest, NoStreams) {
427 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
428 .WillOnce(PostCallback<1>(PIPELINE_OK));
429 EXPECT_CALL(*demuxer_, Stop());
430 EXPECT_CALL(callbacks_, OnMetadata(_));
432 StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER);
435 TEST_F(PipelineTest, AudioStream) {
436 CreateAudioStream();
437 MockDemuxerStreamVector streams;
438 streams.push_back(audio_stream());
440 SetDemuxerExpectations(&streams);
441 SetRendererExpectations();
443 StartPipelineAndExpect(PIPELINE_OK);
444 EXPECT_TRUE(metadata_.has_audio);
445 EXPECT_FALSE(metadata_.has_video);
448 TEST_F(PipelineTest, VideoStream) {
449 CreateVideoStream();
450 MockDemuxerStreamVector streams;
451 streams.push_back(video_stream());
453 SetDemuxerExpectations(&streams);
454 SetRendererExpectations();
456 StartPipelineAndExpect(PIPELINE_OK);
457 EXPECT_FALSE(metadata_.has_audio);
458 EXPECT_TRUE(metadata_.has_video);
461 TEST_F(PipelineTest, AudioVideoStream) {
462 CreateAudioStream();
463 CreateVideoStream();
464 MockDemuxerStreamVector streams;
465 streams.push_back(audio_stream());
466 streams.push_back(video_stream());
468 SetDemuxerExpectations(&streams);
469 SetRendererExpectations();
471 StartPipelineAndExpect(PIPELINE_OK);
472 EXPECT_TRUE(metadata_.has_audio);
473 EXPECT_TRUE(metadata_.has_video);
476 TEST_F(PipelineTest, VideoTextStream) {
477 CreateVideoStream();
478 CreateTextStream();
479 MockDemuxerStreamVector streams;
480 streams.push_back(video_stream());
482 SetDemuxerExpectations(&streams);
483 SetRendererExpectations();
485 StartPipelineAndExpect(PIPELINE_OK);
486 EXPECT_FALSE(metadata_.has_audio);
487 EXPECT_TRUE(metadata_.has_video);
489 AddTextStream();
492 TEST_F(PipelineTest, VideoAudioTextStream) {
493 CreateVideoStream();
494 CreateAudioStream();
495 CreateTextStream();
496 MockDemuxerStreamVector streams;
497 streams.push_back(video_stream());
498 streams.push_back(audio_stream());
500 SetDemuxerExpectations(&streams);
501 SetRendererExpectations();
503 StartPipelineAndExpect(PIPELINE_OK);
504 EXPECT_TRUE(metadata_.has_audio);
505 EXPECT_TRUE(metadata_.has_video);
507 AddTextStream();
510 TEST_F(PipelineTest, Seek) {
511 CreateAudioStream();
512 CreateVideoStream();
513 CreateTextStream();
514 MockDemuxerStreamVector streams;
515 streams.push_back(audio_stream());
516 streams.push_back(video_stream());
518 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
519 SetRendererExpectations();
521 // Initialize then seek!
522 StartPipelineAndExpect(PIPELINE_OK);
524 // Every filter should receive a call to Seek().
525 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
526 ExpectSeek(expected, false);
527 DoSeek(expected);
530 TEST_F(PipelineTest, SeekAfterError) {
531 CreateAudioStream();
532 MockDemuxerStreamVector streams;
533 streams.push_back(audio_stream());
535 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
536 SetRendererExpectations();
538 // Initialize then seek!
539 StartPipelineAndExpect(PIPELINE_OK);
541 EXPECT_CALL(*demuxer_, Stop());
542 EXPECT_CALL(callbacks_, OnError(_));
544 static_cast<DemuxerHost*>(pipeline_.get())
545 ->OnDemuxerError(PIPELINE_ERROR_ABORT);
546 message_loop_.RunUntilIdle();
548 pipeline_->Seek(
549 base::TimeDelta::FromMilliseconds(100),
550 base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
551 message_loop_.RunUntilIdle();
554 TEST_F(PipelineTest, SetVolume) {
555 CreateAudioStream();
556 MockDemuxerStreamVector streams;
557 streams.push_back(audio_stream());
559 SetDemuxerExpectations(&streams);
560 SetRendererExpectations();
562 // The audio renderer should receive a call to SetVolume().
563 float expected = 0.5f;
564 EXPECT_CALL(*renderer_, SetVolume(expected));
566 // Initialize then set volume!
567 StartPipelineAndExpect(PIPELINE_OK);
568 pipeline_->SetVolume(expected);
571 TEST_F(PipelineTest, Properties) {
572 CreateVideoStream();
573 MockDemuxerStreamVector streams;
574 streams.push_back(video_stream());
576 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
577 SetDemuxerExpectations(&streams, kDuration);
578 SetRendererExpectations();
580 StartPipelineAndExpect(PIPELINE_OK);
581 EXPECT_EQ(kDuration.ToInternalValue(),
582 pipeline_->GetMediaDuration().ToInternalValue());
583 EXPECT_FALSE(pipeline_->DidLoadingProgress());
586 TEST_F(PipelineTest, GetBufferedTimeRanges) {
587 CreateVideoStream();
588 MockDemuxerStreamVector streams;
589 streams.push_back(video_stream());
591 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
592 SetDemuxerExpectations(&streams, kDuration);
593 SetRendererExpectations();
595 StartPipelineAndExpect(PIPELINE_OK);
597 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
599 EXPECT_FALSE(pipeline_->DidLoadingProgress());
600 pipeline_->AddBufferedTimeRange(base::TimeDelta(), kDuration / 8);
601 EXPECT_TRUE(pipeline_->DidLoadingProgress());
602 EXPECT_FALSE(pipeline_->DidLoadingProgress());
603 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
604 EXPECT_EQ(base::TimeDelta(), pipeline_->GetBufferedTimeRanges().start(0));
605 EXPECT_EQ(kDuration / 8, pipeline_->GetBufferedTimeRanges().end(0));
607 base::TimeDelta kSeekTime = kDuration / 2;
608 ExpectSeek(kSeekTime, false);
609 DoSeek(kSeekTime);
611 EXPECT_FALSE(pipeline_->DidLoadingProgress());
614 TEST_F(PipelineTest, EndedCallback) {
615 CreateAudioStream();
616 CreateVideoStream();
617 CreateTextStream();
618 MockDemuxerStreamVector streams;
619 streams.push_back(audio_stream());
620 streams.push_back(video_stream());
622 SetDemuxerExpectations(&streams);
623 SetRendererExpectations();
624 StartPipelineAndExpect(PIPELINE_OK);
626 AddTextStream();
628 // The ended callback shouldn't run until all renderers have ended.
629 ended_cb_.Run();
630 message_loop_.RunUntilIdle();
632 EXPECT_CALL(callbacks_, OnEnded());
633 // Since the |ended_cb_| is manually invoked above, the duration does not
634 // match the expected duration and is updated upon ended.
635 EXPECT_CALL(callbacks_, OnDurationChange());
636 text_stream()->SendEosNotification();
637 message_loop_.RunUntilIdle();
640 TEST_F(PipelineTest, ErrorDuringSeek) {
641 CreateAudioStream();
642 MockDemuxerStreamVector streams;
643 streams.push_back(audio_stream());
645 SetDemuxerExpectations(&streams);
646 SetRendererExpectations();
647 StartPipelineAndExpect(PIPELINE_OK);
649 float playback_rate = 1.0f;
650 EXPECT_CALL(*renderer_, SetPlaybackRate(playback_rate));
651 pipeline_->SetPlaybackRate(playback_rate);
652 message_loop_.RunUntilIdle();
654 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
656 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
657 EXPECT_CALL(*renderer_, Flush(_))
658 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
659 BUFFERING_HAVE_NOTHING),
660 RunClosure<0>()));
662 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
663 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
664 EXPECT_CALL(*demuxer_, Stop());
666 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
667 base::Unretained(&callbacks_)));
668 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
669 message_loop_.RunUntilIdle();
672 // Invoked function OnError. This asserts that the pipeline does not enqueue
673 // non-teardown related tasks while tearing down.
674 static void TestNoCallsAfterError(
675 Pipeline* pipeline, base::MessageLoop* message_loop,
676 PipelineStatus /* status */) {
677 CHECK(pipeline);
678 CHECK(message_loop);
680 // When we get to this stage, the message loop should be empty.
681 EXPECT_TRUE(message_loop->IsIdleForTesting());
683 // Make calls on pipeline after error has occurred.
684 pipeline->SetPlaybackRate(0.5f);
685 pipeline->SetVolume(0.5f);
687 // No additional tasks should be queued as a result of these calls.
688 EXPECT_TRUE(message_loop->IsIdleForTesting());
691 TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
692 CreateAudioStream();
693 MockDemuxerStreamVector streams;
694 streams.push_back(audio_stream());
696 SetDemuxerExpectations(&streams);
697 SetRendererExpectations();
698 StartPipelineAndExpect(PIPELINE_OK);
700 // Trigger additional requests on the pipeline during tear down from error.
701 base::Callback<void(PipelineStatus)> cb = base::Bind(
702 &TestNoCallsAfterError, pipeline_.get(), &message_loop_);
703 ON_CALL(callbacks_, OnError(_))
704 .WillByDefault(Invoke(&cb, &base::Callback<void(PipelineStatus)>::Run));
706 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
708 // Seek() isn't called as the demuxer errors out first.
709 EXPECT_CALL(*renderer_, Flush(_))
710 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
711 BUFFERING_HAVE_NOTHING),
712 RunClosure<0>()));
713 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
715 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
716 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
717 EXPECT_CALL(*demuxer_, Stop());
719 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
720 base::Unretained(&callbacks_)));
721 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
722 message_loop_.RunUntilIdle();
725 TEST_F(PipelineTest, DestroyAfterStop) {
726 CreateAudioStream();
727 MockDemuxerStreamVector streams;
728 streams.push_back(audio_stream());
729 SetDemuxerExpectations(&streams);
730 SetRendererExpectations();
731 StartPipelineAndExpect(PIPELINE_OK);
733 ExpectDemuxerStop();
735 ExpectPipelineStopAndDestroyPipeline();
736 pipeline_->Stop(
737 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
738 message_loop_.RunUntilIdle();
741 TEST_F(PipelineTest, Underflow) {
742 CreateAudioStream();
743 CreateVideoStream();
744 MockDemuxerStreamVector streams;
745 streams.push_back(audio_stream());
746 streams.push_back(video_stream());
748 SetDemuxerExpectations(&streams);
749 SetRendererExpectations();
750 StartPipelineAndExpect(PIPELINE_OK);
752 // Simulate underflow.
753 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
754 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
756 // Seek while underflowed.
757 base::TimeDelta expected = base::TimeDelta::FromSeconds(5);
758 ExpectSeek(expected, true);
759 DoSeek(expected);
762 TEST_F(PipelineTest, PositiveStartTime) {
763 start_time_ = base::TimeDelta::FromSeconds(1);
764 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
765 CreateAudioStream();
766 MockDemuxerStreamVector streams;
767 streams.push_back(audio_stream());
768 SetDemuxerExpectations(&streams);
769 SetRendererExpectations();
770 StartPipelineAndExpect(PIPELINE_OK);
771 ExpectDemuxerStop();
772 ExpectPipelineStopAndDestroyPipeline();
773 pipeline_->Stop(
774 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
775 message_loop_.RunUntilIdle();
778 class PipelineTeardownTest : public PipelineTest {
779 public:
780 enum TeardownState {
781 kInitDemuxer,
782 kInitRenderer,
783 kFlushing,
784 kSeeking,
785 kPlaying,
788 enum StopOrError {
789 kStop,
790 kError,
791 kErrorAndStop,
794 PipelineTeardownTest() {}
795 ~PipelineTeardownTest() override {}
797 void RunTest(TeardownState state, StopOrError stop_or_error) {
798 switch (state) {
799 case kInitDemuxer:
800 case kInitRenderer:
801 DoInitialize(state, stop_or_error);
802 break;
804 case kFlushing:
805 case kSeeking:
806 DoInitialize(state, stop_or_error);
807 DoSeek(state, stop_or_error);
808 break;
810 case kPlaying:
811 DoInitialize(state, stop_or_error);
812 DoStopOrError(stop_or_error);
813 break;
817 private:
818 // TODO(scherkus): We do radically different things whether teardown is
819 // invoked via stop vs error. The teardown path should be the same,
820 // see http://crbug.com/110228
821 void DoInitialize(TeardownState state, StopOrError stop_or_error) {
822 PipelineStatus expected_status =
823 SetInitializeExpectations(state, stop_or_error);
825 EXPECT_CALL(callbacks_, OnStart(expected_status));
826 StartPipeline();
827 message_loop_.RunUntilIdle();
830 PipelineStatus SetInitializeExpectations(TeardownState state,
831 StopOrError stop_or_error) {
832 PipelineStatus status = PIPELINE_OK;
833 base::Closure stop_cb = base::Bind(
834 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
836 if (state == kInitDemuxer) {
837 if (stop_or_error == kStop) {
838 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
839 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
840 PostCallback<1>(PIPELINE_OK)));
841 ExpectPipelineStopAndDestroyPipeline();
842 } else {
843 status = DEMUXER_ERROR_COULD_NOT_OPEN;
844 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
845 .WillOnce(PostCallback<1>(status));
848 EXPECT_CALL(*demuxer_, Stop());
849 return status;
852 CreateAudioStream();
853 CreateVideoStream();
854 MockDemuxerStreamVector streams;
855 streams.push_back(audio_stream());
856 streams.push_back(video_stream());
857 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
859 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(true));
860 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(true));
862 if (state == kInitRenderer) {
863 if (stop_or_error == kStop) {
864 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _))
865 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
866 PostCallback<1>(PIPELINE_OK)));
867 ExpectPipelineStopAndDestroyPipeline();
868 } else {
869 status = PIPELINE_ERROR_INITIALIZATION_FAILED;
870 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _))
871 .WillOnce(PostCallback<1>(status));
874 EXPECT_CALL(*demuxer_, Stop());
875 EXPECT_CALL(callbacks_, OnMetadata(_));
876 return status;
879 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _))
880 .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_),
881 PostCallback<1>(PIPELINE_OK)));
883 EXPECT_CALL(callbacks_, OnMetadata(_));
885 // If we get here it's a successful initialization.
886 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0f));
887 EXPECT_CALL(*renderer_, SetVolume(1.0f));
888 EXPECT_CALL(*renderer_, StartPlayingFrom(base::TimeDelta()))
889 .WillOnce(SetBufferingState(&buffering_state_cb_,
890 BUFFERING_HAVE_ENOUGH));
892 if (status == PIPELINE_OK)
893 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
895 return status;
898 void DoSeek(TeardownState state, StopOrError stop_or_error) {
899 InSequence s;
900 PipelineStatus status = SetSeekExpectations(state, stop_or_error);
902 EXPECT_CALL(*demuxer_, Stop());
903 EXPECT_CALL(callbacks_, OnSeek(status));
905 if (status == PIPELINE_OK) {
906 ExpectPipelineStopAndDestroyPipeline();
909 pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
910 &CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
911 message_loop_.RunUntilIdle();
914 PipelineStatus SetSeekExpectations(TeardownState state,
915 StopOrError stop_or_error) {
916 PipelineStatus status = PIPELINE_OK;
917 base::Closure stop_cb = base::Bind(
918 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
920 if (state == kFlushing) {
921 if (stop_or_error == kStop) {
922 EXPECT_CALL(*renderer_, Flush(_))
923 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
924 SetBufferingState(&buffering_state_cb_,
925 BUFFERING_HAVE_NOTHING),
926 RunClosure<0>()));
927 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
928 } else {
929 status = PIPELINE_ERROR_READ;
930 EXPECT_CALL(*renderer_, Flush(_))
931 .WillOnce(DoAll(SetError(pipeline_.get(), status),
932 SetBufferingState(&buffering_state_cb_,
933 BUFFERING_HAVE_NOTHING),
934 RunClosure<0>()));
935 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
938 return status;
941 EXPECT_CALL(*renderer_, Flush(_))
942 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
943 BUFFERING_HAVE_NOTHING),
944 RunClosure<0>()));
945 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
947 if (state == kSeeking) {
948 if (stop_or_error == kStop) {
949 EXPECT_CALL(*demuxer_, Seek(_, _))
950 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
951 RunCallback<1>(PIPELINE_OK)));
952 } else {
953 status = PIPELINE_ERROR_READ;
954 EXPECT_CALL(*demuxer_, Seek(_, _))
955 .WillOnce(RunCallback<1>(status));
958 return status;
961 NOTREACHED() << "State not supported: " << state;
962 return status;
965 void DoStopOrError(StopOrError stop_or_error) {
966 InSequence s;
968 EXPECT_CALL(*demuxer_, Stop());
970 switch (stop_or_error) {
971 case kStop:
972 ExpectPipelineStopAndDestroyPipeline();
973 pipeline_->Stop(base::Bind(
974 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
975 break;
977 case kError:
978 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
979 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
980 break;
982 case kErrorAndStop:
983 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
984 ExpectPipelineStopAndDestroyPipeline();
985 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
986 message_loop_.RunUntilIdle();
987 pipeline_->Stop(base::Bind(
988 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
989 break;
992 message_loop_.RunUntilIdle();
995 DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest);
998 #define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \
999 TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
1000 RunTest(k##state, k##stop_or_error); \
1003 INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer);
1004 INSTANTIATE_TEARDOWN_TEST(Stop, InitRenderer);
1005 INSTANTIATE_TEARDOWN_TEST(Stop, Flushing);
1006 INSTANTIATE_TEARDOWN_TEST(Stop, Seeking);
1007 INSTANTIATE_TEARDOWN_TEST(Stop, Playing);
1009 INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer);
1010 INSTANTIATE_TEARDOWN_TEST(Error, InitRenderer);
1011 INSTANTIATE_TEARDOWN_TEST(Error, Flushing);
1012 INSTANTIATE_TEARDOWN_TEST(Error, Seeking);
1013 INSTANTIATE_TEARDOWN_TEST(Error, Playing);
1015 INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);
1017 } // namespace media