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