suppress uninit error at WebEmbeddedWorkerImpl::startWorkerContext
[chromium-blink-merge.git] / media / base / pipeline_unittest.cc
blob05ffc8c391a3918514b9b5a895b36226a2b8f623
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/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"
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 // Used for setting expectations on pipeline callbacks. Using a StrictMock
55 // also lets us test for missing callbacks.
56 class CallbackHelper {
57 public:
58 CallbackHelper() {}
59 virtual ~CallbackHelper() {}
61 MOCK_METHOD1(OnStart, void(PipelineStatus));
62 MOCK_METHOD1(OnSeek, void(PipelineStatus));
63 MOCK_METHOD0(OnStop, void());
64 MOCK_METHOD0(OnEnded, void());
65 MOCK_METHOD1(OnError, void(PipelineStatus));
66 MOCK_METHOD1(OnMetadata, void(PipelineMetadata));
67 MOCK_METHOD0(OnPrerollCompleted, void());
68 MOCK_METHOD0(OnDurationChange, void());
70 private:
71 DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
74 // TODO(scherkus): even though some filters are initialized on separate
75 // threads these test aren't flaky... why? It's because filters' Initialize()
76 // is executed on |message_loop_| and the mock filters instantly call
77 // InitializationComplete(), which keeps the pipeline humming along. If
78 // either filters don't call InitializationComplete() immediately or filter
79 // initialization is moved to a separate thread this test will become flaky.
80 class PipelineTest : public ::testing::Test {
81 public:
82 PipelineTest()
83 : pipeline_(new Pipeline(message_loop_.message_loop_proxy(),
84 new MediaLog())),
85 filter_collection_(new FilterCollection()),
86 demuxer_(new MockDemuxer()) {
87 filter_collection_->SetDemuxer(demuxer_.get());
89 video_renderer_ = new MockVideoRenderer();
90 scoped_ptr<VideoRenderer> video_renderer(video_renderer_);
91 filter_collection_->SetVideoRenderer(video_renderer.Pass());
93 audio_renderer_ = new MockAudioRenderer();
94 scoped_ptr<AudioRenderer> audio_renderer(audio_renderer_);
95 filter_collection_->SetAudioRenderer(audio_renderer.Pass());
97 text_renderer_ = new TextRenderer(
98 message_loop_.message_loop_proxy(),
99 base::Bind(&PipelineTest::OnAddTextTrack,
100 base::Unretained(this)));
101 scoped_ptr<TextRenderer> text_renderer(text_renderer_);
102 filter_collection_->SetTextRenderer(text_renderer.Pass());
104 // InitializeDemuxer() adds overriding expectations for expected non-NULL
105 // streams.
106 DemuxerStream* null_pointer = NULL;
107 EXPECT_CALL(*demuxer_, GetStream(_))
108 .WillRepeatedly(Return(null_pointer));
110 EXPECT_CALL(*demuxer_, GetTimelineOffset())
111 .WillRepeatedly(Return(base::Time()));
113 EXPECT_CALL(*demuxer_, GetLiveness())
114 .WillRepeatedly(Return(Demuxer::LIVENESS_UNKNOWN));
117 virtual ~PipelineTest() {
118 if (!pipeline_ || !pipeline_->IsRunning())
119 return;
121 ExpectStop();
123 // The mock demuxer doesn't stop the fake text track stream,
124 // so just stop it manually.
125 if (text_stream_) {
126 text_stream_->Stop();
127 message_loop_.RunUntilIdle();
130 // Expect a stop callback if we were started.
131 EXPECT_CALL(callbacks_, OnStop());
132 pipeline_->Stop(base::Bind(&CallbackHelper::OnStop,
133 base::Unretained(&callbacks_)));
134 message_loop_.RunUntilIdle();
137 protected:
138 // Sets up expectations to allow the demuxer to initialize.
139 typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector;
140 void InitializeDemuxer(MockDemuxerStreamVector* streams,
141 const base::TimeDelta& duration) {
142 EXPECT_CALL(callbacks_, OnDurationChange());
143 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
144 .WillOnce(DoAll(SetDemuxerProperties(duration),
145 RunCallback<1>(PIPELINE_OK)));
147 // Configure the demuxer to return the streams.
148 for (size_t i = 0; i < streams->size(); ++i) {
149 DemuxerStream* stream = (*streams)[i];
150 EXPECT_CALL(*demuxer_, GetStream(stream->type()))
151 .WillRepeatedly(Return(stream));
155 void InitializeDemuxer(MockDemuxerStreamVector* streams) {
156 // Initialize with a default non-zero duration.
157 InitializeDemuxer(streams, base::TimeDelta::FromSeconds(10));
160 scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream(
161 DemuxerStream::Type type) {
162 scoped_ptr<StrictMock<MockDemuxerStream> > stream(
163 new StrictMock<MockDemuxerStream>(type));
164 return stream.Pass();
167 // Sets up expectations to allow the video renderer to initialize.
168 void InitializeVideoRenderer(DemuxerStream* stream) {
169 EXPECT_CALL(*video_renderer_, Initialize(stream, _, _, _, _, _, _, _, _))
170 .WillOnce(RunCallback<2>(PIPELINE_OK));
171 EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
173 // Startup sequence.
174 EXPECT_CALL(*video_renderer_, Preroll(base::TimeDelta(), _))
175 .WillOnce(RunCallback<1>(PIPELINE_OK));
176 EXPECT_CALL(*video_renderer_, Play(_))
177 .WillOnce(RunClosure<0>());
180 // Sets up expectations to allow the audio renderer to initialize.
181 void InitializeAudioRenderer(DemuxerStream* stream) {
182 EXPECT_CALL(*audio_renderer_, Initialize(stream, _, _, _, _, _, _))
183 .WillOnce(DoAll(SaveArg<4>(&audio_time_cb_),
184 RunCallback<1>(PIPELINE_OK)));
187 void AddTextStream() {
188 EXPECT_CALL(*this, OnAddTextTrack(_,_))
189 .WillOnce(Invoke(this, &PipelineTest::DoOnAddTextTrack));
190 static_cast<DemuxerHost*>(pipeline_.get())->AddTextStream(text_stream(),
191 TextTrackConfig(kTextSubtitles, "", "", ""));
194 // Sets up expectations on the callback and initializes the pipeline. Called
195 // after tests have set expectations any filters they wish to use.
196 void InitializePipeline(PipelineStatus start_status) {
197 EXPECT_CALL(callbacks_, OnStart(start_status));
199 if (start_status == PIPELINE_OK) {
200 EXPECT_CALL(callbacks_, OnMetadata(_)).WillOnce(SaveArg<0>(&metadata_));
202 if (audio_stream_) {
203 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
204 EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
206 // Startup sequence.
207 EXPECT_CALL(*audio_renderer_, Preroll(base::TimeDelta(), _))
208 .WillOnce(RunCallback<1>(PIPELINE_OK));
209 EXPECT_CALL(*audio_renderer_, StartRendering());
211 EXPECT_CALL(callbacks_, OnPrerollCompleted());
214 pipeline_->Start(
215 filter_collection_.Pass(),
216 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
217 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
218 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
219 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
220 base::Bind(&CallbackHelper::OnPrerollCompleted,
221 base::Unretained(&callbacks_)),
222 base::Bind(&CallbackHelper::OnDurationChange,
223 base::Unretained(&callbacks_)));
224 message_loop_.RunUntilIdle();
227 void CreateAudioStream() {
228 audio_stream_ = CreateStream(DemuxerStream::AUDIO);
231 void CreateVideoStream() {
232 video_stream_ = CreateStream(DemuxerStream::VIDEO);
233 video_stream_->set_video_decoder_config(video_decoder_config_);
236 void CreateTextStream() {
237 scoped_ptr<FakeTextTrackStream> text_stream(new FakeTextTrackStream());
238 EXPECT_CALL(*text_stream, OnRead()).Times(AnyNumber());
239 text_stream_ = text_stream.Pass();
242 MockDemuxerStream* audio_stream() {
243 return audio_stream_.get();
246 MockDemuxerStream* video_stream() {
247 return video_stream_.get();
250 FakeTextTrackStream* text_stream() {
251 return text_stream_.get();
254 void ExpectSeek(const base::TimeDelta& seek_time) {
255 // Every filter should receive a call to Seek().
256 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
257 .WillOnce(RunCallback<1>(PIPELINE_OK));
259 if (audio_stream_) {
260 EXPECT_CALL(*audio_renderer_, StopRendering());
261 EXPECT_CALL(*audio_renderer_, Flush(_))
262 .WillOnce(RunClosure<0>());
263 EXPECT_CALL(*audio_renderer_, Preroll(seek_time, _))
264 .WillOnce(RunCallback<1>(PIPELINE_OK));
265 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(_));
266 EXPECT_CALL(*audio_renderer_, SetVolume(_));
267 EXPECT_CALL(*audio_renderer_, StartRendering());
270 if (video_stream_) {
271 EXPECT_CALL(*video_renderer_, Flush(_))
272 .WillOnce(RunClosure<0>());
273 EXPECT_CALL(*video_renderer_, Preroll(seek_time, _))
274 .WillOnce(RunCallback<1>(PIPELINE_OK));
275 EXPECT_CALL(*video_renderer_, SetPlaybackRate(_));
276 EXPECT_CALL(*video_renderer_, Play(_))
277 .WillOnce(RunClosure<0>());
280 EXPECT_CALL(callbacks_, OnPrerollCompleted());
282 // We expect a successful seek callback.
283 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
286 void DoSeek(const base::TimeDelta& seek_time) {
287 pipeline_->Seek(seek_time,
288 base::Bind(&CallbackHelper::OnSeek,
289 base::Unretained(&callbacks_)));
291 // We expect the time to be updated only after the seek has completed.
292 EXPECT_NE(seek_time, pipeline_->GetMediaTime());
293 message_loop_.RunUntilIdle();
294 EXPECT_EQ(seek_time, pipeline_->GetMediaTime());
297 void ExpectStop() {
298 if (demuxer_)
299 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
301 if (audio_stream_)
302 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
304 if (video_stream_)
305 EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
308 MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&,
309 const AddTextTrackDoneCB&));
311 void DoOnAddTextTrack(const TextTrackConfig& config,
312 const AddTextTrackDoneCB& done_cb) {
313 scoped_ptr<TextTrack> text_track(new MockTextTrack);
314 done_cb.Run(text_track.Pass());
317 // Fixture members.
318 StrictMock<CallbackHelper> callbacks_;
319 base::SimpleTestTickClock test_tick_clock_;
320 base::MessageLoop message_loop_;
321 scoped_ptr<Pipeline> pipeline_;
323 scoped_ptr<FilterCollection> filter_collection_;
324 scoped_ptr<MockDemuxer> demuxer_;
325 MockVideoRenderer* video_renderer_;
326 MockAudioRenderer* audio_renderer_;
327 StrictMock<CallbackHelper> text_renderer_callbacks_;
328 TextRenderer* text_renderer_;
329 scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
330 scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
331 scoped_ptr<FakeTextTrackStream> text_stream_;
332 AudioRenderer::TimeCB audio_time_cb_;
333 VideoDecoderConfig video_decoder_config_;
334 PipelineMetadata metadata_;
336 private:
337 DISALLOW_COPY_AND_ASSIGN(PipelineTest);
340 // Test that playback controls methods no-op when the pipeline hasn't been
341 // started.
342 TEST_F(PipelineTest, NotStarted) {
343 const base::TimeDelta kZero;
345 EXPECT_FALSE(pipeline_->IsRunning());
347 // Setting should still work.
348 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
349 pipeline_->SetPlaybackRate(-1.0f);
350 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate());
351 pipeline_->SetPlaybackRate(1.0f);
352 EXPECT_EQ(1.0f, pipeline_->GetPlaybackRate());
354 // Setting should still work.
355 EXPECT_EQ(1.0f, pipeline_->GetVolume());
356 pipeline_->SetVolume(-1.0f);
357 EXPECT_EQ(1.0f, pipeline_->GetVolume());
358 pipeline_->SetVolume(0.0f);
359 EXPECT_EQ(0.0f, pipeline_->GetVolume());
361 EXPECT_TRUE(kZero == pipeline_->GetMediaTime());
362 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
363 EXPECT_TRUE(kZero == pipeline_->GetMediaDuration());
366 TEST_F(PipelineTest, NeverInitializes) {
367 // Don't execute the callback passed into Initialize().
368 EXPECT_CALL(*demuxer_, Initialize(_, _, _));
370 // This test hangs during initialization by never calling
371 // InitializationComplete(). StrictMock<> will ensure that the callback is
372 // never executed.
373 pipeline_->Start(
374 filter_collection_.Pass(),
375 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
376 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
377 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
378 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
379 base::Bind(&CallbackHelper::OnPrerollCompleted,
380 base::Unretained(&callbacks_)),
381 base::Bind(&CallbackHelper::OnDurationChange,
382 base::Unretained(&callbacks_)));
383 message_loop_.RunUntilIdle();
386 // Because our callback will get executed when the test tears down, we'll
387 // verify that nothing has been called, then set our expectation for the call
388 // made during tear down.
389 Mock::VerifyAndClear(&callbacks_);
390 EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
393 TEST_F(PipelineTest, URLNotFound) {
394 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
395 .WillOnce(RunCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND));
396 EXPECT_CALL(*demuxer_, Stop(_))
397 .WillOnce(RunClosure<0>());
399 InitializePipeline(PIPELINE_ERROR_URL_NOT_FOUND);
402 TEST_F(PipelineTest, NoStreams) {
403 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
404 .WillOnce(RunCallback<1>(PIPELINE_OK));
405 EXPECT_CALL(*demuxer_, Stop(_))
406 .WillOnce(RunClosure<0>());
408 InitializePipeline(PIPELINE_ERROR_COULD_NOT_RENDER);
411 TEST_F(PipelineTest, AudioStream) {
412 CreateAudioStream();
413 MockDemuxerStreamVector streams;
414 streams.push_back(audio_stream());
416 InitializeDemuxer(&streams);
417 InitializeAudioRenderer(audio_stream());
419 InitializePipeline(PIPELINE_OK);
420 EXPECT_TRUE(metadata_.has_audio);
421 EXPECT_FALSE(metadata_.has_video);
424 TEST_F(PipelineTest, VideoStream) {
425 CreateVideoStream();
426 MockDemuxerStreamVector streams;
427 streams.push_back(video_stream());
429 InitializeDemuxer(&streams);
430 InitializeVideoRenderer(video_stream());
432 InitializePipeline(PIPELINE_OK);
433 EXPECT_FALSE(metadata_.has_audio);
434 EXPECT_TRUE(metadata_.has_video);
437 TEST_F(PipelineTest, AudioVideoStream) {
438 CreateAudioStream();
439 CreateVideoStream();
440 MockDemuxerStreamVector streams;
441 streams.push_back(audio_stream());
442 streams.push_back(video_stream());
444 InitializeDemuxer(&streams);
445 InitializeAudioRenderer(audio_stream());
446 InitializeVideoRenderer(video_stream());
448 InitializePipeline(PIPELINE_OK);
449 EXPECT_TRUE(metadata_.has_audio);
450 EXPECT_TRUE(metadata_.has_video);
453 TEST_F(PipelineTest, VideoTextStream) {
454 CreateVideoStream();
455 CreateTextStream();
456 MockDemuxerStreamVector streams;
457 streams.push_back(video_stream());
459 InitializeDemuxer(&streams);
460 InitializeVideoRenderer(video_stream());
462 InitializePipeline(PIPELINE_OK);
463 EXPECT_FALSE(metadata_.has_audio);
464 EXPECT_TRUE(metadata_.has_video);
466 AddTextStream();
467 message_loop_.RunUntilIdle();
470 TEST_F(PipelineTest, VideoAudioTextStream) {
471 CreateVideoStream();
472 CreateAudioStream();
473 CreateTextStream();
474 MockDemuxerStreamVector streams;
475 streams.push_back(video_stream());
476 streams.push_back(audio_stream());
478 InitializeDemuxer(&streams);
479 InitializeVideoRenderer(video_stream());
480 InitializeAudioRenderer(audio_stream());
482 InitializePipeline(PIPELINE_OK);
483 EXPECT_TRUE(metadata_.has_audio);
484 EXPECT_TRUE(metadata_.has_video);
486 AddTextStream();
487 message_loop_.RunUntilIdle();
490 TEST_F(PipelineTest, Seek) {
491 CreateAudioStream();
492 CreateVideoStream();
493 CreateTextStream();
494 MockDemuxerStreamVector streams;
495 streams.push_back(audio_stream());
496 streams.push_back(video_stream());
498 InitializeDemuxer(&streams, base::TimeDelta::FromSeconds(3000));
499 InitializeAudioRenderer(audio_stream());
500 InitializeVideoRenderer(video_stream());
502 // Initialize then seek!
503 InitializePipeline(PIPELINE_OK);
505 AddTextStream();
506 message_loop_.RunUntilIdle();
508 // Every filter should receive a call to Seek().
509 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000);
510 ExpectSeek(expected);
511 DoSeek(expected);
514 TEST_F(PipelineTest, SetVolume) {
515 CreateAudioStream();
516 MockDemuxerStreamVector streams;
517 streams.push_back(audio_stream());
519 InitializeDemuxer(&streams);
520 InitializeAudioRenderer(audio_stream());
522 // The audio renderer should receive a call to SetVolume().
523 float expected = 0.5f;
524 EXPECT_CALL(*audio_renderer_, SetVolume(expected));
526 // Initialize then set volume!
527 InitializePipeline(PIPELINE_OK);
528 pipeline_->SetVolume(expected);
531 TEST_F(PipelineTest, Properties) {
532 CreateVideoStream();
533 MockDemuxerStreamVector streams;
534 streams.push_back(video_stream());
536 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
537 InitializeDemuxer(&streams, kDuration);
538 InitializeVideoRenderer(video_stream());
540 InitializePipeline(PIPELINE_OK);
541 EXPECT_EQ(kDuration.ToInternalValue(),
542 pipeline_->GetMediaDuration().ToInternalValue());
543 EXPECT_FALSE(pipeline_->DidLoadingProgress());
546 TEST_F(PipelineTest, GetBufferedTimeRanges) {
547 CreateVideoStream();
548 MockDemuxerStreamVector streams;
549 streams.push_back(video_stream());
551 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100);
552 InitializeDemuxer(&streams, kDuration);
553 InitializeVideoRenderer(video_stream());
555 InitializePipeline(PIPELINE_OK);
557 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
559 EXPECT_FALSE(pipeline_->DidLoadingProgress());
560 pipeline_->AddBufferedTimeRange(base::TimeDelta(), kDuration / 8);
561 EXPECT_TRUE(pipeline_->DidLoadingProgress());
562 EXPECT_FALSE(pipeline_->DidLoadingProgress());
563 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
564 EXPECT_EQ(base::TimeDelta(), pipeline_->GetBufferedTimeRanges().start(0));
565 EXPECT_EQ(kDuration / 8, pipeline_->GetBufferedTimeRanges().end(0));
567 base::TimeDelta kSeekTime = kDuration / 2;
568 ExpectSeek(kSeekTime);
569 DoSeek(kSeekTime);
571 EXPECT_FALSE(pipeline_->DidLoadingProgress());
574 TEST_F(PipelineTest, EndedCallback) {
575 CreateAudioStream();
576 CreateVideoStream();
577 CreateTextStream();
578 MockDemuxerStreamVector streams;
579 streams.push_back(audio_stream());
580 streams.push_back(video_stream());
582 InitializeDemuxer(&streams);
583 InitializeAudioRenderer(audio_stream());
584 InitializeVideoRenderer(video_stream());
585 InitializePipeline(PIPELINE_OK);
587 AddTextStream();
589 // The ended callback shouldn't run until all renderers have ended.
590 pipeline_->OnAudioRendererEnded();
591 message_loop_.RunUntilIdle();
593 pipeline_->OnVideoRendererEnded();
594 message_loop_.RunUntilIdle();
596 EXPECT_CALL(*audio_renderer_, StopRendering());
597 EXPECT_CALL(callbacks_, OnEnded());
598 text_stream()->SendEosNotification();
599 message_loop_.RunUntilIdle();
602 TEST_F(PipelineTest, AudioStreamShorterThanVideo) {
603 base::TimeDelta duration = base::TimeDelta::FromSeconds(10);
605 CreateAudioStream();
606 CreateVideoStream();
607 MockDemuxerStreamVector streams;
608 streams.push_back(audio_stream());
609 streams.push_back(video_stream());
611 // Replace the clock so we can simulate wall clock time advancing w/o using
612 // Sleep().
613 pipeline_->SetClockForTesting(new Clock(&test_tick_clock_));
615 InitializeDemuxer(&streams, duration);
616 InitializeAudioRenderer(audio_stream());
617 InitializeVideoRenderer(video_stream());
618 InitializePipeline(PIPELINE_OK);
620 EXPECT_EQ(0, pipeline_->GetMediaTime().ToInternalValue());
622 float playback_rate = 1.0f;
623 EXPECT_CALL(*video_renderer_, SetPlaybackRate(playback_rate));
624 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
625 pipeline_->SetPlaybackRate(playback_rate);
626 message_loop_.RunUntilIdle();
628 InSequence s;
630 // Verify that the clock doesn't advance since it hasn't been started by
631 // a time update from the audio stream.
632 int64 start_time = pipeline_->GetMediaTime().ToInternalValue();
633 test_tick_clock_.Advance(base::TimeDelta::FromMilliseconds(100));
634 EXPECT_EQ(pipeline_->GetMediaTime().ToInternalValue(), start_time);
636 // Signal end of audio stream.
637 pipeline_->OnAudioRendererEnded();
638 message_loop_.RunUntilIdle();
640 // Verify that the clock advances.
641 start_time = pipeline_->GetMediaTime().ToInternalValue();
642 test_tick_clock_.Advance(base::TimeDelta::FromMilliseconds(100));
643 EXPECT_GT(pipeline_->GetMediaTime().ToInternalValue(), start_time);
645 // Signal end of video stream and make sure OnEnded() callback occurs.
646 EXPECT_CALL(*audio_renderer_, StopRendering());
647 EXPECT_CALL(callbacks_, OnEnded());
648 pipeline_->OnVideoRendererEnded();
651 TEST_F(PipelineTest, ErrorDuringSeek) {
652 CreateAudioStream();
653 MockDemuxerStreamVector streams;
654 streams.push_back(audio_stream());
656 InitializeDemuxer(&streams);
657 InitializeAudioRenderer(audio_stream());
658 InitializePipeline(PIPELINE_OK);
660 float playback_rate = 1.0f;
661 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
662 pipeline_->SetPlaybackRate(playback_rate);
663 message_loop_.RunUntilIdle();
665 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
667 // Preroll() isn't called as the demuxer errors out first.
668 EXPECT_CALL(*audio_renderer_, StopRendering());
669 EXPECT_CALL(*audio_renderer_, Flush(_))
670 .WillOnce(RunClosure<0>());
671 EXPECT_CALL(*audio_renderer_, Stop(_))
672 .WillOnce(RunClosure<0>());
674 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
675 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
676 EXPECT_CALL(*demuxer_, Stop(_))
677 .WillOnce(RunClosure<0>());
679 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
680 base::Unretained(&callbacks_)));
681 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
682 message_loop_.RunUntilIdle();
685 // Invoked function OnError. This asserts that the pipeline does not enqueue
686 // non-teardown related tasks while tearing down.
687 static void TestNoCallsAfterError(
688 Pipeline* pipeline, base::MessageLoop* message_loop,
689 PipelineStatus /* status */) {
690 CHECK(pipeline);
691 CHECK(message_loop);
693 // When we get to this stage, the message loop should be empty.
694 EXPECT_TRUE(message_loop->IsIdleForTesting());
696 // Make calls on pipeline after error has occurred.
697 pipeline->SetPlaybackRate(0.5f);
698 pipeline->SetVolume(0.5f);
700 // No additional tasks should be queued as a result of these calls.
701 EXPECT_TRUE(message_loop->IsIdleForTesting());
704 TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
705 CreateAudioStream();
706 MockDemuxerStreamVector streams;
707 streams.push_back(audio_stream());
709 InitializeDemuxer(&streams);
710 InitializeAudioRenderer(audio_stream());
711 InitializePipeline(PIPELINE_OK);
713 // Trigger additional requests on the pipeline during tear down from error.
714 base::Callback<void(PipelineStatus)> cb = base::Bind(
715 &TestNoCallsAfterError, pipeline_.get(), &message_loop_);
716 ON_CALL(callbacks_, OnError(_))
717 .WillByDefault(Invoke(&cb, &base::Callback<void(PipelineStatus)>::Run));
719 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
721 // Seek() isn't called as the demuxer errors out first.
722 EXPECT_CALL(*audio_renderer_, StopRendering());
723 EXPECT_CALL(*audio_renderer_, Flush(_))
724 .WillOnce(RunClosure<0>());
725 EXPECT_CALL(*audio_renderer_, Stop(_))
726 .WillOnce(RunClosure<0>());
728 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
729 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
730 EXPECT_CALL(*demuxer_, Stop(_))
731 .WillOnce(RunClosure<0>());
733 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
734 base::Unretained(&callbacks_)));
735 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ));
736 message_loop_.RunUntilIdle();
739 static void RunTimeCB(const AudioRenderer::TimeCB& time_cb,
740 int time_in_ms,
741 int max_time_in_ms) {
742 time_cb.Run(base::TimeDelta::FromMilliseconds(time_in_ms),
743 base::TimeDelta::FromMilliseconds(max_time_in_ms));
746 TEST_F(PipelineTest, AudioTimeUpdateDuringSeek) {
747 CreateAudioStream();
748 MockDemuxerStreamVector streams;
749 streams.push_back(audio_stream());
751 InitializeDemuxer(&streams);
752 InitializeAudioRenderer(audio_stream());
753 InitializePipeline(PIPELINE_OK);
755 float playback_rate = 1.0f;
756 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(playback_rate));
757 pipeline_->SetPlaybackRate(playback_rate);
758 message_loop_.RunUntilIdle();
760 // Provide an initial time update so that the pipeline transitions out of the
761 // "waiting for time update" state.
762 audio_time_cb_.Run(base::TimeDelta::FromMilliseconds(100),
763 base::TimeDelta::FromMilliseconds(500));
765 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
767 // Arrange to trigger a time update while the demuxer is in the middle of
768 // seeking. This update should be ignored by the pipeline and the clock should
769 // not get updated.
770 base::Closure closure = base::Bind(&RunTimeCB, audio_time_cb_, 300, 700);
771 EXPECT_CALL(*demuxer_, Seek(seek_time, _))
772 .WillOnce(DoAll(InvokeWithoutArgs(&closure, &base::Closure::Run),
773 RunCallback<1>(PIPELINE_OK)));
775 EXPECT_CALL(*audio_renderer_, StopRendering());
776 EXPECT_CALL(*audio_renderer_, Flush(_))
777 .WillOnce(RunClosure<0>());
778 EXPECT_CALL(*audio_renderer_, Preroll(seek_time, _))
779 .WillOnce(RunCallback<1>(PIPELINE_OK));
780 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(_));
781 EXPECT_CALL(*audio_renderer_, SetVolume(_));
782 EXPECT_CALL(*audio_renderer_, StartRendering());
784 EXPECT_CALL(callbacks_, OnPrerollCompleted());
785 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK));
786 DoSeek(seek_time);
788 EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
790 // Now that the seek is complete, verify that time updates advance the current
791 // time.
792 base::TimeDelta new_time = seek_time + base::TimeDelta::FromMilliseconds(100);
793 audio_time_cb_.Run(new_time, new_time);
795 EXPECT_EQ(pipeline_->GetMediaTime(), new_time);
798 static void DeletePipeline(scoped_ptr<Pipeline> pipeline) {
799 // |pipeline| will go out of scope.
802 TEST_F(PipelineTest, DeleteAfterStop) {
803 CreateAudioStream();
804 MockDemuxerStreamVector streams;
805 streams.push_back(audio_stream());
806 InitializeDemuxer(&streams);
807 InitializeAudioRenderer(audio_stream());
808 InitializePipeline(PIPELINE_OK);
810 ExpectStop();
812 Pipeline* pipeline = pipeline_.get();
813 pipeline->Stop(base::Bind(&DeletePipeline, base::Passed(&pipeline_)));
814 message_loop_.RunUntilIdle();
817 class PipelineTeardownTest : public PipelineTest {
818 public:
819 enum TeardownState {
820 kInitDemuxer,
821 kInitAudioRenderer,
822 kInitVideoRenderer,
823 kFlushing,
824 kSeeking,
825 kPrerolling,
826 kPlaying,
829 enum StopOrError {
830 kStop,
831 kError,
832 kErrorAndStop,
835 PipelineTeardownTest() {}
836 virtual ~PipelineTeardownTest() {}
838 void RunTest(TeardownState state, StopOrError stop_or_error) {
839 switch (state) {
840 case kInitDemuxer:
841 case kInitAudioRenderer:
842 case kInitVideoRenderer:
843 DoInitialize(state, stop_or_error);
844 break;
846 case kFlushing:
847 case kSeeking:
848 case kPrerolling:
849 DoInitialize(state, stop_or_error);
850 DoSeek(state, stop_or_error);
851 break;
853 case kPlaying:
854 DoInitialize(state, stop_or_error);
855 DoStopOrError(stop_or_error);
856 break;
860 private:
861 // TODO(scherkus): We do radically different things whether teardown is
862 // invoked via stop vs error. The teardown path should be the same,
863 // see http://crbug.com/110228
864 void DoInitialize(TeardownState state, StopOrError stop_or_error) {
865 PipelineStatus expected_status =
866 SetInitializeExpectations(state, stop_or_error);
868 EXPECT_CALL(callbacks_, OnStart(expected_status));
869 pipeline_->Start(
870 filter_collection_.Pass(),
871 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
872 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
873 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)),
874 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)),
875 base::Bind(&CallbackHelper::OnPrerollCompleted,
876 base::Unretained(&callbacks_)),
877 base::Bind(&CallbackHelper::OnDurationChange,
878 base::Unretained(&callbacks_)));
879 message_loop_.RunUntilIdle();
882 PipelineStatus SetInitializeExpectations(TeardownState state,
883 StopOrError stop_or_error) {
884 PipelineStatus status = PIPELINE_OK;
885 base::Closure stop_cb = base::Bind(
886 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
888 if (state == kInitDemuxer) {
889 if (stop_or_error == kStop) {
890 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
891 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
892 RunCallback<1>(PIPELINE_OK)));
893 EXPECT_CALL(callbacks_, OnStop());
894 } else {
895 status = DEMUXER_ERROR_COULD_NOT_OPEN;
896 EXPECT_CALL(*demuxer_, Initialize(_, _, _))
897 .WillOnce(RunCallback<1>(status));
900 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
901 return status;
904 CreateAudioStream();
905 CreateVideoStream();
906 MockDemuxerStreamVector streams;
907 streams.push_back(audio_stream());
908 streams.push_back(video_stream());
909 InitializeDemuxer(&streams, base::TimeDelta::FromSeconds(3000));
911 if (state == kInitAudioRenderer) {
912 if (stop_or_error == kStop) {
913 EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
914 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
915 RunCallback<1>(PIPELINE_OK)));
916 EXPECT_CALL(callbacks_, OnStop());
917 } else {
918 status = PIPELINE_ERROR_INITIALIZATION_FAILED;
919 EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
920 .WillOnce(RunCallback<1>(status));
923 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
924 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
925 return status;
928 EXPECT_CALL(*audio_renderer_, Initialize(_, _, _, _, _, _, _))
929 .WillOnce(RunCallback<1>(PIPELINE_OK));
931 if (state == kInitVideoRenderer) {
932 if (stop_or_error == kStop) {
933 EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
934 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
935 RunCallback<2>(PIPELINE_OK)));
936 EXPECT_CALL(callbacks_, OnStop());
937 } else {
938 status = PIPELINE_ERROR_INITIALIZATION_FAILED;
939 EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
940 .WillOnce(RunCallback<2>(status));
943 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
944 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
945 EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
946 return status;
949 EXPECT_CALL(*video_renderer_, Initialize(_, _, _, _, _, _, _, _, _))
950 .WillOnce(RunCallback<2>(PIPELINE_OK));
952 EXPECT_CALL(callbacks_, OnMetadata(_));
954 // If we get here it's a successful initialization.
955 EXPECT_CALL(*audio_renderer_, Preroll(base::TimeDelta(), _))
956 .WillOnce(RunCallback<1>(PIPELINE_OK));
957 EXPECT_CALL(*video_renderer_, Preroll(base::TimeDelta(), _))
958 .WillOnce(RunCallback<1>(PIPELINE_OK));
960 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
961 EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
962 EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
964 EXPECT_CALL(*audio_renderer_, StartRendering());
965 EXPECT_CALL(*video_renderer_, Play(_))
966 .WillOnce(RunClosure<0>());
968 if (status == PIPELINE_OK)
969 EXPECT_CALL(callbacks_, OnPrerollCompleted());
971 return status;
974 void DoSeek(TeardownState state, StopOrError stop_or_error) {
975 InSequence s;
976 PipelineStatus status = SetSeekExpectations(state, stop_or_error);
978 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
979 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
980 EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
981 EXPECT_CALL(callbacks_, OnSeek(status));
983 if (status == PIPELINE_OK) {
984 EXPECT_CALL(callbacks_, OnStop());
987 pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
988 &CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
989 message_loop_.RunUntilIdle();
992 PipelineStatus SetSeekExpectations(TeardownState state,
993 StopOrError stop_or_error) {
994 PipelineStatus status = PIPELINE_OK;
995 base::Closure stop_cb = base::Bind(
996 &CallbackHelper::OnStop, base::Unretained(&callbacks_));
998 EXPECT_CALL(*audio_renderer_, StopRendering());
1000 if (state == kFlushing) {
1001 if (stop_or_error == kStop) {
1002 EXPECT_CALL(*audio_renderer_, Flush(_))
1003 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), RunClosure<0>()));
1004 } else {
1005 status = PIPELINE_ERROR_READ;
1006 EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(
1007 DoAll(SetError(pipeline_.get(), status), RunClosure<0>()));
1010 return status;
1013 EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(RunClosure<0>());
1014 EXPECT_CALL(*video_renderer_, Flush(_)).WillOnce(RunClosure<0>());
1016 if (state == kSeeking) {
1017 if (stop_or_error == kStop) {
1018 EXPECT_CALL(*demuxer_, Seek(_, _))
1019 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
1020 RunCallback<1>(PIPELINE_OK)));
1021 } else {
1022 status = PIPELINE_ERROR_READ;
1023 EXPECT_CALL(*demuxer_, Seek(_, _))
1024 .WillOnce(RunCallback<1>(status));
1027 return status;
1030 EXPECT_CALL(*demuxer_, Seek(_, _))
1031 .WillOnce(RunCallback<1>(PIPELINE_OK));
1033 if (state == kPrerolling) {
1034 if (stop_or_error == kStop) {
1035 EXPECT_CALL(*audio_renderer_, Preroll(_, _))
1036 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
1037 RunCallback<1>(PIPELINE_OK)));
1038 } else {
1039 status = PIPELINE_ERROR_READ;
1040 EXPECT_CALL(*audio_renderer_, Preroll(_, _))
1041 .WillOnce(RunCallback<1>(status));
1044 return status;
1047 EXPECT_CALL(*audio_renderer_, Preroll(_, _))
1048 .WillOnce(RunCallback<1>(PIPELINE_OK));
1049 EXPECT_CALL(*video_renderer_, Preroll(_, _))
1050 .WillOnce(RunCallback<1>(PIPELINE_OK));
1052 // Playback rate and volume are updated prior to starting.
1053 EXPECT_CALL(*audio_renderer_, SetPlaybackRate(0.0f));
1054 EXPECT_CALL(*video_renderer_, SetPlaybackRate(0.0f));
1055 EXPECT_CALL(*audio_renderer_, SetVolume(1.0f));
1057 NOTREACHED() << "State not supported: " << state;
1058 return status;
1061 void DoStopOrError(StopOrError stop_or_error) {
1062 InSequence s;
1064 EXPECT_CALL(*demuxer_, Stop(_)).WillOnce(RunClosure<0>());
1065 EXPECT_CALL(*audio_renderer_, Stop(_)).WillOnce(RunClosure<0>());
1066 EXPECT_CALL(*video_renderer_, Stop(_)).WillOnce(RunClosure<0>());
1068 switch (stop_or_error) {
1069 case kStop:
1070 EXPECT_CALL(callbacks_, OnStop());
1071 pipeline_->Stop(base::Bind(
1072 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
1073 break;
1075 case kError:
1076 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ));
1077 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
1078 break;
1080 case kErrorAndStop:
1081 EXPECT_CALL(callbacks_, OnStop());
1082 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
1083 pipeline_->Stop(base::Bind(
1084 &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
1085 break;
1088 message_loop_.RunUntilIdle();
1091 DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest);
1094 #define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \
1095 TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
1096 RunTest(k##state, k##stop_or_error); \
1099 INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer);
1100 INSTANTIATE_TEARDOWN_TEST(Stop, InitAudioRenderer);
1101 INSTANTIATE_TEARDOWN_TEST(Stop, InitVideoRenderer);
1102 INSTANTIATE_TEARDOWN_TEST(Stop, Flushing);
1103 INSTANTIATE_TEARDOWN_TEST(Stop, Seeking);
1104 INSTANTIATE_TEARDOWN_TEST(Stop, Prerolling);
1105 INSTANTIATE_TEARDOWN_TEST(Stop, Playing);
1107 INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer);
1108 INSTANTIATE_TEARDOWN_TEST(Error, InitAudioRenderer);
1109 INSTANTIATE_TEARDOWN_TEST(Error, InitVideoRenderer);
1110 INSTANTIATE_TEARDOWN_TEST(Error, Flushing);
1111 INSTANTIATE_TEARDOWN_TEST(Error, Seeking);
1112 INSTANTIATE_TEARDOWN_TEST(Error, Prerolling);
1113 INSTANTIATE_TEARDOWN_TEST(Error, Playing);
1115 INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);
1117 } // namespace media