1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 #include "base/message_loop/message_loop.h"
9 #include "base/stl_util.h"
10 #include "base/test/simple_test_tick_clock.h"
11 #include "base/threading/simple_thread.h"
12 #include "base/time/clock.h"
13 #include "media/base/clock.h"
14 #include "media/base/fake_text_track_stream.h"
15 #include "media/base/gmock_callback_support.h"
16 #include "media/base/media_log.h"
17 #include "media/base/mock_filters.h"
18 #include "media/base/pipeline.h"
19 #include "media/base/test_helpers.h"
20 #include "media/base/text_renderer.h"
21 #include "media/base/text_track_config.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "ui/gfx/size.h"
26 using ::testing::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 // Used for setting expectations on pipeline callbacks. Using a StrictMock
55 // also lets us test for missing callbacks.
56 class 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());
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
{
83 : pipeline_(new Pipeline(message_loop_
.message_loop_proxy(),
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
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())
123 // The mock demuxer doesn't stop the fake text track stream,
124 // so just stop it manually.
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();
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
));
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_
));
203 EXPECT_CALL(*audio_renderer_
, SetPlaybackRate(0.0f
));
204 EXPECT_CALL(*audio_renderer_
, SetVolume(1.0f
));
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());
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
));
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());
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());
299 EXPECT_CALL(*demuxer_
, Stop(_
)).WillOnce(RunClosure
<0>());
302 EXPECT_CALL(*audio_renderer_
, Stop(_
)).WillOnce(RunClosure
<0>());
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());
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_
;
337 DISALLOW_COPY_AND_ASSIGN(PipelineTest
);
340 // Test that playback controls methods no-op when the pipeline hasn't been
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
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
) {
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
) {
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
) {
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
) {
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
);
467 message_loop_
.RunUntilIdle();
470 TEST_F(PipelineTest
, VideoAudioTextStream
) {
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
);
487 message_loop_
.RunUntilIdle();
490 TEST_F(PipelineTest
, Seek
) {
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
);
506 message_loop_
.RunUntilIdle();
508 // Every filter should receive a call to Seek().
509 base::TimeDelta expected
= base::TimeDelta::FromSeconds(2000);
510 ExpectSeek(expected
);
514 TEST_F(PipelineTest
, SetVolume
) {
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
) {
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
) {
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
);
571 EXPECT_FALSE(pipeline_
->DidLoadingProgress());
574 TEST_F(PipelineTest
, EndedCallback
) {
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
);
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);
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
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();
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
) {
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 */) {
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
) {
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
,
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
) {
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
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
));
788 EXPECT_EQ(pipeline_
->GetMediaTime(), seek_time
);
790 // Now that the seek is complete, verify that time updates advance the current
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
) {
804 MockDemuxerStreamVector streams
;
805 streams
.push_back(audio_stream());
806 InitializeDemuxer(&streams
);
807 InitializeAudioRenderer(audio_stream());
808 InitializePipeline(PIPELINE_OK
);
812 Pipeline
* pipeline
= pipeline_
.get();
813 pipeline
->Stop(base::Bind(&DeletePipeline
, base::Passed(&pipeline_
)));
814 message_loop_
.RunUntilIdle();
817 class PipelineTeardownTest
: public PipelineTest
{
835 PipelineTeardownTest() {}
836 virtual ~PipelineTeardownTest() {}
838 void RunTest(TeardownState state
, StopOrError stop_or_error
) {
841 case kInitAudioRenderer
:
842 case kInitVideoRenderer
:
843 DoInitialize(state
, stop_or_error
);
849 DoInitialize(state
, stop_or_error
);
850 DoSeek(state
, stop_or_error
);
854 DoInitialize(state
, stop_or_error
);
855 DoStopOrError(stop_or_error
);
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
));
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());
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>());
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());
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>());
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());
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>());
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());
974 void DoSeek(TeardownState state
, StopOrError stop_or_error
) {
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>()));
1005 status
= PIPELINE_ERROR_READ
;
1006 EXPECT_CALL(*audio_renderer_
, Flush(_
)).WillOnce(
1007 DoAll(SetError(pipeline_
.get(), status
), RunClosure
<0>()));
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
)));
1022 status
= PIPELINE_ERROR_READ
;
1023 EXPECT_CALL(*demuxer_
, Seek(_
, _
))
1024 .WillOnce(RunCallback
<1>(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
)));
1039 status
= PIPELINE_ERROR_READ
;
1040 EXPECT_CALL(*audio_renderer_
, Preroll(_
, _
))
1041 .WillOnce(RunCallback
<1>(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
;
1061 void DoStopOrError(StopOrError stop_or_error
) {
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
) {
1070 EXPECT_CALL(callbacks_
, OnStop());
1071 pipeline_
->Stop(base::Bind(
1072 &CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
1076 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_READ
));
1077 pipeline_
->SetErrorForTesting(PIPELINE_ERROR_READ
);
1081 EXPECT_CALL(callbacks_
, OnStop());
1082 pipeline_
->SetErrorForTesting(PIPELINE_ERROR_READ
);
1083 pipeline_
->Stop(base::Bind(
1084 &CallbackHelper::OnStop
, base::Unretained(&callbacks_
)));
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