[Easy Unlock] Fix a DCHECK: Load localized string correctly.
[chromium-blink-merge.git] / media / base / pipeline_unittest.cc
blob7b29698c3b7311e7ca08ec391cbeab3dd4e80565
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/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 // TODO(scherkus): even though some filters are initialized on separate
59 // threads these test aren't flaky... why? It's because filters' Initialize()
60 // is executed on |message_loop_| and the mock filters instantly call
61 // InitializationComplete(), which keeps the pipeline humming along. If
62 // either filters don't call InitializationComplete() immediately or filter
63 // initialization is moved to a separate thread this test will become flaky.
64 class PipelineTest : public ::testing::Test {
65 public:
66 // Used for setting expectations on pipeline callbacks. Using a StrictMock
67 // also lets us test for missing callbacks.
68 class CallbackHelper {
69 public:
70 CallbackHelper() {}
71 virtual ~CallbackHelper() {}
73 MOCK_METHOD1(OnStart, void(PipelineStatus));
74 MOCK_METHOD1(OnSeek, void(PipelineStatus));
75 MOCK_METHOD0(OnStop, void());
76 MOCK_METHOD0(OnEnded, void());
77 MOCK_METHOD1(OnError, void(PipelineStatus));
78 MOCK_METHOD1(OnMetadata, void(PipelineMetadata));
79 MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
80 MOCK_METHOD0(OnDurationChange, void());
82 private:
83 DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
86 PipelineTest()
87 : pipeline_(new Pipeline(message_loop_.message_loop_proxy(),
88 new MediaLog())),
89 demuxer_(new StrictMock<MockDemuxer>()),
90 scoped_renderer_(new StrictMock<MockRenderer>()),
91 renderer_(scoped_renderer_.get()) {
92 // SetDemuxerExpectations() adds overriding expectations for expected
93 // non-NULL streams.
94 DemuxerStream* null_pointer = NULL;
95 EXPECT_CALL(*demuxer_, GetStream(_))
96 .WillRepeatedly(Return(null_pointer));
98 EXPECT_CALL(*demuxer_, GetTimelineOffset())
99 .WillRepeatedly(Return(base::Time()));
101 EXPECT_CALL(*demuxer_, GetLiveness())
102 .WillRepeatedly(Return(Demuxer::LIVENESS_UNKNOWN));
104 EXPECT_CALL(*renderer_, GetMediaTime())
105 .WillRepeatedly(Return(base::TimeDelta()));
107 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
110 virtual ~PipelineTest() {
111 if (!pipeline_ || !pipeline_->IsRunning())
112 return;
114 ExpectDemuxerStop();
116 // The mock demuxer doesn't stop the fake text track stream,
117 // so just stop it manually.
118 if (text_stream_) {
119 text_stream_->Stop();
120 message_loop_.RunUntilIdle();
123 // Expect a stop callback if we were started.
124 ExpectPipelineStopAndDestroyPipeline();
125 pipeline_->Stop(base::Bind(&CallbackHelper::OnStop,
126 base::Unretained(&callbacks_)));
127 message_loop_.RunUntilIdle();
130 void OnDemuxerError() {
131 // Cast because OnDemuxerError is private in Pipeline.
132 static_cast<DemuxerHost*>(pipeline_.get())
133 ->OnDemuxerError(PIPELINE_ERROR_ABORT);
136 protected:
137 // Sets up expectations to allow the demuxer to initialize.
138 typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector;
139 void SetDemuxerExpectations(MockDemuxerStreamVector* streams,
140 const base::TimeDelta& duration) {
141 EXPECT_CALL(callbacks_, OnDurationChange());
142 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
143 .WillOnce(DoAll(SetDemuxerProperties(duration),
144 RunCallback<1>(PIPELINE_OK)));
146 // Configure the demuxer to return the streams.
147 for (size_t i = 0; i < streams->size(); ++i) {
148 DemuxerStream* stream = (*streams)[i];
149 EXPECT_CALL(*demuxer_, GetStream(stream->type()))
150 .WillRepeatedly(Return(stream));
154 void SetDemuxerExpectations(MockDemuxerStreamVector* streams) {
155 // Initialize with a default non-zero duration.
156 SetDemuxerExpectations(streams, base::TimeDelta::FromSeconds(10));
159 scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream(
160 DemuxerStream::Type type) {
161 scoped_ptr<StrictMock<MockDemuxerStream> > stream(
162 new StrictMock<MockDemuxerStream>(type));
163 return stream.Pass();
166 // Sets up expectations to allow the video renderer to initialize.
167 void SetRendererExpectations() {
168 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _))
169 .WillOnce(DoAll(SaveArg<2>(&ended_cb_),
170 SaveArg<4>(&buffering_state_cb_),
171 RunCallback<0>()));
172 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(audio_stream()));
173 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(video_stream()));
176 void AddTextStream() {
177 EXPECT_CALL(*this, OnAddTextTrack(_,_))
178 .WillOnce(Invoke(this, &PipelineTest::DoOnAddTextTrack));
179 static_cast<DemuxerHost*>(pipeline_.get())->AddTextStream(text_stream(),
180 TextTrackConfig(kTextSubtitles, "", "", ""));
181 message_loop_.RunUntilIdle();
184 void StartPipeline() {
185 pipeline_->Start(
186 demuxer_.get(),
187 scoped_renderer_.PassAs<Renderer>(),
188 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
189 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
190 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
191 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
192 base::Bind(&CallbackHelper::OnBufferingStateChange,
193 base::Unretained(&callbacks_)),
194 base::Bind(&CallbackHelper::OnDurationChange,
195 base::Unretained(&callbacks_)),
196 base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this)));
199 // Sets up expectations on the callback and initializes the pipeline. Called
200 // after tests have set expectations any filters they wish to use.
201 void StartPipelineAndExpect(PipelineStatus start_status) {
202 EXPECT_CALL(callbacks_, OnStart(start_status));
204 if (start_status == PIPELINE_OK) {
205 EXPECT_CALL(callbacks_, OnMetadata(_)).WillOnce(SaveArg<0>(&metadata_));
206 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0f));
207 EXPECT_CALL(*renderer_, SetVolume(1.0f));
208 EXPECT_CALL(*renderer_, StartPlayingFrom(start_time_))
209 .WillOnce(SetBufferingState(&buffering_state_cb_,
210 BUFFERING_HAVE_ENOUGH));
211 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
214 StartPipeline();
215 message_loop_.RunUntilIdle();
218 void CreateAudioStream() {
219 audio_stream_ = CreateStream(DemuxerStream::AUDIO);
222 void CreateVideoStream() {
223 video_stream_ = CreateStream(DemuxerStream::VIDEO);
224 video_stream_->set_video_decoder_config(video_decoder_config_);
227 void CreateTextStream() {
228 scoped_ptr<FakeTextTrackStream> text_stream(new FakeTextTrackStream());
229 EXPECT_CALL(*text_stream, OnRead()).Times(AnyNumber());
230 text_stream_ = text_stream.Pass();
233 MockDemuxerStream* audio_stream() {
234 return audio_stream_.get();
237 MockDemuxerStream* video_stream() {
238 return video_stream_.get();
241 FakeTextTrackStream* text_stream() {
242 return text_stream_.get();
245 void ExpectSeek(const base::TimeDelta& seek_time, bool underflowed) {
246 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
247 .WillOnce(RunCallback<1>(PIPELINE_OK));
249 EXPECT_CALL(*renderer_, Flush(_))
250 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
251 BUFFERING_HAVE_NOTHING),
252 RunClosure<0>()));
253 EXPECT_CALL(*renderer_, SetPlaybackRate(_));
254 EXPECT_CALL(*renderer_, SetVolume(_));
255 EXPECT_CALL(*renderer_, StartPlayingFrom(seek_time))
256 .WillOnce(SetBufferingState(&buffering_state_cb_,
257 BUFFERING_HAVE_ENOUGH));
258 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
260 // We expect a successful seek callback followed by a buffering update.
261 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
262 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
265 void DoSeek(const base::TimeDelta& seek_time) {
266 pipeline_->Seek(seek_time,
267 base::Bind(&CallbackHelper::OnSeek,
268 base::Unretained(&callbacks_)));
269 message_loop_.RunUntilIdle();
272 void DestroyPipeline() {
273 // In real code Pipeline could be destroyed on a different thread. All weak
274 // pointers must have been invalidated before the stop callback returns.
275 DCHECK(!pipeline_->HasWeakPtrsForTesting());
276 pipeline_.reset();
279 void ExpectDemuxerStop() {
280 if (demuxer_)
281 EXPECT_CALL(*demuxer_, Stop());
284 void ExpectPipelineStopAndDestroyPipeline() {
285 // After the Pipeline is stopped, it could be destroyed any time. Always
286 // destroy the pipeline immediately after OnStop() to test this.
287 EXPECT_CALL(callbacks_, OnStop())
288 .WillOnce(Invoke(this, &PipelineTest::DestroyPipeline));
291 MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&,
292 const AddTextTrackDoneCB&));
294 void DoOnAddTextTrack(const TextTrackConfig& config,
295 const AddTextTrackDoneCB& done_cb) {
296 scoped_ptr<TextTrack> text_track(new MockTextTrack);
297 done_cb.Run(text_track.Pass());
300 // Fixture members.
301 StrictMock<CallbackHelper> callbacks_;
302 base::SimpleTestTickClock test_tick_clock_;
303 base::MessageLoop message_loop_;
304 scoped_ptr<Pipeline> pipeline_;
306 scoped_ptr<StrictMock<MockDemuxer> > demuxer_;
307 scoped_ptr<StrictMock<MockRenderer> > scoped_renderer_;
308 StrictMock<MockRenderer>* renderer_;
309 StrictMock<CallbackHelper> text_renderer_callbacks_;
310 TextRenderer* text_renderer_;
311 scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
312 scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
313 scoped_ptr<FakeTextTrackStream> text_stream_;
314 BufferingStateCB buffering_state_cb_;
315 base::Closure ended_cb_;
316 VideoDecoderConfig video_decoder_config_;
317 PipelineMetadata metadata_;
318 base::TimeDelta start_time_;
320 private:
321 DISALLOW_COPY_AND_ASSIGN(PipelineTest);
324 // Test that playback controls methods no-op when the pipeline hasn't been
325 // started.
326 TEST_F(PipelineTest, NotStarted) {
327 const base::TimeDelta kZero;
329 EXPECT_FALSE(pipeline_->IsRunning());
331 // Setting should still work.
332 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
333 pipeline_->SetPlaybackRate(-1.0f);
334 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
335 pipeline_->SetPlaybackRate(1.0f);
336 EXPECT_EQ(1.0f, pipeline_->GetPlaybackRate());
338 // Setting should still work.
339 EXPECT_EQ(1.0f, pipeline_->GetVolume());
340 pipeline_->SetVolume(-1.0f);
341 EXPECT_EQ(1.0f, pipeline_->GetVolume());
342 pipeline_->SetVolume(0.0f);
343 EXPECT_EQ(0.0f, pipeline_->GetVolume());
345 EXPECT_TRUE(kZero == pipeline_->GetMediaTime());
346 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
347 EXPECT_TRUE(kZero == pipeline_->GetMediaDuration());
350 TEST_F(PipelineTest, NeverInitializes) {
351 // Don't execute the callback passed into Initialize().
352 EXPECT_CALL(*demuxer_, Initialize(_, _, _));
354 // This test hangs during initialization by never calling
355 // InitializationComplete(). StrictMock<> will ensure that the callback is
356 // never executed.
357 StartPipeline();
358 message_loop_.RunUntilIdle();
360 // Because our callback will get executed when the test tears down, we'll
361 // verify that nothing has been called, then set our expectation for the call
362 // made during tear down.
363 Mock::VerifyAndClear(&callbacks_);
364 EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
367 TEST_F(PipelineTest, StopWithoutStart) {
368 ExpectPipelineStopAndDestroyPipeline();
369 pipeline_->Stop(
370 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
371 message_loop_.RunUntilIdle();
374 TEST_F(PipelineTest, StartThenStopImmediately) {
375 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
376 .WillOnce(RunCallback<1>(PIPELINE_OK));
377 EXPECT_CALL(*demuxer_, Stop());
379 EXPECT_CALL(callbacks_, OnStart(_));
380 StartPipeline();
382 // Expect a stop callback if we were started.
383 ExpectPipelineStopAndDestroyPipeline();
384 pipeline_->Stop(
385 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
386 message_loop_.RunUntilIdle();
389 TEST_F(PipelineTest, DemuxerErrorDuringStop) {
390 CreateAudioStream();
391 MockDemuxerStreamVector streams;
392 streams.push_back(audio_stream());
394 SetDemuxerExpectations(&streams);
395 SetRendererExpectations();
397 StartPipelineAndExpect(PIPELINE_OK);
399 EXPECT_CALL(*demuxer_, Stop())
400 .WillOnce(InvokeWithoutArgs(this, &PipelineTest::OnDemuxerError));
401 ExpectPipelineStopAndDestroyPipeline();
403 pipeline_->Stop(
404 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
405 message_loop_.RunUntilIdle();
408 TEST_F(PipelineTest, URLNotFound) {
409 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
410 .WillOnce(RunCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND));
411 EXPECT_CALL(*demuxer_, Stop());
413 StartPipelineAndExpect(PIPELINE_ERROR_URL_NOT_FOUND);
416 TEST_F(PipelineTest, NoStreams) {
417 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
418 .WillOnce(RunCallback<1>(PIPELINE_OK));
419 EXPECT_CALL(*demuxer_, Stop());
421 StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER);
424 TEST_F(PipelineTest, AudioStream) {
425 CreateAudioStream();
426 MockDemuxerStreamVector streams;
427 streams.push_back(audio_stream());
429 SetDemuxerExpectations(&streams);
430 SetRendererExpectations();
432 StartPipelineAndExpect(PIPELINE_OK);
433 EXPECT_TRUE(metadata_.has_audio);
434 EXPECT_FALSE(metadata_.has_video);
437 TEST_F(PipelineTest, VideoStream) {
438 CreateVideoStream();
439 MockDemuxerStreamVector streams;
440 streams.push_back(video_stream());
442 SetDemuxerExpectations(&streams);
443 SetRendererExpectations();
445 StartPipelineAndExpect(PIPELINE_OK);
446 EXPECT_FALSE(metadata_.has_audio);
447 EXPECT_TRUE(metadata_.has_video);
450 TEST_F(PipelineTest, AudioVideoStream) {
451 CreateAudioStream();
452 CreateVideoStream();
453 MockDemuxerStreamVector streams;
454 streams.push_back(audio_stream());
455 streams.push_back(video_stream());
457 SetDemuxerExpectations(&streams);
458 SetRendererExpectations();
460 StartPipelineAndExpect(PIPELINE_OK);
461 EXPECT_TRUE(metadata_.has_audio);
462 EXPECT_TRUE(metadata_.has_video);
465 TEST_F(PipelineTest, VideoTextStream) {
466 CreateVideoStream();
467 CreateTextStream();
468 MockDemuxerStreamVector streams;
469 streams.push_back(video_stream());
471 SetDemuxerExpectations(&streams);
472 SetRendererExpectations();
474 StartPipelineAndExpect(PIPELINE_OK);
475 EXPECT_FALSE(metadata_.has_audio);
476 EXPECT_TRUE(metadata_.has_video);
478 AddTextStream();
481 TEST_F(PipelineTest, VideoAudioTextStream) {
482 CreateVideoStream();
483 CreateAudioStream();
484 CreateTextStream();
485 MockDemuxerStreamVector streams;
486 streams.push_back(video_stream());
487 streams.push_back(audio_stream());
489 SetDemuxerExpectations(&streams);
490 SetRendererExpectations();
492 StartPipelineAndExpect(PIPELINE_OK);
493 EXPECT_TRUE(metadata_.has_audio);
494 EXPECT_TRUE(metadata_.has_video);
496 AddTextStream();
499 TEST_F(PipelineTest, Seek) {
500 CreateAudioStream();
501 CreateVideoStream();
502 CreateTextStream();
503 MockDemuxerStreamVector streams;
504 streams.push_back(audio_stream());
505 streams.push_back(video_stream());
507 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
508 SetRendererExpectations();
510 // Initialize then seek!
511 StartPipelineAndExpect(PIPELINE_OK);
513 // Every filter should receive a call to Seek().
514 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
515 ExpectSeek(expected, false);
516 DoSeek(expected);
519 TEST_F(PipelineTest, SeekAfterError) {
520 CreateAudioStream();
521 MockDemuxerStreamVector streams;
522 streams.push_back(audio_stream());
524 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
525 SetRendererExpectations();
527 // Initialize then seek!
528 StartPipelineAndExpect(PIPELINE_OK);
530 EXPECT_CALL(*demuxer_, Stop());
531 EXPECT_CALL(callbacks_, OnError(_));
533 static_cast<DemuxerHost*>(pipeline_.get())
534 ->OnDemuxerError(PIPELINE_ERROR_ABORT);
535 message_loop_.RunUntilIdle();
537 pipeline_->Seek(
538 base::TimeDelta::FromMilliseconds(100),
539 base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
540 message_loop_.RunUntilIdle();
543 TEST_F(PipelineTest, SetVolume) {
544 CreateAudioStream();
545 MockDemuxerStreamVector streams;
546 streams.push_back(audio_stream());
548 SetDemuxerExpectations(&streams);
549 SetRendererExpectations();
551 // The audio renderer should receive a call to SetVolume().
552 float expected = 0.5f;
553 EXPECT_CALL(*renderer_, SetVolume(expected));
555 // Initialize then set volume!
556 StartPipelineAndExpect(PIPELINE_OK);
557 pipeline_->SetVolume(expected);
560 TEST_F(PipelineTest, Properties) {
561 CreateVideoStream();
562 MockDemuxerStreamVector streams;
563 streams.push_back(video_stream());
565 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
566 SetDemuxerExpectations(&streams, kDuration);
567 SetRendererExpectations();
569 StartPipelineAndExpect(PIPELINE_OK);
570 EXPECT_EQ(kDuration.ToInternalValue(),
571 pipeline_->GetMediaDuration().ToInternalValue());
572 EXPECT_FALSE(pipeline_->DidLoadingProgress());
575 TEST_F(PipelineTest, GetBufferedTimeRanges) {
576 CreateVideoStream();
577 MockDemuxerStreamVector streams;
578 streams.push_back(video_stream());
580 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
581 SetDemuxerExpectations(&streams, kDuration);
582 SetRendererExpectations();
584 StartPipelineAndExpect(PIPELINE_OK);
586 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
588 EXPECT_FALSE(pipeline_->DidLoadingProgress());
589 pipeline_->AddBufferedTimeRange(base::TimeDelta(), kDuration / 8);
590 EXPECT_TRUE(pipeline_->DidLoadingProgress());
591 EXPECT_FALSE(pipeline_->DidLoadingProgress());
592 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
593 EXPECT_EQ(base::TimeDelta(), pipeline_->GetBufferedTimeRanges().start(0));
594 EXPECT_EQ(kDuration / 8, pipeline_->GetBufferedTimeRanges().end(0));
596 base::TimeDelta kSeekTime = kDuration / 2;
597 ExpectSeek(kSeekTime, false);
598 DoSeek(kSeekTime);
600 EXPECT_FALSE(pipeline_->DidLoadingProgress());
603 TEST_F(PipelineTest, EndedCallback) {
604 CreateAudioStream();
605 CreateVideoStream();
606 CreateTextStream();
607 MockDemuxerStreamVector streams;
608 streams.push_back(audio_stream());
609 streams.push_back(video_stream());
611 SetDemuxerExpectations(&streams);
612 SetRendererExpectations();
613 StartPipelineAndExpect(PIPELINE_OK);
615 AddTextStream();
617 // The ended callback shouldn't run until all renderers have ended.
618 ended_cb_.Run();
619 message_loop_.RunUntilIdle();
621 EXPECT_CALL(callbacks_, OnEnded());
622 text_stream()->SendEosNotification();
623 message_loop_.RunUntilIdle();
626 TEST_F(PipelineTest, ErrorDuringSeek) {
627 CreateAudioStream();
628 MockDemuxerStreamVector streams;
629 streams.push_back(audio_stream());
631 SetDemuxerExpectations(&streams);
632 SetRendererExpectations();
633 StartPipelineAndExpect(PIPELINE_OK);
635 float playback_rate = 1.0f;
636 EXPECT_CALL(*renderer_, SetPlaybackRate(playback_rate));
637 pipeline_->SetPlaybackRate(playback_rate);
638 message_loop_.RunUntilIdle();
640 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
642 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
643 EXPECT_CALL(*renderer_, Flush(_))
644 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
645 BUFFERING_HAVE_NOTHING),
646 RunClosure<0>()));
648 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
649 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
650 EXPECT_CALL(*demuxer_, Stop());
652 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
653 base::Unretained(&callbacks_)));
654 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
655 message_loop_.RunUntilIdle();
658 // Invoked function OnError. This asserts that the pipeline does not enqueue
659 // non-teardown related tasks while tearing down.
660 static void TestNoCallsAfterError(
661 Pipeline* pipeline, base::MessageLoop* message_loop,
662 PipelineStatus /* status */) {
663 CHECK(pipeline);
664 CHECK(message_loop);
666 // When we get to this stage, the message loop should be empty.
667 EXPECT_TRUE(message_loop->IsIdleForTesting());
669 // Make calls on pipeline after error has occurred.
670 pipeline->SetPlaybackRate(0.5f);
671 pipeline->SetVolume(0.5f);
673 // No additional tasks should be queued as a result of these calls.
674 EXPECT_TRUE(message_loop->IsIdleForTesting());
677 TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
678 CreateAudioStream();
679 MockDemuxerStreamVector streams;
680 streams.push_back(audio_stream());
682 SetDemuxerExpectations(&streams);
683 SetRendererExpectations();
684 StartPipelineAndExpect(PIPELINE_OK);
686 // Trigger additional requests on the pipeline during tear down from error.
687 base::Callback<void(PipelineStatus)> cb = base::Bind(
688 &TestNoCallsAfterError, pipeline_.get(), &message_loop_);
689 ON_CALL(callbacks_, OnError(_))
690 .WillByDefault(Invoke(&cb, &base::Callback<void(PipelineStatus)>::Run));
692 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
694 // Seek() isn't called as the demuxer errors out first.
695 EXPECT_CALL(*renderer_, Flush(_))
696 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
697 BUFFERING_HAVE_NOTHING),
698 RunClosure<0>()));
699 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
701 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
702 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
703 EXPECT_CALL(*demuxer_, Stop());
705 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
706 base::Unretained(&callbacks_)));
707 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
708 message_loop_.RunUntilIdle();
711 TEST_F(PipelineTest, DestroyAfterStop) {
712 CreateAudioStream();
713 MockDemuxerStreamVector streams;
714 streams.push_back(audio_stream());
715 SetDemuxerExpectations(&streams);
716 SetRendererExpectations();
717 StartPipelineAndExpect(PIPELINE_OK);
719 ExpectDemuxerStop();
721 ExpectPipelineStopAndDestroyPipeline();
722 pipeline_->Stop(
723 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
724 message_loop_.RunUntilIdle();
727 TEST_F(PipelineTest, Underflow) {
728 CreateAudioStream();
729 CreateVideoStream();
730 MockDemuxerStreamVector streams;
731 streams.push_back(audio_stream());
732 streams.push_back(video_stream());
734 SetDemuxerExpectations(&streams);
735 SetRendererExpectations();
736 StartPipelineAndExpect(PIPELINE_OK);
738 // Simulate underflow.
739 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
740 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
742 // Seek while underflowed.
743 base::TimeDelta expected = base::TimeDelta::FromSeconds(5);
744 ExpectSeek(expected, true);
745 DoSeek(expected);
748 TEST_F(PipelineTest, PositiveStartTime) {
749 start_time_ = base::TimeDelta::FromSeconds(1);
750 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
751 CreateAudioStream();
752 MockDemuxerStreamVector streams;
753 streams.push_back(audio_stream());
754 SetDemuxerExpectations(&streams);
755 SetRendererExpectations();
756 StartPipelineAndExpect(PIPELINE_OK);
757 ExpectDemuxerStop();
758 ExpectPipelineStopAndDestroyPipeline();
759 pipeline_->Stop(
760 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
761 message_loop_.RunUntilIdle();
764 class PipelineTeardownTest : public PipelineTest {
765 public:
766 enum TeardownState {
767 kInitDemuxer,
768 kInitRenderer,
769 kFlushing,
770 kSeeking,
771 kPlaying,
774 enum StopOrError {
775 kStop,
776 kError,
777 kErrorAndStop,
780 PipelineTeardownTest() {}
781 virtual ~PipelineTeardownTest() {}
783 void RunTest(TeardownState state, StopOrError stop_or_error) {
784 switch (state) {
785 case kInitDemuxer:
786 case kInitRenderer:
787 DoInitialize(state, stop_or_error);
788 break;
790 case kFlushing:
791 case kSeeking:
792 DoInitialize(state, stop_or_error);
793 DoSeek(state, stop_or_error);
794 break;
796 case kPlaying:
797 DoInitialize(state, stop_or_error);
798 DoStopOrError(stop_or_error);
799 break;
803 private:
804 // TODO(scherkus): We do radically different things whether teardown is
805 // invoked via stop vs error. The teardown path should be the same,
806 // see http://crbug.com/110228
807 void DoInitialize(TeardownState state, StopOrError stop_or_error) {
808 PipelineStatus expected_status =
809 SetInitializeExpectations(state, stop_or_error);
811 EXPECT_CALL(callbacks_, OnStart(expected_status));
812 StartPipeline();
813 message_loop_.RunUntilIdle();
816 PipelineStatus SetInitializeExpectations(TeardownState state,
817 StopOrError stop_or_error) {
818 PipelineStatus status = PIPELINE_OK;
819 base::Closure stop_cb = base::Bind(
820 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
822 if (state == kInitDemuxer) {
823 if (stop_or_error == kStop) {
824 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
825 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
826 RunCallback<1>(PIPELINE_OK)));
827 ExpectPipelineStopAndDestroyPipeline();
828 } else {
829 status = DEMUXER_ERROR_COULD_NOT_OPEN;
830 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
831 .WillOnce(RunCallback<1>(status));
834 EXPECT_CALL(*demuxer_, Stop());
835 return status;
838 CreateAudioStream();
839 CreateVideoStream();
840 MockDemuxerStreamVector streams;
841 streams.push_back(audio_stream());
842 streams.push_back(video_stream());
843 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000));
845 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(true));
846 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(true));
848 if (state == kInitRenderer) {
849 if (stop_or_error == kStop) {
850 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _))
851 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
852 RunCallback<0>()));
853 ExpectPipelineStopAndDestroyPipeline();
854 } else {
855 status = PIPELINE_ERROR_INITIALIZATION_FAILED;
856 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _))
857 .WillOnce(DoAll(RunCallback<3>(status), RunCallback<0>()));
860 EXPECT_CALL(*demuxer_, Stop());
861 return status;
864 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _))
865 .WillOnce(DoAll(SaveArg<4>(&buffering_state_cb_),
866 RunCallback<0>()));
868 EXPECT_CALL(callbacks_, OnMetadata(_));
870 // If we get here it's a successful initialization.
871 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0f));
872 EXPECT_CALL(*renderer_, SetVolume(1.0f));
873 EXPECT_CALL(*renderer_, StartPlayingFrom(base::TimeDelta()))
874 .WillOnce(SetBufferingState(&buffering_state_cb_,
875 BUFFERING_HAVE_ENOUGH));
877 if (status == PIPELINE_OK)
878 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
880 return status;
883 void DoSeek(TeardownState state, StopOrError stop_or_error) {
884 InSequence s;
885 PipelineStatus status = SetSeekExpectations(state, stop_or_error);
887 EXPECT_CALL(*demuxer_, Stop());
888 EXPECT_CALL(callbacks_, OnSeek(status));
890 if (status == PIPELINE_OK) {
891 ExpectPipelineStopAndDestroyPipeline();
894 pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
895 &CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
896 message_loop_.RunUntilIdle();
899 PipelineStatus SetSeekExpectations(TeardownState state,
900 StopOrError stop_or_error) {
901 PipelineStatus status = PIPELINE_OK;
902 base::Closure stop_cb = base::Bind(
903 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
905 if (state == kFlushing) {
906 if (stop_or_error == kStop) {
907 EXPECT_CALL(*renderer_, Flush(_))
908 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
909 SetBufferingState(&buffering_state_cb_,
910 BUFFERING_HAVE_NOTHING),
911 RunClosure<0>()));
912 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
913 } else {
914 status = PIPELINE_ERROR_READ;
915 EXPECT_CALL(*renderer_, Flush(_))
916 .WillOnce(DoAll(SetError(pipeline_.get(), status),
917 SetBufferingState(&buffering_state_cb_,
918 BUFFERING_HAVE_NOTHING),
919 RunClosure<0>()));
920 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
923 return status;
926 EXPECT_CALL(*renderer_, Flush(_))
927 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
928 BUFFERING_HAVE_NOTHING),
929 RunClosure<0>()));
930 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
932 if (state == kSeeking) {
933 if (stop_or_error == kStop) {
934 EXPECT_CALL(*demuxer_, Seek(_, _))
935 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
936 RunCallback<1>(PIPELINE_OK)));
937 } else {
938 status = PIPELINE_ERROR_READ;
939 EXPECT_CALL(*demuxer_, Seek(_, _))
940 .WillOnce(RunCallback<1>(status));
943 return status;
946 NOTREACHED() << "State not supported: " << state;
947 return status;
950 void DoStopOrError(StopOrError stop_or_error) {
951 InSequence s;
953 EXPECT_CALL(*demuxer_, Stop());
955 switch (stop_or_error) {
956 case kStop:
957 ExpectPipelineStopAndDestroyPipeline();
958 pipeline_->Stop(base::Bind(
959 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
960 break;
962 case kError:
963 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
964 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
965 break;
967 case kErrorAndStop:
968 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
969 ExpectPipelineStopAndDestroyPipeline();
970 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
971 message_loop_.RunUntilIdle();
972 pipeline_->Stop(base::Bind(
973 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
974 break;
977 message_loop_.RunUntilIdle();
980 DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest);
983 #define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \
984 TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
985 RunTest(k##state, k##stop_or_error); \
988 INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer);
989 INSTANTIATE_TEARDOWN_TEST(Stop, InitRenderer);
990 INSTANTIATE_TEARDOWN_TEST(Stop, Flushing);
991 INSTANTIATE_TEARDOWN_TEST(Stop, Seeking);
992 INSTANTIATE_TEARDOWN_TEST(Stop, Playing);
994 INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer);
995 INSTANTIATE_TEARDOWN_TEST(Error, InitRenderer);
996 INSTANTIATE_TEARDOWN_TEST(Error, Flushing);
997 INSTANTIATE_TEARDOWN_TEST(Error, Seeking);
998 INSTANTIATE_TEARDOWN_TEST(Error, Playing);
1000 INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);
1002 } // namespace media