1// Copyright (c) 2012 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/stl_util.h" 10#include "base/test/simple_test_tick_clock.h" 11#include "base/threading/simple_thread.h" 12#include "base/time/clock.h" 13#include "media/base/fake_text_track_stream.h" 14#include "media/base/gmock_callback_support.h" 15#include "media/base/media_log.h" 16#include "media/base/mock_filters.h" 17#include "media/base/pipeline.h" 18#include "media/base/test_helpers.h" 19#include "media/base/text_renderer.h" 20#include "media/base/text_track_config.h" 21#include "media/base/time_delta_interpolator.h" 22#include "testing/gtest/include/gtest/gtest.h" 23#include "ui/gfx/size.h" 24 25using ::testing::_; 26using ::testing::AnyNumber; 27using ::testing::DeleteArg; 28using ::testing::DoAll; 29// TODO(scherkus): Remove InSequence after refactoring Pipeline. 30using ::testing::InSequence; 31using ::testing::Invoke; 32using ::testing::InvokeWithoutArgs; 33using ::testing::Mock; 34using ::testing::NotNull; 35using ::testing::Return; 36using ::testing::SaveArg; 37using ::testing::StrictMock; 38using ::testing::WithArg; 39 40namespace media { 41 42ACTION_P(SetDemuxerProperties, duration) { 43 arg0->SetDuration(duration); 44} 45 46ACTION_P2(Stop, pipeline, stop_cb) { 47 pipeline->Stop(stop_cb); 48} 49 50ACTION_P2(SetError, pipeline, status) { 51 pipeline->SetErrorForTesting(status); 52} 53 54ACTION_P2(SetBufferingState, cb, buffering_state) { 55 cb->Run(buffering_state); 56} 57 58// TODO(scherkus): even though some filters are initialized on separate 59// threads these test aren't flaky... why? It's because filters' Initialize() 60// is executed on |message_loop_| and the mock filters instantly call 61// InitializationComplete(), which keeps the pipeline humming along. If 62// either filters don't call InitializationComplete() immediately or filter 63// initialization is moved to a separate thread this test will become flaky. 64class PipelineTest : public ::testing::Test { 65 public: 66 // Used for setting expectations on pipeline callbacks. Using a StrictMock 67 // also lets us test for missing callbacks. 68 class CallbackHelper { 69 public: 70 CallbackHelper() {} 71 virtual ~CallbackHelper() {} 72 73 MOCK_METHOD1(OnStart, void(PipelineStatus)); 74 MOCK_METHOD1(OnSeek, void(PipelineStatus)); 75 MOCK_METHOD0(OnStop, void()); 76 MOCK_METHOD0(OnEnded, void()); 77 MOCK_METHOD1(OnError, void(PipelineStatus)); 78 MOCK_METHOD1(OnMetadata, void(PipelineMetadata)); 79 MOCK_METHOD1(OnBufferingStateChange, void(BufferingState)); 80 MOCK_METHOD0(OnDurationChange, void()); 81 82 private: 83 DISALLOW_COPY_AND_ASSIGN(CallbackHelper); 84 }; 85 86 PipelineTest() 87 : pipeline_(new Pipeline(message_loop_.message_loop_proxy(), 88 new MediaLog())), 89 demuxer_(new StrictMock<MockDemuxer>()), 90 scoped_renderer_(new StrictMock<MockRenderer>()), 91 renderer_(scoped_renderer_.get()) { 92 // SetDemuxerExpectations() adds overriding expectations for expected 93 // non-NULL streams. 94 DemuxerStream* null_pointer = NULL; 95 EXPECT_CALL(*demuxer_, GetStream(_)) 96 .WillRepeatedly(Return(null_pointer)); 97 98 EXPECT_CALL(*demuxer_, GetTimelineOffset()) 99 .WillRepeatedly(Return(base::Time())); 100 101 EXPECT_CALL(*demuxer_, GetLiveness()) 102 .WillRepeatedly(Return(Demuxer::LIVENESS_UNKNOWN)); 103 104 EXPECT_CALL(*renderer_, GetMediaTime()) 105 .WillRepeatedly(Return(base::TimeDelta())); 106 107 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_)); 108 } 109 110 virtual ~PipelineTest() { 111 if (!pipeline_ || !pipeline_->IsRunning()) 112 return; 113 114 ExpectDemuxerStop(); 115 116 // The mock demuxer doesn't stop the fake text track stream, 117 // so just stop it manually. 118 if (text_stream_) { 119 text_stream_->Stop(); 120 message_loop_.RunUntilIdle(); 121 } 122 123 // Expect a stop callback if we were started. 124 ExpectPipelineStopAndDestroyPipeline(); 125 pipeline_->Stop(base::Bind(&CallbackHelper::OnStop, 126 base::Unretained(&callbacks_))); 127 message_loop_.RunUntilIdle(); 128 } 129 130 void OnDemuxerError() { 131 // Cast because OnDemuxerError is private in Pipeline. 132 static_cast<DemuxerHost*>(pipeline_.get()) 133 ->OnDemuxerError(PIPELINE_ERROR_ABORT); 134 } 135 136 protected: 137 // Sets up expectations to allow the demuxer to initialize. 138 typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector; 139 void SetDemuxerExpectations(MockDemuxerStreamVector* streams, 140 const base::TimeDelta& duration) { 141 EXPECT_CALL(callbacks_, OnDurationChange()); 142 EXPECT_CALL(*demuxer_, Initialize(_, _, _)) 143 .WillOnce(DoAll(SetDemuxerProperties(duration), 144 RunCallback<1>(PIPELINE_OK))); 145 146 // Configure the demuxer to return the streams. 147 for (size_t i = 0; i < streams->size(); ++i) { 148 DemuxerStream* stream = (*streams)[i]; 149 EXPECT_CALL(*demuxer_, GetStream(stream->type())) 150 .WillRepeatedly(Return(stream)); 151 } 152 } 153 154 void SetDemuxerExpectations(MockDemuxerStreamVector* streams) { 155 // Initialize with a default non-zero duration. 156 SetDemuxerExpectations(streams, base::TimeDelta::FromSeconds(10)); 157 } 158 159 scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream( 160 DemuxerStream::Type type) { 161 scoped_ptr<StrictMock<MockDemuxerStream> > stream( 162 new StrictMock<MockDemuxerStream>(type)); 163 return stream.Pass(); 164 } 165 166 // Sets up expectations to allow the video renderer to initialize. 167 void SetRendererExpectations() { 168 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _)) 169 .WillOnce(DoAll(SaveArg<2>(&ended_cb_), 170 SaveArg<4>(&buffering_state_cb_), 171 RunCallback<0>())); 172 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(audio_stream())); 173 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(video_stream())); 174 } 175 176 void AddTextStream() { 177 EXPECT_CALL(*this, OnAddTextTrack(_,_)) 178 .WillOnce(Invoke(this, &PipelineTest::DoOnAddTextTrack)); 179 static_cast<DemuxerHost*>(pipeline_.get())->AddTextStream(text_stream(), 180 TextTrackConfig(kTextSubtitles, "", "", "")); 181 message_loop_.RunUntilIdle(); 182 } 183 184 void StartPipeline() { 185 pipeline_->Start( 186 demuxer_.get(), 187 scoped_renderer_.PassAs<Renderer>(), 188 base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)), 189 base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)), 190 base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)), 191 base::Bind(&CallbackHelper::OnMetadata, base::Unretained(&callbacks_)), 192 base::Bind(&CallbackHelper::OnBufferingStateChange, 193 base::Unretained(&callbacks_)), 194 base::Bind(&CallbackHelper::OnDurationChange, 195 base::Unretained(&callbacks_)), 196 base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this))); 197 } 198 199 // Sets up expectations on the callback and initializes the pipeline. Called 200 // after tests have set expectations any filters they wish to use. 201 void StartPipelineAndExpect(PipelineStatus start_status) { 202 EXPECT_CALL(callbacks_, OnStart(start_status)); 203 204 if (start_status == PIPELINE_OK) { 205 EXPECT_CALL(callbacks_, OnMetadata(_)).WillOnce(SaveArg<0>(&metadata_)); 206 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0f)); 207 EXPECT_CALL(*renderer_, SetVolume(1.0f)); 208 EXPECT_CALL(*renderer_, StartPlayingFrom(start_time_)) 209 .WillOnce(SetBufferingState(&buffering_state_cb_, 210 BUFFERING_HAVE_ENOUGH)); 211 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH)); 212 } 213 214 StartPipeline(); 215 message_loop_.RunUntilIdle(); 216 } 217 218 void CreateAudioStream() { 219 audio_stream_ = CreateStream(DemuxerStream::AUDIO); 220 } 221 222 void CreateVideoStream() { 223 video_stream_ = CreateStream(DemuxerStream::VIDEO); 224 video_stream_->set_video_decoder_config(video_decoder_config_); 225 } 226 227 void CreateTextStream() { 228 scoped_ptr<FakeTextTrackStream> text_stream(new FakeTextTrackStream()); 229 EXPECT_CALL(*text_stream, OnRead()).Times(AnyNumber()); 230 text_stream_ = text_stream.Pass(); 231 } 232 233 MockDemuxerStream* audio_stream() { 234 return audio_stream_.get(); 235 } 236 237 MockDemuxerStream* video_stream() { 238 return video_stream_.get(); 239 } 240 241 FakeTextTrackStream* text_stream() { 242 return text_stream_.get(); 243 } 244 245 void ExpectSeek(const base::TimeDelta& seek_time, bool underflowed) { 246 EXPECT_CALL(*demuxer_, Seek(seek_time, _)) 247 .WillOnce(RunCallback<1>(PIPELINE_OK)); 248 249 EXPECT_CALL(*renderer_, Flush(_)) 250 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_, 251 BUFFERING_HAVE_NOTHING), 252 RunClosure<0>())); 253 EXPECT_CALL(*renderer_, SetPlaybackRate(_)); 254 EXPECT_CALL(*renderer_, SetVolume(_)); 255 EXPECT_CALL(*renderer_, StartPlayingFrom(seek_time)) 256 .WillOnce(SetBufferingState(&buffering_state_cb_, 257 BUFFERING_HAVE_ENOUGH)); 258 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); 259 260 // We expect a successful seek callback followed by a buffering update. 261 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_OK)); 262 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH)); 263 } 264 265 void DoSeek(const base::TimeDelta& seek_time) { 266 pipeline_->Seek(seek_time, 267 base::Bind(&CallbackHelper::OnSeek, 268 base::Unretained(&callbacks_))); 269 message_loop_.RunUntilIdle(); 270 } 271 272 void DestroyPipeline() { 273 // In real code Pipeline could be destroyed on a different thread. All weak 274 // pointers must have been invalidated before the stop callback returns. 275 DCHECK(!pipeline_->HasWeakPtrsForTesting()); 276 pipeline_.reset(); 277 } 278 279 void ExpectDemuxerStop() { 280 if (demuxer_) 281 EXPECT_CALL(*demuxer_, Stop()); 282 } 283 284 void ExpectPipelineStopAndDestroyPipeline() { 285 // After the Pipeline is stopped, it could be destroyed any time. Always 286 // destroy the pipeline immediately after OnStop() to test this. 287 EXPECT_CALL(callbacks_, OnStop()) 288 .WillOnce(Invoke(this, &PipelineTest::DestroyPipeline)); 289 } 290 291 MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&, 292 const AddTextTrackDoneCB&)); 293 294 void DoOnAddTextTrack(const TextTrackConfig& config, 295 const AddTextTrackDoneCB& done_cb) { 296 scoped_ptr<TextTrack> text_track(new MockTextTrack); 297 done_cb.Run(text_track.Pass()); 298 } 299 300 // Fixture members. 301 StrictMock<CallbackHelper> callbacks_; 302 base::SimpleTestTickClock test_tick_clock_; 303 base::MessageLoop message_loop_; 304 scoped_ptr<Pipeline> pipeline_; 305 306 scoped_ptr<StrictMock<MockDemuxer> > demuxer_; 307 scoped_ptr<StrictMock<MockRenderer> > scoped_renderer_; 308 StrictMock<MockRenderer>* renderer_; 309 StrictMock<CallbackHelper> text_renderer_callbacks_; 310 TextRenderer* text_renderer_; 311 scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_; 312 scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_; 313 scoped_ptr<FakeTextTrackStream> text_stream_; 314 BufferingStateCB buffering_state_cb_; 315 base::Closure ended_cb_; 316 VideoDecoderConfig video_decoder_config_; 317 PipelineMetadata metadata_; 318 base::TimeDelta start_time_; 319 320 private: 321 DISALLOW_COPY_AND_ASSIGN(PipelineTest); 322}; 323 324// Test that playback controls methods no-op when the pipeline hasn't been 325// started. 326TEST_F(PipelineTest, NotStarted) { 327 const base::TimeDelta kZero; 328 329 EXPECT_FALSE(pipeline_->IsRunning()); 330 331 // Setting should still work. 332 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate()); 333 pipeline_->SetPlaybackRate(-1.0f); 334 EXPECT_EQ(0.0f, pipeline_->GetPlaybackRate()); 335 pipeline_->SetPlaybackRate(1.0f); 336 EXPECT_EQ(1.0f, pipeline_->GetPlaybackRate()); 337 338 // Setting should still work. 339 EXPECT_EQ(1.0f, pipeline_->GetVolume()); 340 pipeline_->SetVolume(-1.0f); 341 EXPECT_EQ(1.0f, pipeline_->GetVolume()); 342 pipeline_->SetVolume(0.0f); 343 EXPECT_EQ(0.0f, pipeline_->GetVolume()); 344 345 EXPECT_TRUE(kZero == pipeline_->GetMediaTime()); 346 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size()); 347 EXPECT_TRUE(kZero == pipeline_->GetMediaDuration()); 348} 349 350TEST_F(PipelineTest, NeverInitializes) { 351 // Don't execute the callback passed into Initialize(). 352 EXPECT_CALL(*demuxer_, Initialize(_, _, _)); 353 354 // This test hangs during initialization by never calling 355 // InitializationComplete(). StrictMock<> will ensure that the callback is 356 // never executed. 357 StartPipeline(); 358 message_loop_.RunUntilIdle(); 359 360 // Because our callback will get executed when the test tears down, we'll 361 // verify that nothing has been called, then set our expectation for the call 362 // made during tear down. 363 Mock::VerifyAndClear(&callbacks_); 364 EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK)); 365} 366 367TEST_F(PipelineTest, StopWithoutStart) { 368 ExpectPipelineStopAndDestroyPipeline(); 369 pipeline_->Stop( 370 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_))); 371 message_loop_.RunUntilIdle(); 372} 373 374TEST_F(PipelineTest, StartThenStopImmediately) { 375 EXPECT_CALL(*demuxer_, Initialize(_, _, _)) 376 .WillOnce(RunCallback<1>(PIPELINE_OK)); 377 EXPECT_CALL(*demuxer_, Stop()); 378 379 EXPECT_CALL(callbacks_, OnStart(_)); 380 StartPipeline(); 381 382 // Expect a stop callback if we were started. 383 ExpectPipelineStopAndDestroyPipeline(); 384 pipeline_->Stop( 385 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_))); 386 message_loop_.RunUntilIdle(); 387} 388 389TEST_F(PipelineTest, DemuxerErrorDuringStop) { 390 CreateAudioStream(); 391 MockDemuxerStreamVector streams; 392 streams.push_back(audio_stream()); 393 394 SetDemuxerExpectations(&streams); 395 SetRendererExpectations(); 396 397 StartPipelineAndExpect(PIPELINE_OK); 398 399 EXPECT_CALL(*demuxer_, Stop()) 400 .WillOnce(InvokeWithoutArgs(this, &PipelineTest::OnDemuxerError)); 401 ExpectPipelineStopAndDestroyPipeline(); 402 403 pipeline_->Stop( 404 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_))); 405 message_loop_.RunUntilIdle(); 406} 407 408TEST_F(PipelineTest, URLNotFound) { 409 EXPECT_CALL(*demuxer_, Initialize(_, _, _)) 410 .WillOnce(RunCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND)); 411 EXPECT_CALL(*demuxer_, Stop()); 412 413 StartPipelineAndExpect(PIPELINE_ERROR_URL_NOT_FOUND); 414} 415 416TEST_F(PipelineTest, NoStreams) { 417 EXPECT_CALL(*demuxer_, Initialize(_, _, _)) 418 .WillOnce(RunCallback<1>(PIPELINE_OK)); 419 EXPECT_CALL(*demuxer_, Stop()); 420 421 StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER); 422} 423 424TEST_F(PipelineTest, AudioStream) { 425 CreateAudioStream(); 426 MockDemuxerStreamVector streams; 427 streams.push_back(audio_stream()); 428 429 SetDemuxerExpectations(&streams); 430 SetRendererExpectations(); 431 432 StartPipelineAndExpect(PIPELINE_OK); 433 EXPECT_TRUE(metadata_.has_audio); 434 EXPECT_FALSE(metadata_.has_video); 435} 436 437TEST_F(PipelineTest, VideoStream) { 438 CreateVideoStream(); 439 MockDemuxerStreamVector streams; 440 streams.push_back(video_stream()); 441 442 SetDemuxerExpectations(&streams); 443 SetRendererExpectations(); 444 445 StartPipelineAndExpect(PIPELINE_OK); 446 EXPECT_FALSE(metadata_.has_audio); 447 EXPECT_TRUE(metadata_.has_video); 448} 449 450TEST_F(PipelineTest, AudioVideoStream) { 451 CreateAudioStream(); 452 CreateVideoStream(); 453 MockDemuxerStreamVector streams; 454 streams.push_back(audio_stream()); 455 streams.push_back(video_stream()); 456 457 SetDemuxerExpectations(&streams); 458 SetRendererExpectations(); 459 460 StartPipelineAndExpect(PIPELINE_OK); 461 EXPECT_TRUE(metadata_.has_audio); 462 EXPECT_TRUE(metadata_.has_video); 463} 464 465TEST_F(PipelineTest, VideoTextStream) { 466 CreateVideoStream(); 467 CreateTextStream(); 468 MockDemuxerStreamVector streams; 469 streams.push_back(video_stream()); 470 471 SetDemuxerExpectations(&streams); 472 SetRendererExpectations(); 473 474 StartPipelineAndExpect(PIPELINE_OK); 475 EXPECT_FALSE(metadata_.has_audio); 476 EXPECT_TRUE(metadata_.has_video); 477 478 AddTextStream(); 479} 480 481TEST_F(PipelineTest, VideoAudioTextStream) { 482 CreateVideoStream(); 483 CreateAudioStream(); 484 CreateTextStream(); 485 MockDemuxerStreamVector streams; 486 streams.push_back(video_stream()); 487 streams.push_back(audio_stream()); 488 489 SetDemuxerExpectations(&streams); 490 SetRendererExpectations(); 491 492 StartPipelineAndExpect(PIPELINE_OK); 493 EXPECT_TRUE(metadata_.has_audio); 494 EXPECT_TRUE(metadata_.has_video); 495 496 AddTextStream(); 497} 498 499TEST_F(PipelineTest, Seek) { 500 CreateAudioStream(); 501 CreateVideoStream(); 502 CreateTextStream(); 503 MockDemuxerStreamVector streams; 504 streams.push_back(audio_stream()); 505 streams.push_back(video_stream()); 506 507 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000)); 508 SetRendererExpectations(); 509 510 // Initialize then seek! 511 StartPipelineAndExpect(PIPELINE_OK); 512 513 // Every filter should receive a call to Seek(). 514 base::TimeDelta expected = base::TimeDelta::FromSeconds(2000); 515 ExpectSeek(expected, false); 516 DoSeek(expected); 517} 518 519TEST_F(PipelineTest, SeekAfterError) { 520 CreateAudioStream(); 521 MockDemuxerStreamVector streams; 522 streams.push_back(audio_stream()); 523 524 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000)); 525 SetRendererExpectations(); 526 527 // Initialize then seek! 528 StartPipelineAndExpect(PIPELINE_OK); 529 530 EXPECT_CALL(*demuxer_, Stop()); 531 EXPECT_CALL(callbacks_, OnError(_)); 532 533 static_cast<DemuxerHost*>(pipeline_.get()) 534 ->OnDemuxerError(PIPELINE_ERROR_ABORT); 535 message_loop_.RunUntilIdle(); 536 537 pipeline_->Seek( 538 base::TimeDelta::FromMilliseconds(100), 539 base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_))); 540 message_loop_.RunUntilIdle(); 541} 542 543TEST_F(PipelineTest, SetVolume) { 544 CreateAudioStream(); 545 MockDemuxerStreamVector streams; 546 streams.push_back(audio_stream()); 547 548 SetDemuxerExpectations(&streams); 549 SetRendererExpectations(); 550 551 // The audio renderer should receive a call to SetVolume(). 552 float expected = 0.5f; 553 EXPECT_CALL(*renderer_, SetVolume(expected)); 554 555 // Initialize then set volume! 556 StartPipelineAndExpect(PIPELINE_OK); 557 pipeline_->SetVolume(expected); 558} 559 560TEST_F(PipelineTest, Properties) { 561 CreateVideoStream(); 562 MockDemuxerStreamVector streams; 563 streams.push_back(video_stream()); 564 565 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100); 566 SetDemuxerExpectations(&streams, kDuration); 567 SetRendererExpectations(); 568 569 StartPipelineAndExpect(PIPELINE_OK); 570 EXPECT_EQ(kDuration.ToInternalValue(), 571 pipeline_->GetMediaDuration().ToInternalValue()); 572 EXPECT_FALSE(pipeline_->DidLoadingProgress()); 573} 574 575TEST_F(PipelineTest, GetBufferedTimeRanges) { 576 CreateVideoStream(); 577 MockDemuxerStreamVector streams; 578 streams.push_back(video_stream()); 579 580 const base::TimeDelta kDuration = base::TimeDelta::FromSeconds(100); 581 SetDemuxerExpectations(&streams, kDuration); 582 SetRendererExpectations(); 583 584 StartPipelineAndExpect(PIPELINE_OK); 585 586 EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size()); 587 588 EXPECT_FALSE(pipeline_->DidLoadingProgress()); 589 pipeline_->AddBufferedTimeRange(base::TimeDelta(), kDuration / 8); 590 EXPECT_TRUE(pipeline_->DidLoadingProgress()); 591 EXPECT_FALSE(pipeline_->DidLoadingProgress()); 592 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size()); 593 EXPECT_EQ(base::TimeDelta(), pipeline_->GetBufferedTimeRanges().start(0)); 594 EXPECT_EQ(kDuration / 8, pipeline_->GetBufferedTimeRanges().end(0)); 595 596 base::TimeDelta kSeekTime = kDuration / 2; 597 ExpectSeek(kSeekTime, false); 598 DoSeek(kSeekTime); 599 600 EXPECT_FALSE(pipeline_->DidLoadingProgress()); 601} 602 603TEST_F(PipelineTest, EndedCallback) { 604 CreateAudioStream(); 605 CreateVideoStream(); 606 CreateTextStream(); 607 MockDemuxerStreamVector streams; 608 streams.push_back(audio_stream()); 609 streams.push_back(video_stream()); 610 611 SetDemuxerExpectations(&streams); 612 SetRendererExpectations(); 613 StartPipelineAndExpect(PIPELINE_OK); 614 615 AddTextStream(); 616 617 // The ended callback shouldn't run until all renderers have ended. 618 ended_cb_.Run(); 619 message_loop_.RunUntilIdle(); 620 621 EXPECT_CALL(callbacks_, OnEnded()); 622 text_stream()->SendEosNotification(); 623 message_loop_.RunUntilIdle(); 624} 625 626TEST_F(PipelineTest, ErrorDuringSeek) { 627 CreateAudioStream(); 628 MockDemuxerStreamVector streams; 629 streams.push_back(audio_stream()); 630 631 SetDemuxerExpectations(&streams); 632 SetRendererExpectations(); 633 StartPipelineAndExpect(PIPELINE_OK); 634 635 float playback_rate = 1.0f; 636 EXPECT_CALL(*renderer_, SetPlaybackRate(playback_rate)); 637 pipeline_->SetPlaybackRate(playback_rate); 638 message_loop_.RunUntilIdle(); 639 640 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5); 641 642 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); 643 EXPECT_CALL(*renderer_, Flush(_)) 644 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_, 645 BUFFERING_HAVE_NOTHING), 646 RunClosure<0>())); 647 648 EXPECT_CALL(*demuxer_, Seek(seek_time, _)) 649 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ)); 650 EXPECT_CALL(*demuxer_, Stop()); 651 652 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek, 653 base::Unretained(&callbacks_))); 654 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ)); 655 message_loop_.RunUntilIdle(); 656} 657 658// Invoked function OnError. This asserts that the pipeline does not enqueue 659// non-teardown related tasks while tearing down. 660static void TestNoCallsAfterError( 661 Pipeline* pipeline, base::MessageLoop* message_loop, 662 PipelineStatus /* status */) { 663 CHECK(pipeline); 664 CHECK(message_loop); 665 666 // When we get to this stage, the message loop should be empty. 667 EXPECT_TRUE(message_loop->IsIdleForTesting()); 668 669 // Make calls on pipeline after error has occurred. 670 pipeline->SetPlaybackRate(0.5f); 671 pipeline->SetVolume(0.5f); 672 673 // No additional tasks should be queued as a result of these calls. 674 EXPECT_TRUE(message_loop->IsIdleForTesting()); 675} 676 677TEST_F(PipelineTest, NoMessageDuringTearDownFromError) { 678 CreateAudioStream(); 679 MockDemuxerStreamVector streams; 680 streams.push_back(audio_stream()); 681 682 SetDemuxerExpectations(&streams); 683 SetRendererExpectations(); 684 StartPipelineAndExpect(PIPELINE_OK); 685 686 // Trigger additional requests on the pipeline during tear down from error. 687 base::Callback<void(PipelineStatus)> cb = base::Bind( 688 &TestNoCallsAfterError, pipeline_.get(), &message_loop_); 689 ON_CALL(callbacks_, OnError(_)) 690 .WillByDefault(Invoke(&cb, &base::Callback<void(PipelineStatus)>::Run)); 691 692 base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5); 693 694 // Seek() isn't called as the demuxer errors out first. 695 EXPECT_CALL(*renderer_, Flush(_)) 696 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_, 697 BUFFERING_HAVE_NOTHING), 698 RunClosure<0>())); 699 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); 700 701 EXPECT_CALL(*demuxer_, Seek(seek_time, _)) 702 .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ)); 703 EXPECT_CALL(*demuxer_, Stop()); 704 705 pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek, 706 base::Unretained(&callbacks_))); 707 EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ)); 708 message_loop_.RunUntilIdle(); 709} 710 711TEST_F(PipelineTest, DestroyAfterStop) { 712 CreateAudioStream(); 713 MockDemuxerStreamVector streams; 714 streams.push_back(audio_stream()); 715 SetDemuxerExpectations(&streams); 716 SetRendererExpectations(); 717 StartPipelineAndExpect(PIPELINE_OK); 718 719 ExpectDemuxerStop(); 720 721 ExpectPipelineStopAndDestroyPipeline(); 722 pipeline_->Stop( 723 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_))); 724 message_loop_.RunUntilIdle(); 725} 726 727TEST_F(PipelineTest, Underflow) { 728 CreateAudioStream(); 729 CreateVideoStream(); 730 MockDemuxerStreamVector streams; 731 streams.push_back(audio_stream()); 732 streams.push_back(video_stream()); 733 734 SetDemuxerExpectations(&streams); 735 SetRendererExpectations(); 736 StartPipelineAndExpect(PIPELINE_OK); 737 738 // Simulate underflow. 739 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); 740 buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING); 741 742 // Seek while underflowed. 743 base::TimeDelta expected = base::TimeDelta::FromSeconds(5); 744 ExpectSeek(expected, true); 745 DoSeek(expected); 746} 747 748TEST_F(PipelineTest, PositiveStartTime) { 749 start_time_ = base::TimeDelta::FromSeconds(1); 750 EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_)); 751 CreateAudioStream(); 752 MockDemuxerStreamVector streams; 753 streams.push_back(audio_stream()); 754 SetDemuxerExpectations(&streams); 755 SetRendererExpectations(); 756 StartPipelineAndExpect(PIPELINE_OK); 757 ExpectDemuxerStop(); 758 ExpectPipelineStopAndDestroyPipeline(); 759 pipeline_->Stop( 760 base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_))); 761 message_loop_.RunUntilIdle(); 762} 763 764class PipelineTeardownTest : public PipelineTest { 765 public: 766 enum TeardownState { 767 kInitDemuxer, 768 kInitRenderer, 769 kFlushing, 770 kSeeking, 771 kPlaying, 772 }; 773 774 enum StopOrError { 775 kStop, 776 kError, 777 kErrorAndStop, 778 }; 779 780 PipelineTeardownTest() {} 781 virtual ~PipelineTeardownTest() {} 782 783 void RunTest(TeardownState state, StopOrError stop_or_error) { 784 switch (state) { 785 case kInitDemuxer: 786 case kInitRenderer: 787 DoInitialize(state, stop_or_error); 788 break; 789 790 case kFlushing: 791 case kSeeking: 792 DoInitialize(state, stop_or_error); 793 DoSeek(state, stop_or_error); 794 break; 795 796 case kPlaying: 797 DoInitialize(state, stop_or_error); 798 DoStopOrError(stop_or_error); 799 break; 800 } 801 } 802 803 private: 804 // TODO(scherkus): We do radically different things whether teardown is 805 // invoked via stop vs error. The teardown path should be the same, 806 // see http://crbug.com/110228 807 void DoInitialize(TeardownState state, StopOrError stop_or_error) { 808 PipelineStatus expected_status = 809 SetInitializeExpectations(state, stop_or_error); 810 811 EXPECT_CALL(callbacks_, OnStart(expected_status)); 812 StartPipeline(); 813 message_loop_.RunUntilIdle(); 814 } 815 816 PipelineStatus SetInitializeExpectations(TeardownState state, 817 StopOrError stop_or_error) { 818 PipelineStatus status = PIPELINE_OK; 819 base::Closure stop_cb = base::Bind( 820 &CallbackHelper::OnStop, base::Unretained(&callbacks_)); 821 822 if (state == kInitDemuxer) { 823 if (stop_or_error == kStop) { 824 EXPECT_CALL(*demuxer_, Initialize(_, _, _)) 825 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), 826 RunCallback<1>(PIPELINE_OK))); 827 ExpectPipelineStopAndDestroyPipeline(); 828 } else { 829 status = DEMUXER_ERROR_COULD_NOT_OPEN; 830 EXPECT_CALL(*demuxer_, Initialize(_, _, _)) 831 .WillOnce(RunCallback<1>(status)); 832 } 833 834 EXPECT_CALL(*demuxer_, Stop()); 835 return status; 836 } 837 838 CreateAudioStream(); 839 CreateVideoStream(); 840 MockDemuxerStreamVector streams; 841 streams.push_back(audio_stream()); 842 streams.push_back(video_stream()); 843 SetDemuxerExpectations(&streams, base::TimeDelta::FromSeconds(3000)); 844 845 EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(true)); 846 EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(true)); 847 848 if (state == kInitRenderer) { 849 if (stop_or_error == kStop) { 850 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _)) 851 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), 852 RunCallback<0>())); 853 ExpectPipelineStopAndDestroyPipeline(); 854 } else { 855 status = PIPELINE_ERROR_INITIALIZATION_FAILED; 856 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _)) 857 .WillOnce(DoAll(RunCallback<3>(status), RunCallback<0>())); 858 } 859 860 EXPECT_CALL(*demuxer_, Stop()); 861 return status; 862 } 863 864 EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _)) 865 .WillOnce(DoAll(SaveArg<4>(&buffering_state_cb_), 866 RunCallback<0>())); 867 868 EXPECT_CALL(callbacks_, OnMetadata(_)); 869 870 // If we get here it's a successful initialization. 871 EXPECT_CALL(*renderer_, SetPlaybackRate(0.0f)); 872 EXPECT_CALL(*renderer_, SetVolume(1.0f)); 873 EXPECT_CALL(*renderer_, StartPlayingFrom(base::TimeDelta())) 874 .WillOnce(SetBufferingState(&buffering_state_cb_, 875 BUFFERING_HAVE_ENOUGH)); 876 877 if (status == PIPELINE_OK) 878 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH)); 879 880 return status; 881 } 882 883 void DoSeek(TeardownState state, StopOrError stop_or_error) { 884 InSequence s; 885 PipelineStatus status = SetSeekExpectations(state, stop_or_error); 886 887 EXPECT_CALL(*demuxer_, Stop()); 888 EXPECT_CALL(callbacks_, OnSeek(status)); 889 890 if (status == PIPELINE_OK) { 891 ExpectPipelineStopAndDestroyPipeline(); 892 } 893 894 pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind( 895 &CallbackHelper::OnSeek, base::Unretained(&callbacks_))); 896 message_loop_.RunUntilIdle(); 897 } 898 899 PipelineStatus SetSeekExpectations(TeardownState state, 900 StopOrError stop_or_error) { 901 PipelineStatus status = PIPELINE_OK; 902 base::Closure stop_cb = base::Bind( 903 &CallbackHelper::OnStop, base::Unretained(&callbacks_)); 904 905 if (state == kFlushing) { 906 if (stop_or_error == kStop) { 907 EXPECT_CALL(*renderer_, Flush(_)) 908 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), 909 SetBufferingState(&buffering_state_cb_, 910 BUFFERING_HAVE_NOTHING), 911 RunClosure<0>())); 912 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); 913 } else { 914 status = PIPELINE_ERROR_READ; 915 EXPECT_CALL(*renderer_, Flush(_)) 916 .WillOnce(DoAll(SetError(pipeline_.get(), status), 917 SetBufferingState(&buffering_state_cb_, 918 BUFFERING_HAVE_NOTHING), 919 RunClosure<0>())); 920 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); 921 } 922 923 return status; 924 } 925 926 EXPECT_CALL(*renderer_, Flush(_)) 927 .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_, 928 BUFFERING_HAVE_NOTHING), 929 RunClosure<0>())); 930 EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); 931 932 if (state == kSeeking) { 933 if (stop_or_error == kStop) { 934 EXPECT_CALL(*demuxer_, Seek(_, _)) 935 .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb), 936 RunCallback<1>(PIPELINE_OK))); 937 } else { 938 status = PIPELINE_ERROR_READ; 939 EXPECT_CALL(*demuxer_, Seek(_, _)) 940 .WillOnce(RunCallback<1>(status)); 941 } 942 943 return status; 944 } 945 946 NOTREACHED() << "State not supported: " << state; 947 return status; 948 } 949 950 void DoStopOrError(StopOrError stop_or_error) { 951 InSequence s; 952 953 EXPECT_CALL(*demuxer_, Stop()); 954 955 switch (stop_or_error) { 956 case kStop: 957 ExpectPipelineStopAndDestroyPipeline(); 958 pipeline_->Stop(base::Bind( 959 &CallbackHelper::OnStop, base::Unretained(&callbacks_))); 960 break; 961 962 case kError: 963 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ)); 964 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ); 965 break; 966 967 case kErrorAndStop: 968 EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_READ)); 969 ExpectPipelineStopAndDestroyPipeline(); 970 pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ); 971 message_loop_.RunUntilIdle(); 972 pipeline_->Stop(base::Bind( 973 &CallbackHelper::OnStop, base::Unretained(&callbacks_))); 974 break; 975 } 976 977 message_loop_.RunUntilIdle(); 978 } 979 980 DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest); 981}; 982 983#define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \ 984 TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \ 985 RunTest(k##state, k##stop_or_error); \ 986 } 987 988INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer); 989INSTANTIATE_TEARDOWN_TEST(Stop, InitRenderer); 990INSTANTIATE_TEARDOWN_TEST(Stop, Flushing); 991INSTANTIATE_TEARDOWN_TEST(Stop, Seeking); 992INSTANTIATE_TEARDOWN_TEST(Stop, Playing); 993 994INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer); 995INSTANTIATE_TEARDOWN_TEST(Error, InitRenderer); 996INSTANTIATE_TEARDOWN_TEST(Error, Flushing); 997INSTANTIATE_TEARDOWN_TEST(Error, Seeking); 998INSTANTIATE_TEARDOWN_TEST(Error, Playing); 999 1000INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing); 1001 1002} // namespace media 1003