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_METHOD1(OnVideoFramePaint
, void(const scoped_refptr
<VideoFrame
>&));
88 MOCK_METHOD0(OnDurationChange
, void());
91 DISALLOW_COPY_AND_ASSIGN(CallbackHelper
);
95 : pipeline_(new Pipeline(message_loop_
.message_loop_proxy(),
97 demuxer_(new StrictMock
<MockDemuxer
>()),
98 scoped_renderer_(new StrictMock
<MockRenderer
>()),
99 renderer_(scoped_renderer_
.get()) {
100 // SetDemuxerExpectations() adds overriding expectations for expected
102 DemuxerStream
* null_pointer
= NULL
;
103 EXPECT_CALL(*demuxer_
, GetStream(_
))
104 .WillRepeatedly(Return(null_pointer
));
106 EXPECT_CALL(*demuxer_
, GetTimelineOffset())
107 .WillRepeatedly(Return(base::Time()));
109 EXPECT_CALL(*renderer_
, GetMediaTime())
110 .WillRepeatedly(Return(base::TimeDelta()));
112 EXPECT_CALL(*demuxer_
, GetStartTime()).WillRepeatedly(Return(start_time_
));
115 virtual ~PipelineTest() {
116 if (!pipeline_
|| !pipeline_
->IsRunning())
121 // The mock demuxer doesn't stop the fake text track stream,
122 // so just stop it manually.
124 text_stream_
->Stop();
125 message_loop_
.RunUntilIdle();
128 // Expect a stop callback if we were started.
129 ExpectPipelineStopAndDestroyPipeline();
130 pipeline_
->Stop(base::Bind(&CallbackHelper::OnStop
,
131 base::Unretained(&callbacks_
)));
132 message_loop_
.RunUntilIdle();
135 void OnDemuxerError() {
136 // Cast because OnDemuxerError is private in Pipeline.
137 static_cast<DemuxerHost
*>(pipeline_
.get())
138 ->OnDemuxerError(PIPELINE_ERROR_ABORT
);
142 // Sets up expectations to allow the demuxer to initialize.
143 typedef std::vector
<MockDemuxerStream
*> MockDemuxerStreamVector
;
144 void SetDemuxerExpectations(MockDemuxerStreamVector
* streams
,
145 const base::TimeDelta
& duration
) {
146 EXPECT_CALL(callbacks_
, OnDurationChange());
147 EXPECT_CALL(*demuxer_
, Initialize(_
, _
, _
))
148 .WillOnce(DoAll(SetDemuxerProperties(duration
),
149 PostCallback
<1>(PIPELINE_OK
)));
151 // Configure the demuxer to return the streams.
152 for (size_t i
= 0; i
< streams
->size(); ++i
) {
153 DemuxerStream
* stream
= (*streams
)[i
];
154 EXPECT_CALL(*demuxer_
, GetStream(stream
->type()))
155 .WillRepeatedly(Return(stream
));
159 void SetDemuxerExpectations(MockDemuxerStreamVector
* streams
) {
160 // Initialize with a default non-zero duration.
161 SetDemuxerExpectations(streams
, base::TimeDelta::FromSeconds(10));
164 scoped_ptr
<StrictMock
<MockDemuxerStream
> > CreateStream(
165 DemuxerStream::Type type
) {
166 scoped_ptr
<StrictMock
<MockDemuxerStream
> > stream(
167 new StrictMock
<MockDemuxerStream
>(type
));
168 return stream
.Pass();
171 // Sets up expectations to allow the video renderer to initialize.
172 void SetRendererExpectations() {
173 EXPECT_CALL(*renderer_
, Initialize(_
, _
, _
, _
, _
, _
, _
, _
))
174 .WillOnce(DoAll(SaveArg
<3>(&buffering_state_cb_
),
175 SaveArg
<5>(&ended_cb_
),
176 PostCallback
<1>(PIPELINE_OK
)));
177 EXPECT_CALL(*renderer_
, HasAudio()).WillRepeatedly(Return(audio_stream()));
178 EXPECT_CALL(*renderer_
, HasVideo()).WillRepeatedly(Return(video_stream()));
181 void AddTextStream() {
182 EXPECT_CALL(*this, OnAddTextTrack(_
,_
))
183 .WillOnce(Invoke(this, &PipelineTest::DoOnAddTextTrack
));
184 static_cast<DemuxerHost
*>(pipeline_
.get())->AddTextStream(text_stream(),
185 TextTrackConfig(kTextSubtitles
, "", "", ""));
186 message_loop_
.RunUntilIdle();
189 void StartPipeline() {
190 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
192 demuxer_
.get(), scoped_renderer_
.Pass(),
193 base::Bind(&CallbackHelper::OnEnded
, base::Unretained(&callbacks_
)),
194 base::Bind(&CallbackHelper::OnError
, base::Unretained(&callbacks_
)),
195 base::Bind(&CallbackHelper::OnStart
, base::Unretained(&callbacks_
)),
196 base::Bind(&CallbackHelper::OnMetadata
, base::Unretained(&callbacks_
)),
197 base::Bind(&CallbackHelper::OnBufferingStateChange
,
198 base::Unretained(&callbacks_
)),
199 base::Bind(&CallbackHelper::OnVideoFramePaint
,
200 base::Unretained(&callbacks_
)),
201 base::Bind(&CallbackHelper::OnDurationChange
,
202 base::Unretained(&callbacks_
)),
203 base::Bind(&PipelineTest::OnAddTextTrack
, base::Unretained(this)),
204 base::Bind(&PipelineTest::OnWaitingForDecryptionKey
,
205 base::Unretained(this)));
208 // Sets up expectations on the callback and initializes the pipeline. Called
209 // after tests have set expectations any filters they wish to use.
210 void StartPipelineAndExpect(PipelineStatus start_status
) {
211 EXPECT_CALL(callbacks_
, OnStart(start_status
));
213 if (start_status
== PIPELINE_OK
) {
214 EXPECT_CALL(callbacks_
, OnMetadata(_
)).WillOnce(SaveArg
<0>(&metadata_
));
215 EXPECT_CALL(*renderer_
, SetPlaybackRate(0.0f
));
216 EXPECT_CALL(*renderer_
, SetVolume(1.0f
));
217 EXPECT_CALL(*renderer_
, StartPlayingFrom(start_time_
))
218 .WillOnce(SetBufferingState(&buffering_state_cb_
,
219 BUFFERING_HAVE_ENOUGH
));
220 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH
));
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
, bool underflowed
) {
255 EXPECT_CALL(*demuxer_
, Seek(seek_time
, _
))
256 .WillOnce(RunCallback
<1>(PIPELINE_OK
));
258 EXPECT_CALL(*renderer_
, Flush(_
))
259 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_
,
260 BUFFERING_HAVE_NOTHING
),
262 EXPECT_CALL(*renderer_
, SetPlaybackRate(_
));
263 EXPECT_CALL(*renderer_
, SetVolume(_
));
264 EXPECT_CALL(*renderer_
, StartPlayingFrom(seek_time
))
265 .WillOnce(SetBufferingState(&buffering_state_cb_
,
266 BUFFERING_HAVE_ENOUGH
));
267 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_NOTHING
));
269 // We expect a successful seek callback followed by a buffering update.
270 EXPECT_CALL(callbacks_
, OnSeek(PIPELINE_OK
));
271 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH
));
274 void DoSeek(const base::TimeDelta
& seek_time
) {
275 pipeline_
->Seek(seek_time
,
276 base::Bind(&CallbackHelper::OnSeek
,
277 base::Unretained(&callbacks_
)));
278 message_loop_
.RunUntilIdle();
281 void DestroyPipeline() {
282 // In real code Pipeline could be destroyed on a different thread. All weak
283 // pointers must have been invalidated before the stop callback returns.
284 DCHECK(!pipeline_
->HasWeakPtrsForTesting());
288 void ExpectDemuxerStop() {
290 EXPECT_CALL(*demuxer_
, Stop());
293 void ExpectPipelineStopAndDestroyPipeline() {
294 // After the Pipeline is stopped, it could be destroyed any time. Always
295 // destroy the pipeline immediately after OnStop() to test this.
296 EXPECT_CALL(callbacks_
, OnStop())
297 .WillOnce(Invoke(this, &PipelineTest::DestroyPipeline
));
300 MOCK_METHOD2(OnAddTextTrack
, void(const TextTrackConfig
&,
301 const AddTextTrackDoneCB
&));
302 MOCK_METHOD0(OnWaitingForDecryptionKey
, void(void));
304 void DoOnAddTextTrack(const TextTrackConfig
& config
,
305 const AddTextTrackDoneCB
& done_cb
) {
306 scoped_ptr
<TextTrack
> text_track(new MockTextTrack
);
307 done_cb
.Run(text_track
.Pass());
311 StrictMock
<CallbackHelper
> callbacks_
;
312 base::SimpleTestTickClock test_tick_clock_
;
313 base::MessageLoop message_loop_
;
314 scoped_ptr
<Pipeline
> pipeline_
;
316 scoped_ptr
<StrictMock
<MockDemuxer
> > demuxer_
;
317 scoped_ptr
<StrictMock
<MockRenderer
> > scoped_renderer_
;
318 StrictMock
<MockRenderer
>* renderer_
;
319 StrictMock
<CallbackHelper
> text_renderer_callbacks_
;
320 TextRenderer
* text_renderer_
;
321 scoped_ptr
<StrictMock
<MockDemuxerStream
> > audio_stream_
;
322 scoped_ptr
<StrictMock
<MockDemuxerStream
> > video_stream_
;
323 scoped_ptr
<FakeTextTrackStream
> text_stream_
;
324 BufferingStateCB buffering_state_cb_
;
325 base::Closure ended_cb_
;
326 VideoDecoderConfig video_decoder_config_
;
327 PipelineMetadata metadata_
;
328 base::TimeDelta start_time_
;
331 DISALLOW_COPY_AND_ASSIGN(PipelineTest
);
334 // Test that playback controls methods no-op when the pipeline hasn't been
336 TEST_F(PipelineTest
, NotStarted
) {
337 const base::TimeDelta kZero
;
339 EXPECT_FALSE(pipeline_
->IsRunning());
341 // Setting should still work.
342 EXPECT_EQ(0.0f
, pipeline_
->GetPlaybackRate());
343 pipeline_
->SetPlaybackRate(-1.0f
);
344 EXPECT_EQ(0.0f
, pipeline_
->GetPlaybackRate());
345 pipeline_
->SetPlaybackRate(1.0f
);
346 EXPECT_EQ(1.0f
, pipeline_
->GetPlaybackRate());
348 // Setting should still work.
349 EXPECT_EQ(1.0f
, pipeline_
->GetVolume());
350 pipeline_
->SetVolume(-1.0f
);
351 EXPECT_EQ(1.0f
, pipeline_
->GetVolume());
352 pipeline_
->SetVolume(0.0f
);
353 EXPECT_EQ(0.0f
, pipeline_
->GetVolume());
355 EXPECT_TRUE(kZero
== pipeline_
->GetMediaTime());
356 EXPECT_EQ(0u, pipeline_
->GetBufferedTimeRanges().size());
357 EXPECT_TRUE(kZero
== pipeline_
->GetMediaDuration());
360 TEST_F(PipelineTest
, NeverInitializes
) {
361 // Don't execute the callback passed into Initialize().
362 EXPECT_CALL(*demuxer_
, Initialize(_
, _
, _
));
364 // This test hangs during initialization by never calling
365 // InitializationComplete(). StrictMock<> will ensure that the callback is
368 message_loop_
.RunUntilIdle();
370 // Because our callback will get executed when the test tears down, we'll
371 // verify that nothing has been called, then set our expectation for the call
372 // made during tear down.
373 Mock::VerifyAndClear(&callbacks_
);
374 EXPECT_CALL(callbacks_
, OnStart(PIPELINE_OK
));
377 TEST_F(PipelineTest
, StopWithoutStart
) {
378 ExpectPipelineStopAndDestroyPipeline();
380 base::Bind(&CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
381 message_loop_
.RunUntilIdle();
384 TEST_F(PipelineTest
, StartThenStopImmediately
) {
385 EXPECT_CALL(*demuxer_
, Initialize(_
, _
, _
))
386 .WillOnce(PostCallback
<1>(PIPELINE_OK
));
387 EXPECT_CALL(*demuxer_
, Stop());
389 EXPECT_CALL(callbacks_
, OnStart(_
));
392 // Expect a stop callback if we were started.
393 ExpectPipelineStopAndDestroyPipeline();
395 base::Bind(&CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
396 message_loop_
.RunUntilIdle();
399 TEST_F(PipelineTest
, DemuxerErrorDuringStop
) {
401 MockDemuxerStreamVector streams
;
402 streams
.push_back(audio_stream());
404 SetDemuxerExpectations(&streams
);
405 SetRendererExpectations();
407 StartPipelineAndExpect(PIPELINE_OK
);
409 EXPECT_CALL(*demuxer_
, Stop())
410 .WillOnce(InvokeWithoutArgs(this, &PipelineTest::OnDemuxerError
));
411 ExpectPipelineStopAndDestroyPipeline();
414 base::Bind(&CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
415 message_loop_
.RunUntilIdle();
418 TEST_F(PipelineTest
, URLNotFound
) {
419 EXPECT_CALL(*demuxer_
, Initialize(_
, _
, _
))
420 .WillOnce(PostCallback
<1>(PIPELINE_ERROR_URL_NOT_FOUND
));
421 EXPECT_CALL(*demuxer_
, Stop());
423 StartPipelineAndExpect(PIPELINE_ERROR_URL_NOT_FOUND
);
426 TEST_F(PipelineTest
, NoStreams
) {
427 EXPECT_CALL(*demuxer_
, Initialize(_
, _
, _
))
428 .WillOnce(PostCallback
<1>(PIPELINE_OK
));
429 EXPECT_CALL(*demuxer_
, Stop());
430 EXPECT_CALL(callbacks_
, OnMetadata(_
));
432 StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER
);
435 TEST_F(PipelineTest
, AudioStream
) {
437 MockDemuxerStreamVector streams
;
438 streams
.push_back(audio_stream());
440 SetDemuxerExpectations(&streams
);
441 SetRendererExpectations();
443 StartPipelineAndExpect(PIPELINE_OK
);
444 EXPECT_TRUE(metadata_
.has_audio
);
445 EXPECT_FALSE(metadata_
.has_video
);
448 TEST_F(PipelineTest
, VideoStream
) {
450 MockDemuxerStreamVector streams
;
451 streams
.push_back(video_stream());
453 SetDemuxerExpectations(&streams
);
454 SetRendererExpectations();
456 StartPipelineAndExpect(PIPELINE_OK
);
457 EXPECT_FALSE(metadata_
.has_audio
);
458 EXPECT_TRUE(metadata_
.has_video
);
461 TEST_F(PipelineTest
, AudioVideoStream
) {
464 MockDemuxerStreamVector streams
;
465 streams
.push_back(audio_stream());
466 streams
.push_back(video_stream());
468 SetDemuxerExpectations(&streams
);
469 SetRendererExpectations();
471 StartPipelineAndExpect(PIPELINE_OK
);
472 EXPECT_TRUE(metadata_
.has_audio
);
473 EXPECT_TRUE(metadata_
.has_video
);
476 TEST_F(PipelineTest
, VideoTextStream
) {
479 MockDemuxerStreamVector streams
;
480 streams
.push_back(video_stream());
482 SetDemuxerExpectations(&streams
);
483 SetRendererExpectations();
485 StartPipelineAndExpect(PIPELINE_OK
);
486 EXPECT_FALSE(metadata_
.has_audio
);
487 EXPECT_TRUE(metadata_
.has_video
);
492 TEST_F(PipelineTest
, VideoAudioTextStream
) {
496 MockDemuxerStreamVector streams
;
497 streams
.push_back(video_stream());
498 streams
.push_back(audio_stream());
500 SetDemuxerExpectations(&streams
);
501 SetRendererExpectations();
503 StartPipelineAndExpect(PIPELINE_OK
);
504 EXPECT_TRUE(metadata_
.has_audio
);
505 EXPECT_TRUE(metadata_
.has_video
);
510 TEST_F(PipelineTest
, Seek
) {
514 MockDemuxerStreamVector streams
;
515 streams
.push_back(audio_stream());
516 streams
.push_back(video_stream());
518 SetDemuxerExpectations(&streams
, base::TimeDelta::FromSeconds(3000));
519 SetRendererExpectations();
521 // Initialize then seek!
522 StartPipelineAndExpect(PIPELINE_OK
);
524 // Every filter should receive a call to Seek().
525 base::TimeDelta expected
= base::TimeDelta::FromSeconds(2000);
526 ExpectSeek(expected
, false);
530 TEST_F(PipelineTest
, SeekAfterError
) {
532 MockDemuxerStreamVector streams
;
533 streams
.push_back(audio_stream());
535 SetDemuxerExpectations(&streams
, base::TimeDelta::FromSeconds(3000));
536 SetRendererExpectations();
538 // Initialize then seek!
539 StartPipelineAndExpect(PIPELINE_OK
);
541 EXPECT_CALL(*demuxer_
, Stop());
542 EXPECT_CALL(callbacks_
, OnError(_
));
544 static_cast<DemuxerHost
*>(pipeline_
.get())
545 ->OnDemuxerError(PIPELINE_ERROR_ABORT
);
546 message_loop_
.RunUntilIdle();
549 base::TimeDelta::FromMilliseconds(100),
550 base::Bind(&CallbackHelper::OnSeek
, base::Unretained(&callbacks_
)));
551 message_loop_
.RunUntilIdle();
554 TEST_F(PipelineTest
, SetVolume
) {
556 MockDemuxerStreamVector streams
;
557 streams
.push_back(audio_stream());
559 SetDemuxerExpectations(&streams
);
560 SetRendererExpectations();
562 // The audio renderer should receive a call to SetVolume().
563 float expected
= 0.5f
;
564 EXPECT_CALL(*renderer_
, SetVolume(expected
));
566 // Initialize then set volume!
567 StartPipelineAndExpect(PIPELINE_OK
);
568 pipeline_
->SetVolume(expected
);
571 TEST_F(PipelineTest
, Properties
) {
573 MockDemuxerStreamVector streams
;
574 streams
.push_back(video_stream());
576 const base::TimeDelta kDuration
= base::TimeDelta::FromSeconds(100);
577 SetDemuxerExpectations(&streams
, kDuration
);
578 SetRendererExpectations();
580 StartPipelineAndExpect(PIPELINE_OK
);
581 EXPECT_EQ(kDuration
.ToInternalValue(),
582 pipeline_
->GetMediaDuration().ToInternalValue());
583 EXPECT_FALSE(pipeline_
->DidLoadingProgress());
586 TEST_F(PipelineTest
, GetBufferedTimeRanges
) {
588 MockDemuxerStreamVector streams
;
589 streams
.push_back(video_stream());
591 const base::TimeDelta kDuration
= base::TimeDelta::FromSeconds(100);
592 SetDemuxerExpectations(&streams
, kDuration
);
593 SetRendererExpectations();
595 StartPipelineAndExpect(PIPELINE_OK
);
597 EXPECT_EQ(0u, pipeline_
->GetBufferedTimeRanges().size());
599 EXPECT_FALSE(pipeline_
->DidLoadingProgress());
600 pipeline_
->AddBufferedTimeRange(base::TimeDelta(), kDuration
/ 8);
601 EXPECT_TRUE(pipeline_
->DidLoadingProgress());
602 EXPECT_FALSE(pipeline_
->DidLoadingProgress());
603 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
604 EXPECT_EQ(base::TimeDelta(), pipeline_
->GetBufferedTimeRanges().start(0));
605 EXPECT_EQ(kDuration
/ 8, pipeline_
->GetBufferedTimeRanges().end(0));
607 base::TimeDelta kSeekTime
= kDuration
/ 2;
608 ExpectSeek(kSeekTime
, false);
611 EXPECT_FALSE(pipeline_
->DidLoadingProgress());
614 TEST_F(PipelineTest
, EndedCallback
) {
618 MockDemuxerStreamVector streams
;
619 streams
.push_back(audio_stream());
620 streams
.push_back(video_stream());
622 SetDemuxerExpectations(&streams
);
623 SetRendererExpectations();
624 StartPipelineAndExpect(PIPELINE_OK
);
628 // The ended callback shouldn't run until all renderers have ended.
630 message_loop_
.RunUntilIdle();
632 EXPECT_CALL(callbacks_
, OnEnded());
633 // Since the |ended_cb_| is manually invoked above, the duration does not
634 // match the expected duration and is updated upon ended.
635 EXPECT_CALL(callbacks_
, OnDurationChange());
636 text_stream()->SendEosNotification();
637 message_loop_
.RunUntilIdle();
640 TEST_F(PipelineTest
, ErrorDuringSeek
) {
642 MockDemuxerStreamVector streams
;
643 streams
.push_back(audio_stream());
645 SetDemuxerExpectations(&streams
);
646 SetRendererExpectations();
647 StartPipelineAndExpect(PIPELINE_OK
);
649 float playback_rate
= 1.0f
;
650 EXPECT_CALL(*renderer_
, SetPlaybackRate(playback_rate
));
651 pipeline_
->SetPlaybackRate(playback_rate
);
652 message_loop_
.RunUntilIdle();
654 base::TimeDelta seek_time
= base::TimeDelta::FromSeconds(5);
656 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_NOTHING
));
657 EXPECT_CALL(*renderer_
, Flush(_
))
658 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_
,
659 BUFFERING_HAVE_NOTHING
),
662 EXPECT_CALL(*demuxer_
, Seek(seek_time
, _
))
663 .WillOnce(RunCallback
<1>(PIPELINE_ERROR_READ
));
664 EXPECT_CALL(*demuxer_
, Stop());
666 pipeline_
->Seek(seek_time
, base::Bind(&CallbackHelper::OnSeek
,
667 base::Unretained(&callbacks_
)));
668 EXPECT_CALL(callbacks_
, OnSeek(PIPELINE_ERROR_READ
));
669 message_loop_
.RunUntilIdle();
672 // Invoked function OnError. This asserts that the pipeline does not enqueue
673 // non-teardown related tasks while tearing down.
674 static void TestNoCallsAfterError(
675 Pipeline
* pipeline
, base::MessageLoop
* message_loop
,
676 PipelineStatus
/* status */) {
680 // When we get to this stage, the message loop should be empty.
681 EXPECT_TRUE(message_loop
->IsIdleForTesting());
683 // Make calls on pipeline after error has occurred.
684 pipeline
->SetPlaybackRate(0.5f
);
685 pipeline
->SetVolume(0.5f
);
687 // No additional tasks should be queued as a result of these calls.
688 EXPECT_TRUE(message_loop
->IsIdleForTesting());
691 TEST_F(PipelineTest
, NoMessageDuringTearDownFromError
) {
693 MockDemuxerStreamVector streams
;
694 streams
.push_back(audio_stream());
696 SetDemuxerExpectations(&streams
);
697 SetRendererExpectations();
698 StartPipelineAndExpect(PIPELINE_OK
);
700 // Trigger additional requests on the pipeline during tear down from error.
701 base::Callback
<void(PipelineStatus
)> cb
= base::Bind(
702 &TestNoCallsAfterError
, pipeline_
.get(), &message_loop_
);
703 ON_CALL(callbacks_
, OnError(_
))
704 .WillByDefault(Invoke(&cb
, &base::Callback
<void(PipelineStatus
)>::Run
));
706 base::TimeDelta seek_time
= base::TimeDelta::FromSeconds(5);
708 // Seek() isn't called as the demuxer errors out first.
709 EXPECT_CALL(*renderer_
, Flush(_
))
710 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_
,
711 BUFFERING_HAVE_NOTHING
),
713 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_NOTHING
));
715 EXPECT_CALL(*demuxer_
, Seek(seek_time
, _
))
716 .WillOnce(RunCallback
<1>(PIPELINE_ERROR_READ
));
717 EXPECT_CALL(*demuxer_
, Stop());
719 pipeline_
->Seek(seek_time
, base::Bind(&CallbackHelper::OnSeek
,
720 base::Unretained(&callbacks_
)));
721 EXPECT_CALL(callbacks_
, OnSeek(PIPELINE_ERROR_READ
));
722 message_loop_
.RunUntilIdle();
725 TEST_F(PipelineTest
, DestroyAfterStop
) {
727 MockDemuxerStreamVector streams
;
728 streams
.push_back(audio_stream());
729 SetDemuxerExpectations(&streams
);
730 SetRendererExpectations();
731 StartPipelineAndExpect(PIPELINE_OK
);
735 ExpectPipelineStopAndDestroyPipeline();
737 base::Bind(&CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
738 message_loop_
.RunUntilIdle();
741 TEST_F(PipelineTest
, Underflow
) {
744 MockDemuxerStreamVector streams
;
745 streams
.push_back(audio_stream());
746 streams
.push_back(video_stream());
748 SetDemuxerExpectations(&streams
);
749 SetRendererExpectations();
750 StartPipelineAndExpect(PIPELINE_OK
);
752 // Simulate underflow.
753 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_NOTHING
));
754 buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
756 // Seek while underflowed.
757 base::TimeDelta expected
= base::TimeDelta::FromSeconds(5);
758 ExpectSeek(expected
, true);
762 TEST_F(PipelineTest
, PositiveStartTime
) {
763 start_time_
= base::TimeDelta::FromSeconds(1);
764 EXPECT_CALL(*demuxer_
, GetStartTime()).WillRepeatedly(Return(start_time_
));
766 MockDemuxerStreamVector streams
;
767 streams
.push_back(audio_stream());
768 SetDemuxerExpectations(&streams
);
769 SetRendererExpectations();
770 StartPipelineAndExpect(PIPELINE_OK
);
772 ExpectPipelineStopAndDestroyPipeline();
774 base::Bind(&CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
775 message_loop_
.RunUntilIdle();
778 class PipelineTeardownTest
: public PipelineTest
{
794 PipelineTeardownTest() {}
795 ~PipelineTeardownTest() override
{}
797 void RunTest(TeardownState state
, StopOrError stop_or_error
) {
801 DoInitialize(state
, stop_or_error
);
806 DoInitialize(state
, stop_or_error
);
807 DoSeek(state
, stop_or_error
);
811 DoInitialize(state
, stop_or_error
);
812 DoStopOrError(stop_or_error
);
818 // TODO(scherkus): We do radically different things whether teardown is
819 // invoked via stop vs error. The teardown path should be the same,
820 // see http://crbug.com/110228
821 void DoInitialize(TeardownState state
, StopOrError stop_or_error
) {
822 PipelineStatus expected_status
=
823 SetInitializeExpectations(state
, stop_or_error
);
825 EXPECT_CALL(callbacks_
, OnStart(expected_status
));
827 message_loop_
.RunUntilIdle();
830 PipelineStatus
SetInitializeExpectations(TeardownState state
,
831 StopOrError stop_or_error
) {
832 PipelineStatus status
= PIPELINE_OK
;
833 base::Closure stop_cb
= base::Bind(
834 &CallbackHelper::OnStop
, base::Unretained(&callbacks_
));
836 if (state
== kInitDemuxer
) {
837 if (stop_or_error
== kStop
) {
838 EXPECT_CALL(*demuxer_
, Initialize(_
, _
, _
))
839 .WillOnce(DoAll(Stop(pipeline_
.get(), stop_cb
),
840 PostCallback
<1>(PIPELINE_OK
)));
841 ExpectPipelineStopAndDestroyPipeline();
843 status
= DEMUXER_ERROR_COULD_NOT_OPEN
;
844 EXPECT_CALL(*demuxer_
, Initialize(_
, _
, _
))
845 .WillOnce(PostCallback
<1>(status
));
848 EXPECT_CALL(*demuxer_
, Stop());
854 MockDemuxerStreamVector streams
;
855 streams
.push_back(audio_stream());
856 streams
.push_back(video_stream());
857 SetDemuxerExpectations(&streams
, base::TimeDelta::FromSeconds(3000));
859 EXPECT_CALL(*renderer_
, HasAudio()).WillRepeatedly(Return(true));
860 EXPECT_CALL(*renderer_
, HasVideo()).WillRepeatedly(Return(true));
862 if (state
== kInitRenderer
) {
863 if (stop_or_error
== kStop
) {
864 EXPECT_CALL(*renderer_
, Initialize(_
, _
, _
, _
, _
, _
, _
, _
))
865 .WillOnce(DoAll(Stop(pipeline_
.get(), stop_cb
),
866 PostCallback
<1>(PIPELINE_OK
)));
867 ExpectPipelineStopAndDestroyPipeline();
869 status
= PIPELINE_ERROR_INITIALIZATION_FAILED
;
870 EXPECT_CALL(*renderer_
, Initialize(_
, _
, _
, _
, _
, _
, _
, _
))
871 .WillOnce(PostCallback
<1>(status
));
874 EXPECT_CALL(*demuxer_
, Stop());
875 EXPECT_CALL(callbacks_
, OnMetadata(_
));
879 EXPECT_CALL(*renderer_
, Initialize(_
, _
, _
, _
, _
, _
, _
, _
))
880 .WillOnce(DoAll(SaveArg
<3>(&buffering_state_cb_
),
881 PostCallback
<1>(PIPELINE_OK
)));
883 EXPECT_CALL(callbacks_
, OnMetadata(_
));
885 // If we get here it's a successful initialization.
886 EXPECT_CALL(*renderer_
, SetPlaybackRate(0.0f
));
887 EXPECT_CALL(*renderer_
, SetVolume(1.0f
));
888 EXPECT_CALL(*renderer_
, StartPlayingFrom(base::TimeDelta()))
889 .WillOnce(SetBufferingState(&buffering_state_cb_
,
890 BUFFERING_HAVE_ENOUGH
));
892 if (status
== PIPELINE_OK
)
893 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH
));
898 void DoSeek(TeardownState state
, StopOrError stop_or_error
) {
900 PipelineStatus status
= SetSeekExpectations(state
, stop_or_error
);
902 EXPECT_CALL(*demuxer_
, Stop());
903 EXPECT_CALL(callbacks_
, OnSeek(status
));
905 if (status
== PIPELINE_OK
) {
906 ExpectPipelineStopAndDestroyPipeline();
909 pipeline_
->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
910 &CallbackHelper::OnSeek
, base::Unretained(&callbacks_
)));
911 message_loop_
.RunUntilIdle();
914 PipelineStatus
SetSeekExpectations(TeardownState state
,
915 StopOrError stop_or_error
) {
916 PipelineStatus status
= PIPELINE_OK
;
917 base::Closure stop_cb
= base::Bind(
918 &CallbackHelper::OnStop
, base::Unretained(&callbacks_
));
920 if (state
== kFlushing
) {
921 if (stop_or_error
== kStop
) {
922 EXPECT_CALL(*renderer_
, Flush(_
))
923 .WillOnce(DoAll(Stop(pipeline_
.get(), stop_cb
),
924 SetBufferingState(&buffering_state_cb_
,
925 BUFFERING_HAVE_NOTHING
),
927 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_NOTHING
));
929 status
= PIPELINE_ERROR_READ
;
930 EXPECT_CALL(*renderer_
, Flush(_
))
931 .WillOnce(DoAll(SetError(pipeline_
.get(), status
),
932 SetBufferingState(&buffering_state_cb_
,
933 BUFFERING_HAVE_NOTHING
),
935 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_NOTHING
));
941 EXPECT_CALL(*renderer_
, Flush(_
))
942 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_
,
943 BUFFERING_HAVE_NOTHING
),
945 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_NOTHING
));
947 if (state
== kSeeking
) {
948 if (stop_or_error
== kStop
) {
949 EXPECT_CALL(*demuxer_
, Seek(_
, _
))
950 .WillOnce(DoAll(Stop(pipeline_
.get(), stop_cb
),
951 RunCallback
<1>(PIPELINE_OK
)));
953 status
= PIPELINE_ERROR_READ
;
954 EXPECT_CALL(*demuxer_
, Seek(_
, _
))
955 .WillOnce(RunCallback
<1>(status
));
961 NOTREACHED() << "State not supported: " << state
;
965 void DoStopOrError(StopOrError stop_or_error
) {
968 EXPECT_CALL(*demuxer_
, Stop());
970 switch (stop_or_error
) {
972 ExpectPipelineStopAndDestroyPipeline();
973 pipeline_
->Stop(base::Bind(
974 &CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
978 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_READ
));
979 pipeline_
->SetErrorForTesting(PIPELINE_ERROR_READ
);
983 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_READ
));
984 ExpectPipelineStopAndDestroyPipeline();
985 pipeline_
->SetErrorForTesting(PIPELINE_ERROR_READ
);
986 message_loop_
.RunUntilIdle();
987 pipeline_
->Stop(base::Bind(
988 &CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
992 message_loop_
.RunUntilIdle();
995 DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest
);
998 #define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \
999 TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
1000 RunTest(k##state, k##stop_or_error); \
1003 INSTANTIATE_TEARDOWN_TEST(Stop
, InitDemuxer
);
1004 INSTANTIATE_TEARDOWN_TEST(Stop
, InitRenderer
);
1005 INSTANTIATE_TEARDOWN_TEST(Stop
, Flushing
);
1006 INSTANTIATE_TEARDOWN_TEST(Stop
, Seeking
);
1007 INSTANTIATE_TEARDOWN_TEST(Stop
, Playing
);
1009 INSTANTIATE_TEARDOWN_TEST(Error
, InitDemuxer
);
1010 INSTANTIATE_TEARDOWN_TEST(Error
, InitRenderer
);
1011 INSTANTIATE_TEARDOWN_TEST(Error
, Flushing
);
1012 INSTANTIATE_TEARDOWN_TEST(Error
, Seeking
);
1013 INSTANTIATE_TEARDOWN_TEST(Error
, Playing
);
1015 INSTANTIATE_TEARDOWN_TEST(ErrorAndStop
, Playing
);
1017 } // namespace media