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/base/time_delta_interpolator.h"
15 #include "media/filters/renderer_impl.h"
16 #include "testing/gtest/include/gtest/gtest.h"
19 using ::testing::DoAll
;
20 using ::testing::InSequence
;
21 using ::testing::Mock
;
22 using ::testing::Return
;
23 using ::testing::SaveArg
;
24 using ::testing::StrictMock
;
28 const int64 kStartPlayingTimeInMs
= 100;
29 const int64 kDurationInMs
= 3000;
30 const int64 kAudioUpdateTimeMs
= 150;
31 const int64 kAudioUpdateMaxTimeMs
= 1000;
33 ACTION_P2(SetBufferingState
, cb
, buffering_state
) {
34 cb
->Run(buffering_state
);
37 ACTION_P3(UpdateAudioTime
, cb
, time
, max_time
) {
38 cb
->Run(base::TimeDelta::FromMilliseconds(time
),
39 base::TimeDelta::FromMilliseconds(max_time
));
42 ACTION_P2(AudioError
, cb
, error
) {
46 static base::TimeDelta
GetDuration() {
47 return base::TimeDelta::FromMilliseconds(kDurationInMs
);
50 class RendererImplTest
: public ::testing::Test
{
52 // Used for setting expectations on pipeline callbacks. Using a StrictMock
53 // also lets us test for missing callbacks.
54 class CallbackHelper
{
57 virtual ~CallbackHelper() {}
59 MOCK_METHOD1(OnInitialize
, void(PipelineStatus
));
60 MOCK_METHOD0(OnFlushed
, void());
61 MOCK_METHOD0(OnEnded
, void());
62 MOCK_METHOD1(OnError
, void(PipelineStatus
));
63 MOCK_METHOD1(OnUpdateStatistics
, void(const PipelineStatistics
&));
64 MOCK_METHOD1(OnBufferingStateChange
, void(BufferingState
));
67 DISALLOW_COPY_AND_ASSIGN(CallbackHelper
);
71 : demuxer_(new StrictMock
<MockDemuxer
>()),
72 video_renderer_(new StrictMock
<MockVideoRenderer
>()),
73 audio_renderer_(new StrictMock
<MockAudioRenderer
>()),
75 new RendererImpl(message_loop_
.message_loop_proxy(),
77 scoped_ptr
<AudioRenderer
>(audio_renderer_
),
78 scoped_ptr
<VideoRenderer
>(video_renderer_
))) {
79 // SetDemuxerExpectations() adds overriding expectations for expected
81 DemuxerStream
* null_pointer
= NULL
;
82 EXPECT_CALL(*demuxer_
, GetStream(_
))
83 .WillRepeatedly(Return(null_pointer
));
84 EXPECT_CALL(*demuxer_
, GetLiveness())
85 .WillRepeatedly(Return(Demuxer::LIVENESS_UNKNOWN
));
88 virtual ~RendererImplTest() {
89 renderer_impl_
.reset();
90 base::RunLoop().RunUntilIdle();
94 typedef std::vector
<MockDemuxerStream
*> MockDemuxerStreamVector
;
96 scoped_ptr
<StrictMock
<MockDemuxerStream
> > CreateStream(
97 DemuxerStream::Type type
) {
98 scoped_ptr
<StrictMock
<MockDemuxerStream
> > stream(
99 new StrictMock
<MockDemuxerStream
>(type
));
100 return stream
.Pass();
103 // Sets up expectations to allow the audio renderer to initialize.
104 void SetAudioRendererInitializeExpectations(PipelineStatus status
) {
105 EXPECT_CALL(*audio_renderer_
,
106 Initialize(audio_stream_
.get(), _
, _
, _
, _
, _
, _
))
107 .WillOnce(DoAll(SaveArg
<3>(&audio_time_cb_
),
108 SaveArg
<4>(&audio_buffering_state_cb_
),
109 SaveArg
<5>(&audio_ended_cb_
),
110 SaveArg
<6>(&audio_error_cb_
),
111 RunCallback
<1>(status
)));
112 if (status
== PIPELINE_OK
) {
113 EXPECT_CALL(*audio_renderer_
, GetTimeSource())
114 .WillOnce(Return(&time_source_
));
118 // Sets up expectations to allow the video renderer to initialize.
119 void SetVideoRendererInitializeExpectations(PipelineStatus status
) {
120 EXPECT_CALL(*video_renderer_
,
121 Initialize(video_stream_
.get(), _
, _
, _
, _
, _
, _
, _
, _
, _
))
122 .WillOnce(DoAll(SaveArg
<5>(&video_buffering_state_cb_
),
123 SaveArg
<6>(&video_ended_cb_
),
124 RunCallback
<2>(status
)));
127 void InitializeAndExpect(PipelineStatus start_status
) {
128 EXPECT_CALL(callbacks_
, OnInitialize(start_status
));
130 renderer_impl_
->Initialize(
131 base::Bind(&CallbackHelper::OnInitialize
,
132 base::Unretained(&callbacks_
)),
133 base::Bind(&CallbackHelper::OnUpdateStatistics
,
134 base::Unretained(&callbacks_
)),
135 base::Bind(&CallbackHelper::OnEnded
, base::Unretained(&callbacks_
)),
136 base::Bind(&CallbackHelper::OnError
, base::Unretained(&callbacks_
)),
137 base::Bind(&CallbackHelper::OnBufferingStateChange
,
138 base::Unretained(&callbacks_
)),
139 base::Bind(&GetDuration
));
140 base::RunLoop().RunUntilIdle();
143 void CreateAudioStream() {
144 audio_stream_
= CreateStream(DemuxerStream::AUDIO
);
145 streams_
.push_back(audio_stream_
.get());
146 EXPECT_CALL(*demuxer_
, GetStream(DemuxerStream::AUDIO
))
147 .WillRepeatedly(Return(audio_stream_
.get()));
150 void CreateVideoStream() {
151 video_stream_
= CreateStream(DemuxerStream::VIDEO
);
152 video_stream_
->set_video_decoder_config(video_decoder_config_
);
153 streams_
.push_back(video_stream_
.get());
154 EXPECT_CALL(*demuxer_
, GetStream(DemuxerStream::VIDEO
))
155 .WillRepeatedly(Return(video_stream_
.get()));
158 void CreateAudioAndVideoStream() {
163 void InitializeWithAudio() {
165 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
166 InitializeAndExpect(PIPELINE_OK
);
169 void InitializeWithVideo() {
171 SetVideoRendererInitializeExpectations(PIPELINE_OK
);
172 InitializeAndExpect(PIPELINE_OK
);
175 void InitializeWithAudioAndVideo() {
176 CreateAudioAndVideoStream();
177 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
178 SetVideoRendererInitializeExpectations(PIPELINE_OK
);
179 InitializeAndExpect(PIPELINE_OK
);
183 DCHECK(audio_stream_
|| video_stream_
);
184 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH
));
187 EXPECT_CALL(time_source_
,
188 SetMediaTime(base::TimeDelta::FromMilliseconds(
189 kStartPlayingTimeInMs
)));
190 EXPECT_CALL(time_source_
, StartTicking());
191 EXPECT_CALL(*audio_renderer_
, StartPlaying())
192 .WillOnce(SetBufferingState(&audio_buffering_state_cb_
,
193 BUFFERING_HAVE_ENOUGH
));
197 EXPECT_CALL(*video_renderer_
, StartPlaying())
198 .WillOnce(SetBufferingState(&video_buffering_state_cb_
,
199 BUFFERING_HAVE_ENOUGH
));
202 renderer_impl_
->StartPlayingFrom(
203 base::TimeDelta::FromMilliseconds(kStartPlayingTimeInMs
));
204 base::RunLoop().RunUntilIdle();
207 void Flush(bool underflowed
) {
210 EXPECT_CALL(time_source_
, StopTicking());
211 EXPECT_CALL(*audio_renderer_
, Flush(_
))
212 .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_
,
213 BUFFERING_HAVE_NOTHING
),
218 EXPECT_CALL(*video_renderer_
, Flush(_
))
219 .WillOnce(DoAll(SetBufferingState(&video_buffering_state_cb_
,
220 BUFFERING_HAVE_NOTHING
),
224 EXPECT_CALL(callbacks_
, OnFlushed());
226 renderer_impl_
->Flush(
227 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
228 base::RunLoop().RunUntilIdle();
231 void SetPlaybackRate(float playback_rate
) {
232 EXPECT_CALL(time_source_
, SetPlaybackRate(playback_rate
));
233 renderer_impl_
->SetPlaybackRate(playback_rate
);
234 base::RunLoop().RunUntilIdle();
237 int64
GetMediaTimeMs() {
238 return renderer_impl_
->GetMediaTime().InMilliseconds();
241 bool IsMediaTimeAdvancing(float playback_rate
) {
242 int64 start_time_ms
= GetMediaTimeMs();
243 const int64 time_to_advance_ms
= 100;
245 test_tick_clock_
.Advance(
246 base::TimeDelta::FromMilliseconds(time_to_advance_ms
));
248 if (GetMediaTimeMs() == start_time_ms
+ time_to_advance_ms
* playback_rate
)
251 DCHECK_EQ(start_time_ms
, GetMediaTimeMs());
255 bool IsMediaTimeAdvancing() {
256 return IsMediaTimeAdvancing(1.0f
);
260 base::MessageLoop message_loop_
;
261 StrictMock
<CallbackHelper
> callbacks_
;
262 base::SimpleTestTickClock test_tick_clock_
;
264 scoped_ptr
<StrictMock
<MockDemuxer
> > demuxer_
;
265 StrictMock
<MockVideoRenderer
>* video_renderer_
;
266 StrictMock
<MockAudioRenderer
>* audio_renderer_
;
267 scoped_ptr
<RendererImpl
> renderer_impl_
;
269 StrictMock
<MockTimeSource
> time_source_
;
270 scoped_ptr
<StrictMock
<MockDemuxerStream
> > audio_stream_
;
271 scoped_ptr
<StrictMock
<MockDemuxerStream
> > video_stream_
;
272 MockDemuxerStreamVector streams_
;
273 AudioRenderer::TimeCB audio_time_cb_
;
274 BufferingStateCB audio_buffering_state_cb_
;
275 BufferingStateCB video_buffering_state_cb_
;
276 base::Closure audio_ended_cb_
;
277 base::Closure video_ended_cb_
;
278 PipelineStatusCB audio_error_cb_
;
279 VideoDecoderConfig video_decoder_config_
;
282 DISALLOW_COPY_AND_ASSIGN(RendererImplTest
);
285 TEST_F(RendererImplTest
, DestroyBeforeInitialize
) {
286 // |renderer_impl_| will be destroyed in the dtor.
289 TEST_F(RendererImplTest
, InitializeWithAudio
) {
290 InitializeWithAudio();
293 TEST_F(RendererImplTest
, InitializeWithVideo
) {
294 InitializeWithVideo();
297 TEST_F(RendererImplTest
, InitializeWithAudioVideo
) {
298 InitializeWithAudioAndVideo();
301 TEST_F(RendererImplTest
, InitializeWithAudio_Failed
) {
303 SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
304 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
307 TEST_F(RendererImplTest
, InitializeWithVideo_Failed
) {
309 SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
310 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
313 TEST_F(RendererImplTest
, InitializeWithAudioVideo_AudioRendererFailed
) {
314 CreateAudioAndVideoStream();
315 SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
316 // VideoRenderer::Initialize() should not be called.
317 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
320 TEST_F(RendererImplTest
, InitializeWithAudioVideo_VideoRendererFailed
) {
321 CreateAudioAndVideoStream();
322 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
323 SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
324 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
327 TEST_F(RendererImplTest
, StartPlayingFrom
) {
328 InitializeWithAudioAndVideo();
332 TEST_F(RendererImplTest
, FlushAfterInitialization
) {
333 InitializeWithAudioAndVideo();
337 TEST_F(RendererImplTest
, FlushAfterPlay
) {
338 InitializeWithAudioAndVideo();
343 TEST_F(RendererImplTest
, FlushAfterUnderflow
) {
344 InitializeWithAudioAndVideo();
347 // Simulate underflow.
348 EXPECT_CALL(time_source_
, StopTicking());
349 audio_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
351 // Flush while underflowed. We shouldn't call StopTicking() again.
355 TEST_F(RendererImplTest
, SetPlaybackRate
) {
356 InitializeWithAudioAndVideo();
357 SetPlaybackRate(1.0f
);
358 SetPlaybackRate(2.0f
);
361 TEST_F(RendererImplTest
, SetVolume
) {
362 InitializeWithAudioAndVideo();
363 EXPECT_CALL(*audio_renderer_
, SetVolume(2.0f
));
364 renderer_impl_
->SetVolume(2.0f
);
367 TEST_F(RendererImplTest
, GetMediaTime
) {
368 // Replace what's used for interpolating to simulate wall clock time.
369 renderer_impl_
->SetTimeDeltaInterpolatorForTesting(
370 new TimeDeltaInterpolator(&test_tick_clock_
));
372 InitializeWithAudioAndVideo();
375 EXPECT_EQ(kStartPlayingTimeInMs
, GetMediaTimeMs());
377 // Verify that the clock doesn't advance since it hasn't been started by
378 // a time update from the audio stream.
379 EXPECT_FALSE(IsMediaTimeAdvancing());
381 // Provide an initial time update so that the pipeline transitions out of the
382 // "waiting for time update" state.
383 audio_time_cb_
.Run(base::TimeDelta::FromMilliseconds(kAudioUpdateTimeMs
),
384 base::TimeDelta::FromMilliseconds(kAudioUpdateMaxTimeMs
));
385 EXPECT_EQ(kAudioUpdateTimeMs
, GetMediaTimeMs());
387 // Advance the clock so that GetMediaTime() also advances. This also verifies
388 // that the default playback rate is 1.
389 EXPECT_TRUE(IsMediaTimeAdvancing());
391 // Verify that playback rate affects the rate GetMediaTime() advances.
392 SetPlaybackRate(2.0f
);
393 EXPECT_TRUE(IsMediaTimeAdvancing(2.0f
));
395 // Verify that GetMediaTime() is bounded by audio max time.
396 DCHECK_GT(GetMediaTimeMs() + 2000, kAudioUpdateMaxTimeMs
);
397 test_tick_clock_
.Advance(base::TimeDelta::FromMilliseconds(2000));
398 EXPECT_EQ(kAudioUpdateMaxTimeMs
, GetMediaTimeMs());
401 TEST_F(RendererImplTest
, AudioStreamShorterThanVideo
) {
402 // Replace what's used for interpolating to simulate wall clock time.
403 renderer_impl_
->SetTimeDeltaInterpolatorForTesting(
404 new TimeDeltaInterpolator(&test_tick_clock_
));
406 InitializeWithAudioAndVideo();
409 EXPECT_EQ(kStartPlayingTimeInMs
, GetMediaTimeMs());
411 // Verify that the clock doesn't advance since it hasn't been started by
412 // a time update from the audio stream.
413 EXPECT_FALSE(IsMediaTimeAdvancing());
415 // Signal end of audio stream.
416 audio_ended_cb_
.Run();
417 base::RunLoop().RunUntilIdle();
419 // Verify that the clock advances.
420 EXPECT_TRUE(IsMediaTimeAdvancing());
422 // Signal end of video stream and make sure OnEnded() callback occurs.
423 EXPECT_CALL(time_source_
, StopTicking());
424 EXPECT_CALL(callbacks_
, OnEnded());
425 video_ended_cb_
.Run();
426 base::RunLoop().RunUntilIdle();
429 TEST_F(RendererImplTest
, AudioTimeUpdateDuringFlush
) {
430 // Replace what's used for interpolating to simulate wall clock time.
431 renderer_impl_
->SetTimeDeltaInterpolatorForTesting(
432 new TimeDeltaInterpolator(&test_tick_clock_
));
434 InitializeWithAudio();
437 // Provide an initial time update so that the pipeline transitions out of the
438 // "waiting for time update" state.
439 audio_time_cb_
.Run(base::TimeDelta::FromMilliseconds(kAudioUpdateTimeMs
),
440 base::TimeDelta::FromMilliseconds(kAudioUpdateMaxTimeMs
));
441 EXPECT_EQ(kAudioUpdateTimeMs
, GetMediaTimeMs());
443 int64 start_time
= GetMediaTimeMs();
445 EXPECT_CALL(*audio_renderer_
, Flush(_
)).WillOnce(DoAll(
447 &audio_time_cb_
, kAudioUpdateTimeMs
+ 100, kAudioUpdateMaxTimeMs
),
448 SetBufferingState(&audio_buffering_state_cb_
, BUFFERING_HAVE_NOTHING
),
450 EXPECT_CALL(time_source_
, StopTicking());
451 EXPECT_CALL(callbacks_
, OnFlushed());
452 renderer_impl_
->Flush(
453 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
455 // Audio time update during Flush() has no effect.
456 EXPECT_EQ(start_time
, GetMediaTimeMs());
458 // Verify that the clock doesn't advance since it hasn't been started by
459 // a time update from the audio stream.
460 EXPECT_FALSE(IsMediaTimeAdvancing());
463 TEST_F(RendererImplTest
, PostTimeUpdateDuringDestroy
) {
464 InitializeWithAudioAndVideo();
466 // Simulate the case where TimeCB is posted during ~AudioRenderer(), which is
467 // triggered in ~Renderer().
468 base::TimeDelta time
= base::TimeDelta::FromMilliseconds(100);
469 message_loop_
.PostTask(FROM_HERE
, base::Bind(audio_time_cb_
, time
, time
));
471 renderer_impl_
.reset();
472 message_loop_
.RunUntilIdle();
475 TEST_F(RendererImplTest
, AudioStreamEnded
) {
476 InitializeWithAudio();
479 EXPECT_CALL(time_source_
, StopTicking());
480 EXPECT_CALL(callbacks_
, OnEnded());
482 audio_ended_cb_
.Run();
483 base::RunLoop().RunUntilIdle();
486 TEST_F(RendererImplTest
, VideoStreamEnded
) {
487 InitializeWithVideo();
490 // Video ended won't affect |time_source_|.
491 EXPECT_CALL(callbacks_
, OnEnded());
493 video_ended_cb_
.Run();
494 base::RunLoop().RunUntilIdle();
497 TEST_F(RendererImplTest
, AudioVideoStreamsEnded
) {
498 InitializeWithAudioAndVideo();
501 // OnEnded() is called only when all streams have finished.
502 audio_ended_cb_
.Run();
503 base::RunLoop().RunUntilIdle();
505 EXPECT_CALL(time_source_
, StopTicking());
506 EXPECT_CALL(callbacks_
, OnEnded());
508 video_ended_cb_
.Run();
509 base::RunLoop().RunUntilIdle();
512 TEST_F(RendererImplTest
, ErrorAfterInitialize
) {
513 InitializeWithAudio();
514 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
515 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
516 base::RunLoop().RunUntilIdle();
519 TEST_F(RendererImplTest
, ErrorDuringPlaying
) {
520 InitializeWithAudio();
523 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
524 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
525 base::RunLoop().RunUntilIdle();
528 TEST_F(RendererImplTest
, ErrorDuringFlush
) {
529 InitializeWithAudio();
533 EXPECT_CALL(time_source_
, StopTicking());
534 EXPECT_CALL(*audio_renderer_
, Flush(_
)).WillOnce(DoAll(
535 AudioError(&audio_error_cb_
, PIPELINE_ERROR_DECODE
),
537 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
538 EXPECT_CALL(callbacks_
, OnFlushed());
539 renderer_impl_
->Flush(
540 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
541 base::RunLoop().RunUntilIdle();
544 TEST_F(RendererImplTest
, ErrorAfterFlush
) {
545 InitializeWithAudio();
549 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
550 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
551 base::RunLoop().RunUntilIdle();