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.
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/clock.h"
14 #include "media/base/fake_text_track_stream.h"
15 #include "media/base/gmock_callback_support.h"
16 #include "media/base/media_log.h"
17 #include "media/base/mock_filters.h"
18 #include "media/base/pipeline.h"
19 #include "media/base/test_helpers.h"
20 #include "media/base/text_renderer.h"
21 #include "media/base/text_track_config.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "ui/gfx/size.h"
26 using ::testing::DeleteArg;
27 using ::testing::DoAll;
28 // TODO(scherkus): Remove InSequence after refactoring Pipeline.
29 using ::testing::InSequence;
30 using ::testing::Invoke;
31 using ::testing::InvokeWithoutArgs;
32 using ::testing::Mock;
33 using ::testing::NotNull;
34 using ::testing::Return;
35 using ::testing::SaveArg;
36 using ::testing::StrictMock;
37 using ::testing::WithArg;
41 ACTION_P(SetDemuxerProperties, duration) {
42 arg0->SetDuration(duration);
45 ACTION_P2(Stop, pipeline, stop_cb) {
46 pipeline->Stop(stop_cb);
49 ACTION_P2(SetError, pipeline, status) {
50 pipeline->SetErrorForTesting(status);
53 // Used for setting expectations on pipeline callbacks. Using a StrictMock
54 // also lets us test for missing callbacks.
55 class CallbackHelper {
58 virtual ~CallbackHelper() {}
60 MOCK_METHOD1(OnStart, void(PipelineStatus));
61 MOCK_METHOD1(OnSeek, void(PipelineStatus));
62 MOCK_METHOD0(OnStop, void());
63 MOCK_METHOD0(OnEnded, void());
64 MOCK_METHOD1(OnError, void(PipelineStatus));
65 MOCK_METHOD1(OnMetadata, void(PipelineMetadata));
66 MOCK_METHOD0(OnPrerollCompleted, void());
67 MOCK_METHOD0(OnDurationChange, void());
70 DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
73 // TODO(scherkus): even though some filters are initialized on separate
74 // threads these test aren't flaky... why? It's because filters' Initialize()
75 // is executed on |message_loop_| and the mock filters instantly call
76 // InitializationComplete(), which keeps the pipeline humming along. If
77 // either filters don't call InitializationComplete() immediately or filter
78 // initialization is moved to a separate thread this test will become flaky.
79 class PipelineTest : public ::testing::Test {
82 : pipeline_(new Pipeline(message_loop_.message_loop_proxy(),
84 filter_collection_(new FilterCollection()),
85 demuxer_(new MockDemuxer()) {
86 filter_collection_->SetDemuxer(demuxer_.get());
88 video_renderer_ = new MockVideoRenderer();
89 scoped_ptr<VideoRenderer> video_renderer(video_renderer_);
90 filter_collection_->SetVideoRenderer(video_renderer.Pass());
92 audio_renderer_ = new MockAudioRenderer();
93 scoped_ptr<AudioRenderer> audio_renderer(audio_renderer_);
94 filter_collection_->SetAudioRenderer(audio_renderer.Pass());
96 text_renderer_ = new TextRenderer(
97 message_loop_.message_loop_proxy(),
98 base::Bind(&PipelineTest::OnAddTextTrack,
99 base::Unretained(this)));
100 scoped_ptr<TextRenderer> text_renderer(text_renderer_);
101 filter_collection_->SetTextRenderer(text_renderer.Pass());
103 // InitializeDemuxer() adds overriding expectations for expected non-NULL
105 DemuxerStream* null_pointer = NULL;
106 EXPECT_CALL(*demuxer_, GetStream(_))
107 .WillRepeatedly(Return(null_pointer));
109 EXPECT_CALL(*demuxer_, GetStartTime())
110 .WillRepeatedly(Return(base::TimeDelta()));
112 EXPECT_CALL(*demuxer_, GetTimelineOffset())
113 .WillRepeatedly(Return(base::Time()));
115 EXPECT_CALL(*demuxer_, GetLiveness())
116 .WillRepeatedly(Return(Demuxer::LIVENESS_UNKNOWN));
119 virtual ~PipelineTest() {
120 if (!pipeline_ || !pipeline_->IsRunning())
125 // The mock demuxer doesn't stop the fake text track stream,
126 // so just stop it manually.
128 text_stream_->Stop();
129 message_loop_.RunUntilIdle();
132 // Expect a stop callback if we were started.
133 EXPECT_CALL(callbacks_, OnStop());
134 pipeline_->Stop(base::Bind(&CallbackHelper::OnStop,
135 base::Unretained(&callbacks_)));
136 message_loop_.RunUntilIdle();
140 // Sets up expectations to allow the demuxer to initialize.
141 typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector;
142 void InitializeDemuxer(MockDemuxerStreamVector* streams,
143 const base::TimeDelta& duration) {
144 EXPECT_CALL(callbacks_, OnDurationChange());
145 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
146 .WillOnce(DoAll(SetDemuxerProperties(duration),
147 RunCallback<1>(PIPELINE_OK)));
149 // Configure the demuxer to return the streams.
150 for (size_t i = 0; i < streams->size(); ++i) {
151 DemuxerStream* stream = (*streams)[i];
152 EXPECT_CALL(*demuxer_, GetStream(stream->type()))
153 .WillRepeatedly(Return(stream));
157 void InitializeDemuxer(MockDemuxerStreamVector* streams) {
158 // Initialize with a default non-zero duration.
159 InitializeDemuxer(streams, base::TimeDelta::FromSeconds(10));
162 scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream(
163 DemuxerStream::Type type) {
164 scoped_ptr<StrictMock<MockDemuxerStream> > stream(
165 new StrictMock<MockDemuxerStream>(type));
166 return stream.Pass();
169 // Sets up expectations to allow the video renderer to initialize.
170 void InitializeVideoRenderer(DemuxerStream* stream) {
171 EXPECT_CALL(*video_renderer_, Initialize(stream, _, _, _, _, _, _, _, _))
172 .WillOnce(RunCallback<2>(PIPELINE_OK));
173 EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
176 EXPECT_CALL(*video_renderer_, Preroll(demuxer_->GetStartTime(), _))
177 .WillOnce(RunCallback<1>(PIPELINE_OK));
178 EXPECT_CALL(*video_renderer_, Play(_))
179 .WillOnce(RunClosure<0>());
182 // Sets up expectations to allow the audio renderer to initialize.
183 void InitializeAudioRenderer(DemuxerStream* stream) {
184 EXPECT_CALL(*audio_renderer_, Initialize(stream, _, _, _, _, _, _))
185 .WillOnce(DoAll(SaveArg<4>(&audio_time_cb_),
186 RunCallback<1>(PIPELINE_OK)));
189 void AddTextStream() {
190 EXPECT_CALL(*this, OnAddTextTrack(_,_))
191 .WillOnce(Invoke(this, &PipelineTest::DoOnAddTextTrack));
192 static_cast<DemuxerHost*>(pipeline_.get())->AddTextStream(text_stream(),
193 TextTrackConfig(kTextSubtitles, "", "", ""));
196 // Sets up expectations on the callback and initializes the pipeline. Called
197 // after tests have set expectations any filters they wish to use.
198 void InitializePipeline(PipelineStatus start_status) {
199 EXPECT_CALL(callbacks_, OnStart(start_status));
201 if (start_status == PIPELINE_OK) {
202 EXPECT_CALL(callbacks_, OnMetadata(_)).WillOnce(SaveArg<0>(&metadata_));
205 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
206 EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
209 EXPECT_CALL(*audio_renderer_, Preroll(base::TimeDelta(), _))
210 .WillOnce(RunCallback<1>(PIPELINE_OK));
211 EXPECT_CALL(*audio_renderer_, Play(_))
212 .WillOnce(RunClosure<0>());
214 EXPECT_CALL(callbacks_, OnPrerollCompleted());
218 filter_collection_.Pass(),
219 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
220 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
221 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
222 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
223 base::Bind(&CallbackHelper::OnPrerollCompleted,
224 base::Unretained(&callbacks_)),
225 base::Bind(&CallbackHelper::OnDurationChange,
226 base::Unretained(&callbacks_)));
227 message_loop_.RunUntilIdle();
230 void CreateAudioStream() {
231 audio_stream_ = CreateStream(DemuxerStream::AUDIO);
234 void CreateVideoStream() {
235 video_stream_ = CreateStream(DemuxerStream::VIDEO);
236 video_stream_->set_video_decoder_config(video_decoder_config_);
239 void CreateTextStream() {
240 scoped_ptr<FakeTextTrackStream> text_stream(new FakeTextTrackStream);
241 text_stream_ = text_stream.Pass();
244 MockDemuxerStream* audio_stream() {
245 return audio_stream_.get();
248 MockDemuxerStream* video_stream() {
249 return video_stream_.get();
252 FakeTextTrackStream* text_stream() {
253 return text_stream_.get();
256 void ExpectSeek(const base::TimeDelta& seek_time) {
257 // Every filter should receive a call to Seek().
258 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
259 .WillOnce(RunCallback<1>(PIPELINE_OK));
262 EXPECT_CALL(*audio_renderer_, Pause(_))
263 .WillOnce(RunClosure<0>());
264 EXPECT_CALL(*audio_renderer_, Flush(_))
265 .WillOnce(RunClosure<0>());
266 EXPECT_CALL(*audio_renderer_, Preroll(seek_time, _))
267 .WillOnce(RunCallback<1>(PIPELINE_OK));
268 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(_));
269 EXPECT_CALL(*audio_renderer_, SetVolume(_));
270 EXPECT_CALL(*audio_renderer_, Play(_))
271 .WillOnce(RunClosure<0>());
275 EXPECT_CALL(*video_renderer_, Pause(_))
276 .WillOnce(RunClosure<0>());
277 EXPECT_CALL(*video_renderer_, Flush(_))
278 .WillOnce(RunClosure<0>());
279 EXPECT_CALL(*video_renderer_, Preroll(seek_time, _))
280 .WillOnce(RunCallback<1>(PIPELINE_OK));
281 EXPECT_CALL(*video_renderer_, SetPlaybackRate(_));
282 EXPECT_CALL(*video_renderer_, Play(_))
283 .WillOnce(RunClosure<0>());
286 EXPECT_CALL(callbacks_, OnPrerollCompleted());
288 // We expect a successful seek callback.
289 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
292 void DoSeek(const base::TimeDelta& seek_time) {
293 pipeline_->Seek(seek_time,
294 base::Bind(&CallbackHelper::OnSeek,
295 base::Unretained(&callbacks_)));
297 // We expect the time to be updated only after the seek has completed.
298 EXPECT_NE(seek_time, pipeline_->GetMediaTime());
299 message_loop_.RunUntilIdle();
300 EXPECT_EQ(seek_time, pipeline_->GetMediaTime());
305 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
308 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
311 EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
314 MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&,
315 const AddTextTrackDoneCB&));
317 void DoOnAddTextTrack(const TextTrackConfig& config,
318 const AddTextTrackDoneCB& done_cb) {
319 scoped_ptr<TextTrack> text_track(new MockTextTrack);
320 done_cb.Run(text_track.Pass());
324 StrictMock<CallbackHelper> callbacks_;
325 base::SimpleTestTickClock test_tick_clock_;
326 base::MessageLoop message_loop_;
327 scoped_ptr<Pipeline> pipeline_;
329 scoped_ptr<FilterCollection> filter_collection_;
330 scoped_ptr<MockDemuxer> demuxer_;
331 MockVideoRenderer* video_renderer_;
332 MockAudioRenderer* audio_renderer_;
333 StrictMock<CallbackHelper> text_renderer_callbacks_;
334 TextRenderer* text_renderer_;
335 scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
336 scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
337 scoped_ptr<FakeTextTrackStream> text_stream_;
338 AudioRenderer::TimeCB audio_time_cb_;
339 VideoDecoderConfig video_decoder_config_;
340 PipelineMetadata metadata_;
343 DISALLOW_COPY_AND_ASSIGN(PipelineTest);
346 // Test that playback controls methods no-op when the pipeline hasn't been
348 TEST_F(PipelineTest, NotStarted) {
349 const base::TimeDelta kZero;
351 EXPECT_FALSE(pipeline_->IsRunning());
353 // Setting should still work.
354 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
355 pipeline_->SetPlaybackRate(-1.0f);
356 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
357 pipeline_->SetPlaybackRate(1.0f);
358 EXPECT_EQ(1.0f, pipeline_->GetPlaybackRate());
360 // Setting should still work.
361 EXPECT_EQ(1.0f, pipeline_->GetVolume());
362 pipeline_->SetVolume(-1.0f);
363 EXPECT_EQ(1.0f, pipeline_->GetVolume());
364 pipeline_->SetVolume(0.0f);
365 EXPECT_EQ(0.0f, pipeline_->GetVolume());
367 EXPECT_TRUE(kZero == pipeline_->GetMediaTime());
368 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
369 EXPECT_TRUE(kZero == pipeline_->GetMediaDuration());
372 TEST_F(PipelineTest, NeverInitializes) {
373 // Don't execute the callback passed into Initialize().
374 EXPECT_CALL(*demuxer_, Initialize(_, _, _));
376 // This test hangs during initialization by never calling
377 // InitializationComplete(). StrictMock<> will ensure that the callback is
380 filter_collection_.Pass(),
381 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
382 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
383 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
384 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
385 base::Bind(&CallbackHelper::OnPrerollCompleted,
386 base::Unretained(&callbacks_)),
387 base::Bind(&CallbackHelper::OnDurationChange,
388 base::Unretained(&callbacks_)));
389 message_loop_.RunUntilIdle();
392 // Because our callback will get executed when the test tears down, we'll
393 // verify that nothing has been called, then set our expectation for the call
394 // made during tear down.
395 Mock::VerifyAndClear(&callbacks_);
396 EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
399 TEST_F(PipelineTest, URLNotFound) {
400 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
401 .WillOnce(RunCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND));
402 EXPECT_CALL(*demuxer_, Stop(_))
403 .WillOnce(RunClosure<0>());
405 InitializePipeline(PIPELINE_ERROR_URL_NOT_FOUND);
408 TEST_F(PipelineTest, NoStreams) {
409 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
410 .WillOnce(RunCallback<1>(PIPELINE_OK));
411 EXPECT_CALL(*demuxer_, Stop(_))
412 .WillOnce(RunClosure<0>());
414 InitializePipeline(PIPELINE_ERROR_COULD_NOT_RENDER);
417 TEST_F(PipelineTest, AudioStream) {
419 MockDemuxerStreamVector streams;
420 streams.push_back(audio_stream());
422 InitializeDemuxer(&streams);
423 InitializeAudioRenderer(audio_stream());
425 InitializePipeline(PIPELINE_OK);
426 EXPECT_TRUE(metadata_.has_audio);
427 EXPECT_FALSE(metadata_.has_video);
430 TEST_F(PipelineTest, VideoStream) {
432 MockDemuxerStreamVector streams;
433 streams.push_back(video_stream());
435 InitializeDemuxer(&streams);
436 InitializeVideoRenderer(video_stream());
438 InitializePipeline(PIPELINE_OK);
439 EXPECT_FALSE(metadata_.has_audio);
440 EXPECT_TRUE(metadata_.has_video);
443 TEST_F(PipelineTest, AudioVideoStream) {
446 MockDemuxerStreamVector streams;
447 streams.push_back(audio_stream());
448 streams.push_back(video_stream());
450 InitializeDemuxer(&streams);
451 InitializeAudioRenderer(audio_stream());
452 InitializeVideoRenderer(video_stream());
454 InitializePipeline(PIPELINE_OK);
455 EXPECT_TRUE(metadata_.has_audio);
456 EXPECT_TRUE(metadata_.has_video);
459 TEST_F(PipelineTest, VideoTextStream) {
462 MockDemuxerStreamVector streams;
463 streams.push_back(video_stream());
465 InitializeDemuxer(&streams);
466 InitializeVideoRenderer(video_stream());
468 InitializePipeline(PIPELINE_OK);
469 EXPECT_FALSE(metadata_.has_audio);
470 EXPECT_TRUE(metadata_.has_video);
473 message_loop_.RunUntilIdle();
476 TEST_F(PipelineTest, VideoAudioTextStream) {
480 MockDemuxerStreamVector streams;
481 streams.push_back(video_stream());
482 streams.push_back(audio_stream());
484 InitializeDemuxer(&streams);
485 InitializeVideoRenderer(video_stream());
486 InitializeAudioRenderer(audio_stream());
488 InitializePipeline(PIPELINE_OK);
489 EXPECT_TRUE(metadata_.has_audio);
490 EXPECT_TRUE(metadata_.has_video);
493 message_loop_.RunUntilIdle();
496 TEST_F(PipelineTest, Seek) {
500 MockDemuxerStreamVector streams;
501 streams.push_back(audio_stream());
502 streams.push_back(video_stream());
504 InitializeDemuxer(&streams, base::TimeDelta::FromSeconds(3000));
505 InitializeAudioRenderer(audio_stream());
506 InitializeVideoRenderer(video_stream());
508 // Initialize then seek!
509 InitializePipeline(PIPELINE_OK);
512 message_loop_.RunUntilIdle();
514 // Every filter should receive a call to Seek().
515 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
516 ExpectSeek(expected);
520 TEST_F(PipelineTest, SetVolume) {
522 MockDemuxerStreamVector streams;
523 streams.push_back(audio_stream());
525 InitializeDemuxer(&streams);
526 InitializeAudioRenderer(audio_stream());
528 // The audio renderer should receive a call to SetVolume().
529 float expected = 0.5f;
530 EXPECT_CALL(*audio_renderer_, SetVolume(expected));
532 // Initialize then set volume!
533 InitializePipeline(PIPELINE_OK);
534 pipeline_->SetVolume(expected);
537 TEST_F(PipelineTest, Properties) {
539 MockDemuxerStreamVector streams;
540 streams.push_back(video_stream());
542 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
543 InitializeDemuxer(&streams, kDuration);
544 InitializeVideoRenderer(video_stream());
546 InitializePipeline(PIPELINE_OK);
547 EXPECT_EQ(kDuration.ToInternalValue(),
548 pipeline_->GetMediaDuration().ToInternalValue());
549 EXPECT_FALSE(pipeline_->DidLoadingProgress());
552 TEST_F(PipelineTest, GetBufferedTimeRanges) {
554 MockDemuxerStreamVector streams;
555 streams.push_back(video_stream());
557 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
558 InitializeDemuxer(&streams, kDuration);
559 InitializeVideoRenderer(video_stream());
561 InitializePipeline(PIPELINE_OK);
563 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
565 EXPECT_FALSE(pipeline_->DidLoadingProgress());
566 pipeline_->AddBufferedTimeRange(base::TimeDelta(), kDuration / 8);
567 EXPECT_TRUE(pipeline_->DidLoadingProgress());
568 EXPECT_FALSE(pipeline_->DidLoadingProgress());
569 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
570 EXPECT_EQ(base::TimeDelta(), pipeline_->GetBufferedTimeRanges().start(0));
571 EXPECT_EQ(kDuration / 8, pipeline_->GetBufferedTimeRanges().end(0));
573 base::TimeDelta kSeekTime = kDuration / 2;
574 ExpectSeek(kSeekTime);
577 EXPECT_FALSE(pipeline_->DidLoadingProgress());
580 TEST_F(PipelineTest, EndedCallback) {
584 MockDemuxerStreamVector streams;
585 streams.push_back(audio_stream());
586 streams.push_back(video_stream());
588 InitializeDemuxer(&streams);
589 InitializeAudioRenderer(audio_stream());
590 InitializeVideoRenderer(video_stream());
591 InitializePipeline(PIPELINE_OK);
595 // The ended callback shouldn't run until all renderers have ended.
596 pipeline_->OnAudioRendererEnded();
597 message_loop_.RunUntilIdle();
599 pipeline_->OnVideoRendererEnded();
600 message_loop_.RunUntilIdle();
602 EXPECT_CALL(callbacks_, OnEnded());
603 text_stream()->SendEosNotification();
604 message_loop_.RunUntilIdle();
607 TEST_F(PipelineTest, AudioStreamShorterThanVideo) {
608 base::TimeDelta duration = base::TimeDelta::FromSeconds(10);
612 MockDemuxerStreamVector streams;
613 streams.push_back(audio_stream());
614 streams.push_back(video_stream());
616 // Replace the clock so we can simulate wall clock time advancing w/o using
618 pipeline_->SetClockForTesting(new Clock(&test_tick_clock_));
620 InitializeDemuxer(&streams, duration);
621 InitializeAudioRenderer(audio_stream());
622 InitializeVideoRenderer(video_stream());
623 InitializePipeline(PIPELINE_OK);
625 EXPECT_EQ(0, pipeline_->GetMediaTime().ToInternalValue());
627 float playback_rate = 1.0f;
628 EXPECT_CALL(*video_renderer_, SetPlaybackRate(playback_rate));
629 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
630 pipeline_->SetPlaybackRate(playback_rate);
631 message_loop_.RunUntilIdle();
635 // Verify that the clock doesn't advance since it hasn't been started by
636 // a time update from the audio stream.
637 int64 start_time = pipeline_->GetMediaTime().ToInternalValue();
638 test_tick_clock_.Advance(base::TimeDelta::FromMilliseconds(100));
639 EXPECT_EQ(pipeline_->GetMediaTime().ToInternalValue(), start_time);
641 // Signal end of audio stream.
642 pipeline_->OnAudioRendererEnded();
643 message_loop_.RunUntilIdle();
645 // Verify that the clock advances.
646 start_time = pipeline_->GetMediaTime().ToInternalValue();
647 test_tick_clock_.Advance(base::TimeDelta::FromMilliseconds(100));
648 EXPECT_GT(pipeline_->GetMediaTime().ToInternalValue(), start_time);
650 // Signal end of video stream and make sure OnEnded() callback occurs.
651 EXPECT_CALL(callbacks_, OnEnded());
652 pipeline_->OnVideoRendererEnded();
655 TEST_F(PipelineTest, ErrorDuringSeek) {
657 MockDemuxerStreamVector streams;
658 streams.push_back(audio_stream());
660 InitializeDemuxer(&streams);
661 InitializeAudioRenderer(audio_stream());
662 InitializePipeline(PIPELINE_OK);
664 float playback_rate = 1.0f;
665 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
666 pipeline_->SetPlaybackRate(playback_rate);
667 message_loop_.RunUntilIdle();
669 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
671 // Preroll() isn't called as the demuxer errors out first.
672 EXPECT_CALL(*audio_renderer_, Pause(_))
673 .WillOnce(RunClosure<0>());
674 EXPECT_CALL(*audio_renderer_, Flush(_))
675 .WillOnce(RunClosure<0>());
676 EXPECT_CALL(*audio_renderer_, Stop(_))
677 .WillOnce(RunClosure<0>());
679 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
680 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
681 EXPECT_CALL(*demuxer_, Stop(_))
682 .WillOnce(RunClosure<0>());
684 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
685 base::Unretained(&callbacks_)));
686 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
687 message_loop_.RunUntilIdle();
690 // Invoked function OnError. This asserts that the pipeline does not enqueue
691 // non-teardown related tasks while tearing down.
692 static void TestNoCallsAfterError(
693 Pipeline* pipeline, base::MessageLoop* message_loop,
694 PipelineStatus /* status */) {
698 // When we get to this stage, the message loop should be empty.
699 EXPECT_TRUE(message_loop->IsIdleForTesting());
701 // Make calls on pipeline after error has occurred.
702 pipeline->SetPlaybackRate(0.5f);
703 pipeline->SetVolume(0.5f);
705 // No additional tasks should be queued as a result of these calls.
706 EXPECT_TRUE(message_loop->IsIdleForTesting());
709 TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
711 MockDemuxerStreamVector streams;
712 streams.push_back(audio_stream());
714 InitializeDemuxer(&streams);
715 InitializeAudioRenderer(audio_stream());
716 InitializePipeline(PIPELINE_OK);
718 // Trigger additional requests on the pipeline during tear down from error.
719 base::Callback<void(PipelineStatus)> cb = base::Bind(
720 &TestNoCallsAfterError, pipeline_.get(), &message_loop_);
721 ON_CALL(callbacks_, OnError(_))
722 .WillByDefault(Invoke(&cb, &base::Callback<void(PipelineStatus)>::Run));
724 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
726 // Seek() isn't called as the demuxer errors out first.
727 EXPECT_CALL(*audio_renderer_, Pause(_))
728 .WillOnce(RunClosure<0>());
729 EXPECT_CALL(*audio_renderer_, Flush(_))
730 .WillOnce(RunClosure<0>());
731 EXPECT_CALL(*audio_renderer_, Stop(_))
732 .WillOnce(RunClosure<0>());
734 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
735 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
736 EXPECT_CALL(*demuxer_, Stop(_))
737 .WillOnce(RunClosure<0>());
739 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
740 base::Unretained(&callbacks_)));
741 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
742 message_loop_.RunUntilIdle();
745 TEST_F(PipelineTest, StartTimeIsZero) {
747 MockDemuxerStreamVector streams;
748 streams.push_back(video_stream());
750 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
751 InitializeDemuxer(&streams, kDuration);
752 InitializeVideoRenderer(video_stream());
754 InitializePipeline(PIPELINE_OK);
755 EXPECT_FALSE(metadata_.has_audio);
756 EXPECT_TRUE(metadata_.has_video);
758 EXPECT_EQ(base::TimeDelta(), pipeline_->GetMediaTime());
761 TEST_F(PipelineTest, StartTimeIsNonZero) {
762 const base::TimeDelta kStartTime = base::TimeDelta::FromSeconds(4);
763 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
765 EXPECT_CALL(*demuxer_, GetStartTime())
766 .WillRepeatedly(Return(kStartTime));
769 MockDemuxerStreamVector streams;
770 streams.push_back(video_stream());
772 InitializeDemuxer(&streams, kDuration);
773 InitializeVideoRenderer(video_stream());
775 InitializePipeline(PIPELINE_OK);
776 EXPECT_FALSE(metadata_.has_audio);
777 EXPECT_TRUE(metadata_.has_video);
779 EXPECT_EQ(kStartTime, pipeline_->GetMediaTime());
782 static void RunTimeCB(const AudioRenderer::TimeCB& time_cb,
784 int max_time_in_ms) {
785 time_cb.Run(base::TimeDelta::FromMilliseconds(time_in_ms),
786 base::TimeDelta::FromMilliseconds(max_time_in_ms));
789 TEST_F(PipelineTest, AudioTimeUpdateDuringSeek) {
791 MockDemuxerStreamVector streams;
792 streams.push_back(audio_stream());
794 InitializeDemuxer(&streams);
795 InitializeAudioRenderer(audio_stream());
796 InitializePipeline(PIPELINE_OK);
798 float playback_rate = 1.0f;
799 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
800 pipeline_->SetPlaybackRate(playback_rate);
801 message_loop_.RunUntilIdle();
803 // Provide an initial time update so that the pipeline transitions out of the
804 // "waiting for time update" state.
805 audio_time_cb_.Run(base::TimeDelta::FromMilliseconds(100),
806 base::TimeDelta::FromMilliseconds(500));
808 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
810 // Arrange to trigger a time update while the demuxer is in the middle of
811 // seeking. This update should be ignored by the pipeline and the clock should
813 base::Closure closure = base::Bind(&RunTimeCB, audio_time_cb_, 300, 700);
814 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
815 .WillOnce(DoAll(InvokeWithoutArgs(&closure, &base::Closure::Run),
816 RunCallback<1>(PIPELINE_OK)));
818 EXPECT_CALL(*audio_renderer_, Pause(_))
819 .WillOnce(RunClosure<0>());
820 EXPECT_CALL(*audio_renderer_, Flush(_))
821 .WillOnce(RunClosure<0>());
822 EXPECT_CALL(*audio_renderer_, Preroll(seek_time, _))
823 .WillOnce(RunCallback<1>(PIPELINE_OK));
824 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(_));
825 EXPECT_CALL(*audio_renderer_, SetVolume(_));
826 EXPECT_CALL(*audio_renderer_, Play(_))
827 .WillOnce(RunClosure<0>());
829 EXPECT_CALL(callbacks_, OnPrerollCompleted());
830 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
833 EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
835 // Now that the seek is complete, verify that time updates advance the current
837 base::TimeDelta new_time = seek_time + base::TimeDelta::FromMilliseconds(100);
838 audio_time_cb_.Run(new_time, new_time);
840 EXPECT_EQ(pipeline_->GetMediaTime(), new_time);
843 static void DeletePipeline(scoped_ptr<Pipeline> pipeline) {
844 // |pipeline| will go out of scope.
847 TEST_F(PipelineTest, DeleteAfterStop) {
849 MockDemuxerStreamVector streams;
850 streams.push_back(audio_stream());
851 InitializeDemuxer(&streams);
852 InitializeAudioRenderer(audio_stream());
853 InitializePipeline(PIPELINE_OK);
857 Pipeline* pipeline = pipeline_.get();
858 pipeline->Stop(base::Bind(&DeletePipeline, base::Passed(&pipeline_)));
859 message_loop_.RunUntilIdle();
862 class PipelineTeardownTest : public PipelineTest {
882 PipelineTeardownTest() {}
883 virtual ~PipelineTeardownTest() {}
885 void RunTest(TeardownState state, StopOrError stop_or_error) {
888 case kInitAudioRenderer:
889 case kInitVideoRenderer:
890 DoInitialize(state, stop_or_error);
898 DoInitialize(state, stop_or_error);
899 DoSeek(state, stop_or_error);
903 DoInitialize(state, stop_or_error);
904 DoStopOrError(stop_or_error);
910 // TODO(scherkus): We do radically different things whether teardown is
911 // invoked via stop vs error. The teardown path should be the same,
912 // see http://crbug.com/110228
913 void DoInitialize(TeardownState state, StopOrError stop_or_error) {
914 PipelineStatus expected_status =
915 SetInitializeExpectations(state, stop_or_error);
917 EXPECT_CALL(callbacks_, OnStart(expected_status));
919 filter_collection_.Pass(),
920 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
921 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
922 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
923 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
924 base::Bind(&CallbackHelper::OnPrerollCompleted,
925 base::Unretained(&callbacks_)),
926 base::Bind(&CallbackHelper::OnDurationChange,
927 base::Unretained(&callbacks_)));
928 message_loop_.RunUntilIdle();
931 PipelineStatus SetInitializeExpectations(TeardownState state,
932 StopOrError stop_or_error) {
933 PipelineStatus status = PIPELINE_OK;
934 base::Closure stop_cb = base::Bind(
935 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
937 if (state == kInitDemuxer) {
938 if (stop_or_error == kStop) {
939 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
940 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
941 RunCallback<1>(PIPELINE_OK)));
942 EXPECT_CALL(callbacks_, OnStop());
944 status = DEMUXER_ERROR_COULD_NOT_OPEN;
945 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
946 .WillOnce(RunCallback<1>(status));
949 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
955 MockDemuxerStreamVector streams;
956 streams.push_back(audio_stream());
957 streams.push_back(video_stream());
958 InitializeDemuxer(&streams, base::TimeDelta::FromSeconds(3000));
960 if (state == kInitAudioRenderer) {
961 if (stop_or_error == kStop) {
962 EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
963 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
964 RunCallback<1>(PIPELINE_OK)));
965 EXPECT_CALL(callbacks_, OnStop());
967 status = PIPELINE_ERROR_INITIALIZATION_FAILED;
968 EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
969 .WillOnce(RunCallback<1>(status));
972 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
973 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
977 EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
978 .WillOnce(RunCallback<1>(PIPELINE_OK));
980 if (state == kInitVideoRenderer) {
981 if (stop_or_error == kStop) {
982 EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
983 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
984 RunCallback<2>(PIPELINE_OK)));
985 EXPECT_CALL(callbacks_, OnStop());
987 status = PIPELINE_ERROR_INITIALIZATION_FAILED;
988 EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
989 .WillOnce(RunCallback<2>(status));
992 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
993 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
994 EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
998 EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
999 .WillOnce(RunCallback<2>(PIPELINE_OK));
1001 EXPECT_CALL(callbacks_, OnMetadata(_));
1003 // If we get here it's a successful initialization.
1004 EXPECT_CALL(*audio_renderer_, Preroll(base::TimeDelta(), _))
1005 .WillOnce(RunCallback<1>(PIPELINE_OK));
1006 EXPECT_CALL(*video_renderer_, Preroll(base::TimeDelta(), _))
1007 .WillOnce(RunCallback<1>(PIPELINE_OK));
1009 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
1010 EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
1011 EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
1013 EXPECT_CALL(*audio_renderer_, Play(_))
1014 .WillOnce(RunClosure<0>());
1015 EXPECT_CALL(*video_renderer_, Play(_))
1016 .WillOnce(RunClosure<0>());
1018 if (status == PIPELINE_OK)
1019 EXPECT_CALL(callbacks_, OnPrerollCompleted());
1024 void DoSeek(TeardownState state, StopOrError stop_or_error) {
1026 PipelineStatus status = SetSeekExpectations(state, stop_or_error);
1028 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
1029 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
1030 EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
1031 EXPECT_CALL(callbacks_, OnSeek(status));
1033 if (status == PIPELINE_OK) {
1034 EXPECT_CALL(callbacks_, OnStop());
1037 pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
1038 &CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
1039 message_loop_.RunUntilIdle();
1042 PipelineStatus SetSeekExpectations(TeardownState state,
1043 StopOrError stop_or_error) {
1044 PipelineStatus status = PIPELINE_OK;
1045 base::Closure stop_cb = base::Bind(
1046 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
1048 if (state == kPausing) {
1049 if (stop_or_error == kStop) {
1050 EXPECT_CALL(*audio_renderer_, Pause(_))
1051 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), RunClosure<0>()));
1053 status = PIPELINE_ERROR_READ;
1054 EXPECT_CALL(*audio_renderer_, Pause(_)).WillOnce(
1055 DoAll(SetError(pipeline_.get(), status), RunClosure<0>()));
1061 EXPECT_CALL(*audio_renderer_, Pause(_)).WillOnce(RunClosure<0>());
1062 EXPECT_CALL(*video_renderer_, Pause(_)).WillOnce(RunClosure<0>());
1064 if (state == kFlushing) {
1065 if (stop_or_error == kStop) {
1066 EXPECT_CALL(*audio_renderer_, Flush(_))
1067 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), RunClosure<0>()));
1069 status = PIPELINE_ERROR_READ;
1070 EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(
1071 DoAll(SetError(pipeline_.get(), status), RunClosure<0>()));
1077 EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(RunClosure<0>());
1078 EXPECT_CALL(*video_renderer_, Flush(_)).WillOnce(RunClosure<0>());
1080 if (state == kSeeking) {
1081 if (stop_or_error == kStop) {
1082 EXPECT_CALL(*demuxer_, Seek(_, _))
1083 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
1084 RunCallback<1>(PIPELINE_OK)));
1086 status = PIPELINE_ERROR_READ;
1087 EXPECT_CALL(*demuxer_, Seek(_, _))
1088 .WillOnce(RunCallback<1>(status));
1094 EXPECT_CALL(*demuxer_, Seek(_, _))
1095 .WillOnce(RunCallback<1>(PIPELINE_OK));
1097 if (state == kPrerolling) {
1098 if (stop_or_error == kStop) {
1099 EXPECT_CALL(*audio_renderer_, Preroll(_, _))
1100 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
1101 RunCallback<1>(PIPELINE_OK)));
1103 status = PIPELINE_ERROR_READ;
1104 EXPECT_CALL(*audio_renderer_, Preroll(_, _))
1105 .WillOnce(RunCallback<1>(status));
1111 EXPECT_CALL(*audio_renderer_, Preroll(_, _))
1112 .WillOnce(RunCallback<1>(PIPELINE_OK));
1113 EXPECT_CALL(*video_renderer_, Preroll(_, _))
1114 .WillOnce(RunCallback<1>(PIPELINE_OK));
1116 // Playback rate and volume are updated prior to starting.
1117 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
1118 EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
1119 EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
1121 if (state == kStarting) {
1122 if (stop_or_error == kStop) {
1123 EXPECT_CALL(*audio_renderer_, Play(_))
1124 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), RunClosure<0>()));
1126 status = PIPELINE_ERROR_READ;
1127 EXPECT_CALL(*audio_renderer_, Play(_)).WillOnce(
1128 DoAll(SetError(pipeline_.get(), status), RunClosure<0>()));
1133 NOTREACHED() << "State not supported: " << state;
1137 void DoStopOrError(StopOrError stop_or_error) {
1140 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
1141 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
1142 EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
1144 switch (stop_or_error) {
1146 EXPECT_CALL(callbacks_, OnStop());
1147 pipeline_->Stop(base::Bind(
1148 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
1152 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
1153 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
1157 EXPECT_CALL(callbacks_, OnStop());
1158 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
1159 pipeline_->Stop(base::Bind(
1160 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
1164 message_loop_.RunUntilIdle();
1167 DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest);
1170 #define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \
1171 TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
1172 RunTest(k##state, k##stop_or_error); \
1175 INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer);
1176 INSTANTIATE_TEARDOWN_TEST(Stop, InitAudioRenderer);
1177 INSTANTIATE_TEARDOWN_TEST(Stop, InitVideoRenderer);
1178 INSTANTIATE_TEARDOWN_TEST(Stop, Pausing);
1179 INSTANTIATE_TEARDOWN_TEST(Stop, Flushing);
1180 INSTANTIATE_TEARDOWN_TEST(Stop, Seeking);
1181 INSTANTIATE_TEARDOWN_TEST(Stop, Prerolling);
1182 INSTANTIATE_TEARDOWN_TEST(Stop, Starting);
1183 INSTANTIATE_TEARDOWN_TEST(Stop, Playing);
1185 INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer);
1186 INSTANTIATE_TEARDOWN_TEST(Error, InitAudioRenderer);
1187 INSTANTIATE_TEARDOWN_TEST(Error, InitVideoRenderer);
1188 INSTANTIATE_TEARDOWN_TEST(Error, Pausing);
1189 INSTANTIATE_TEARDOWN_TEST(Error, Flushing);
1190 INSTANTIATE_TEARDOWN_TEST(Error, Seeking);
1191 INSTANTIATE_TEARDOWN_TEST(Error, Prerolling);
1192 INSTANTIATE_TEARDOWN_TEST(Error, Starting);
1193 INSTANTIATE_TEARDOWN_TEST(Error, Playing);
1195 INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);
1197 } // namespace media