OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <vector> | |
6 | |
7 #include "base/bind.h" | |
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" | |
17 | |
18 using ::testing::_; | |
19 using ::testing::DoAll; | |
20 using ::testing::InSequence; | |
21 using ::testing::Mock; | |
22 using ::testing::Return; | |
23 using ::testing::SaveArg; | |
24 using ::testing::StrictMock; | |
25 | |
26 namespace media { | |
27 | |
28 const int64 kStartPlayingTimeInMs = 100; | |
29 const int64 kDurationInMs = 3000; | |
30 const int64 kAudioUpdateTimeMs = 150; | |
31 const int64 kAudioUpdateMaxTimeMs = 1000; | |
32 | |
33 ACTION_P2(SetBufferingState, cb, buffering_state) { | |
34 cb->Run(buffering_state); | |
35 } | |
36 | |
37 ACTION_P3(UpdateAudioTime, cb, time, max_time) { | |
38 cb->Run(base::TimeDelta::FromMilliseconds(time), | |
39 base::TimeDelta::FromMilliseconds(max_time)); | |
40 } | |
41 | |
42 ACTION_P2(AudioError, cb, error) { | |
43 cb->Run(error); | |
44 } | |
45 | |
46 static base::TimeDelta GetDuration() { | |
47 return base::TimeDelta::FromMilliseconds(kDurationInMs); | |
48 } | |
49 | |
50 class RendererImplTest : public ::testing::Test { | |
51 public: | |
52 // Used for setting expectations on pipeline callbacks. Using a StrictMock | |
53 // also lets us test for missing callbacks. | |
54 class CallbackHelper { | |
55 public: | |
56 CallbackHelper() {} | |
57 virtual ~CallbackHelper() {} | |
58 | |
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)); | |
65 | |
66 private: | |
67 DISALLOW_COPY_AND_ASSIGN(CallbackHelper); | |
68 }; | |
69 | |
70 RendererImplTest() | |
71 : demuxer_(new StrictMock<MockDemuxer>()), | |
72 video_renderer_(new StrictMock<MockVideoRenderer>()), | |
73 audio_renderer_(new StrictMock<MockAudioRenderer>()), | |
74 renderer_impl_( | |
75 new RendererImpl(message_loop_.message_loop_proxy(), | |
76 demuxer_.get(), | |
77 scoped_ptr<AudioRenderer>(audio_renderer_), | |
78 scoped_ptr<VideoRenderer>(video_renderer_))) { | |
79 // SetDemuxerExpectations() adds overriding expectations for expected | |
80 // non-NULL streams. | |
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)); | |
86 } | |
87 | |
88 virtual ~RendererImplTest() { | |
89 renderer_impl_.reset(); | |
90 base::RunLoop().RunUntilIdle(); | |
91 } | |
92 | |
93 protected: | |
94 typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector; | |
95 | |
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(); | |
101 } | |
102 | |
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_)); | |
115 } | |
116 } | |
117 | |
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))); | |
125 } | |
126 | |
127 void InitializeAndExpect(PipelineStatus start_status) { | |
128 EXPECT_CALL(callbacks_, OnInitialize(start_status)); | |
129 | |
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(); | |
141 } | |
142 | |
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())); | |
148 } | |
149 | |
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())); | |
156 } | |
157 | |
158 void CreateAudioAndVideoStream() { | |
159 CreateAudioStream(); | |
160 CreateVideoStream(); | |
161 } | |
162 | |
163 void InitializeWithAudio() { | |
164 CreateAudioStream(); | |
165 SetAudioRendererInitializeExpectations(PIPELINE_OK); | |
166 InitializeAndExpect(PIPELINE_OK); | |
167 } | |
168 | |
169 void InitializeWithVideo() { | |
170 CreateVideoStream(); | |
171 SetVideoRendererInitializeExpectations(PIPELINE_OK); | |
172 InitializeAndExpect(PIPELINE_OK); | |
173 } | |
174 | |
175 void InitializeWithAudioAndVideo() { | |
176 CreateAudioAndVideoStream(); | |
177 SetAudioRendererInitializeExpectations(PIPELINE_OK); | |
178 SetVideoRendererInitializeExpectations(PIPELINE_OK); | |
179 InitializeAndExpect(PIPELINE_OK); | |
180 } | |
181 | |
182 void Play() { | |
183 DCHECK(audio_stream_ || video_stream_); | |
184 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH)); | |
185 | |
186 if (audio_stream_) { | |
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)); | |
194 } | |
195 | |
196 if (video_stream_) { | |
197 EXPECT_CALL(*video_renderer_, StartPlaying()) | |
198 .WillOnce(SetBufferingState(&video_buffering_state_cb_, | |
199 BUFFERING_HAVE_ENOUGH)); | |
200 } | |
201 | |
202 renderer_impl_->StartPlayingFrom( | |
203 base::TimeDelta::FromMilliseconds(kStartPlayingTimeInMs)); | |
204 base::RunLoop().RunUntilIdle(); | |
205 } | |
206 | |
207 void Flush(bool underflowed) { | |
208 if (audio_stream_) { | |
209 if (!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), | |
214 RunClosure<0>())); | |
215 } | |
216 | |
217 if (video_stream_) { | |
218 EXPECT_CALL(*video_renderer_, Flush(_)) | |
219 .WillOnce(DoAll(SetBufferingState(&video_buffering_state_cb_, | |
220 BUFFERING_HAVE_NOTHING), | |
221 RunClosure<0>())); | |
222 } | |
223 | |
224 EXPECT_CALL(callbacks_, OnFlushed()); | |
225 | |
226 renderer_impl_->Flush( | |
227 base::Bind(&CallbackHelper::OnFlushed, base::Unretained(&callbacks_))); | |
228 base::RunLoop().RunUntilIdle(); | |
229 } | |
230 | |
231 void SetPlaybackRate(float playback_rate) { | |
232 EXPECT_CALL(time_source_, SetPlaybackRate(playback_rate)); | |
233 renderer_impl_->SetPlaybackRate(playback_rate); | |
234 base::RunLoop().RunUntilIdle(); | |
235 } | |
236 | |
237 int64 GetMediaTimeMs() { | |
238 return renderer_impl_->GetMediaTime().InMilliseconds(); | |
239 } | |
240 | |
241 bool IsMediaTimeAdvancing(float playback_rate) { | |
242 int64 start_time_ms = GetMediaTimeMs(); | |
243 const int64 time_to_advance_ms = 100; | |
244 | |
245 test_tick_clock_.Advance( | |
246 base::TimeDelta::FromMilliseconds(time_to_advance_ms)); | |
247 | |
248 if (GetMediaTimeMs() == start_time_ms + time_to_advance_ms * playback_rate) | |
249 return true; | |
250 | |
251 DCHECK_EQ(start_time_ms, GetMediaTimeMs()); | |
252 return false; | |
253 } | |
254 | |
255 bool IsMediaTimeAdvancing() { | |
256 return IsMediaTimeAdvancing(1.0f); | |
257 } | |
258 | |
259 // Fixture members. | |
260 base::MessageLoop message_loop_; | |
261 StrictMock<CallbackHelper> callbacks_; | |
262 base::SimpleTestTickClock test_tick_clock_; | |
263 | |
264 scoped_ptr<StrictMock<MockDemuxer> > demuxer_; | |
265 StrictMock<MockVideoRenderer>* video_renderer_; | |
266 StrictMock<MockAudioRenderer>* audio_renderer_; | |
267 scoped_ptr<RendererImpl> renderer_impl_; | |
268 | |
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_; | |
280 | |
281 private: | |
282 DISALLOW_COPY_AND_ASSIGN(RendererImplTest); | |
283 }; | |
284 | |
285 TEST_F(RendererImplTest, DestroyBeforeInitialize) { | |
286 // |renderer_impl_| will be destroyed in the dtor. | |
287 } | |
288 | |
289 TEST_F(RendererImplTest, InitializeWithAudio) { | |
290 InitializeWithAudio(); | |
291 } | |
292 | |
293 TEST_F(RendererImplTest, InitializeWithVideo) { | |
294 InitializeWithVideo(); | |
295 } | |
296 | |
297 TEST_F(RendererImplTest, InitializeWithAudioVideo) { | |
298 InitializeWithAudioAndVideo(); | |
299 } | |
300 | |
301 TEST_F(RendererImplTest, InitializeWithAudio_Failed) { | |
302 CreateAudioStream(); | |
303 SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED); | |
304 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED); | |
305 } | |
306 | |
307 TEST_F(RendererImplTest, InitializeWithVideo_Failed) { | |
308 CreateVideoStream(); | |
309 SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED); | |
310 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED); | |
311 } | |
312 | |
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); | |
318 } | |
319 | |
320 TEST_F(RendererImplTest, InitializeWithAudioVideo_VideoRendererFailed) { | |
321 CreateAudioAndVideoStream(); | |
322 SetAudioRendererInitializeExpectations(PIPELINE_OK); | |
323 SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED); | |
324 InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED); | |
325 } | |
326 | |
327 TEST_F(RendererImplTest, StartPlayingFrom) { | |
328 InitializeWithAudioAndVideo(); | |
329 Play(); | |
330 } | |
331 | |
332 TEST_F(RendererImplTest, FlushAfterInitialization) { | |
333 InitializeWithAudioAndVideo(); | |
334 Flush(true); | |
335 } | |
336 | |
337 TEST_F(RendererImplTest, FlushAfterPlay) { | |
338 InitializeWithAudioAndVideo(); | |
339 Play(); | |
340 Flush(false); | |
341 } | |
342 | |
343 TEST_F(RendererImplTest, FlushAfterUnderflow) { | |
344 InitializeWithAudioAndVideo(); | |
345 Play(); | |
346 | |
347 // Simulate underflow. | |
348 EXPECT_CALL(time_source_, StopTicking()); | |
349 audio_buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING); | |
350 | |
351 // Flush while underflowed. We shouldn't call StopTicking() again. | |
352 Flush(true); | |
353 } | |
354 | |
355 TEST_F(RendererImplTest, SetPlaybackRate) { | |
356 InitializeWithAudioAndVideo(); | |
357 SetPlaybackRate(1.0f); | |
358 SetPlaybackRate(2.0f); | |
359 } | |
360 | |
361 TEST_F(RendererImplTest, SetVolume) { | |
362 InitializeWithAudioAndVideo(); | |
363 EXPECT_CALL(*audio_renderer_, SetVolume(2.0f)); | |
364 renderer_impl_->SetVolume(2.0f); | |
365 } | |
366 | |
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_)); | |
371 | |
372 InitializeWithAudioAndVideo(); | |
373 Play(); | |
374 | |
375 EXPECT_EQ(kStartPlayingTimeInMs, GetMediaTimeMs()); | |
376 | |
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()); | |
380 | |
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()); | |
386 | |
387 // Advance the clock so that GetMediaTime() also advances. This also verifies | |
388 // that the default playback rate is 1. | |
389 EXPECT_TRUE(IsMediaTimeAdvancing()); | |
390 | |
391 // Verify that playback rate affects the rate GetMediaTime() advances. | |
392 SetPlaybackRate(2.0f); | |
393 EXPECT_TRUE(IsMediaTimeAdvancing(2.0f)); | |
394 | |
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()); | |
399 } | |
400 | |
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_)); | |
405 | |
406 InitializeWithAudioAndVideo(); | |
407 Play(); | |
408 | |
409 EXPECT_EQ(kStartPlayingTimeInMs, GetMediaTimeMs()); | |
410 | |
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()); | |
414 | |
415 // Signal end of audio stream. | |
416 audio_ended_cb_.Run(); | |
417 base::RunLoop().RunUntilIdle(); | |
418 | |
419 // Verify that the clock advances. | |
420 EXPECT_TRUE(IsMediaTimeAdvancing()); | |
421 | |
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(); | |
427 } | |
428 | |
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_)); | |
433 | |
434 InitializeWithAudio(); | |
435 Play(); | |
436 | |
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()); | |
442 | |
443 int64 start_time = GetMediaTimeMs(); | |
444 | |
445 EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(DoAll( | |
446 UpdateAudioTime( | |
447 &audio_time_cb_, kAudioUpdateTimeMs + 100, kAudioUpdateMaxTimeMs), | |
448 SetBufferingState(&audio_buffering_state_cb_, BUFFERING_HAVE_NOTHING), | |
449 RunClosure<0>())); | |
450 EXPECT_CALL(time_source_, StopTicking()); | |
451 EXPECT_CALL(callbacks_, OnFlushed()); | |
452 renderer_impl_->Flush( | |
453 base::Bind(&CallbackHelper::OnFlushed, base::Unretained(&callbacks_))); | |
454 | |
455 // Audio time update during Flush() has no effect. | |
456 EXPECT_EQ(start_time, GetMediaTimeMs()); | |
457 | |
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()); | |
461 } | |
462 | |
463 TEST_F(RendererImplTest, PostTimeUpdateDuringDestroy) { | |
464 InitializeWithAudioAndVideo(); | |
465 | |
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)); | |
470 | |
471 renderer_impl_.reset(); | |
472 message_loop_.RunUntilIdle(); | |
473 } | |
474 | |
475 TEST_F(RendererImplTest, AudioStreamEnded) { | |
476 InitializeWithAudio(); | |
477 Play(); | |
478 | |
479 EXPECT_CALL(time_source_, StopTicking()); | |
480 EXPECT_CALL(callbacks_, OnEnded()); | |
481 | |
482 audio_ended_cb_.Run(); | |
483 base::RunLoop().RunUntilIdle(); | |
484 } | |
485 | |
486 TEST_F(RendererImplTest, VideoStreamEnded) { | |
487 InitializeWithVideo(); | |
488 Play(); | |
489 | |
490 // Video ended won't affect |time_source_|. | |
491 EXPECT_CALL(callbacks_, OnEnded()); | |
492 | |
493 video_ended_cb_.Run(); | |
494 base::RunLoop().RunUntilIdle(); | |
495 } | |
496 | |
497 TEST_F(RendererImplTest, AudioVideoStreamsEnded) { | |
498 InitializeWithAudioAndVideo(); | |
499 Play(); | |
500 | |
501 // OnEnded() is called only when all streams have finished. | |
502 audio_ended_cb_.Run(); | |
503 base::RunLoop().RunUntilIdle(); | |
504 | |
505 EXPECT_CALL(time_source_, StopTicking()); | |
506 EXPECT_CALL(callbacks_, OnEnded()); | |
507 | |
508 video_ended_cb_.Run(); | |
509 base::RunLoop().RunUntilIdle(); | |
510 } | |
511 | |
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(); | |
517 } | |
518 | |
519 TEST_F(RendererImplTest, ErrorDuringPlaying) { | |
520 InitializeWithAudio(); | |
521 Play(); | |
522 | |
523 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_DECODE)); | |
524 audio_error_cb_.Run(PIPELINE_ERROR_DECODE); | |
525 base::RunLoop().RunUntilIdle(); | |
526 } | |
527 | |
528 TEST_F(RendererImplTest, ErrorDuringFlush) { | |
529 InitializeWithAudio(); | |
530 Play(); | |
531 | |
532 InSequence s; | |
533 EXPECT_CALL(time_source_, StopTicking()); | |
534 EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(DoAll( | |
535 AudioError(&audio_error_cb_, PIPELINE_ERROR_DECODE), | |
536 RunClosure<0>())); | |
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(); | |
542 } | |
543 | |
544 TEST_F(RendererImplTest, ErrorAfterFlush) { | |
545 InitializeWithAudio(); | |
546 Play(); | |
547 Flush(false); | |
548 | |
549 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_DECODE)); | |
550 audio_error_cb_.Run(PIPELINE_ERROR_DECODE); | |
551 base::RunLoop().RunUntilIdle(); | |
552 } | |
553 | |
554 } // namespace media | |
OLD | NEW |