Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / base / pipeline_unittest.cc
blob83367b55960566eca4ac958394c241ef1a7a8a7c
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_METHOD0(OnDurationChange, void());
89 private:
90 DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
93 PipelineTest()
94 : pipeline_(new Pipeline(message_loop_.task_runner(),
95 new MediaLog())),
96 demuxer_(new StrictMock<MockDemuxer>()),
97 scoped_renderer_(new StrictMock<MockRenderer>()),
98 renderer_(scoped_renderer_.get()) {
99 // SetDemuxerExpectations() adds overriding expectations for expected
100 // non-NULL streams.
101 DemuxerStream* null_pointer = NULL;
102 EXPECT_CALL(*demuxer_, GetStream(_))
103 .WillRepeatedly(Return(null_pointer));
105 EXPECT_CALL(*demuxer_, GetTimelineOffset())
106 .WillRepeatedly(Return(base::Time()));
108 EXPECT_CALL(*renderer_, GetMediaTime())
109 .WillRepeatedly(Return(base::TimeDelta()));
111 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
114 virtual ~PipelineTest() {
115 if (!pipeline_ || !pipeline_->IsRunning())
116 return;
118 ExpectDemuxerStop();
120 // The mock demuxer doesn't stop the fake text track stream,
121 // so just stop it manually.
122 if (text_stream_) {
123 text_stream_->Stop();
124 message_loop_.RunUntilIdle();
127 // Expect a stop callback if we were started.
128 ExpectPipelineStopAndDestroyPipeline();
129 pipeline_->Stop(base::Bind(&CallbackHelper::OnStop,
130 base::Unretained(&callbacks_)));
131 message_loop_.RunUntilIdle();
134 void OnDemuxerError() {
135 // Cast because OnDemuxerError is private in Pipeline.
136 static_cast<DemuxerHost*>(pipeline_.get())
137 ->OnDemuxerError(PIPELINE_ERROR_ABORT);
140 protected:
141 // Sets up expectations to allow the demuxer to initialize.
142 typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector;
143 void SetDemuxerExpectations(MockDemuxerStreamVector* streams,
144 const base::TimeDelta& duration) {
145 EXPECT_CALL(callbacks_, OnDurationChange());
146 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
147 .WillOnce(DoAll(SetDemuxerProperties(duration),
148 PostCallback<1>(PIPELINE_OK)));
150 // Configure the demuxer to return the streams.
151 for (size_t i = 0; i < streams->size(); ++i) {
152 DemuxerStream* stream = (*streams)[i];
153 EXPECT_CALL(*demuxer_, GetStream(stream->type()))
154 .WillRepeatedly(Return(stream));
158 void SetDemuxerExpectations(MockDemuxerStreamVector* streams) {
159 // Initialize with a default non-zero duration.
160 SetDemuxerExpectations(streams, base::TimeDelta::FromSeconds(10));
163 scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream(
164 DemuxerStream::Type type) {
165 scoped_ptr<StrictMock<MockDemuxerStream> > stream(
166 new StrictMock<MockDemuxerStream>(type));
167 return stream.Pass();
170 // Sets up expectations to allow the video renderer to initialize.
171 void SetRendererExpectations() {
172 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
173 .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_),
174 SaveArg<4>(&ended_cb_),
175 PostCallback<1>(PIPELINE_OK)));
176 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(audio_stream()));
177 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(video_stream()));
180 void AddTextStream() {
181 EXPECT_CALL(*this, OnAddTextTrack(_,_))
182 .WillOnce(Invoke(this, &PipelineTest::DoOnAddTextTrack));
183 static_cast<DemuxerHost*>(pipeline_.get())->AddTextStream(text_stream(),
184 TextTrackConfig(kTextSubtitles, "", "", ""));
185 message_loop_.RunUntilIdle();
188 void StartPipeline() {
189 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
190 pipeline_->Start(
191 demuxer_.get(), scoped_renderer_.Pass(),
192 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
193 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
194 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
195 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
196 base::Bind(&CallbackHelper::OnBufferingStateChange,
197 base::Unretained(&callbacks_)),
198 base::Bind(&CallbackHelper::OnDurationChange,
199 base::Unretained(&callbacks_)),
200 base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this)),
201 base::Bind(&PipelineTest::OnWaitingForDecryptionKey,
202 base::Unretained(this)));
205 // Sets up expectations on the callback and initializes the pipeline. Called
206 // after tests have set expectations any filters they wish to use.
207 void StartPipelineAndExpect(PipelineStatus start_status) {
208 EXPECT_CALL(callbacks_, OnStart(start_status));
210 if (start_status == PIPELINE_OK) {
211 EXPECT_CALL(callbacks_, OnMetadata(_)).WillOnce(SaveArg<0>(&metadata_));
212 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0));
213 EXPECT_CALL(*renderer_, SetVolume(1.0f));
214 EXPECT_CALL(*renderer_, StartPlayingFrom(start_time_))
215 .WillOnce(SetBufferingState(&buffering_state_cb_,
216 BUFFERING_HAVE_ENOUGH));
217 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
220 StartPipeline();
221 message_loop_.RunUntilIdle();
224 void CreateAudioStream() {
225 audio_stream_ = CreateStream(DemuxerStream::AUDIO);
228 void CreateVideoStream() {
229 video_stream_ = CreateStream(DemuxerStream::VIDEO);
230 video_stream_->set_video_decoder_config(video_decoder_config_);
233 void CreateTextStream() {
234 scoped_ptr<FakeTextTrackStream> text_stream(new FakeTextTrackStream());
235 EXPECT_CALL(*text_stream, OnRead()).Times(AnyNumber());
236 text_stream_ = text_stream.Pass();
239 MockDemuxerStream* audio_stream() {
240 return audio_stream_.get();
243 MockDemuxerStream* video_stream() {
244 return video_stream_.get();
247 FakeTextTrackStream* text_stream() {
248 return text_stream_.get();
251 void ExpectSeek(const base::TimeDelta& seek_time, bool underflowed) {
252 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
253 .WillOnce(RunCallback<1>(PIPELINE_OK));
255 EXPECT_CALL(*renderer_, Flush(_))
256 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
257 BUFFERING_HAVE_NOTHING),
258 RunClosure<0>()));
259 EXPECT_CALL(*renderer_, SetPlaybackRate(_));
260 EXPECT_CALL(*renderer_, SetVolume(_));
261 EXPECT_CALL(*renderer_, StartPlayingFrom(seek_time))
262 .WillOnce(SetBufferingState(&buffering_state_cb_,
263 BUFFERING_HAVE_ENOUGH));
264 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
266 // We expect a successful seek callback followed by a buffering update.
267 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
268 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
271 void DoSeek(const base::TimeDelta& seek_time) {
272 pipeline_->Seek(seek_time,
273 base::Bind(&CallbackHelper::OnSeek,
274 base::Unretained(&callbacks_)));
275 message_loop_.RunUntilIdle();
278 void DestroyPipeline() {
279 // In real code Pipeline could be destroyed on a different thread. All weak
280 // pointers must have been invalidated before the stop callback returns.
281 DCHECK(!pipeline_->HasWeakPtrsForTesting());
282 pipeline_.reset();
285 void ExpectDemuxerStop() {
286 if (demuxer_)
287 EXPECT_CALL(*demuxer_, Stop());
290 void ExpectPipelineStopAndDestroyPipeline() {
291 // After the Pipeline is stopped, it could be destroyed any time. Always
292 // destroy the pipeline immediately after OnStop() to test this.
293 EXPECT_CALL(callbacks_, OnStop())
294 .WillOnce(Invoke(this, &PipelineTest::DestroyPipeline));
297 MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&,
298 const AddTextTrackDoneCB&));
299 MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
301 void DoOnAddTextTrack(const TextTrackConfig& config,
302 const AddTextTrackDoneCB& done_cb) {
303 scoped_ptr<TextTrack> text_track(new MockTextTrack);
304 done_cb.Run(text_track.Pass());
307 // Fixture members.
308 StrictMock<CallbackHelper> callbacks_;
309 base::SimpleTestTickClock test_tick_clock_;
310 base::MessageLoop message_loop_;
311 scoped_ptr<Pipeline> pipeline_;
313 scoped_ptr<StrictMock<MockDemuxer> > demuxer_;
314 scoped_ptr<StrictMock<MockRenderer> > scoped_renderer_;
315 StrictMock<MockRenderer>* renderer_;
316 StrictMock<CallbackHelper> text_renderer_callbacks_;
317 TextRenderer* text_renderer_;
318 scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
319 scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
320 scoped_ptr<FakeTextTrackStream> text_stream_;
321 BufferingStateCB buffering_state_cb_;
322 base::Closure ended_cb_;
323 VideoDecoderConfig video_decoder_config_;
324 PipelineMetadata metadata_;
325 base::TimeDelta start_time_;
327 private:
328 DISALLOW_COPY_AND_ASSIGN(PipelineTest);
331 // Test that playback controls methods no-op when the pipeline hasn't been
332 // started.
333 TEST_F(PipelineTest, NotStarted) {
334 const base::TimeDelta kZero;
336 EXPECT_FALSE(pipeline_->IsRunning());
338 // Setting should still work.
339 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
340 pipeline_->SetPlaybackRate(-1.0);
341 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
342 pipeline_->SetPlaybackRate(1.0);
343 EXPECT_EQ(1.0f, pipeline_->GetPlaybackRate());
345 // Setting should still work.
346 EXPECT_EQ(1.0f, pipeline_->GetVolume());
347 pipeline_->SetVolume(-1.0f);
348 EXPECT_EQ(1.0f, pipeline_->GetVolume());
349 pipeline_->SetVolume(0.0f);
350 EXPECT_EQ(0.0f, pipeline_->GetVolume());
352 EXPECT_TRUE(kZero == pipeline_->GetMediaTime());
353 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
354 EXPECT_TRUE(kZero == pipeline_->GetMediaDuration());
357 TEST_F(PipelineTest, NeverInitializes) {
358 // Don't execute the callback passed into Initialize().
359 EXPECT_CALL(*demuxer_, Initialize(_, _, _));
361 // This test hangs during initialization by never calling
362 // InitializationComplete(). StrictMock<> will ensure that the callback is
363 // never executed.
364 StartPipeline();
365 message_loop_.RunUntilIdle();
367 // Because our callback will get executed when the test tears down, we'll
368 // verify that nothing has been called, then set our expectation for the call
369 // made during tear down.
370 Mock::VerifyAndClear(&callbacks_);
371 EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
374 TEST_F(PipelineTest, StopWithoutStart) {
375 ExpectPipelineStopAndDestroyPipeline();
376 pipeline_->Stop(
377 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
378 message_loop_.RunUntilIdle();
381 TEST_F(PipelineTest, StartThenStopImmediately) {
382 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
383 .WillOnce(PostCallback<1>(PIPELINE_OK));
384 EXPECT_CALL(*demuxer_, Stop());
386 EXPECT_CALL(callbacks_, OnStart(_));
387 StartPipeline();
389 // Expect a stop callback if we were started.
390 ExpectPipelineStopAndDestroyPipeline();
391 pipeline_->Stop(
392 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
393 message_loop_.RunUntilIdle();
396 TEST_F(PipelineTest, DemuxerErrorDuringStop) {
397 CreateAudioStream();
398 MockDemuxerStreamVector streams;
399 streams.push_back(audio_stream());
401 SetDemuxerExpectations(&streams);
402 SetRendererExpectations();
404 StartPipelineAndExpect(PIPELINE_OK);
406 EXPECT_CALL(*demuxer_, Stop())
407 .WillOnce(InvokeWithoutArgs(this, &PipelineTest::OnDemuxerError));
408 ExpectPipelineStopAndDestroyPipeline();
410 pipeline_->Stop(
411 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
412 message_loop_.RunUntilIdle();
415 TEST_F(PipelineTest, URLNotFound) {
416 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
417 .WillOnce(PostCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND));
418 EXPECT_CALL(*demuxer_, Stop());
420 StartPipelineAndExpect(PIPELINE_ERROR_URL_NOT_FOUND);
423 TEST_F(PipelineTest, NoStreams) {
424 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
425 .WillOnce(PostCallback<1>(PIPELINE_OK));
426 EXPECT_CALL(*demuxer_, Stop());
427 EXPECT_CALL(callbacks_, OnMetadata(_));
429 StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER);
432 TEST_F(PipelineTest, AudioStream) {
433 CreateAudioStream();
434 MockDemuxerStreamVector streams;
435 streams.push_back(audio_stream());
437 SetDemuxerExpectations(&streams);
438 SetRendererExpectations();
440 StartPipelineAndExpect(PIPELINE_OK);
441 EXPECT_TRUE(metadata_.has_audio);
442 EXPECT_FALSE(metadata_.has_video);
445 TEST_F(PipelineTest, VideoStream) {
446 CreateVideoStream();
447 MockDemuxerStreamVector streams;
448 streams.push_back(video_stream());
450 SetDemuxerExpectations(&streams);
451 SetRendererExpectations();
453 StartPipelineAndExpect(PIPELINE_OK);
454 EXPECT_FALSE(metadata_.has_audio);
455 EXPECT_TRUE(metadata_.has_video);
458 TEST_F(PipelineTest, AudioVideoStream) {
459 CreateAudioStream();
460 CreateVideoStream();
461 MockDemuxerStreamVector streams;
462 streams.push_back(audio_stream());
463 streams.push_back(video_stream());
465 SetDemuxerExpectations(&streams);
466 SetRendererExpectations();
468 StartPipelineAndExpect(PIPELINE_OK);
469 EXPECT_TRUE(metadata_.has_audio);
470 EXPECT_TRUE(metadata_.has_video);
473 TEST_F(PipelineTest, VideoTextStream) {
474 CreateVideoStream();
475 CreateTextStream();
476 MockDemuxerStreamVector streams;
477 streams.push_back(video_stream());
479 SetDemuxerExpectations(&streams);
480 SetRendererExpectations();
482 StartPipelineAndExpect(PIPELINE_OK);
483 EXPECT_FALSE(metadata_.has_audio);
484 EXPECT_TRUE(metadata_.has_video);
486 AddTextStream();
489 TEST_F(PipelineTest, VideoAudioTextStream) {
490 CreateVideoStream();
491 CreateAudioStream();
492 CreateTextStream();
493 MockDemuxerStreamVector streams;
494 streams.push_back(video_stream());
495 streams.push_back(audio_stream());
497 SetDemuxerExpectations(&streams);
498 SetRendererExpectations();
500 StartPipelineAndExpect(PIPELINE_OK);
501 EXPECT_TRUE(metadata_.has_audio);
502 EXPECT_TRUE(metadata_.has_video);
504 AddTextStream();
507 TEST_F(PipelineTest, Seek) {
508 CreateAudioStream();
509 CreateVideoStream();
510 CreateTextStream();
511 MockDemuxerStreamVector streams;
512 streams.push_back(audio_stream());
513 streams.push_back(video_stream());
515 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
516 SetRendererExpectations();
518 // Initialize then seek!
519 StartPipelineAndExpect(PIPELINE_OK);
521 // Every filter should receive a call to Seek().
522 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
523 ExpectSeek(expected, false);
524 DoSeek(expected);
527 TEST_F(PipelineTest, SeekAfterError) {
528 CreateAudioStream();
529 MockDemuxerStreamVector streams;
530 streams.push_back(audio_stream());
532 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
533 SetRendererExpectations();
535 // Initialize then seek!
536 StartPipelineAndExpect(PIPELINE_OK);
538 EXPECT_CALL(*demuxer_, Stop());
539 EXPECT_CALL(callbacks_, OnError(_));
541 static_cast<DemuxerHost*>(pipeline_.get())
542 ->OnDemuxerError(PIPELINE_ERROR_ABORT);
543 message_loop_.RunUntilIdle();
545 pipeline_->Seek(
546 base::TimeDelta::FromMilliseconds(100),
547 base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
548 message_loop_.RunUntilIdle();
551 TEST_F(PipelineTest, SetVolume) {
552 CreateAudioStream();
553 MockDemuxerStreamVector streams;
554 streams.push_back(audio_stream());
556 SetDemuxerExpectations(&streams);
557 SetRendererExpectations();
559 // The audio renderer should receive a call to SetVolume().
560 float expected = 0.5f;
561 EXPECT_CALL(*renderer_, SetVolume(expected));
563 // Initialize then set volume!
564 StartPipelineAndExpect(PIPELINE_OK);
565 pipeline_->SetVolume(expected);
568 TEST_F(PipelineTest, Properties) {
569 CreateVideoStream();
570 MockDemuxerStreamVector streams;
571 streams.push_back(video_stream());
573 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
574 SetDemuxerExpectations(&streams, kDuration);
575 SetRendererExpectations();
577 StartPipelineAndExpect(PIPELINE_OK);
578 EXPECT_EQ(kDuration.ToInternalValue(),
579 pipeline_->GetMediaDuration().ToInternalValue());
580 EXPECT_FALSE(pipeline_->DidLoadingProgress());
583 TEST_F(PipelineTest, GetBufferedTimeRanges) {
584 CreateVideoStream();
585 MockDemuxerStreamVector streams;
586 streams.push_back(video_stream());
588 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
589 SetDemuxerExpectations(&streams, kDuration);
590 SetRendererExpectations();
592 StartPipelineAndExpect(PIPELINE_OK);
594 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
596 EXPECT_FALSE(pipeline_->DidLoadingProgress());
597 pipeline_->AddBufferedTimeRange(base::TimeDelta(), kDuration / 8);
598 EXPECT_TRUE(pipeline_->DidLoadingProgress());
599 EXPECT_FALSE(pipeline_->DidLoadingProgress());
600 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
601 EXPECT_EQ(base::TimeDelta(), pipeline_->GetBufferedTimeRanges().start(0));
602 EXPECT_EQ(kDuration / 8, pipeline_->GetBufferedTimeRanges().end(0));
604 base::TimeDelta kSeekTime = kDuration / 2;
605 ExpectSeek(kSeekTime, false);
606 DoSeek(kSeekTime);
608 EXPECT_FALSE(pipeline_->DidLoadingProgress());
611 TEST_F(PipelineTest, EndedCallback) {
612 CreateAudioStream();
613 CreateVideoStream();
614 CreateTextStream();
615 MockDemuxerStreamVector streams;
616 streams.push_back(audio_stream());
617 streams.push_back(video_stream());
619 SetDemuxerExpectations(&streams);
620 SetRendererExpectations();
621 StartPipelineAndExpect(PIPELINE_OK);
623 AddTextStream();
625 // The ended callback shouldn't run until all renderers have ended.
626 ended_cb_.Run();
627 message_loop_.RunUntilIdle();
629 EXPECT_CALL(callbacks_, OnEnded());
630 text_stream()->SendEosNotification();
631 message_loop_.RunUntilIdle();
634 TEST_F(PipelineTest, ErrorDuringSeek) {
635 CreateAudioStream();
636 MockDemuxerStreamVector streams;
637 streams.push_back(audio_stream());
639 SetDemuxerExpectations(&streams);
640 SetRendererExpectations();
641 StartPipelineAndExpect(PIPELINE_OK);
643 double playback_rate = 1.0;
644 EXPECT_CALL(*renderer_, SetPlaybackRate(playback_rate));
645 pipeline_->SetPlaybackRate(playback_rate);
646 message_loop_.RunUntilIdle();
648 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
650 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
651 EXPECT_CALL(*renderer_, Flush(_))
652 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
653 BUFFERING_HAVE_NOTHING),
654 RunClosure<0>()));
656 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
657 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
658 EXPECT_CALL(*demuxer_, Stop());
660 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
661 base::Unretained(&callbacks_)));
662 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
663 message_loop_.RunUntilIdle();
666 // Invoked function OnError. This asserts that the pipeline does not enqueue
667 // non-teardown related tasks while tearing down.
668 static void TestNoCallsAfterError(
669 Pipeline* pipeline, base::MessageLoop* message_loop,
670 PipelineStatus /* status */) {
671 CHECK(pipeline);
672 CHECK(message_loop);
674 // When we get to this stage, the message loop should be empty.
675 EXPECT_TRUE(message_loop->IsIdleForTesting());
677 // Make calls on pipeline after error has occurred.
678 pipeline->SetPlaybackRate(0.5);
679 pipeline->SetVolume(0.5f);
681 // No additional tasks should be queued as a result of these calls.
682 EXPECT_TRUE(message_loop->IsIdleForTesting());
685 TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
686 CreateAudioStream();
687 MockDemuxerStreamVector streams;
688 streams.push_back(audio_stream());
690 SetDemuxerExpectations(&streams);
691 SetRendererExpectations();
692 StartPipelineAndExpect(PIPELINE_OK);
694 // Trigger additional requests on the pipeline during tear down from error.
695 base::Callback<void(PipelineStatus)> cb = base::Bind(
696 &TestNoCallsAfterError, pipeline_.get(), &message_loop_);
697 ON_CALL(callbacks_, OnError(_))
698 .WillByDefault(Invoke(&cb, &base::Callback<void(PipelineStatus)>::Run));
700 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
702 // Seek() isn't called as the demuxer errors out first.
703 EXPECT_CALL(*renderer_, Flush(_))
704 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
705 BUFFERING_HAVE_NOTHING),
706 RunClosure<0>()));
707 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
709 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
710 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
711 EXPECT_CALL(*demuxer_, Stop());
713 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
714 base::Unretained(&callbacks_)));
715 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
716 message_loop_.RunUntilIdle();
719 TEST_F(PipelineTest, DestroyAfterStop) {
720 CreateAudioStream();
721 MockDemuxerStreamVector streams;
722 streams.push_back(audio_stream());
723 SetDemuxerExpectations(&streams);
724 SetRendererExpectations();
725 StartPipelineAndExpect(PIPELINE_OK);
727 ExpectDemuxerStop();
729 ExpectPipelineStopAndDestroyPipeline();
730 pipeline_->Stop(
731 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
732 message_loop_.RunUntilIdle();
735 TEST_F(PipelineTest, Underflow) {
736 CreateAudioStream();
737 CreateVideoStream();
738 MockDemuxerStreamVector streams;
739 streams.push_back(audio_stream());
740 streams.push_back(video_stream());
742 SetDemuxerExpectations(&streams);
743 SetRendererExpectations();
744 StartPipelineAndExpect(PIPELINE_OK);
746 // Simulate underflow.
747 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
748 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
750 // Seek while underflowed.
751 base::TimeDelta expected = base::TimeDelta::FromSeconds(5);
752 ExpectSeek(expected, true);
753 DoSeek(expected);
756 TEST_F(PipelineTest, PositiveStartTime) {
757 start_time_ = base::TimeDelta::FromSeconds(1);
758 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
759 CreateAudioStream();
760 MockDemuxerStreamVector streams;
761 streams.push_back(audio_stream());
762 SetDemuxerExpectations(&streams);
763 SetRendererExpectations();
764 StartPipelineAndExpect(PIPELINE_OK);
765 ExpectDemuxerStop();
766 ExpectPipelineStopAndDestroyPipeline();
767 pipeline_->Stop(
768 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
769 message_loop_.RunUntilIdle();
772 class PipelineTeardownTest : public PipelineTest {
773 public:
774 enum TeardownState {
775 kInitDemuxer,
776 kInitRenderer,
777 kFlushing,
778 kSeeking,
779 kPlaying,
782 enum StopOrError {
783 kStop,
784 kError,
785 kErrorAndStop,
788 PipelineTeardownTest() {}
789 ~PipelineTeardownTest() override {}
791 void RunTest(TeardownState state, StopOrError stop_or_error) {
792 switch (state) {
793 case kInitDemuxer:
794 case kInitRenderer:
795 DoInitialize(state, stop_or_error);
796 break;
798 case kFlushing:
799 case kSeeking:
800 DoInitialize(state, stop_or_error);
801 DoSeek(state, stop_or_error);
802 break;
804 case kPlaying:
805 DoInitialize(state, stop_or_error);
806 DoStopOrError(stop_or_error);
807 break;
811 private:
812 // TODO(scherkus): We do radically different things whether teardown is
813 // invoked via stop vs error. The teardown path should be the same,
814 // see http://crbug.com/110228
815 void DoInitialize(TeardownState state, StopOrError stop_or_error) {
816 PipelineStatus expected_status =
817 SetInitializeExpectations(state, stop_or_error);
819 EXPECT_CALL(callbacks_, OnStart(expected_status));
820 StartPipeline();
821 message_loop_.RunUntilIdle();
824 PipelineStatus SetInitializeExpectations(TeardownState state,
825 StopOrError stop_or_error) {
826 PipelineStatus status = PIPELINE_OK;
827 base::Closure stop_cb = base::Bind(
828 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
830 if (state == kInitDemuxer) {
831 if (stop_or_error == kStop) {
832 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
833 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
834 PostCallback<1>(PIPELINE_OK)));
835 ExpectPipelineStopAndDestroyPipeline();
836 } else {
837 status = DEMUXER_ERROR_COULD_NOT_OPEN;
838 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
839 .WillOnce(PostCallback<1>(status));
842 EXPECT_CALL(*demuxer_, Stop());
843 return status;
846 CreateAudioStream();
847 CreateVideoStream();
848 MockDemuxerStreamVector streams;
849 streams.push_back(audio_stream());
850 streams.push_back(video_stream());
851 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
853 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(true));
854 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(true));
856 if (state == kInitRenderer) {
857 if (stop_or_error == kStop) {
858 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
859 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
860 PostCallback<1>(PIPELINE_OK)));
861 ExpectPipelineStopAndDestroyPipeline();
862 } else {
863 status = PIPELINE_ERROR_INITIALIZATION_FAILED;
864 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
865 .WillOnce(PostCallback<1>(status));
868 EXPECT_CALL(*demuxer_, Stop());
869 EXPECT_CALL(callbacks_, OnMetadata(_));
870 return status;
873 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
874 .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_),
875 PostCallback<1>(PIPELINE_OK)));
877 EXPECT_CALL(callbacks_, OnMetadata(_));
879 // If we get here it's a successful initialization.
880 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0));
881 EXPECT_CALL(*renderer_, SetVolume(1.0f));
882 EXPECT_CALL(*renderer_, StartPlayingFrom(base::TimeDelta()))
883 .WillOnce(SetBufferingState(&buffering_state_cb_,
884 BUFFERING_HAVE_ENOUGH));
886 if (status == PIPELINE_OK)
887 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
889 return status;
892 void DoSeek(TeardownState state, StopOrError stop_or_error) {
893 InSequence s;
894 PipelineStatus status = SetSeekExpectations(state, stop_or_error);
896 EXPECT_CALL(*demuxer_, Stop());
897 EXPECT_CALL(callbacks_, OnSeek(status));
899 if (status == PIPELINE_OK) {
900 ExpectPipelineStopAndDestroyPipeline();
903 pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
904 &CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
905 message_loop_.RunUntilIdle();
908 PipelineStatus SetSeekExpectations(TeardownState state,
909 StopOrError stop_or_error) {
910 PipelineStatus status = PIPELINE_OK;
911 base::Closure stop_cb = base::Bind(
912 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
914 if (state == kFlushing) {
915 if (stop_or_error == kStop) {
916 EXPECT_CALL(*renderer_, Flush(_))
917 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
918 SetBufferingState(&buffering_state_cb_,
919 BUFFERING_HAVE_NOTHING),
920 RunClosure<0>()));
921 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
922 } else {
923 status = PIPELINE_ERROR_READ;
924 EXPECT_CALL(*renderer_, Flush(_))
925 .WillOnce(DoAll(SetError(pipeline_.get(), status),
926 SetBufferingState(&buffering_state_cb_,
927 BUFFERING_HAVE_NOTHING),
928 RunClosure<0>()));
929 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
932 return status;
935 EXPECT_CALL(*renderer_, Flush(_))
936 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
937 BUFFERING_HAVE_NOTHING),
938 RunClosure<0>()));
939 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
941 if (state == kSeeking) {
942 if (stop_or_error == kStop) {
943 EXPECT_CALL(*demuxer_, Seek(_, _))
944 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
945 RunCallback<1>(PIPELINE_OK)));
946 } else {
947 status = PIPELINE_ERROR_READ;
948 EXPECT_CALL(*demuxer_, Seek(_, _))
949 .WillOnce(RunCallback<1>(status));
952 return status;
955 NOTREACHED() << "State not supported: " << state;
956 return status;
959 void DoStopOrError(StopOrError stop_or_error) {
960 InSequence s;
962 EXPECT_CALL(*demuxer_, Stop());
964 switch (stop_or_error) {
965 case kStop:
966 ExpectPipelineStopAndDestroyPipeline();
967 pipeline_->Stop(base::Bind(
968 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
969 break;
971 case kError:
972 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
973 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
974 break;
976 case kErrorAndStop:
977 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
978 ExpectPipelineStopAndDestroyPipeline();
979 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
980 message_loop_.RunUntilIdle();
981 pipeline_->Stop(base::Bind(
982 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
983 break;
986 message_loop_.RunUntilIdle();
989 DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest);
992 #define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \
993 TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
994 RunTest(k##state, k##stop_or_error); \
997 INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer);
998 INSTANTIATE_TEARDOWN_TEST(Stop, InitRenderer);
999 INSTANTIATE_TEARDOWN_TEST(Stop, Flushing);
1000 INSTANTIATE_TEARDOWN_TEST(Stop, Seeking);
1001 INSTANTIATE_TEARDOWN_TEST(Stop, Playing);
1003 INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer);
1004 INSTANTIATE_TEARDOWN_TEST(Error, InitRenderer);
1005 INSTANTIATE_TEARDOWN_TEST(Error, Flushing);
1006 INSTANTIATE_TEARDOWN_TEST(Error, Seeking);
1007 INSTANTIATE_TEARDOWN_TEST(Error, Playing);
1009 INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);
1011 } // namespace media