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_METHOD1(OnVideoFramePaint
, void(const scoped_refptr
<VideoFrame
>&));
53 MOCK_METHOD0(OnWaitingForDecryptionKey
, void());
56 DISALLOW_COPY_AND_ASSIGN(CallbackHelper
);
60 : demuxer_(new StrictMock
<MockDemuxer
>()),
61 video_renderer_(new StrictMock
<MockVideoRenderer
>()),
62 audio_renderer_(new StrictMock
<MockAudioRenderer
>()),
64 new RendererImpl(message_loop_
.message_loop_proxy(),
65 scoped_ptr
<AudioRenderer
>(audio_renderer_
),
66 scoped_ptr
<VideoRenderer
>(video_renderer_
))) {
67 // SetDemuxerExpectations() adds overriding expectations for expected
69 DemuxerStream
* null_pointer
= NULL
;
70 EXPECT_CALL(*demuxer_
, GetStream(_
))
71 .WillRepeatedly(Return(null_pointer
));
74 virtual ~RendererImplTest() {
75 renderer_impl_
.reset();
76 base::RunLoop().RunUntilIdle();
80 typedef std::vector
<MockDemuxerStream
*> MockDemuxerStreamVector
;
82 scoped_ptr
<StrictMock
<MockDemuxerStream
> > CreateStream(
83 DemuxerStream::Type type
) {
84 scoped_ptr
<StrictMock
<MockDemuxerStream
> > stream(
85 new StrictMock
<MockDemuxerStream
>(type
));
89 // Sets up expectations to allow the audio renderer to initialize.
90 void SetAudioRendererInitializeExpectations(PipelineStatus status
) {
91 EXPECT_CALL(*audio_renderer_
,
92 Initialize(audio_stream_
.get(), _
, _
, _
, _
, _
, _
, _
))
93 .WillOnce(DoAll(SaveArg
<4>(&audio_buffering_state_cb_
),
94 SaveArg
<5>(&audio_ended_cb_
),
95 SaveArg
<6>(&audio_error_cb_
), RunCallback
<1>(status
)));
98 // Sets up expectations to allow the video renderer to initialize.
99 void SetVideoRendererInitializeExpectations(PipelineStatus status
) {
100 EXPECT_CALL(*video_renderer_
,
101 Initialize(video_stream_
.get(), _
, _
, _
, _
, _
, _
, _
, _
, _
))
102 .WillOnce(DoAll(SaveArg
<4>(&video_buffering_state_cb_
),
103 SaveArg
<6>(&video_ended_cb_
), RunCallback
<1>(status
)));
106 void InitializeAndExpect(PipelineStatus start_status
) {
107 EXPECT_CALL(callbacks_
, OnInitialize(start_status
));
108 EXPECT_CALL(callbacks_
, OnWaitingForDecryptionKey()).Times(0);
110 if (start_status
== PIPELINE_OK
&& audio_stream_
) {
111 EXPECT_CALL(*audio_renderer_
, GetTimeSource())
112 .WillOnce(Return(&time_source_
));
115 renderer_impl_
->Initialize(
117 base::Bind(&CallbackHelper::OnInitialize
,
118 base::Unretained(&callbacks_
)),
119 base::Bind(&CallbackHelper::OnUpdateStatistics
,
120 base::Unretained(&callbacks_
)),
121 base::Bind(&CallbackHelper::OnBufferingStateChange
,
122 base::Unretained(&callbacks_
)),
123 base::Bind(&CallbackHelper::OnVideoFramePaint
,
124 base::Unretained(&callbacks_
)),
125 base::Bind(&CallbackHelper::OnEnded
, base::Unretained(&callbacks_
)),
126 base::Bind(&CallbackHelper::OnError
, base::Unretained(&callbacks_
)),
127 base::Bind(&CallbackHelper::OnWaitingForDecryptionKey
,
128 base::Unretained(&callbacks_
)));
129 base::RunLoop().RunUntilIdle();
132 void CreateAudioStream() {
133 audio_stream_
= CreateStream(DemuxerStream::AUDIO
);
134 streams_
.push_back(audio_stream_
.get());
135 EXPECT_CALL(*demuxer_
, GetStream(DemuxerStream::AUDIO
))
136 .WillRepeatedly(Return(audio_stream_
.get()));
139 void CreateVideoStream() {
140 video_stream_
= CreateStream(DemuxerStream::VIDEO
);
141 video_stream_
->set_video_decoder_config(video_decoder_config_
);
142 streams_
.push_back(video_stream_
.get());
143 EXPECT_CALL(*demuxer_
, GetStream(DemuxerStream::VIDEO
))
144 .WillRepeatedly(Return(video_stream_
.get()));
147 void CreateAudioAndVideoStream() {
152 void InitializeWithAudio() {
154 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
155 InitializeAndExpect(PIPELINE_OK
);
158 void InitializeWithVideo() {
160 SetVideoRendererInitializeExpectations(PIPELINE_OK
);
161 InitializeAndExpect(PIPELINE_OK
);
164 void InitializeWithAudioAndVideo() {
165 CreateAudioAndVideoStream();
166 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
167 SetVideoRendererInitializeExpectations(PIPELINE_OK
);
168 InitializeAndExpect(PIPELINE_OK
);
172 DCHECK(audio_stream_
|| video_stream_
);
173 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH
));
175 base::TimeDelta
start_time(
176 base::TimeDelta::FromMilliseconds(kStartPlayingTimeInMs
));
179 EXPECT_CALL(time_source_
, SetMediaTime(start_time
));
180 EXPECT_CALL(time_source_
, StartTicking());
181 EXPECT_CALL(*audio_renderer_
, StartPlaying())
182 .WillOnce(SetBufferingState(&audio_buffering_state_cb_
,
183 BUFFERING_HAVE_ENOUGH
));
187 EXPECT_CALL(*video_renderer_
, StartPlayingFrom(start_time
))
188 .WillOnce(SetBufferingState(&video_buffering_state_cb_
,
189 BUFFERING_HAVE_ENOUGH
));
192 renderer_impl_
->StartPlayingFrom(start_time
);
193 base::RunLoop().RunUntilIdle();
196 void Flush(bool underflowed
) {
199 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(float 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(float 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.0f
);
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
, FlushAfterInitialization
) {
321 InitializeWithAudioAndVideo();
325 TEST_F(RendererImplTest
, FlushAfterPlay
) {
326 InitializeWithAudioAndVideo();
331 TEST_F(RendererImplTest
, FlushAfterUnderflow
) {
332 InitializeWithAudioAndVideo();
335 // Simulate underflow.
336 EXPECT_CALL(time_source_
, StopTicking());
337 audio_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
339 // Flush while underflowed. We shouldn't call StopTicking() again.
343 TEST_F(RendererImplTest
, SetPlaybackRate
) {
344 InitializeWithAudioAndVideo();
345 SetPlaybackRate(1.0f
);
346 SetPlaybackRate(2.0f
);
349 TEST_F(RendererImplTest
, SetVolume
) {
350 InitializeWithAudioAndVideo();
351 EXPECT_CALL(*audio_renderer_
, SetVolume(2.0f
));
352 renderer_impl_
->SetVolume(2.0f
);
355 TEST_F(RendererImplTest
, AudioStreamEnded
) {
356 InitializeWithAudio();
359 EXPECT_CALL(time_source_
, StopTicking());
360 EXPECT_CALL(callbacks_
, OnEnded());
362 audio_ended_cb_
.Run();
363 base::RunLoop().RunUntilIdle();
366 TEST_F(RendererImplTest
, VideoStreamEnded
) {
367 InitializeWithVideo();
370 // Video ended won't affect |time_source_|.
371 EXPECT_CALL(callbacks_
, OnEnded());
373 video_ended_cb_
.Run();
374 base::RunLoop().RunUntilIdle();
377 TEST_F(RendererImplTest
, AudioVideoStreamsEnded
) {
378 InitializeWithAudioAndVideo();
381 // OnEnded() is called only when all streams have finished.
382 audio_ended_cb_
.Run();
383 base::RunLoop().RunUntilIdle();
385 EXPECT_CALL(time_source_
, StopTicking());
386 EXPECT_CALL(callbacks_
, OnEnded());
388 video_ended_cb_
.Run();
389 base::RunLoop().RunUntilIdle();
392 TEST_F(RendererImplTest
, ErrorAfterInitialize
) {
393 InitializeWithAudio();
394 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
395 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
396 base::RunLoop().RunUntilIdle();
399 TEST_F(RendererImplTest
, ErrorDuringPlaying
) {
400 InitializeWithAudio();
403 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
404 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
405 base::RunLoop().RunUntilIdle();
408 TEST_F(RendererImplTest
, ErrorDuringFlush
) {
409 InitializeWithAudio();
413 EXPECT_CALL(time_source_
, StopTicking());
414 EXPECT_CALL(*audio_renderer_
, Flush(_
)).WillOnce(DoAll(
415 AudioError(&audio_error_cb_
, PIPELINE_ERROR_DECODE
),
417 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
418 EXPECT_CALL(callbacks_
, OnFlushed());
419 renderer_impl_
->Flush(
420 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
421 base::RunLoop().RunUntilIdle();
424 TEST_F(RendererImplTest
, ErrorAfterFlush
) {
425 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
, ErrorDuringInitialize
) {
435 CreateAudioAndVideoStream();
436 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
438 // Force an audio error to occur during video renderer initialization.
439 EXPECT_CALL(*video_renderer_
,
440 Initialize(video_stream_
.get(), _
, _
, _
, _
, _
, _
, _
, _
, _
))
441 .WillOnce(DoAll(AudioError(&audio_error_cb_
, PIPELINE_ERROR_DECODE
),
442 SaveArg
<4>(&video_buffering_state_cb_
),
443 SaveArg
<6>(&video_ended_cb_
),
444 RunCallback
<1>(PIPELINE_OK
)));
446 InitializeAndExpect(PIPELINE_ERROR_DECODE
);