[Ozone-Gbm] Explicitly crash if trying software rendering on GBM
[chromium-blink-merge.git] / media / base / pipeline_unittest.cc
blobaffb64326f3aa23b12ba1c949e38b295cf1c6293
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 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::OnVideoFramePaint,
199 base::Unretained(&callbacks_)),
200 base::Bind(&CallbackHelper::OnDurationChange,
201 base::Unretained(&callbacks_)),
202 base::Bind(&PipelineTest::OnAddTextTrack, 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.0f));
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&));
300 void DoOnAddTextTrack(const TextTrackConfig& config,
301 const AddTextTrackDoneCB& done_cb) {
302 scoped_ptr<TextTrack> text_track(new MockTextTrack);
303 done_cb.Run(text_track.Pass());
306 // Fixture members.
307 StrictMock<CallbackHelper> callbacks_;
308 base::SimpleTestTickClock test_tick_clock_;
309 base::MessageLoop message_loop_;
310 scoped_ptr<Pipeline> pipeline_;
312 scoped_ptr<StrictMock<MockDemuxer> > demuxer_;
313 scoped_ptr<StrictMock<MockRenderer> > scoped_renderer_;
314 StrictMock<MockRenderer>* renderer_;
315 StrictMock<CallbackHelper> text_renderer_callbacks_;
316 TextRenderer* text_renderer_;
317 scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
318 scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
319 scoped_ptr<FakeTextTrackStream> text_stream_;
320 BufferingStateCB buffering_state_cb_;
321 base::Closure ended_cb_;
322 VideoDecoderConfig video_decoder_config_;
323 PipelineMetadata metadata_;
324 base::TimeDelta start_time_;
326 private:
327 DISALLOW_COPY_AND_ASSIGN(PipelineTest);
330 // Test that playback controls methods no-op when the pipeline hasn't been
331 // started.
332 TEST_F(PipelineTest, NotStarted) {
333 const base::TimeDelta kZero;
335 EXPECT_FALSE(pipeline_->IsRunning());
337 // Setting should still work.
338 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
339 pipeline_->SetPlaybackRate(-1.0f);
340 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
341 pipeline_->SetPlaybackRate(1.0f);
342 EXPECT_EQ(1.0f, pipeline_->GetPlaybackRate());
344 // Setting should still work.
345 EXPECT_EQ(1.0f, pipeline_->GetVolume());
346 pipeline_->SetVolume(-1.0f);
347 EXPECT_EQ(1.0f, pipeline_->GetVolume());
348 pipeline_->SetVolume(0.0f);
349 EXPECT_EQ(0.0f, pipeline_->GetVolume());
351 EXPECT_TRUE(kZero == pipeline_->GetMediaTime());
352 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
353 EXPECT_TRUE(kZero == pipeline_->GetMediaDuration());
356 TEST_F(PipelineTest, NeverInitializes) {
357 // Don't execute the callback passed into Initialize().
358 EXPECT_CALL(*demuxer_, Initialize(_, _, _));
360 // This test hangs during initialization by never calling
361 // InitializationComplete(). StrictMock<> will ensure that the callback is
362 // never executed.
363 StartPipeline();
364 message_loop_.RunUntilIdle();
366 // Because our callback will get executed when the test tears down, we'll
367 // verify that nothing has been called, then set our expectation for the call
368 // made during tear down.
369 Mock::VerifyAndClear(&callbacks_);
370 EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
373 TEST_F(PipelineTest, StopWithoutStart) {
374 ExpectPipelineStopAndDestroyPipeline();
375 pipeline_->Stop(
376 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
377 message_loop_.RunUntilIdle();
380 TEST_F(PipelineTest, StartThenStopImmediately) {
381 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
382 .WillOnce(PostCallback<1>(PIPELINE_OK));
383 EXPECT_CALL(*demuxer_, Stop());
385 EXPECT_CALL(callbacks_, OnStart(_));
386 StartPipeline();
388 // Expect a stop callback if we were started.
389 ExpectPipelineStopAndDestroyPipeline();
390 pipeline_->Stop(
391 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
392 message_loop_.RunUntilIdle();
395 TEST_F(PipelineTest, DemuxerErrorDuringStop) {
396 CreateAudioStream();
397 MockDemuxerStreamVector streams;
398 streams.push_back(audio_stream());
400 SetDemuxerExpectations(&streams);
401 SetRendererExpectations();
403 StartPipelineAndExpect(PIPELINE_OK);
405 EXPECT_CALL(*demuxer_, Stop())
406 .WillOnce(InvokeWithoutArgs(this, &PipelineTest::OnDemuxerError));
407 ExpectPipelineStopAndDestroyPipeline();
409 pipeline_->Stop(
410 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
411 message_loop_.RunUntilIdle();
414 TEST_F(PipelineTest, URLNotFound) {
415 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
416 .WillOnce(PostCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND));
417 EXPECT_CALL(*demuxer_, Stop());
419 StartPipelineAndExpect(PIPELINE_ERROR_URL_NOT_FOUND);
422 TEST_F(PipelineTest, NoStreams) {
423 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
424 .WillOnce(PostCallback<1>(PIPELINE_OK));
425 EXPECT_CALL(*demuxer_, Stop());
426 EXPECT_CALL(callbacks_, OnMetadata(_));
428 StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER);
431 TEST_F(PipelineTest, AudioStream) {
432 CreateAudioStream();
433 MockDemuxerStreamVector streams;
434 streams.push_back(audio_stream());
436 SetDemuxerExpectations(&streams);
437 SetRendererExpectations();
439 StartPipelineAndExpect(PIPELINE_OK);
440 EXPECT_TRUE(metadata_.has_audio);
441 EXPECT_FALSE(metadata_.has_video);
444 TEST_F(PipelineTest, VideoStream) {
445 CreateVideoStream();
446 MockDemuxerStreamVector streams;
447 streams.push_back(video_stream());
449 SetDemuxerExpectations(&streams);
450 SetRendererExpectations();
452 StartPipelineAndExpect(PIPELINE_OK);
453 EXPECT_FALSE(metadata_.has_audio);
454 EXPECT_TRUE(metadata_.has_video);
457 TEST_F(PipelineTest, AudioVideoStream) {
458 CreateAudioStream();
459 CreateVideoStream();
460 MockDemuxerStreamVector streams;
461 streams.push_back(audio_stream());
462 streams.push_back(video_stream());
464 SetDemuxerExpectations(&streams);
465 SetRendererExpectations();
467 StartPipelineAndExpect(PIPELINE_OK);
468 EXPECT_TRUE(metadata_.has_audio);
469 EXPECT_TRUE(metadata_.has_video);
472 TEST_F(PipelineTest, VideoTextStream) {
473 CreateVideoStream();
474 CreateTextStream();
475 MockDemuxerStreamVector streams;
476 streams.push_back(video_stream());
478 SetDemuxerExpectations(&streams);
479 SetRendererExpectations();
481 StartPipelineAndExpect(PIPELINE_OK);
482 EXPECT_FALSE(metadata_.has_audio);
483 EXPECT_TRUE(metadata_.has_video);
485 AddTextStream();
488 TEST_F(PipelineTest, VideoAudioTextStream) {
489 CreateVideoStream();
490 CreateAudioStream();
491 CreateTextStream();
492 MockDemuxerStreamVector streams;
493 streams.push_back(video_stream());
494 streams.push_back(audio_stream());
496 SetDemuxerExpectations(&streams);
497 SetRendererExpectations();
499 StartPipelineAndExpect(PIPELINE_OK);
500 EXPECT_TRUE(metadata_.has_audio);
501 EXPECT_TRUE(metadata_.has_video);
503 AddTextStream();
506 TEST_F(PipelineTest, Seek) {
507 CreateAudioStream();
508 CreateVideoStream();
509 CreateTextStream();
510 MockDemuxerStreamVector streams;
511 streams.push_back(audio_stream());
512 streams.push_back(video_stream());
514 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
515 SetRendererExpectations();
517 // Initialize then seek!
518 StartPipelineAndExpect(PIPELINE_OK);
520 // Every filter should receive a call to Seek().
521 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
522 ExpectSeek(expected, false);
523 DoSeek(expected);
526 TEST_F(PipelineTest, SeekAfterError) {
527 CreateAudioStream();
528 MockDemuxerStreamVector streams;
529 streams.push_back(audio_stream());
531 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
532 SetRendererExpectations();
534 // Initialize then seek!
535 StartPipelineAndExpect(PIPELINE_OK);
537 EXPECT_CALL(*demuxer_, Stop());
538 EXPECT_CALL(callbacks_, OnError(_));
540 static_cast<DemuxerHost*>(pipeline_.get())
541 ->OnDemuxerError(PIPELINE_ERROR_ABORT);
542 message_loop_.RunUntilIdle();
544 pipeline_->Seek(
545 base::TimeDelta::FromMilliseconds(100),
546 base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
547 message_loop_.RunUntilIdle();
550 TEST_F(PipelineTest, SetVolume) {
551 CreateAudioStream();
552 MockDemuxerStreamVector streams;
553 streams.push_back(audio_stream());
555 SetDemuxerExpectations(&streams);
556 SetRendererExpectations();
558 // The audio renderer should receive a call to SetVolume().
559 float expected = 0.5f;
560 EXPECT_CALL(*renderer_, SetVolume(expected));
562 // Initialize then set volume!
563 StartPipelineAndExpect(PIPELINE_OK);
564 pipeline_->SetVolume(expected);
567 TEST_F(PipelineTest, Properties) {
568 CreateVideoStream();
569 MockDemuxerStreamVector streams;
570 streams.push_back(video_stream());
572 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
573 SetDemuxerExpectations(&streams, kDuration);
574 SetRendererExpectations();
576 StartPipelineAndExpect(PIPELINE_OK);
577 EXPECT_EQ(kDuration.ToInternalValue(),
578 pipeline_->GetMediaDuration().ToInternalValue());
579 EXPECT_FALSE(pipeline_->DidLoadingProgress());
582 TEST_F(PipelineTest, GetBufferedTimeRanges) {
583 CreateVideoStream();
584 MockDemuxerStreamVector streams;
585 streams.push_back(video_stream());
587 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
588 SetDemuxerExpectations(&streams, kDuration);
589 SetRendererExpectations();
591 StartPipelineAndExpect(PIPELINE_OK);
593 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
595 EXPECT_FALSE(pipeline_->DidLoadingProgress());
596 pipeline_->AddBufferedTimeRange(base::TimeDelta(), kDuration / 8);
597 EXPECT_TRUE(pipeline_->DidLoadingProgress());
598 EXPECT_FALSE(pipeline_->DidLoadingProgress());
599 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
600 EXPECT_EQ(base::TimeDelta(), pipeline_->GetBufferedTimeRanges().start(0));
601 EXPECT_EQ(kDuration / 8, pipeline_->GetBufferedTimeRanges().end(0));
603 base::TimeDelta kSeekTime = kDuration / 2;
604 ExpectSeek(kSeekTime, false);
605 DoSeek(kSeekTime);
607 EXPECT_FALSE(pipeline_->DidLoadingProgress());
610 TEST_F(PipelineTest, EndedCallback) {
611 CreateAudioStream();
612 CreateVideoStream();
613 CreateTextStream();
614 MockDemuxerStreamVector streams;
615 streams.push_back(audio_stream());
616 streams.push_back(video_stream());
618 SetDemuxerExpectations(&streams);
619 SetRendererExpectations();
620 StartPipelineAndExpect(PIPELINE_OK);
622 AddTextStream();
624 // The ended callback shouldn't run until all renderers have ended.
625 ended_cb_.Run();
626 message_loop_.RunUntilIdle();
628 EXPECT_CALL(callbacks_, OnEnded());
629 // Since the |ended_cb_| is manually invoked above, the duration does not
630 // match the expected duration and is updated upon ended.
631 EXPECT_CALL(callbacks_, OnDurationChange());
632 text_stream()->SendEosNotification();
633 message_loop_.RunUntilIdle();
636 TEST_F(PipelineTest, ErrorDuringSeek) {
637 CreateAudioStream();
638 MockDemuxerStreamVector streams;
639 streams.push_back(audio_stream());
641 SetDemuxerExpectations(&streams);
642 SetRendererExpectations();
643 StartPipelineAndExpect(PIPELINE_OK);
645 float playback_rate = 1.0f;
646 EXPECT_CALL(*renderer_, SetPlaybackRate(playback_rate));
647 pipeline_->SetPlaybackRate(playback_rate);
648 message_loop_.RunUntilIdle();
650 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
652 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
653 EXPECT_CALL(*renderer_, Flush(_))
654 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
655 BUFFERING_HAVE_NOTHING),
656 RunClosure<0>()));
658 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
659 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
660 EXPECT_CALL(*demuxer_, Stop());
662 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
663 base::Unretained(&callbacks_)));
664 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
665 message_loop_.RunUntilIdle();
668 // Invoked function OnError. This asserts that the pipeline does not enqueue
669 // non-teardown related tasks while tearing down.
670 static void TestNoCallsAfterError(
671 Pipeline* pipeline, base::MessageLoop* message_loop,
672 PipelineStatus /* status */) {
673 CHECK(pipeline);
674 CHECK(message_loop);
676 // When we get to this stage, the message loop should be empty.
677 EXPECT_TRUE(message_loop->IsIdleForTesting());
679 // Make calls on pipeline after error has occurred.
680 pipeline->SetPlaybackRate(0.5f);
681 pipeline->SetVolume(0.5f);
683 // No additional tasks should be queued as a result of these calls.
684 EXPECT_TRUE(message_loop->IsIdleForTesting());
687 TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
688 CreateAudioStream();
689 MockDemuxerStreamVector streams;
690 streams.push_back(audio_stream());
692 SetDemuxerExpectations(&streams);
693 SetRendererExpectations();
694 StartPipelineAndExpect(PIPELINE_OK);
696 // Trigger additional requests on the pipeline during tear down from error.
697 base::Callback<void(PipelineStatus)> cb = base::Bind(
698 &TestNoCallsAfterError, pipeline_.get(), &message_loop_);
699 ON_CALL(callbacks_, OnError(_))
700 .WillByDefault(Invoke(&cb, &base::Callback<void(PipelineStatus)>::Run));
702 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
704 // Seek() isn't called as the demuxer errors out first.
705 EXPECT_CALL(*renderer_, Flush(_))
706 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
707 BUFFERING_HAVE_NOTHING),
708 RunClosure<0>()));
709 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
711 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
712 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
713 EXPECT_CALL(*demuxer_, Stop());
715 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
716 base::Unretained(&callbacks_)));
717 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
718 message_loop_.RunUntilIdle();
721 TEST_F(PipelineTest, DestroyAfterStop) {
722 CreateAudioStream();
723 MockDemuxerStreamVector streams;
724 streams.push_back(audio_stream());
725 SetDemuxerExpectations(&streams);
726 SetRendererExpectations();
727 StartPipelineAndExpect(PIPELINE_OK);
729 ExpectDemuxerStop();
731 ExpectPipelineStopAndDestroyPipeline();
732 pipeline_->Stop(
733 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
734 message_loop_.RunUntilIdle();
737 TEST_F(PipelineTest, Underflow) {
738 CreateAudioStream();
739 CreateVideoStream();
740 MockDemuxerStreamVector streams;
741 streams.push_back(audio_stream());
742 streams.push_back(video_stream());
744 SetDemuxerExpectations(&streams);
745 SetRendererExpectations();
746 StartPipelineAndExpect(PIPELINE_OK);
748 // Simulate underflow.
749 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
750 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
752 // Seek while underflowed.
753 base::TimeDelta expected = base::TimeDelta::FromSeconds(5);
754 ExpectSeek(expected, true);
755 DoSeek(expected);
758 TEST_F(PipelineTest, PositiveStartTime) {
759 start_time_ = base::TimeDelta::FromSeconds(1);
760 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
761 CreateAudioStream();
762 MockDemuxerStreamVector streams;
763 streams.push_back(audio_stream());
764 SetDemuxerExpectations(&streams);
765 SetRendererExpectations();
766 StartPipelineAndExpect(PIPELINE_OK);
767 ExpectDemuxerStop();
768 ExpectPipelineStopAndDestroyPipeline();
769 pipeline_->Stop(
770 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
771 message_loop_.RunUntilIdle();
774 class PipelineTeardownTest : public PipelineTest {
775 public:
776 enum TeardownState {
777 kInitDemuxer,
778 kInitRenderer,
779 kFlushing,
780 kSeeking,
781 kPlaying,
784 enum StopOrError {
785 kStop,
786 kError,
787 kErrorAndStop,
790 PipelineTeardownTest() {}
791 ~PipelineTeardownTest() override {}
793 void RunTest(TeardownState state, StopOrError stop_or_error) {
794 switch (state) {
795 case kInitDemuxer:
796 case kInitRenderer:
797 DoInitialize(state, stop_or_error);
798 break;
800 case kFlushing:
801 case kSeeking:
802 DoInitialize(state, stop_or_error);
803 DoSeek(state, stop_or_error);
804 break;
806 case kPlaying:
807 DoInitialize(state, stop_or_error);
808 DoStopOrError(stop_or_error);
809 break;
813 private:
814 // TODO(scherkus): We do radically different things whether teardown is
815 // invoked via stop vs error. The teardown path should be the same,
816 // see http://crbug.com/110228
817 void DoInitialize(TeardownState state, StopOrError stop_or_error) {
818 PipelineStatus expected_status =
819 SetInitializeExpectations(state, stop_or_error);
821 EXPECT_CALL(callbacks_, OnStart(expected_status));
822 StartPipeline();
823 message_loop_.RunUntilIdle();
826 PipelineStatus SetInitializeExpectations(TeardownState state,
827 StopOrError stop_or_error) {
828 PipelineStatus status = PIPELINE_OK;
829 base::Closure stop_cb = base::Bind(
830 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
832 if (state == kInitDemuxer) {
833 if (stop_or_error == kStop) {
834 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
835 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
836 PostCallback<1>(PIPELINE_OK)));
837 ExpectPipelineStopAndDestroyPipeline();
838 } else {
839 status = DEMUXER_ERROR_COULD_NOT_OPEN;
840 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
841 .WillOnce(PostCallback<1>(status));
844 EXPECT_CALL(*demuxer_, Stop());
845 return status;
848 CreateAudioStream();
849 CreateVideoStream();
850 MockDemuxerStreamVector streams;
851 streams.push_back(audio_stream());
852 streams.push_back(video_stream());
853 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
855 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(true));
856 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(true));
858 if (state == kInitRenderer) {
859 if (stop_or_error == kStop) {
860 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
861 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
862 PostCallback<1>(PIPELINE_OK)));
863 ExpectPipelineStopAndDestroyPipeline();
864 } else {
865 status = PIPELINE_ERROR_INITIALIZATION_FAILED;
866 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
867 .WillOnce(PostCallback<1>(status));
870 EXPECT_CALL(*demuxer_, Stop());
871 EXPECT_CALL(callbacks_, OnMetadata(_));
872 return status;
875 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
876 .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_),
877 PostCallback<1>(PIPELINE_OK)));
879 EXPECT_CALL(callbacks_, OnMetadata(_));
881 // If we get here it's a successful initialization.
882 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0f));
883 EXPECT_CALL(*renderer_, SetVolume(1.0f));
884 EXPECT_CALL(*renderer_, StartPlayingFrom(base::TimeDelta()))
885 .WillOnce(SetBufferingState(&buffering_state_cb_,
886 BUFFERING_HAVE_ENOUGH));
888 if (status == PIPELINE_OK)
889 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
891 return status;
894 void DoSeek(TeardownState state, StopOrError stop_or_error) {
895 InSequence s;
896 PipelineStatus status = SetSeekExpectations(state, stop_or_error);
898 EXPECT_CALL(*demuxer_, Stop());
899 EXPECT_CALL(callbacks_, OnSeek(status));
901 if (status == PIPELINE_OK) {
902 ExpectPipelineStopAndDestroyPipeline();
905 pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
906 &CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
907 message_loop_.RunUntilIdle();
910 PipelineStatus SetSeekExpectations(TeardownState state,
911 StopOrError stop_or_error) {
912 PipelineStatus status = PIPELINE_OK;
913 base::Closure stop_cb = base::Bind(
914 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
916 if (state == kFlushing) {
917 if (stop_or_error == kStop) {
918 EXPECT_CALL(*renderer_, Flush(_))
919 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
920 SetBufferingState(&buffering_state_cb_,
921 BUFFERING_HAVE_NOTHING),
922 RunClosure<0>()));
923 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
924 } else {
925 status = PIPELINE_ERROR_READ;
926 EXPECT_CALL(*renderer_, Flush(_))
927 .WillOnce(DoAll(SetError(pipeline_.get(), status),
928 SetBufferingState(&buffering_state_cb_,
929 BUFFERING_HAVE_NOTHING),
930 RunClosure<0>()));
931 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
934 return status;
937 EXPECT_CALL(*renderer_, Flush(_))
938 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
939 BUFFERING_HAVE_NOTHING),
940 RunClosure<0>()));
941 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
943 if (state == kSeeking) {
944 if (stop_or_error == kStop) {
945 EXPECT_CALL(*demuxer_, Seek(_, _))
946 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
947 RunCallback<1>(PIPELINE_OK)));
948 } else {
949 status = PIPELINE_ERROR_READ;
950 EXPECT_CALL(*demuxer_, Seek(_, _))
951 .WillOnce(RunCallback<1>(status));
954 return status;
957 NOTREACHED() << "State not supported: " << state;
958 return status;
961 void DoStopOrError(StopOrError stop_or_error) {
962 InSequence s;
964 EXPECT_CALL(*demuxer_, Stop());
966 switch (stop_or_error) {
967 case kStop:
968 ExpectPipelineStopAndDestroyPipeline();
969 pipeline_->Stop(base::Bind(
970 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
971 break;
973 case kError:
974 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
975 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
976 break;
978 case kErrorAndStop:
979 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
980 ExpectPipelineStopAndDestroyPipeline();
981 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
982 message_loop_.RunUntilIdle();
983 pipeline_->Stop(base::Bind(
984 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
985 break;
988 message_loop_.RunUntilIdle();
991 DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest);
994 #define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \
995 TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
996 RunTest(k##state, k##stop_or_error); \
999 INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer);
1000 INSTANTIATE_TEARDOWN_TEST(Stop, InitRenderer);
1001 INSTANTIATE_TEARDOWN_TEST(Stop, Flushing);
1002 INSTANTIATE_TEARDOWN_TEST(Stop, Seeking);
1003 INSTANTIATE_TEARDOWN_TEST(Stop, Playing);
1005 INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer);
1006 INSTANTIATE_TEARDOWN_TEST(Error, InitRenderer);
1007 INSTANTIATE_TEARDOWN_TEST(Error, Flushing);
1008 INSTANTIATE_TEARDOWN_TEST(Error, Seeking);
1009 INSTANTIATE_TEARDOWN_TEST(Error, Playing);
1011 INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);
1013 } // namespace media