| // Copyright (c) 2012 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. |
| |
| // Unit test for VideoCaptureController. |
| |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "content/browser/browser_thread_impl.h" |
| #include "content/browser/renderer_host/media/media_stream_provider.h" |
| #include "content/browser/renderer_host/media/video_capture_controller.h" |
| #include "content/browser/renderer_host/media/video_capture_manager.h" |
| #include "content/common/media/media_stream_options.h" |
| #include "media/video/capture/fake_video_capture_device.h" |
| #include "media/video/capture/video_capture_device.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::AtLeast; |
| using ::testing::InSequence; |
| using ::testing::Return; |
| |
| namespace content { |
| |
| enum { kDeviceId = 1 }; |
| |
| ACTION_P4(StopCapture, controller, controller_id, controller_handler, |
| message_loop) { |
| message_loop->PostTask(FROM_HERE, |
| base::Bind(&VideoCaptureController::StopCapture, |
| controller, controller_id, controller_handler)); |
| message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); |
| } |
| |
| ACTION_P3(StopSession, controller, session_id, message_loop) { |
| message_loop->PostTask(FROM_HERE, |
| base::Bind(&VideoCaptureController::StopSession, |
| controller, session_id)); |
| message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); |
| } |
| |
| class MockVideoCaptureControllerEventHandler |
| : public VideoCaptureControllerEventHandler { |
| public: |
| MockVideoCaptureControllerEventHandler(VideoCaptureController* controller, |
| base::MessageLoop* message_loop) |
| : controller_(controller), |
| message_loop_(message_loop), |
| controller_id_(kDeviceId), |
| process_handle_(base::kNullProcessHandle) { |
| } |
| virtual ~MockVideoCaptureControllerEventHandler() {} |
| |
| MOCK_METHOD1(DoBufferCreated, void(const VideoCaptureControllerID&)); |
| MOCK_METHOD1(DoBufferReady, void(const VideoCaptureControllerID&)); |
| MOCK_METHOD1(DoFrameInfo, void(const VideoCaptureControllerID&)); |
| MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&)); |
| |
| virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE {} |
| virtual void OnBufferCreated(const VideoCaptureControllerID& id, |
| base::SharedMemoryHandle handle, |
| int length, int buffer_id) OVERRIDE { |
| EXPECT_EQ(id, controller_id_); |
| DoBufferCreated(id); |
| } |
| virtual void OnBufferReady(const VideoCaptureControllerID& id, |
| int buffer_id, |
| base::Time timestamp) OVERRIDE { |
| EXPECT_EQ(id, controller_id_); |
| DoBufferReady(id); |
| message_loop_->PostTask(FROM_HERE, |
| base::Bind(&VideoCaptureController::ReturnBuffer, |
| controller_, controller_id_, this, buffer_id)); |
| } |
| virtual void OnFrameInfo( |
| const VideoCaptureControllerID& id, |
| const media::VideoCaptureCapability& format) OVERRIDE { |
| EXPECT_EQ(id, controller_id_); |
| DoFrameInfo(id); |
| } |
| virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE { |
| EXPECT_EQ(id, controller_id_); |
| DoEnded(id); |
| } |
| |
| scoped_refptr<VideoCaptureController> controller_; |
| base::MessageLoop* message_loop_; |
| VideoCaptureControllerID controller_id_; |
| base::ProcessHandle process_handle_; |
| }; |
| |
| class MockVideoCaptureManager : public VideoCaptureManager { |
| public: |
| MockVideoCaptureManager() |
| : video_session_id_(kStartOpenSessionId), |
| device_name_("fake_device_0", "/dev/video0") {} |
| |
| void Init() { |
| video_capture_device_.reset( |
| media::FakeVideoCaptureDevice::Create(device_name_)); |
| ASSERT_TRUE(video_capture_device_.get() != NULL); |
| } |
| |
| MOCK_METHOD3(StartCapture, void(int, int, |
| media::VideoCaptureDevice::EventHandler*)); |
| MOCK_METHOD1(StopCapture, void(const media::VideoCaptureSessionId&)); |
| |
| void Start(const media::VideoCaptureParams& capture_params, |
| media::VideoCaptureDevice::EventHandler* vc_receiver) OVERRIDE { |
| StartCapture(capture_params.width, capture_params.height, vc_receiver); |
| // TODO(mcasas): Add testing for variable resolution video capture devices, |
| // supported by FakeVideoCaptureDevice. See crbug.com/261410, second part. |
| media::VideoCaptureCapability capture_format( |
| capture_params.width, |
| capture_params.height, |
| capture_params.frame_per_second, |
| media::VideoCaptureCapability::kI420, |
| 0, |
| false, |
| media::ConstantResolutionVideoCaptureDevice); |
| video_capture_device_->Allocate(capture_format, vc_receiver); |
| video_capture_device_->Start(); |
| } |
| |
| void Stop(const media::VideoCaptureSessionId& capture_session_id, |
| base::Closure stopped_cb) OVERRIDE { |
| StopCapture(capture_session_id); |
| video_capture_device_->Stop(); |
| video_capture_device_->DeAllocate(); |
| } |
| |
| int video_session_id_; |
| media::VideoCaptureDevice::Name device_name_; |
| scoped_ptr<media::VideoCaptureDevice> video_capture_device_; |
| |
| private: |
| virtual ~MockVideoCaptureManager() {} |
| DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureManager); |
| }; |
| |
| // Test class. |
| class VideoCaptureControllerTest : public testing::Test { |
| public: |
| VideoCaptureControllerTest() {} |
| virtual ~VideoCaptureControllerTest() {} |
| |
| protected: |
| virtual void SetUp() OVERRIDE { |
| message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO)); |
| file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE, |
| message_loop_.get())); |
| io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO, |
| message_loop_.get())); |
| |
| vcm_ = new MockVideoCaptureManager(); |
| vcm_->Init(); |
| controller_ = new VideoCaptureController(vcm_.get()); |
| controller_handler_.reset(new MockVideoCaptureControllerEventHandler( |
| controller_.get(), message_loop_.get())); |
| } |
| |
| virtual void TearDown() OVERRIDE {} |
| |
| scoped_ptr<base::MessageLoop> message_loop_; |
| scoped_ptr<BrowserThreadImpl> file_thread_; |
| scoped_ptr<BrowserThreadImpl> io_thread_; |
| scoped_refptr<MockVideoCaptureManager> vcm_; |
| scoped_ptr<MockVideoCaptureControllerEventHandler> controller_handler_; |
| scoped_refptr<VideoCaptureController> controller_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest); |
| }; |
| |
| // Try to start and stop capture. |
| TEST_F(VideoCaptureControllerTest, StartAndStop) { |
| media::VideoCaptureParams capture_params; |
| capture_params.session_id = vcm_->video_session_id_; |
| capture_params.width = 320; |
| capture_params.height = 240; |
| capture_params.frame_per_second = 30; |
| |
| InSequence s; |
| EXPECT_CALL(*vcm_.get(), |
| StartCapture(capture_params.width, |
| capture_params.height, |
| controller_.get())).Times(1); |
| EXPECT_CALL(*controller_handler_, |
| DoFrameInfo(controller_handler_->controller_id_)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(*controller_handler_, |
| DoBufferCreated(controller_handler_->controller_id_)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(*controller_handler_, |
| DoBufferReady(controller_handler_->controller_id_)) |
| .Times(AtLeast(1)) |
| .WillOnce(StopCapture(controller_.get(), |
| controller_handler_->controller_id_, |
| controller_handler_.get(), |
| message_loop_.get())); |
| EXPECT_CALL(*vcm_.get(), StopCapture(vcm_->video_session_id_)).Times(1); |
| |
| controller_->StartCapture(controller_handler_->controller_id_, |
| controller_handler_.get(), |
| controller_handler_->process_handle_, |
| capture_params); |
| message_loop_->Run(); |
| } |
| |
| // Try to stop session before stopping capture. |
| TEST_F(VideoCaptureControllerTest, StopSession) { |
| media::VideoCaptureParams capture_params; |
| capture_params.session_id = vcm_->video_session_id_; |
| capture_params.width = 320; |
| capture_params.height = 240; |
| capture_params.frame_per_second = 30; |
| |
| InSequence s; |
| EXPECT_CALL(*vcm_.get(), |
| StartCapture(capture_params.width, |
| capture_params.height, |
| controller_.get())).Times(1); |
| EXPECT_CALL(*controller_handler_, |
| DoFrameInfo(controller_handler_->controller_id_)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(*controller_handler_, |
| DoBufferCreated(controller_handler_->controller_id_)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(*controller_handler_, |
| DoBufferReady(controller_handler_->controller_id_)) |
| .Times(AtLeast(1)) |
| .WillOnce(StopSession(controller_.get(), |
| vcm_->video_session_id_, |
| message_loop_.get())); |
| EXPECT_CALL(*controller_handler_, |
| DoEnded(controller_handler_->controller_id_)) |
| .Times(1); |
| |
| controller_->StartCapture(controller_handler_->controller_id_, |
| controller_handler_.get(), |
| controller_handler_->process_handle_, |
| capture_params); |
| message_loop_->Run(); |
| |
| // The session is stopped now. There should be no buffer coming from |
| // controller. |
| EXPECT_CALL(*controller_handler_, |
| DoBufferReady(controller_handler_->controller_id_)) |
| .Times(0); |
| message_loop_->PostDelayedTask(FROM_HERE, |
| base::MessageLoop::QuitClosure(), base::TimeDelta::FromSeconds(1)); |
| message_loop_->Run(); |
| |
| EXPECT_CALL(*vcm_.get(), StopCapture(vcm_->video_session_id_)).Times(1); |
| controller_->StopCapture(controller_handler_->controller_id_, |
| controller_handler_.get()); |
| } |
| |
| } // namespace content |