| Index: content/renderer/media/webmediaplayer_ms_unittest.cc | 
| diff --git a/content/renderer/media/webmediaplayer_ms_unittest.cc b/content/renderer/media/webmediaplayer_ms_unittest.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..876d2f8d71594dd2bf4a1f7d281ee7130ab2c412 | 
| --- /dev/null | 
| +++ b/content/renderer/media/webmediaplayer_ms_unittest.cc | 
| @@ -0,0 +1,638 @@ | 
| +// Copyright 2015 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| +#include "content/public/renderer/media_stream_renderer_factory.h" | 
| +#include "content/renderer/media/webmediaplayer_ms.h" | 
| +#include "content/renderer/media/webmediaplayer_ms_compositor.h" | 
| +#include "content/renderer/render_frame_impl.h" | 
| +#include "media/base/test_helpers.h" | 
| +#include "media/base/video_frame.h" | 
| +#include "third_party/WebKit/public/platform/WebMediaPlayer.h" | 
| +#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" | 
| + | 
| +namespace content { | 
| + | 
| +enum class FrameType { | 
| +  NORMAL_FRAME = 0, | 
| +  BROKEN_FRAME = -1, | 
| +  TEST_BRAKE = -2,  // Signal to pause message loop. | 
| +  MIN_TYPE = TEST_BRAKE | 
| +}; | 
| + | 
| +using TestFrame = std::pair<FrameType, scoped_refptr<media::VideoFrame>>; | 
| + | 
| +class ReusableMessageLoopEvent { | 
| + public: | 
| +  ReusableMessageLoopEvent() : event_(new media::WaitableMessageLoopEvent()) {} | 
| + | 
| +  base::Closure GetClosure() const { return event_->GetClosure(); } | 
| + | 
| +  media::PipelineStatusCB GetPipelineStatusCB() const { | 
| +    return event_->GetPipelineStatusCB(); | 
| +  } | 
| + | 
| +  void RunAndWait() { | 
| +    event_->RunAndWait(); | 
| +    event_.reset(new media::WaitableMessageLoopEvent()); | 
| +  } | 
| + | 
| +  void RunAndWaitForStatus(media::PipelineStatus expected) { | 
| +    event_->RunAndWaitForStatus(expected); | 
| +    event_.reset(new media::WaitableMessageLoopEvent()); | 
| +  } | 
| + | 
| + private: | 
| +  scoped_ptr<media::WaitableMessageLoopEvent> event_; | 
| +}; | 
| + | 
| +// The class is used mainly to inject VideoFrames into WebMediaPlayerMS. | 
| +class MockVideoFrameProvider : public VideoFrameProvider { | 
| + public: | 
| +  MockVideoFrameProvider( | 
| +      const scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 
| +      ReusableMessageLoopEvent* message_loop_controller, | 
| +      const base::Closure& error_cb, | 
| +      const VideoFrameProvider::RepaintCB& repaint_cb) | 
| +      : started_(false), | 
| +        task_runner_(task_runner), | 
| +        message_loop_controller_(message_loop_controller), | 
| +        error_cb_(error_cb), | 
| +        repaint_cb_(repaint_cb), | 
| +        delay_till_next_generated_frame_( | 
| +            base::TimeDelta::FromSecondsD(1.0 / 30.0)) {} | 
| + | 
| +  // Implementation of VideoFrameProvider | 
| +  void Start() override; | 
| +  void Stop() override; | 
| +  void Play() override; | 
| +  void Pause() override; | 
| + | 
| +  // Methods for test use | 
| +  void QueueFrames(const std::vector<int>& timestamps_or_frame_type); | 
| +  bool Started() { return started_; } | 
| +  bool Paused() { return paused_; } | 
| + | 
| + private: | 
| +  ~MockVideoFrameProvider() override {} | 
| + | 
| +  // Main function that pushes a frame into WebMediaPlayerMS | 
| +  void InjectFrame(); | 
| + | 
| +  // Methods for test use | 
| +  void AddFrame(FrameType category, | 
| +                const scoped_refptr<media::VideoFrame>& frame); | 
| + | 
| +  bool started_; | 
| +  bool paused_; | 
| + | 
| +  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 
| +  ReusableMessageLoopEvent* const message_loop_controller_; | 
| +  const base::Closure error_cb_; | 
| +  const VideoFrameProvider::RepaintCB repaint_cb_; | 
| + | 
| +  std::deque<TestFrame> frames_; | 
| +  base::TimeDelta delay_till_next_generated_frame_; | 
| +}; | 
| + | 
| +void MockVideoFrameProvider::Start() { | 
| +  started_ = true; | 
| +  paused_ = false; | 
| +  task_runner_->PostTask( | 
| +      FROM_HERE, | 
| +      base::Bind(&MockVideoFrameProvider::InjectFrame, base::Unretained(this))); | 
| +} | 
| + | 
| +void MockVideoFrameProvider::Stop() { | 
| +  started_ = false; | 
| +  frames_.clear(); | 
| +} | 
| + | 
| +void MockVideoFrameProvider::Play() { | 
| +  CHECK(started_); | 
| +  paused_ = false; | 
| +} | 
| + | 
| +void MockVideoFrameProvider::Pause() { | 
| +  CHECK(started_); | 
| +  paused_ = true; | 
| +} | 
| + | 
| +void MockVideoFrameProvider::AddFrame( | 
| +    FrameType category, | 
| +    const scoped_refptr<media::VideoFrame>& frame) { | 
| +  frames_.push_back(std::make_pair(category, frame)); | 
| +} | 
| + | 
| +void MockVideoFrameProvider::QueueFrames( | 
| +    const std::vector<int>& timestamp_or_frame_type) { | 
| +  for (const int token : timestamp_or_frame_type) { | 
| +    if (token < static_cast<int>(FrameType::MIN_TYPE)) { | 
| +      CHECK(false) << "Unrecognized frame type: " << token; | 
| +      return; | 
| +    } | 
| + | 
| +    if (token < 0) { | 
| +      AddFrame(static_cast<FrameType>(token), nullptr); | 
| +      continue; | 
| +    } | 
| + | 
| +    if (token >= 0) { | 
| +      gfx::Size natural_size = media::TestVideoConfig::NormalCodedSize(); | 
| +      auto frame = media::VideoFrame::CreateFrame( | 
| +          media::PIXEL_FORMAT_YV12, natural_size, gfx::Rect(natural_size), | 
| +          natural_size, base::TimeDelta::FromMilliseconds(token)); | 
| + | 
| +      frame->metadata()->SetTimeTicks( | 
| +          media::VideoFrameMetadata::Key::REFERENCE_TIME, | 
| +          base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(token)); | 
| + | 
| +      AddFrame(FrameType::NORMAL_FRAME, frame); | 
| +      continue; | 
| +    } | 
| +  } | 
| +} | 
| + | 
| +void MockVideoFrameProvider::InjectFrame() { | 
| +  DCHECK(task_runner_->BelongsToCurrentThread()); | 
| +  if (!started_) | 
| +    return; | 
| + | 
| +  if (frames_.empty()) { | 
| +    message_loop_controller_->GetClosure().Run(); | 
| +    return; | 
| +  } | 
| + | 
| +  auto frame = frames_.front(); | 
| +  frames_.pop_front(); | 
| + | 
| +  if (frame.first == FrameType::BROKEN_FRAME) { | 
| +    error_cb_.Run(); | 
| +    return; | 
| +  } | 
| + | 
| +  // For pause case, the provider will still let the stream continue, but | 
| +  // not send the frames to the player. As is the same case in reality. | 
| +  if (frame.first == FrameType::NORMAL_FRAME) { | 
| +    if (!paused_) | 
| +      repaint_cb_.Run(frame.second); | 
| + | 
| +    for (size_t i = 0; i < frames_.size(); ++i) { | 
| +      if (frames_[i].first == FrameType::NORMAL_FRAME) { | 
| +        delay_till_next_generated_frame_ = | 
| +            (frames_[i].second->timestamp() - frame.second->timestamp()) / | 
| +            (i + 1); | 
| +        break; | 
| +      } | 
| +    } | 
| +  } | 
| + | 
| +  task_runner_->PostDelayedTask( | 
| +      FROM_HERE, | 
| +      base::Bind(&MockVideoFrameProvider::InjectFrame, base::Unretained(this)), | 
| +      delay_till_next_generated_frame_); | 
| + | 
| +  // This will pause the |message_loop_|, and the purpose is to allow the main | 
| +  // test function to do some operations (e.g. call pause(), switch to | 
| +  // background rendering, etc) on WebMediaPlayerMS before resuming | 
| +  // |message_loop_|. | 
| +  if (frame.first == FrameType::TEST_BRAKE) | 
| +    message_loop_controller_->GetClosure().Run(); | 
| +} | 
| + | 
| +// The class is used to generate a MockVideoProvider in | 
| +// WebMediaPlayerMS::load(). | 
| +class MockRenderFactory : public MediaStreamRendererFactory { | 
| + public: | 
| +  MockRenderFactory( | 
| +      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 
| +      ReusableMessageLoopEvent* message_loop_controller) | 
| +      : task_runner_(task_runner), | 
| +        message_loop_controller_(message_loop_controller) {} | 
| + | 
| +  scoped_refptr<VideoFrameProvider> GetVideoFrameProvider( | 
| +      const GURL& url, | 
| +      const base::Closure& error_cb, | 
| +      const VideoFrameProvider::RepaintCB& repaint_cb, | 
| +      const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 
| +      const scoped_refptr<base::TaskRunner>& worker_task_runner, | 
| +      media::GpuVideoAcceleratorFactories* gpu_factories) override; | 
| + | 
| +  MockVideoFrameProvider* provider() { | 
| +    return static_cast<MockVideoFrameProvider*>(provider_.get()); | 
| +  } | 
| + | 
| +  scoped_refptr<MediaStreamAudioRenderer> GetAudioRenderer( | 
| +      const GURL& url, | 
| +      int render_frame_id, | 
| +      const std::string& device_id, | 
| +      const url::Origin& security_origin) override { | 
| +    return nullptr; | 
| +  } | 
| + | 
| + private: | 
| +  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 
| +  scoped_refptr<VideoFrameProvider> provider_; | 
| +  ReusableMessageLoopEvent* const message_loop_controller_; | 
| +}; | 
| + | 
| +scoped_refptr<VideoFrameProvider> MockRenderFactory::GetVideoFrameProvider( | 
| +    const GURL& url, | 
| +    const base::Closure& error_cb, | 
| +    const VideoFrameProvider::RepaintCB& repaint_cb, | 
| +    const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 
| +    const scoped_refptr<base::TaskRunner>& worker_task_runner, | 
| +    media::GpuVideoAcceleratorFactories* gpu_factories) { | 
| +  provider_ = new MockVideoFrameProvider(task_runner_, message_loop_controller_, | 
| +                                         error_cb, repaint_cb); | 
| + | 
| +  return provider_; | 
| +} | 
| + | 
| +// This is the main class coordinating the tests. | 
| +// Basic workflow: | 
| +// 1. WebMediaPlayerMS::Load will generate and start | 
| +// content::VideoFrameProvider. | 
| +// 2. content::VideoFrameProvider will start pushing frames into | 
| +//    WebMediaPlayerMS repeatedly. | 
| +// 3. On WebMediaPlayerMS receiving the first frame, a WebLayer will be created. | 
| +// 4. The WebLayer will call | 
| +//    WebMediaPlayerMSCompositor::SetVideoFrameProviderClient, which in turn | 
| +//    will trigger cc::VideoFrameProviderClient::StartRendering. | 
| +// 5. Then cc::VideoFrameProviderClient will start calling | 
| +//    WebMediaPlayerMSCompositor::UpdateCurrentFrame, GetCurrentFrame for | 
| +//    rendering repeatedly. | 
| +// 6. When WebMediaPlayerMS::pause gets called, it should trigger | 
| +//    content::VideoFrameProvider::Pause, and then the provider will stop | 
| +//    pushing frames into WebMediaPlayerMS, but instead digesting them; | 
| +//    simultanously, it should call cc::VideoFrameProviderClient::StopRendering, | 
| +//    so cc::VideoFrameProviderClient will stop asking frames from | 
| +//    WebMediaPlayerMSCompositor. | 
| +// 7. When WebMediaPlayerMS::play gets called, evething paused in step 6 should | 
| +//    be resumed. | 
| +class WebMediaPlayerMSTest : public testing::Test, | 
| +                             public blink::WebMediaPlayerClient, | 
| +                             public cc::VideoFrameProvider::Client { | 
| + public: | 
| +  WebMediaPlayerMSTest() | 
| +      : render_factory_(new MockRenderFactory(message_loop_.task_runner(), | 
| +                                              &message_loop_controller_)), | 
| +        player_(nullptr, | 
| +                this, | 
| +                base::WeakPtr<media::WebMediaPlayerDelegate>(), | 
| +                new media::MediaLog(), | 
| +                scoped_ptr<MediaStreamRendererFactory>(render_factory_), | 
| +                message_loop_.task_runner(), | 
| +                message_loop_.task_runner(), | 
| +                message_loop_.task_runner(), | 
| +                nullptr, | 
| +                blink::WebString(), | 
| +                blink::WebSecurityOrigin()), | 
| +        rendering_(false) {} | 
| +  ~WebMediaPlayerMSTest() override {} | 
| + | 
| +  MockVideoFrameProvider* LoadAndGetFrameProvider(bool algorithm_enabled); | 
| + | 
| +  // Implementation of WebMediaPlayerClient | 
| +  void networkStateChanged() override; | 
| +  void readyStateChanged() override; | 
| +  void timeChanged() override {} | 
| +  void repaint() override {} | 
| +  void durationChanged() override {} | 
| +  void sizeChanged() override {} | 
| +  void playbackStateChanged() override {} | 
| +  void setWebLayer(blink::WebLayer* layer) override; | 
| +  blink::WebMediaPlayer::TrackId addAudioTrack(const blink::WebString& id, | 
| +                                               AudioTrackKind, | 
| +                                               const blink::WebString& label, | 
| +                                               const blink::WebString& language, | 
| +                                               bool enabled) override { | 
| +    return 0; | 
| +  } | 
| +  void removeAudioTrack(blink::WebMediaPlayer::TrackId) override {} | 
| +  blink::WebMediaPlayer::TrackId addVideoTrack(const blink::WebString& id, | 
| +                                               VideoTrackKind, | 
| +                                               const blink::WebString& label, | 
| +                                               const blink::WebString& language, | 
| +                                               bool selected) override { | 
| +    return 0; | 
| +  } | 
| +  void removeVideoTrack(blink::WebMediaPlayer::TrackId) override {} | 
| +  void addTextTrack(blink::WebInbandTextTrack*) override {} | 
| +  void removeTextTrack(blink::WebInbandTextTrack*) override {} | 
| +  void mediaSourceOpened(blink::WebMediaSource*) override {} | 
| +  void requestSeek(double) override {} | 
| +  void remoteRouteAvailabilityChanged(bool) override {} | 
| +  void connectedToRemoteDevice() override {} | 
| +  void disconnectedFromRemoteDevice() override {} | 
| + | 
| +  // Implementation of cc::VideoFrameProvider::Client | 
| +  void StopUsingProvider() override; | 
| +  void StartRendering() override; | 
| +  void StopRendering() override; | 
| +  void DidReceiveFrame() override {} | 
| +  void DidUpdateMatrix(const float* matrix) override {} | 
| + | 
| +  // For test use | 
| +  void SetBackgroundRendering(bool background_rendering) { | 
| +    background_rendering_ = background_rendering; | 
| +  } | 
| + | 
| + protected: | 
| +  MOCK_METHOD0(DoStartRendering, void()); | 
| +  MOCK_METHOD0(DoStopRendering, void()); | 
| + | 
| +  MOCK_METHOD1(DoSetWebLayer, void(bool)); | 
| +  MOCK_METHOD1(DoNetworkStateChanged, | 
| +               void(blink::WebMediaPlayer::NetworkState)); | 
| +  MOCK_METHOD1(DoReadyStateChanged, void(blink::WebMediaPlayer::ReadyState)); | 
| + | 
| +  base::MessageLoop message_loop_; | 
| +  MockRenderFactory* render_factory_; | 
| +  WebMediaPlayerMS player_; | 
| +  WebMediaPlayerMSCompositor* compositor_; | 
| +  ReusableMessageLoopEvent message_loop_controller_; | 
| + | 
| + private: | 
| +  // Main function trying to ask WebMediaPlayerMS to submit a frame for | 
| +  // rendering. | 
| +  void RenderFrame(); | 
| + | 
| +  bool rendering_; | 
| +  bool background_rendering_; | 
| +}; | 
| + | 
| +MockVideoFrameProvider* WebMediaPlayerMSTest::LoadAndGetFrameProvider( | 
| +    bool algorithm_enabled) { | 
| +  EXPECT_FALSE(!!render_factory_->provider()) << "There should not be a " | 
| +                                                 "FrameProvider yet."; | 
| + | 
| +  EXPECT_CALL( | 
| +      *this, DoNetworkStateChanged(blink::WebMediaPlayer::NetworkStateLoading)); | 
| +  EXPECT_CALL( | 
| +      *this, DoReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveNothing)); | 
| +  player_.load(blink::WebMediaPlayer::LoadTypeURL, blink::WebURL(), | 
| +               blink::WebMediaPlayer::CORSModeUnspecified); | 
| +  compositor_ = player_.compositor_.get(); | 
| +  EXPECT_TRUE(!!compositor_); | 
| +  compositor_->SetAlgorithmEnabledForTesting(algorithm_enabled); | 
| + | 
| +  MockVideoFrameProvider* const provider = render_factory_->provider(); | 
| +  EXPECT_TRUE(!!provider); | 
| +  EXPECT_TRUE(provider->Started()); | 
| + | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| +  return provider; | 
| +} | 
| + | 
| +void WebMediaPlayerMSTest::networkStateChanged() { | 
| +  blink::WebMediaPlayer::NetworkState state = player_.networkState(); | 
| +  DoNetworkStateChanged(state); | 
| +  if (state == blink::WebMediaPlayer::NetworkState::NetworkStateFormatError || | 
| +      state == blink::WebMediaPlayer::NetworkState::NetworkStateDecodeError || | 
| +      state == blink::WebMediaPlayer::NetworkState::NetworkStateNetworkError) { | 
| +    message_loop_controller_.GetPipelineStatusCB().Run( | 
| +        media::PipelineStatus::PIPELINE_ERROR_NETWORK); | 
| +  } | 
| +} | 
| + | 
| +void WebMediaPlayerMSTest::readyStateChanged() { | 
| +  blink::WebMediaPlayer::ReadyState state = player_.readyState(); | 
| +  DoReadyStateChanged(state); | 
| +  if (state == blink::WebMediaPlayer::ReadyState::ReadyStateHaveEnoughData) | 
| +    player_.play(); | 
| +} | 
| + | 
| +void WebMediaPlayerMSTest::setWebLayer(blink::WebLayer* layer) { | 
| +  if (layer) | 
| +    compositor_->SetVideoFrameProviderClient(this); | 
| +  DoSetWebLayer(!!layer); | 
| +} | 
| + | 
| +void WebMediaPlayerMSTest::StopUsingProvider() { | 
| +  if (rendering_) | 
| +    StopRendering(); | 
| +} | 
| + | 
| +void WebMediaPlayerMSTest::StartRendering() { | 
| +  if (!rendering_) { | 
| +    rendering_ = true; | 
| +    message_loop_.PostTask( | 
| +        FROM_HERE, | 
| +        base::Bind(&WebMediaPlayerMSTest::RenderFrame, base::Unretained(this))); | 
| +  } | 
| +  DoStartRendering(); | 
| +} | 
| + | 
| +void WebMediaPlayerMSTest::StopRendering() { | 
| +  rendering_ = false; | 
| +  DoStopRendering(); | 
| +} | 
| + | 
| +void WebMediaPlayerMSTest::RenderFrame() { | 
| +  if (!rendering_ || !compositor_) | 
| +    return; | 
| + | 
| +  base::TimeTicks now = base::TimeTicks::Now(); | 
| +  base::TimeTicks deadline_min = | 
| +      now + base::TimeDelta::FromSecondsD(1.0 / 60.0); | 
| +  base::TimeTicks deadline_max = | 
| +      deadline_min + base::TimeDelta::FromSecondsD(1.0 / 60.0); | 
| + | 
| +  // Background rendering is different from stop rendering. The rendering loop | 
| +  // is still running but we do not ask frames from |compositor_|. And | 
| +  // background rendering is not initiated from |compositor_|. | 
| +  if (!background_rendering_) { | 
| +    compositor_->UpdateCurrentFrame(deadline_min, deadline_max); | 
| +    auto frame = compositor_->GetCurrentFrame(); | 
| +    compositor_->PutCurrentFrame(); | 
| +  } | 
| +  message_loop_.PostDelayedTask( | 
| +      FROM_HERE, | 
| +      base::Bind(&WebMediaPlayerMSTest::RenderFrame, base::Unretained(this)), | 
| +      base::TimeDelta::FromSecondsD(1.0 / 60.0)); | 
| +} | 
| + | 
| +TEST_F(WebMediaPlayerMSTest, Playing_Normal) { | 
| +  // This test sends a bunch of normal frames with increasing timestamps | 
| +  // and verifies that they are produced by WebMediaPlayerMS in appropriate | 
| +  // order. | 
| + | 
| +  MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); | 
| + | 
| +  int tokens[] = {0,   33,  66,  100, 133, 166, 200, 233, 266, 300, | 
| +                  333, 366, 400, 433, 466, 500, 533, 566, 600}; | 
| +  std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | 
| +  provider->QueueFrames(timestamps); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(true)); | 
| +  EXPECT_CALL(*this, DoStartRendering()); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveMetadata)); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(false)); | 
| +  EXPECT_CALL(*this, DoStopRendering()); | 
| +} | 
| + | 
| +TEST_F(WebMediaPlayerMSTest, Playing_ErrorFrame) { | 
| +  // This tests sends a broken frame to WebMediaPlayerMS, and verifies | 
| +  // OnSourceError function works as expected. | 
| + | 
| +  MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); | 
| + | 
| +  const int kBrokenFrame = static_cast<int>(FrameType::BROKEN_FRAME); | 
| +  int tokens[] = {0,   33,  66,  100, 133, 166, 200, 233, 266, 300, | 
| +                  333, 366, 400, 433, 466, 500, 533, 566, 600, kBrokenFrame}; | 
| +  std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | 
| +  provider->QueueFrames(timestamps); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(true)); | 
| +  EXPECT_CALL(*this, DoStartRendering()); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveMetadata)); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | 
| +  EXPECT_CALL(*this, DoNetworkStateChanged( | 
| +                         blink::WebMediaPlayer::NetworkStateFormatError)); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_ERROR_NETWORK); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(false)); | 
| +  EXPECT_CALL(*this, DoStopRendering()); | 
| +} | 
| + | 
| +TEST_F(WebMediaPlayerMSTest, PlayThenPause) { | 
| +  // In the middle of this test, WebMediaPlayerMS::pause will be called, and we | 
| +  // are going to verify that during the pause stage, a frame gets freezed, and | 
| +  // cc::VideoFrameProviderClient should also be paused. | 
| +  MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); | 
| + | 
| +  const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE); | 
| +  int tokens[] = {0,   33,  66,  100, 133, kTestBrake, 166, 200, 233, 266, | 
| +                  300, 333, 366, 400, 433, 466,        500, 533, 566, 600}; | 
| +  std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | 
| +  provider->QueueFrames(timestamps); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(true)); | 
| +  EXPECT_CALL(*this, DoStartRendering()); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveMetadata)); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  // Here we call pause, and expect a freezing frame. | 
| +  EXPECT_CALL(*this, DoStopRendering()); | 
| +  player_.pause(); | 
| +  auto prev_frame = compositor_->GetCurrentFrame(); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  auto after_frame = compositor_->GetCurrentFrame(); | 
| +  EXPECT_EQ(prev_frame->timestamp(), after_frame->timestamp()); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(false)); | 
| +} | 
| + | 
| +TEST_F(WebMediaPlayerMSTest, PlayThenPauseThenPlay) { | 
| +  // Similary to PlayAndPause test above, this one focuses on testing that | 
| +  // WebMediaPlayerMS can be resumed after a period of paused status. | 
| +  MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); | 
| + | 
| +  const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE); | 
| +  int tokens[] = {0,   33,         66,  100, 133, kTestBrake, 166, | 
| +                  200, 233,        266, 300, 333, 366,        400, | 
| +                  433, kTestBrake, 466, 500, 533, 566,        600}; | 
| +  std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | 
| +  provider->QueueFrames(timestamps); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(true)); | 
| +  EXPECT_CALL(*this, DoStartRendering()); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveMetadata)); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  // Here we call pause, and expect a freezing frame. | 
| +  EXPECT_CALL(*this, DoStopRendering()); | 
| +  player_.pause(); | 
| +  auto prev_frame = compositor_->GetCurrentFrame(); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  auto after_frame = compositor_->GetCurrentFrame(); | 
| +  EXPECT_EQ(prev_frame->timestamp(), after_frame->timestamp()); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  // We resume the player, and expect rendering can continue. | 
| +  EXPECT_CALL(*this, DoStartRendering()); | 
| +  player_.play(); | 
| +  prev_frame = compositor_->GetCurrentFrame(); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  after_frame = compositor_->GetCurrentFrame(); | 
| +  EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp()); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(false)); | 
| +  EXPECT_CALL(*this, DoStopRendering()); | 
| +} | 
| + | 
| +TEST_F(WebMediaPlayerMSTest, BackgroudRendering) { | 
| +  // During this test, we will switch to background rendering mode, in which | 
| +  // WebMediaPlayerMS::pause does not get called, but | 
| +  // cc::VideoFrameProviderClient simply stops asking frames from | 
| +  // WebMediaPlayerMS without an explicit notification. We should expect that | 
| +  // WebMediaPlayerMS can digest old frames, rather than piling frames up and | 
| +  // explode. | 
| +  MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); | 
| + | 
| +  const int kTestBrake = static_cast<int>(FrameType::TEST_BRAKE); | 
| +  int tokens[] = {0,   33,         66,  100, 133, kTestBrake, 166, | 
| +                  200, 233,        266, 300, 333, 366,        400, | 
| +                  433, kTestBrake, 466, 500, 533, 566,        600}; | 
| +  std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); | 
| +  provider->QueueFrames(timestamps); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(true)); | 
| +  EXPECT_CALL(*this, DoStartRendering()); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveMetadata)); | 
| +  EXPECT_CALL(*this, DoReadyStateChanged( | 
| +                         blink::WebMediaPlayer::ReadyStateHaveEnoughData)); | 
| + | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  // Switch to background rendering, expect rendering to continue. | 
| +  SetBackgroundRendering(true); | 
| +  auto prev_frame = compositor_->GetCurrentFrame(); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  auto after_frame = compositor_->GetCurrentFrame(); | 
| +  EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp()); | 
| + | 
| +  // Switch to foreground rendering. | 
| +  SetBackgroundRendering(false); | 
| +  prev_frame = compositor_->GetCurrentFrame(); | 
| +  message_loop_controller_.RunAndWaitForStatus( | 
| +      media::PipelineStatus::PIPELINE_OK); | 
| +  after_frame = compositor_->GetCurrentFrame(); | 
| +  EXPECT_NE(prev_frame->timestamp(), after_frame->timestamp()); | 
| +  testing::Mock::VerifyAndClearExpectations(this); | 
| + | 
| +  EXPECT_CALL(*this, DoSetWebLayer(false)); | 
| +  EXPECT_CALL(*this, DoStopRendering()); | 
| +} | 
| + | 
| +}  // namespace content | 
|  |