Chromium Code Reviews| 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..eeb8df0dcddf5b1a823a12a0f6a9d869e10a86a2 |
| --- /dev/null |
| +++ b/content/renderer/media/webmediaplayer_ms_unittest.cc |
| @@ -0,0 +1,700 @@ |
| +// 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 "base/bind.h" |
| +#include "base/logging.h" |
| +#include "base/message_loop/message_loop.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_split.h" |
| +#include "cc/layers/video_frame_provider.h" |
| +#include "content/public/renderer/media_stream_renderer_factory.h" |
| +#include "content/public/renderer/video_frame_provider.h" |
| +#include "content/renderer/media/mock_media_constraint_factory.h" |
| +#include "content/renderer/media/render_media_log.h" |
| +#include "content/renderer/media/webmediaplayer_ms.h" |
| +#include "content/renderer/media/webrtc_audio_renderer.h" |
| +#include "content/renderer/render_frame_impl.h" |
| +#include "media/base/gmock_callback_support.h" |
| +#include "media/base/mock_filters.h" |
| +#include "media/base/test_helpers.h" |
| +#include "media/base/video_frame.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +#include "third_party/WebKit/public/platform/WebMediaPlayer.h" |
| +#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" |
| +#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h" |
|
mcasas
2015/10/21 19:54:02
Needed?
(check all header please).
qiangchen
2015/10/22 17:22:58
Done.
Looks like many includes are included in te
|
| + |
| +namespace content { |
| + |
| +class WebMediaPlayerMSTest; |
| + |
| +class MockCB { |
|
mcasas
2015/10/21 19:54:02
There's indeed plenty of Mock/Test dependent class
qiangchen
2015/10/22 17:22:58
My investigation shows only content::VideoFramePro
|
| + public: |
| + MOCK_METHOD0(StartRendering, void()); |
| + MOCK_METHOD0(StopRendering, void()); |
| + |
| + MOCK_METHOD1(NetworkStateChanged, void(blink::WebMediaPlayer::NetworkState)); |
| + MOCK_METHOD1(ReadyStateChanged, void(blink::WebMediaPlayer::ReadyState)); |
| + void VerifyAndClearExpectations() { |
| + // Note: the raw value of "this" could be different from &mock_cb_. |
| + // So this is not equivalent with calling |
| + // VerifyAndClearExpectations(&mock_cb_) outside. |
| + testing::Mock::VerifyAndClearExpectations(this); |
| + } |
| +}; |
| + |
| +struct TestFrame { |
| + enum TestFrameType { |
| + NORMAL_FRAME, |
| + BROKEN_FRAME, |
| + TEST_BRAKE // Signal to pause message loop. |
| + }; |
| + TestFrame(TestFrameType input_category, |
| + const scoped_refptr<media::VideoFrame>& input_frame) |
| + : category(input_category), frame(input_frame) {} |
| + |
| + TestFrameType category; |
| + scoped_refptr<media::VideoFrame> frame; |
| +}; |
| + |
| +class ReusableMessageLoopEvent { |
| + public: |
| + ReusableMessageLoopEvent() : event_(new media::WaitableMessageLoopEvent()) {} |
| + |
| + base::Closure GetClosure() { return event_->GetClosure(); } |
| + |
| + media::PipelineStatusCB GetPipelineStatusCB() { |
| + 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 mainly used to inject VideoFrames into WebMediaPlayerMS. |
| +class MockVideoFrameProvider : public VideoFrameProvider { |
| + public: |
| + MockVideoFrameProvider(base::MessageLoop* message_loop, |
| + ReusableMessageLoopEvent* message_loop_controller, |
| + const base::Closure& error_cb, |
| + const VideoFrameProvider::RepaintCB& repaint_cb) |
| + : started_(false), |
| + message_loop_(message_loop), |
| + message_loop_controller_(message_loop_controller), |
| + error_cb_(error_cb), |
| + repaint_cb_(repaint_cb), |
| + delay_(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::string& str); |
|
mcasas
2015/10/21 19:54:02
I don't see much added value in creating/passing t
qiangchen
2015/10/22 17:22:58
Done.
|
| + void PrepareFrame(TestFrame::TestFrameType category, |
| + const scoped_refptr<media::VideoFrame>& frame); |
| + bool Started(); |
| + bool Paused(); |
| + |
| + private: |
| + ~MockVideoFrameProvider() override {} |
| + |
| + // Main function that pushes frame into WebMediaPlayerMS |
| + void InjectFrame(); |
| + |
| + bool started_; |
| + bool paused_; |
| + |
| + base::MessageLoop* message_loop_; |
| + ReusableMessageLoopEvent* message_loop_controller_; |
| + base::Closure error_cb_; |
| + VideoFrameProvider::RepaintCB repaint_cb_; |
| + |
| + std::deque<TestFrame> frames_; |
| + base::TimeDelta delay_; |
| +}; |
| + |
| +// The class is used to generate MockVideoProvider |
| +class MockRenderFactory : public MediaStreamRendererFactory { |
| + public: |
| + MockRenderFactory(base::MessageLoop* message_loop, |
| + ReusableMessageLoopEvent* message_loop_controller) |
| + : message_loop_(message_loop), |
| + 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* GetVideoFrameProvider(); |
| + |
| + scoped_refptr<MediaStreamAudioRenderer> GetAudioRenderer( |
| + const GURL& url, |
| + int render_frame_id, |
| + const std::string& device_id, |
| + const url::Origin& security_origin) override; |
| + |
| + private: |
| + base::MessageLoop* message_loop_; |
| + scoped_refptr<VideoFrameProvider> provider_; |
| + ReusableMessageLoopEvent* message_loop_controller_; |
| +}; |
| + |
| +// The class is responsible to pull frames from WebMediaPlayerMS |
| +class MockVideoFrameProviderClient : public cc::VideoFrameProvider::Client { |
| + public: |
| + MockVideoFrameProviderClient(base::MessageLoop* message_loop, |
| + cc::VideoFrameProvider* compositor, |
| + MockCB* mock_cb) |
| + : rendering_(false), |
| + background_rendering_(false), |
| + message_loop_(message_loop), |
| + compositor_(compositor), |
| + mock_cb_(mock_cb) {} |
| + |
| + // 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); |
| + |
| + private: |
| + // Main function trying to ask WebMediaPlayerMS to submit a frame for |
| + // rendering. |
| + void RenderFrame(); |
| + |
| + bool rendering_; |
| + bool background_rendering_; |
| + base::MessageLoop* message_loop_; |
| + cc::VideoFrameProvider* compositor_; |
| + MockCB* mock_cb_; |
| +}; |
| + |
| +// This class is used to respond to WebMediaPlayerMS status change. |
| +class MockClient : public blink::WebMediaPlayerClient { |
| + public: |
| + MockClient(WebMediaPlayerMSTest* test, |
| + WebMediaPlayerMS* player, |
| + base::MessageLoop* message_loop, |
| + ReusableMessageLoopEvent* message_loop_controller) |
| + : test_(test), |
| + player_(player), |
| + message_loop_(message_loop), |
| + message_loop_controller_(message_loop_controller), |
| + compositor_(nullptr) {} |
| + ~MockClient() {} |
| + |
| + // 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; |
| + 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; |
| + 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 {} |
| + |
| + // For test use |
| + MockVideoFrameProviderClient* GetVideoFrameProviderClient(); |
| + |
| + private: |
| + WebMediaPlayerMSTest* test_; |
| + WebMediaPlayerMS* player_; |
| + base::MessageLoop* message_loop_; |
| + ReusableMessageLoopEvent* message_loop_controller_; |
| + cc::VideoFrameProvider* compositor_; |
| + scoped_ptr<MockVideoFrameProviderClient> video_frame_provider_client_; |
| +}; |
| + |
| +class WebMediaPlayerMSTest : public testing::Test { |
| + public: |
| + WebMediaPlayerMSTest() |
| + : client_(this, &player_, &message_loop_, &message_loop_controller_), |
| + render_factory_( |
| + new MockRenderFactory(&message_loop_, &message_loop_controller_)), |
| + player_(nullptr, |
| + &client_, |
| + base::WeakPtr<RenderFrameImpl>(), |
| + new media::MediaLog(), |
| + scoped_ptr<MediaStreamRendererFactory>(render_factory_), |
| + message_loop_.task_runner(), |
| + message_loop_.task_runner(), |
| + message_loop_.task_runner(), |
| + nullptr) {} |
| + ~WebMediaPlayerMSTest() override {} |
| + |
| + MockVideoFrameProvider* LoadAndGetFrameProvider(bool algorithm_enabled); |
| + cc::VideoFrameProvider* GetCompositorForTest(); |
| + MockCB* GetMockCB(); |
| + |
| + protected: |
| + // Use StrictMock<T> to catch missing/extra callbacks. |
| + testing::StrictMock<MockCB> mock_cb_; |
| + |
| + base::MessageLoop message_loop_; |
| + MockClient client_; |
| + MockRenderFactory* render_factory_; |
| + WebMediaPlayerMS player_; |
| + cc::VideoFrameProvider* compositor_; |
| + |
| + ReusableMessageLoopEvent message_loop_controller_; |
| +}; |
| + |
| +MockVideoFrameProvider* WebMediaPlayerMSTest::LoadAndGetFrameProvider( |
| + bool algorithm_enabled) { |
| + MockVideoFrameProvider* provider = render_factory_->GetVideoFrameProvider(); |
| + EXPECT_EQ(nullptr, provider); |
| + |
| + EXPECT_CALL(mock_cb_, |
| + NetworkStateChanged(blink::WebMediaPlayer::NetworkStateLoading)); |
| + EXPECT_CALL(mock_cb_, |
| + ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveNothing)); |
| + compositor_ = player_.LoadForTesting(algorithm_enabled); |
| + |
| + provider = render_factory_->GetVideoFrameProvider(); |
| + EXPECT_NE(nullptr, provider); |
| + EXPECT_TRUE(provider->Started()); |
| + |
| + mock_cb_.VerifyAndClearExpectations(); |
| + return provider; |
| +} |
| + |
| +cc::VideoFrameProvider* WebMediaPlayerMSTest::GetCompositorForTest() { |
| + return compositor_; |
| +} |
| + |
| +MockCB* WebMediaPlayerMSTest::GetMockCB() { |
| + return &mock_cb_; |
| +} |
| + |
| +void MockVideoFrameProvider::Start() { |
| + started_ = true; |
| + paused_ = false; |
| + message_loop_->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::PrepareFrame( |
| + TestFrame::TestFrameType category, |
| + const scoped_refptr<media::VideoFrame>& frame) { |
| + frames_.push_back(TestFrame(category, frame)); |
| +} |
| + |
| +void MockVideoFrameProvider::QueueFrames(const std::string& str) { |
| + for (const std::string& token : base::SplitString( |
| + str, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { |
| + if (token == "error") { |
| + PrepareFrame(TestFrame::TestFrameType::BROKEN_FRAME, nullptr); |
| + continue; |
| + } |
| + if (token == "brake") { |
| + PrepareFrame(TestFrame::TestFrameType::TEST_BRAKE, nullptr); |
| + continue; |
| + } |
| + |
| + int timestamp_in_ms = 0; |
| + if (base::StringToInt(token, ×tamp_in_ms)) { |
| + 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(timestamp_in_ms)); |
| + |
| + frame->metadata()->SetTimeTicks( |
| + media::VideoFrameMetadata::Key::REFERENCE_TIME, |
| + base::TimeTicks::Now() + |
| + base::TimeDelta::FromMilliseconds(timestamp_in_ms)); |
| + |
| + PrepareFrame(TestFrame::TestFrameType::NORMAL_FRAME, frame); |
| + continue; |
| + } |
| + |
| + CHECK(false) << "Unrecognized token: " << token; |
| + } |
| +} |
| + |
| +bool MockVideoFrameProvider::Started() { |
| + return started_; |
| +} |
| + |
| +bool MockVideoFrameProvider::Paused() { |
| + return paused_; |
| +} |
| + |
| +void MockVideoFrameProvider::InjectFrame() { |
| + if (!started_) |
| + return; |
| + |
| + if (frames_.empty()) { |
| + message_loop_controller_->GetClosure().Run(); |
| + return; |
| + } |
| + |
| + auto frame = frames_.front(); |
| + frames_.pop_front(); |
| + |
| + if (frame.category == TestFrame::TestFrameType::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.category == TestFrame::TestFrameType::NORMAL_FRAME) { |
| + if (!paused_) |
| + repaint_cb_.Run(frame.frame); |
| + |
| + size_t i = 0; |
| + while (i < frames_.size() && |
| + frames_[i].category != TestFrame::TestFrameType::NORMAL_FRAME) { |
| + ++i; |
| + } |
| + |
| + if (i < frames_.size()) { |
| + delay_ = |
| + (frames_[i].frame->timestamp() - frame.frame->timestamp()) / (i + 1); |
| + } |
| + } |
| + |
| + message_loop_->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&MockVideoFrameProvider::InjectFrame, base::Unretained(this)), |
| + delay_); |
| + |
| + if (frame.category == TestFrame::TestFrameType::TEST_BRAKE) |
| + message_loop_controller_->GetClosure().Run(); |
| +} |
| + |
| +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( |
| + message_loop_, message_loop_controller_, error_cb, repaint_cb); |
| + |
| + return provider_; |
| +} |
| + |
| +MockVideoFrameProvider* MockRenderFactory::GetVideoFrameProvider() { |
| + return static_cast<MockVideoFrameProvider*>(provider_.get()); |
| +} |
| + |
| +scoped_refptr<MediaStreamAudioRenderer> MockRenderFactory::GetAudioRenderer( |
| + const GURL& url, |
| + int render_frame_id, |
| + const std::string& device_id, |
| + const url::Origin& security_origin) { |
| + return nullptr; |
| +} |
| + |
| +void MockClient::networkStateChanged() { |
| + blink::WebMediaPlayer::NetworkState state = player_->networkState(); |
| + test_->GetMockCB()->NetworkStateChanged(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 MockClient::readyStateChanged() { |
| + blink::WebMediaPlayer::ReadyState state = player_->readyState(); |
| + test_->GetMockCB()->ReadyStateChanged(state); |
| + if (state == blink::WebMediaPlayer::ReadyState::ReadyStateHaveEnoughData) |
| + player_->play(); |
| +} |
| + |
| +blink::WebMediaPlayer::TrackId MockClient::addAudioTrack( |
| + const blink::WebString& id, |
| + AudioTrackKind, |
| + const blink::WebString& label, |
| + const blink::WebString& language, |
| + bool enabled) { |
| + return 0; |
| +} |
| + |
| +blink::WebMediaPlayer::TrackId MockClient::addVideoTrack( |
| + const blink::WebString& id, |
| + VideoTrackKind, |
| + const blink::WebString& label, |
| + const blink::WebString& language, |
| + bool selected) { |
| + return 0; |
| +} |
| + |
| +void MockVideoFrameProviderClient::StopUsingProvider() { |
| + if (rendering_) |
| + StopRendering(); |
| + compositor_ = nullptr; |
| +} |
| + |
| +void MockVideoFrameProviderClient::StartRendering() { |
| + if (!rendering_) { |
| + rendering_ = true; |
| + message_loop_->PostTask( |
| + FROM_HERE, base::Bind(&MockVideoFrameProviderClient::RenderFrame, |
| + base::Unretained(this))); |
| + } |
| + mock_cb_->StartRendering(); |
| +} |
| + |
| +void MockVideoFrameProviderClient::StopRendering() { |
| + rendering_ = false; |
| + mock_cb_->StopRendering(); |
| +} |
| + |
| +void MockVideoFrameProviderClient::SetBackgroundRendering( |
| + bool background_rendering) { |
| + background_rendering_ = background_rendering; |
| +} |
| + |
| +void MockVideoFrameProviderClient::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(&MockVideoFrameProviderClient::RenderFrame, |
| + base::Unretained(this)), |
| + base::TimeDelta::FromSecondsD(1.0 / 60.0)); |
| +} |
| + |
| +void MockClient::setWebLayer(blink::WebLayer* layer) { |
| + if (layer) { |
| + compositor_ = test_->GetCompositorForTest(); |
| + video_frame_provider_client_.reset(new MockVideoFrameProviderClient( |
| + message_loop_, compositor_, test_->GetMockCB())); |
| + compositor_->SetVideoFrameProviderClient( |
| + video_frame_provider_client_.get()); |
| + } |
| +} |
| + |
| +MockVideoFrameProviderClient* MockClient::GetVideoFrameProviderClient() { |
| + return video_frame_provider_client_.get(); |
| +} |
| + |
| +TEST_F(WebMediaPlayerMSTest, Playing_Normal) { |
| + // Workflow: |
| + // 1. WMPMS::Load will generate and start content::VideoFrameProvider. |
| + // 2. content::VideoFrameProvider will start pushing frames into WMPMS |
| + // repeatedly. |
| + // 3. On WMPMS receiving the first frame, a WebLayer will be created. |
| + // 4. The WebLayer will call WMPMSCompositor::SetVideoFrameProviderClient, |
| + // which in turn will trigger cc::VideoFrameProviderClient::StartRendering. |
| + // 5. Then cc::VideoFrameProviderClient will start calling |
| + // WMPMSCompositor::UpdateCurrentFrame, GetCurrentFrame for rendering |
| + // repeatedly. |
| + // 6. When WMPSMS::pause gets called, it should trigger |
| + // content::VideoFrameProvider::Pause, and then the provider will stop |
| + // pushing frames into WMPMS, but instead digesting them; simultanously, it |
| + // should call cc::VideoFrameProviderClient::StopRendering, so the client |
| + // will stop asking frames from WMPMSCompositor. |
| + // 7. When WMPMS::play gets called, evething paused in step 6 should be |
| + // resumed. |
| + MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); |
| + |
| + provider->QueueFrames( |
| + "0 33 66 100 133 166 200 233 266 300 333 366 400 433 " |
| + "466 500 533 566 600"); |
| + |
| + EXPECT_CALL(mock_cb_, StartRendering()); |
| + EXPECT_CALL(mock_cb_, |
| + ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); |
| + EXPECT_CALL(mock_cb_, ReadyStateChanged( |
| + blink::WebMediaPlayer::ReadyStateHaveEnoughData)); |
| + message_loop_controller_.RunAndWaitForStatus( |
| + media::PipelineStatus::PIPELINE_OK); |
| +} |
| + |
| +TEST_F(WebMediaPlayerMSTest, Playing_ErrorFrame) { |
| + MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); |
| + |
| + provider->QueueFrames( |
| + "0 33 66 100 133 166 200 233 266 300 333 366 400 433 " |
| + "466 500 533 566 600 error"); |
| + |
| + EXPECT_CALL(mock_cb_, StartRendering()); |
| + EXPECT_CALL(mock_cb_, |
| + ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); |
| + EXPECT_CALL(mock_cb_, ReadyStateChanged( |
| + blink::WebMediaPlayer::ReadyStateHaveEnoughData)); |
| + EXPECT_CALL(mock_cb_, NetworkStateChanged( |
| + blink::WebMediaPlayer::NetworkStateFormatError)); |
| + message_loop_controller_.RunAndWaitForStatus( |
| + media::PipelineStatus::PIPELINE_ERROR_NETWORK); |
| +} |
| + |
| +TEST_F(WebMediaPlayerMSTest, PlayThenPause) { |
| + MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); |
| + |
| + provider->QueueFrames( |
| + "0 33 66 100 133 brake 166 200 233 266 300 333 366 400 " |
| + "433 466 500 533 566 600"); |
| + |
| + EXPECT_CALL(mock_cb_, StartRendering()); |
| + EXPECT_CALL(mock_cb_, |
| + ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); |
| + EXPECT_CALL(mock_cb_, ReadyStateChanged( |
| + blink::WebMediaPlayer::ReadyStateHaveEnoughData)); |
| + // Rendering will be "paused" at the TestBrake. |
| + message_loop_controller_.RunAndWaitForStatus( |
| + media::PipelineStatus::PIPELINE_OK); |
| + mock_cb_.VerifyAndClearExpectations(); |
| + |
| + // Here No more rendering. 1. Render should not be called, 2. Frame freeze. |
| + EXPECT_CALL(mock_cb_, StopRendering()); |
| + player_.pause(); |
| + cc::VideoFrameProvider* compositor = GetCompositorForTest(); |
| + 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()); |
| +} |
| + |
| +TEST_F(WebMediaPlayerMSTest, PlayThenPauseThenPlay) { |
| + MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); |
| + |
| + provider->QueueFrames( |
| + "0 33 66 100 133 brake 166 200 233 266 300 333 366 400 " |
| + "433 brake 466 500 533 566 600"); |
| + |
| + EXPECT_CALL(mock_cb_, StartRendering()); |
| + EXPECT_CALL(mock_cb_, |
| + ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); |
| + EXPECT_CALL(mock_cb_, ReadyStateChanged( |
| + blink::WebMediaPlayer::ReadyStateHaveEnoughData)); |
| + // Rendering will be "paused" at the TestBrake. |
| + message_loop_controller_.RunAndWaitForStatus( |
| + media::PipelineStatus::PIPELINE_OK); |
| + mock_cb_.VerifyAndClearExpectations(); |
| + |
| + // Here No more rendering. 1. Render should not be called, 2. Frame freeze. |
| + EXPECT_CALL(mock_cb_, StopRendering()); |
| + player_.pause(); |
| + cc::VideoFrameProvider* compositor = GetCompositorForTest(); |
| + 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()); |
| + mock_cb_.VerifyAndClearExpectations(); |
| + |
| + // We resume the player |
| + EXPECT_CALL(mock_cb_, StartRendering()); |
| + 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()); |
| +} |
| + |
| +TEST_F(WebMediaPlayerMSTest, BackgroudRendering) { |
| + MockVideoFrameProvider* provider = LoadAndGetFrameProvider(true); |
| + |
| + provider->QueueFrames( |
| + "0 33 66 100 133 brake 166 200 233 266 300 333 366 400 " |
| + "433 brake 466 500 533 566 600"); |
| + |
| + EXPECT_CALL(mock_cb_, StartRendering()); |
| + EXPECT_CALL(mock_cb_, |
| + ReadyStateChanged(blink::WebMediaPlayer::ReadyStateHaveMetadata)); |
| + EXPECT_CALL(mock_cb_, ReadyStateChanged( |
| + blink::WebMediaPlayer::ReadyStateHaveEnoughData)); |
| + // Rendering will be "paused" at the TestBrake. |
| + message_loop_controller_.RunAndWaitForStatus( |
| + media::PipelineStatus::PIPELINE_OK); |
| + mock_cb_.VerifyAndClearExpectations(); |
| + |
| + // Switch to background rendering, expect rendering to continue |
| + MockVideoFrameProviderClient* client = client_.GetVideoFrameProviderClient(); |
| + client->SetBackgroundRendering(true); |
| + cc::VideoFrameProvider* compositor = GetCompositorForTest(); |
| + 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 |
| + client->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()); |
| +} |
| +} // namespace content |