1 // Copyright 2014 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/run_loop.h"
10 #include "base/test/simple_test_tick_clock.h"
11 #include "media/base/gmock_callback_support.h"
12 #include "media/base/mock_filters.h"
13 #include "media/base/test_helpers.h"
14 #include "media/renderers/renderer_impl.h"
15 #include "testing/gtest/include/gtest/gtest.h"
18 using ::testing::DoAll
;
19 using ::testing::InSequence
;
20 using ::testing::Mock
;
21 using ::testing::Return
;
22 using ::testing::SaveArg
;
23 using ::testing::StrictMock
;
27 const int64 kStartPlayingTimeInMs
= 100;
29 ACTION_P2(SetBufferingState
, cb
, buffering_state
) {
30 cb
->Run(buffering_state
);
33 ACTION_P2(AudioError
, cb
, error
) {
37 class RendererImplTest
: public ::testing::Test
{
39 // Used for setting expectations on pipeline callbacks. Using a StrictMock
40 // also lets us test for missing callbacks.
41 class CallbackHelper
{
44 virtual ~CallbackHelper() {}
46 MOCK_METHOD1(OnInitialize
, void(PipelineStatus
));
47 MOCK_METHOD0(OnFlushed
, void());
48 MOCK_METHOD0(OnEnded
, void());
49 MOCK_METHOD1(OnError
, void(PipelineStatus
));
50 MOCK_METHOD1(OnUpdateStatistics
, void(const PipelineStatistics
&));
51 MOCK_METHOD1(OnBufferingStateChange
, void(BufferingState
));
52 MOCK_METHOD0(OnWaitingForDecryptionKey
, void());
55 DISALLOW_COPY_AND_ASSIGN(CallbackHelper
);
59 : demuxer_(new StrictMock
<MockDemuxer
>()),
60 video_renderer_(new StrictMock
<MockVideoRenderer
>()),
61 audio_renderer_(new StrictMock
<MockAudioRenderer
>()),
63 new RendererImpl(message_loop_
.task_runner(),
64 scoped_ptr
<AudioRenderer
>(audio_renderer_
),
65 scoped_ptr
<VideoRenderer
>(video_renderer_
))) {
66 // SetDemuxerExpectations() adds overriding expectations for expected
68 DemuxerStream
* null_pointer
= NULL
;
69 EXPECT_CALL(*demuxer_
, GetStream(_
))
70 .WillRepeatedly(Return(null_pointer
));
73 virtual ~RendererImplTest() {
74 renderer_impl_
.reset();
75 base::RunLoop().RunUntilIdle();
79 typedef std::vector
<MockDemuxerStream
*> MockDemuxerStreamVector
;
81 scoped_ptr
<StrictMock
<MockDemuxerStream
> > CreateStream(
82 DemuxerStream::Type type
) {
83 scoped_ptr
<StrictMock
<MockDemuxerStream
> > stream(
84 new StrictMock
<MockDemuxerStream
>(type
));
88 // Sets up expectations to allow the audio renderer to initialize.
89 void SetAudioRendererInitializeExpectations(PipelineStatus status
) {
90 EXPECT_CALL(*audio_renderer_
,
91 Initialize(audio_stream_
.get(), _
, _
, _
, _
, _
, _
, _
))
92 .WillOnce(DoAll(SaveArg
<4>(&audio_buffering_state_cb_
),
93 SaveArg
<5>(&audio_ended_cb_
),
94 SaveArg
<6>(&audio_error_cb_
), RunCallback
<1>(status
)));
97 // Sets up expectations to allow the video renderer to initialize.
98 void SetVideoRendererInitializeExpectations(PipelineStatus status
) {
99 EXPECT_CALL(*video_renderer_
,
100 Initialize(video_stream_
.get(), _
, _
, _
, _
, _
, _
, _
, _
))
101 .WillOnce(DoAll(SaveArg
<4>(&video_buffering_state_cb_
),
102 SaveArg
<5>(&video_ended_cb_
), RunCallback
<1>(status
)));
105 void InitializeAndExpect(PipelineStatus start_status
) {
106 EXPECT_CALL(callbacks_
, OnInitialize(start_status
));
107 EXPECT_CALL(callbacks_
, OnWaitingForDecryptionKey()).Times(0);
109 if (start_status
== PIPELINE_OK
&& audio_stream_
) {
110 EXPECT_CALL(*audio_renderer_
, GetTimeSource())
111 .WillOnce(Return(&time_source_
));
113 renderer_impl_
->set_time_source_for_testing(&time_source_
);
116 renderer_impl_
->Initialize(
118 base::Bind(&CallbackHelper::OnInitialize
,
119 base::Unretained(&callbacks_
)),
120 base::Bind(&CallbackHelper::OnUpdateStatistics
,
121 base::Unretained(&callbacks_
)),
122 base::Bind(&CallbackHelper::OnBufferingStateChange
,
123 base::Unretained(&callbacks_
)),
124 base::Bind(&CallbackHelper::OnEnded
, base::Unretained(&callbacks_
)),
125 base::Bind(&CallbackHelper::OnError
, base::Unretained(&callbacks_
)),
126 base::Bind(&CallbackHelper::OnWaitingForDecryptionKey
,
127 base::Unretained(&callbacks_
)));
128 base::RunLoop().RunUntilIdle();
131 void CreateAudioStream() {
132 audio_stream_
= CreateStream(DemuxerStream::AUDIO
);
133 streams_
.push_back(audio_stream_
.get());
134 EXPECT_CALL(*demuxer_
, GetStream(DemuxerStream::AUDIO
))
135 .WillRepeatedly(Return(audio_stream_
.get()));
138 void CreateVideoStream() {
139 video_stream_
= CreateStream(DemuxerStream::VIDEO
);
140 video_stream_
->set_video_decoder_config(video_decoder_config_
);
141 streams_
.push_back(video_stream_
.get());
142 EXPECT_CALL(*demuxer_
, GetStream(DemuxerStream::VIDEO
))
143 .WillRepeatedly(Return(video_stream_
.get()));
146 void CreateAudioAndVideoStream() {
151 void InitializeWithAudio() {
153 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
154 InitializeAndExpect(PIPELINE_OK
);
157 void InitializeWithVideo() {
159 SetVideoRendererInitializeExpectations(PIPELINE_OK
);
160 InitializeAndExpect(PIPELINE_OK
);
163 void InitializeWithAudioAndVideo() {
164 CreateAudioAndVideoStream();
165 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
166 SetVideoRendererInitializeExpectations(PIPELINE_OK
);
167 InitializeAndExpect(PIPELINE_OK
);
171 DCHECK(audio_stream_
|| video_stream_
);
172 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH
));
174 base::TimeDelta
start_time(
175 base::TimeDelta::FromMilliseconds(kStartPlayingTimeInMs
));
176 EXPECT_CALL(time_source_
, SetMediaTime(start_time
));
177 EXPECT_CALL(time_source_
, StartTicking());
180 EXPECT_CALL(*audio_renderer_
, StartPlaying())
181 .WillOnce(SetBufferingState(&audio_buffering_state_cb_
,
182 BUFFERING_HAVE_ENOUGH
));
186 EXPECT_CALL(*video_renderer_
, StartPlayingFrom(start_time
))
187 .WillOnce(SetBufferingState(&video_buffering_state_cb_
,
188 BUFFERING_HAVE_ENOUGH
));
191 renderer_impl_
->StartPlayingFrom(start_time
);
192 base::RunLoop().RunUntilIdle();
195 void Flush(bool underflowed
) {
197 EXPECT_CALL(time_source_
, StopTicking());
200 EXPECT_CALL(*audio_renderer_
, Flush(_
))
201 .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_
,
202 BUFFERING_HAVE_NOTHING
),
207 EXPECT_CALL(*video_renderer_
, Flush(_
))
208 .WillOnce(DoAll(SetBufferingState(&video_buffering_state_cb_
,
209 BUFFERING_HAVE_NOTHING
),
213 EXPECT_CALL(callbacks_
, OnFlushed());
215 renderer_impl_
->Flush(
216 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
217 base::RunLoop().RunUntilIdle();
220 void SetPlaybackRate(double playback_rate
) {
221 EXPECT_CALL(time_source_
, SetPlaybackRate(playback_rate
));
222 renderer_impl_
->SetPlaybackRate(playback_rate
);
223 base::RunLoop().RunUntilIdle();
226 int64
GetMediaTimeMs() {
227 return renderer_impl_
->GetMediaTime().InMilliseconds();
230 bool IsMediaTimeAdvancing(double playback_rate
) {
231 int64 start_time_ms
= GetMediaTimeMs();
232 const int64 time_to_advance_ms
= 100;
234 test_tick_clock_
.Advance(
235 base::TimeDelta::FromMilliseconds(time_to_advance_ms
));
237 if (GetMediaTimeMs() == start_time_ms
+ time_to_advance_ms
* playback_rate
)
240 DCHECK_EQ(start_time_ms
, GetMediaTimeMs());
244 bool IsMediaTimeAdvancing() {
245 return IsMediaTimeAdvancing(1.0);
249 base::MessageLoop message_loop_
;
250 StrictMock
<CallbackHelper
> callbacks_
;
251 base::SimpleTestTickClock test_tick_clock_
;
253 scoped_ptr
<StrictMock
<MockDemuxer
> > demuxer_
;
254 StrictMock
<MockVideoRenderer
>* video_renderer_
;
255 StrictMock
<MockAudioRenderer
>* audio_renderer_
;
256 scoped_ptr
<RendererImpl
> renderer_impl_
;
258 StrictMock
<MockTimeSource
> time_source_
;
259 scoped_ptr
<StrictMock
<MockDemuxerStream
> > audio_stream_
;
260 scoped_ptr
<StrictMock
<MockDemuxerStream
> > video_stream_
;
261 MockDemuxerStreamVector streams_
;
262 BufferingStateCB audio_buffering_state_cb_
;
263 BufferingStateCB video_buffering_state_cb_
;
264 base::Closure audio_ended_cb_
;
265 base::Closure video_ended_cb_
;
266 PipelineStatusCB audio_error_cb_
;
267 VideoDecoderConfig video_decoder_config_
;
270 DISALLOW_COPY_AND_ASSIGN(RendererImplTest
);
273 TEST_F(RendererImplTest
, DestroyBeforeInitialize
) {
274 // |renderer_impl_| will be destroyed in the dtor.
277 TEST_F(RendererImplTest
, InitializeWithAudio
) {
278 InitializeWithAudio();
281 TEST_F(RendererImplTest
, InitializeWithVideo
) {
282 InitializeWithVideo();
285 TEST_F(RendererImplTest
, InitializeWithAudioVideo
) {
286 InitializeWithAudioAndVideo();
289 TEST_F(RendererImplTest
, InitializeWithAudio_Failed
) {
291 SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
292 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
295 TEST_F(RendererImplTest
, InitializeWithVideo_Failed
) {
297 SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
298 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
301 TEST_F(RendererImplTest
, InitializeWithAudioVideo_AudioRendererFailed
) {
302 CreateAudioAndVideoStream();
303 SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
304 // VideoRenderer::Initialize() should not be called.
305 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
308 TEST_F(RendererImplTest
, InitializeWithAudioVideo_VideoRendererFailed
) {
309 CreateAudioAndVideoStream();
310 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
311 SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
312 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
315 TEST_F(RendererImplTest
, StartPlayingFrom
) {
316 InitializeWithAudioAndVideo();
320 TEST_F(RendererImplTest
, StartPlayingFromWithPlaybackRate
) {
321 InitializeWithAudioAndVideo();
323 // Play with a zero playback rate shouldn't start time.
325 Mock::VerifyAndClearExpectations(video_renderer_
);
327 // Positive playback rate when ticking should start time.
328 EXPECT_CALL(*video_renderer_
, OnTimeStateChanged(true));
329 SetPlaybackRate(1.0);
330 Mock::VerifyAndClearExpectations(video_renderer_
);
332 // Double notifications shouldn't be sent.
333 SetPlaybackRate(1.0);
334 Mock::VerifyAndClearExpectations(video_renderer_
);
336 // Zero playback rate should stop time.
337 EXPECT_CALL(*video_renderer_
, OnTimeStateChanged(false));
338 SetPlaybackRate(0.0);
339 Mock::VerifyAndClearExpectations(video_renderer_
);
341 // Double notifications shouldn't be sent.
342 SetPlaybackRate(0.0);
343 Mock::VerifyAndClearExpectations(video_renderer_
);
345 // Starting playback and flushing should cause time to stop.
346 EXPECT_CALL(*video_renderer_
, OnTimeStateChanged(true));
347 EXPECT_CALL(*video_renderer_
, OnTimeStateChanged(false));
348 SetPlaybackRate(1.0);
351 // A positive playback rate when playback isn't started should do nothing.
352 SetPlaybackRate(1.0);
355 TEST_F(RendererImplTest
, FlushAfterInitialization
) {
356 InitializeWithAudioAndVideo();
360 TEST_F(RendererImplTest
, FlushAfterPlay
) {
361 InitializeWithAudioAndVideo();
366 TEST_F(RendererImplTest
, FlushAfterUnderflow
) {
367 InitializeWithAudioAndVideo();
370 // Simulate underflow.
371 EXPECT_CALL(time_source_
, StopTicking());
372 audio_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
374 // Flush while underflowed. We shouldn't call StopTicking() again.
378 TEST_F(RendererImplTest
, SetPlaybackRate
) {
379 InitializeWithAudioAndVideo();
380 SetPlaybackRate(1.0);
381 SetPlaybackRate(2.0);
384 TEST_F(RendererImplTest
, SetVolume
) {
385 InitializeWithAudioAndVideo();
386 EXPECT_CALL(*audio_renderer_
, SetVolume(2.0f
));
387 renderer_impl_
->SetVolume(2.0f
);
390 TEST_F(RendererImplTest
, AudioStreamEnded
) {
391 InitializeWithAudio();
394 EXPECT_CALL(time_source_
, StopTicking());
395 EXPECT_CALL(callbacks_
, OnEnded());
397 audio_ended_cb_
.Run();
398 base::RunLoop().RunUntilIdle();
401 TEST_F(RendererImplTest
, VideoStreamEnded
) {
402 InitializeWithVideo();
405 EXPECT_CALL(time_source_
, StopTicking());
406 EXPECT_CALL(callbacks_
, OnEnded());
408 video_ended_cb_
.Run();
409 base::RunLoop().RunUntilIdle();
412 TEST_F(RendererImplTest
, AudioVideoStreamsEnded
) {
413 InitializeWithAudioAndVideo();
416 // OnEnded() is called only when all streams have finished.
417 audio_ended_cb_
.Run();
418 base::RunLoop().RunUntilIdle();
420 EXPECT_CALL(time_source_
, StopTicking());
421 EXPECT_CALL(callbacks_
, OnEnded());
423 video_ended_cb_
.Run();
424 base::RunLoop().RunUntilIdle();
427 TEST_F(RendererImplTest
, ErrorAfterInitialize
) {
428 InitializeWithAudio();
429 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
430 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
431 base::RunLoop().RunUntilIdle();
434 TEST_F(RendererImplTest
, ErrorDuringPlaying
) {
435 InitializeWithAudio();
438 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
439 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
440 base::RunLoop().RunUntilIdle();
443 TEST_F(RendererImplTest
, ErrorDuringFlush
) {
444 InitializeWithAudio();
448 EXPECT_CALL(time_source_
, StopTicking());
449 EXPECT_CALL(*audio_renderer_
, Flush(_
)).WillOnce(DoAll(
450 AudioError(&audio_error_cb_
, PIPELINE_ERROR_DECODE
),
452 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
453 EXPECT_CALL(callbacks_
, OnFlushed());
454 renderer_impl_
->Flush(
455 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
456 base::RunLoop().RunUntilIdle();
459 TEST_F(RendererImplTest
, ErrorAfterFlush
) {
460 InitializeWithAudio();
464 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
465 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
466 base::RunLoop().RunUntilIdle();
469 TEST_F(RendererImplTest
, ErrorDuringInitialize
) {
470 CreateAudioAndVideoStream();
471 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
473 // Force an audio error to occur during video renderer initialization.
474 EXPECT_CALL(*video_renderer_
,
475 Initialize(video_stream_
.get(), _
, _
, _
, _
, _
, _
, _
, _
))
476 .WillOnce(DoAll(AudioError(&audio_error_cb_
, PIPELINE_ERROR_DECODE
),
477 SaveArg
<4>(&video_buffering_state_cb_
),
478 SaveArg
<5>(&video_ended_cb_
),
479 RunCallback
<1>(PIPELINE_OK
)));
481 InitializeAndExpect(PIPELINE_ERROR_DECODE
);
484 TEST_F(RendererImplTest
, AudioUnderflow
) {
485 InitializeWithAudio();
488 // Underflow should occur immediately with a single audio track.
489 EXPECT_CALL(time_source_
, StopTicking());
490 audio_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
493 TEST_F(RendererImplTest
, AudioUnderflowWithVideo
) {
494 InitializeWithAudioAndVideo();
497 // Underflow should be immediate when both audio and video are present and
499 EXPECT_CALL(time_source_
, StopTicking());
500 audio_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
503 TEST_F(RendererImplTest
, VideoUnderflow
) {
504 InitializeWithVideo();
507 // Underflow should occur immediately with a single video track.
508 EXPECT_CALL(time_source_
, StopTicking());
509 video_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
512 TEST_F(RendererImplTest
, VideoUnderflowWithAudio
) {
513 InitializeWithAudioAndVideo();
516 // Set a zero threshold such that the underflow will be executed on the next
517 // run of the message loop.
518 renderer_impl_
->set_video_underflow_threshold_for_testing(base::TimeDelta());
520 // Underflow should be delayed when both audio and video are present and video
522 video_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
523 Mock::VerifyAndClearExpectations(&time_source_
);
525 EXPECT_CALL(time_source_
, StopTicking());
526 base::RunLoop().RunUntilIdle();
529 TEST_F(RendererImplTest
, VideoUnderflowWithAudioVideoRecovers
) {
530 InitializeWithAudioAndVideo();
533 // Set a zero threshold such that the underflow will be executed on the next
534 // run of the message loop.
535 renderer_impl_
->set_video_underflow_threshold_for_testing(base::TimeDelta());
537 // Underflow should be delayed when both audio and video are present and video
539 video_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
540 Mock::VerifyAndClearExpectations(&time_source_
);
542 // If video recovers, the underflow should never occur.
543 video_buffering_state_cb_
.Run(BUFFERING_HAVE_ENOUGH
);
544 base::RunLoop().RunUntilIdle();
547 TEST_F(RendererImplTest
, VideoAndAudioUnderflow
) {
548 InitializeWithAudioAndVideo();
551 // Set a zero threshold such that the underflow will be executed on the next
552 // run of the message loop.
553 renderer_impl_
->set_video_underflow_threshold_for_testing(base::TimeDelta());
555 // Underflow should be delayed when both audio and video are present and video
557 video_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
558 Mock::VerifyAndClearExpectations(&time_source_
);
560 EXPECT_CALL(time_source_
, StopTicking());
561 audio_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
563 // Nothing else should primed on the message loop.
564 base::RunLoop().RunUntilIdle();
567 TEST_F(RendererImplTest
, VideoUnderflowWithAudioFlush
) {
568 InitializeWithAudioAndVideo();
571 // Set a massive threshold such that it shouldn't fire within this test.
572 renderer_impl_
->set_video_underflow_threshold_for_testing(
573 base::TimeDelta::FromSeconds(100));
575 // Simulate the cases where audio underflows and then video underflows.
576 EXPECT_CALL(time_source_
, StopTicking());
577 audio_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
578 video_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
579 Mock::VerifyAndClearExpectations(&time_source_
);
581 // Flush the audio and video renderers, both think they're in an underflow
582 // state, but if the video renderer underflow was deferred, RendererImpl would
583 // think it still has enough data.
584 EXPECT_CALL(*audio_renderer_
, Flush(_
)).WillOnce(RunClosure
<0>());
585 EXPECT_CALL(*video_renderer_
, Flush(_
)).WillOnce(RunClosure
<0>());
586 EXPECT_CALL(callbacks_
, OnFlushed());
587 renderer_impl_
->Flush(
588 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
589 base::RunLoop().RunUntilIdle();
591 // Start playback after the flush, but never return BUFFERING_HAVE_ENOUGH from
592 // the video renderer (which simulates spool up time for the video renderer).
593 const base::TimeDelta kStartTime
;
594 EXPECT_CALL(time_source_
, SetMediaTime(kStartTime
));
595 EXPECT_CALL(*audio_renderer_
, StartPlaying())
597 SetBufferingState(&audio_buffering_state_cb_
, BUFFERING_HAVE_ENOUGH
));
598 EXPECT_CALL(*video_renderer_
, StartPlayingFrom(kStartTime
));
599 renderer_impl_
->StartPlayingFrom(kStartTime
);
601 // Nothing else should primed on the message loop.
602 base::RunLoop().RunUntilIdle();