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/filters/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
>&));
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_
.message_loop_proxy(),
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
<6>(&video_ended_cb_
), RunCallback
<1>(status
)));
105 void InitializeAndExpect(PipelineStatus start_status
) {
106 EXPECT_CALL(callbacks_
, OnInitialize(start_status
));
108 if (start_status
== PIPELINE_OK
&& audio_stream_
) {
109 EXPECT_CALL(*audio_renderer_
, GetTimeSource())
110 .WillOnce(Return(&time_source_
));
113 renderer_impl_
->Initialize(
115 base::Bind(&CallbackHelper::OnInitialize
,
116 base::Unretained(&callbacks_
)),
117 base::Bind(&CallbackHelper::OnUpdateStatistics
,
118 base::Unretained(&callbacks_
)),
119 base::Bind(&CallbackHelper::OnBufferingStateChange
,
120 base::Unretained(&callbacks_
)),
121 base::Bind(&CallbackHelper::OnVideoFramePaint
,
122 base::Unretained(&callbacks_
)),
123 base::Bind(&CallbackHelper::OnEnded
, base::Unretained(&callbacks_
)),
124 base::Bind(&CallbackHelper::OnError
, base::Unretained(&callbacks_
)));
125 base::RunLoop().RunUntilIdle();
128 void CreateAudioStream() {
129 audio_stream_
= CreateStream(DemuxerStream::AUDIO
);
130 streams_
.push_back(audio_stream_
.get());
131 EXPECT_CALL(*demuxer_
, GetStream(DemuxerStream::AUDIO
))
132 .WillRepeatedly(Return(audio_stream_
.get()));
135 void CreateVideoStream() {
136 video_stream_
= CreateStream(DemuxerStream::VIDEO
);
137 video_stream_
->set_video_decoder_config(video_decoder_config_
);
138 streams_
.push_back(video_stream_
.get());
139 EXPECT_CALL(*demuxer_
, GetStream(DemuxerStream::VIDEO
))
140 .WillRepeatedly(Return(video_stream_
.get()));
143 void CreateAudioAndVideoStream() {
148 void InitializeWithAudio() {
150 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
151 InitializeAndExpect(PIPELINE_OK
);
154 void InitializeWithVideo() {
156 SetVideoRendererInitializeExpectations(PIPELINE_OK
);
157 InitializeAndExpect(PIPELINE_OK
);
160 void InitializeWithAudioAndVideo() {
161 CreateAudioAndVideoStream();
162 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
163 SetVideoRendererInitializeExpectations(PIPELINE_OK
);
164 InitializeAndExpect(PIPELINE_OK
);
168 DCHECK(audio_stream_
|| video_stream_
);
169 EXPECT_CALL(callbacks_
, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH
));
171 base::TimeDelta
start_time(
172 base::TimeDelta::FromMilliseconds(kStartPlayingTimeInMs
));
175 EXPECT_CALL(time_source_
, SetMediaTime(start_time
));
176 EXPECT_CALL(time_source_
, StartTicking());
177 EXPECT_CALL(*audio_renderer_
, StartPlaying())
178 .WillOnce(SetBufferingState(&audio_buffering_state_cb_
,
179 BUFFERING_HAVE_ENOUGH
));
183 EXPECT_CALL(*video_renderer_
, StartPlayingFrom(start_time
))
184 .WillOnce(SetBufferingState(&video_buffering_state_cb_
,
185 BUFFERING_HAVE_ENOUGH
));
188 renderer_impl_
->StartPlayingFrom(start_time
);
189 base::RunLoop().RunUntilIdle();
192 void Flush(bool underflowed
) {
195 EXPECT_CALL(time_source_
, StopTicking());
196 EXPECT_CALL(*audio_renderer_
, Flush(_
))
197 .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_
,
198 BUFFERING_HAVE_NOTHING
),
203 EXPECT_CALL(*video_renderer_
, Flush(_
))
204 .WillOnce(DoAll(SetBufferingState(&video_buffering_state_cb_
,
205 BUFFERING_HAVE_NOTHING
),
209 EXPECT_CALL(callbacks_
, OnFlushed());
211 renderer_impl_
->Flush(
212 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
213 base::RunLoop().RunUntilIdle();
216 void SetPlaybackRate(float playback_rate
) {
217 EXPECT_CALL(time_source_
, SetPlaybackRate(playback_rate
));
218 renderer_impl_
->SetPlaybackRate(playback_rate
);
219 base::RunLoop().RunUntilIdle();
222 int64
GetMediaTimeMs() {
223 return renderer_impl_
->GetMediaTime().InMilliseconds();
226 bool IsMediaTimeAdvancing(float playback_rate
) {
227 int64 start_time_ms
= GetMediaTimeMs();
228 const int64 time_to_advance_ms
= 100;
230 test_tick_clock_
.Advance(
231 base::TimeDelta::FromMilliseconds(time_to_advance_ms
));
233 if (GetMediaTimeMs() == start_time_ms
+ time_to_advance_ms
* playback_rate
)
236 DCHECK_EQ(start_time_ms
, GetMediaTimeMs());
240 bool IsMediaTimeAdvancing() {
241 return IsMediaTimeAdvancing(1.0f
);
245 base::MessageLoop message_loop_
;
246 StrictMock
<CallbackHelper
> callbacks_
;
247 base::SimpleTestTickClock test_tick_clock_
;
249 scoped_ptr
<StrictMock
<MockDemuxer
> > demuxer_
;
250 StrictMock
<MockVideoRenderer
>* video_renderer_
;
251 StrictMock
<MockAudioRenderer
>* audio_renderer_
;
252 scoped_ptr
<RendererImpl
> renderer_impl_
;
254 StrictMock
<MockTimeSource
> time_source_
;
255 scoped_ptr
<StrictMock
<MockDemuxerStream
> > audio_stream_
;
256 scoped_ptr
<StrictMock
<MockDemuxerStream
> > video_stream_
;
257 MockDemuxerStreamVector streams_
;
258 BufferingStateCB audio_buffering_state_cb_
;
259 BufferingStateCB video_buffering_state_cb_
;
260 base::Closure audio_ended_cb_
;
261 base::Closure video_ended_cb_
;
262 PipelineStatusCB audio_error_cb_
;
263 VideoDecoderConfig video_decoder_config_
;
266 DISALLOW_COPY_AND_ASSIGN(RendererImplTest
);
269 TEST_F(RendererImplTest
, DestroyBeforeInitialize
) {
270 // |renderer_impl_| will be destroyed in the dtor.
273 TEST_F(RendererImplTest
, InitializeWithAudio
) {
274 InitializeWithAudio();
277 TEST_F(RendererImplTest
, InitializeWithVideo
) {
278 InitializeWithVideo();
281 TEST_F(RendererImplTest
, InitializeWithAudioVideo
) {
282 InitializeWithAudioAndVideo();
285 TEST_F(RendererImplTest
, InitializeWithAudio_Failed
) {
287 SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
288 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
291 TEST_F(RendererImplTest
, InitializeWithVideo_Failed
) {
293 SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
294 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
297 TEST_F(RendererImplTest
, InitializeWithAudioVideo_AudioRendererFailed
) {
298 CreateAudioAndVideoStream();
299 SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
300 // VideoRenderer::Initialize() should not be called.
301 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
304 TEST_F(RendererImplTest
, InitializeWithAudioVideo_VideoRendererFailed
) {
305 CreateAudioAndVideoStream();
306 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
307 SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED
);
308 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED
);
311 TEST_F(RendererImplTest
, StartPlayingFrom
) {
312 InitializeWithAudioAndVideo();
316 TEST_F(RendererImplTest
, FlushAfterInitialization
) {
317 InitializeWithAudioAndVideo();
321 TEST_F(RendererImplTest
, FlushAfterPlay
) {
322 InitializeWithAudioAndVideo();
327 TEST_F(RendererImplTest
, FlushAfterUnderflow
) {
328 InitializeWithAudioAndVideo();
331 // Simulate underflow.
332 EXPECT_CALL(time_source_
, StopTicking());
333 audio_buffering_state_cb_
.Run(BUFFERING_HAVE_NOTHING
);
335 // Flush while underflowed. We shouldn't call StopTicking() again.
339 TEST_F(RendererImplTest
, SetPlaybackRate
) {
340 InitializeWithAudioAndVideo();
341 SetPlaybackRate(1.0f
);
342 SetPlaybackRate(2.0f
);
345 TEST_F(RendererImplTest
, SetVolume
) {
346 InitializeWithAudioAndVideo();
347 EXPECT_CALL(*audio_renderer_
, SetVolume(2.0f
));
348 renderer_impl_
->SetVolume(2.0f
);
351 TEST_F(RendererImplTest
, AudioStreamEnded
) {
352 InitializeWithAudio();
355 EXPECT_CALL(time_source_
, StopTicking());
356 EXPECT_CALL(callbacks_
, OnEnded());
358 audio_ended_cb_
.Run();
359 base::RunLoop().RunUntilIdle();
362 TEST_F(RendererImplTest
, VideoStreamEnded
) {
363 InitializeWithVideo();
366 // Video ended won't affect |time_source_|.
367 EXPECT_CALL(callbacks_
, OnEnded());
369 video_ended_cb_
.Run();
370 base::RunLoop().RunUntilIdle();
373 TEST_F(RendererImplTest
, AudioVideoStreamsEnded
) {
374 InitializeWithAudioAndVideo();
377 // OnEnded() is called only when all streams have finished.
378 audio_ended_cb_
.Run();
379 base::RunLoop().RunUntilIdle();
381 EXPECT_CALL(time_source_
, StopTicking());
382 EXPECT_CALL(callbacks_
, OnEnded());
384 video_ended_cb_
.Run();
385 base::RunLoop().RunUntilIdle();
388 TEST_F(RendererImplTest
, ErrorAfterInitialize
) {
389 InitializeWithAudio();
390 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
391 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
392 base::RunLoop().RunUntilIdle();
395 TEST_F(RendererImplTest
, ErrorDuringPlaying
) {
396 InitializeWithAudio();
399 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
400 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
401 base::RunLoop().RunUntilIdle();
404 TEST_F(RendererImplTest
, ErrorDuringFlush
) {
405 InitializeWithAudio();
409 EXPECT_CALL(time_source_
, StopTicking());
410 EXPECT_CALL(*audio_renderer_
, Flush(_
)).WillOnce(DoAll(
411 AudioError(&audio_error_cb_
, PIPELINE_ERROR_DECODE
),
413 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
414 EXPECT_CALL(callbacks_
, OnFlushed());
415 renderer_impl_
->Flush(
416 base::Bind(&CallbackHelper::OnFlushed
, base::Unretained(&callbacks_
)));
417 base::RunLoop().RunUntilIdle();
420 TEST_F(RendererImplTest
, ErrorAfterFlush
) {
421 InitializeWithAudio();
425 EXPECT_CALL(callbacks_
, OnError(PIPELINE_ERROR_DECODE
));
426 audio_error_cb_
.Run(PIPELINE_ERROR_DECODE
);
427 base::RunLoop().RunUntilIdle();
430 TEST_F(RendererImplTest
, ErrorDuringInitialize
) {
431 CreateAudioAndVideoStream();
432 SetAudioRendererInitializeExpectations(PIPELINE_OK
);
434 // Force an audio error to occur during video renderer initialization.
435 EXPECT_CALL(*video_renderer_
,
436 Initialize(video_stream_
.get(), _
, _
, _
, _
, _
, _
, _
, _
))
437 .WillOnce(DoAll(AudioError(&audio_error_cb_
, PIPELINE_ERROR_DECODE
),
438 SaveArg
<4>(&video_buffering_state_cb_
),
439 SaveArg
<6>(&video_ended_cb_
),
440 RunCallback
<1>(PIPELINE_OK
)));
442 InitializeAndExpect(PIPELINE_ERROR_DECODE
);