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