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// Unit test for VideoCaptureController. 6 7#include <string> 8 9#include "base/bind.h" 10#include "base/memory/ref_counted.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/message_loop/message_loop.h" 13#include "content/browser/browser_thread_impl.h" 14#include "content/browser/renderer_host/media/media_stream_provider.h" 15#include "content/browser/renderer_host/media/video_capture_controller.h" 16#include "content/browser/renderer_host/media/video_capture_manager.h" 17#include "content/common/media/media_stream_options.h" 18#include "media/video/capture/fake_video_capture_device.h" 19#include "media/video/capture/video_capture_device.h" 20#include "testing/gmock/include/gmock/gmock.h" 21#include "testing/gtest/include/gtest/gtest.h" 22 23using ::testing::_; 24using ::testing::AnyNumber; 25using ::testing::AtLeast; 26using ::testing::InSequence; 27using ::testing::Return; 28 29namespace content { 30 31enum { kDeviceId = 1 }; 32 33ACTION_P4(StopCapture, controller, controller_id, controller_handler, 34 message_loop) { 35 message_loop->PostTask(FROM_HERE, 36 base::Bind(&VideoCaptureController::StopCapture, 37 controller, controller_id, controller_handler)); 38 message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 39} 40 41ACTION_P3(StopSession, controller, session_id, message_loop) { 42 message_loop->PostTask(FROM_HERE, 43 base::Bind(&VideoCaptureController::StopSession, 44 controller, session_id)); 45 message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 46} 47 48class MockVideoCaptureControllerEventHandler 49 : public VideoCaptureControllerEventHandler { 50 public: 51 MockVideoCaptureControllerEventHandler(VideoCaptureController* controller, 52 base::MessageLoop* message_loop) 53 : controller_(controller), 54 message_loop_(message_loop), 55 controller_id_(kDeviceId), 56 process_handle_(base::kNullProcessHandle) { 57 } 58 virtual ~MockVideoCaptureControllerEventHandler() {} 59 60 MOCK_METHOD1(DoBufferCreated, void(const VideoCaptureControllerID&)); 61 MOCK_METHOD1(DoBufferReady, void(const VideoCaptureControllerID&)); 62 MOCK_METHOD1(DoFrameInfo, void(const VideoCaptureControllerID&)); 63 MOCK_METHOD1(DoEnded, void(const VideoCaptureControllerID&)); 64 65 virtual void OnError(const VideoCaptureControllerID& id) OVERRIDE {} 66 virtual void OnBufferCreated(const VideoCaptureControllerID& id, 67 base::SharedMemoryHandle handle, 68 int length, int buffer_id) OVERRIDE { 69 EXPECT_EQ(id, controller_id_); 70 DoBufferCreated(id); 71 } 72 virtual void OnBufferReady(const VideoCaptureControllerID& id, 73 int buffer_id, 74 base::Time timestamp) OVERRIDE { 75 EXPECT_EQ(id, controller_id_); 76 DoBufferReady(id); 77 message_loop_->PostTask(FROM_HERE, 78 base::Bind(&VideoCaptureController::ReturnBuffer, 79 controller_, controller_id_, this, buffer_id)); 80 } 81 virtual void OnFrameInfo( 82 const VideoCaptureControllerID& id, 83 const media::VideoCaptureCapability& format) OVERRIDE { 84 EXPECT_EQ(id, controller_id_); 85 DoFrameInfo(id); 86 } 87 virtual void OnEnded(const VideoCaptureControllerID& id) OVERRIDE { 88 EXPECT_EQ(id, controller_id_); 89 DoEnded(id); 90 } 91 92 scoped_refptr<VideoCaptureController> controller_; 93 base::MessageLoop* message_loop_; 94 VideoCaptureControllerID controller_id_; 95 base::ProcessHandle process_handle_; 96}; 97 98class MockVideoCaptureManager : public VideoCaptureManager { 99 public: 100 MockVideoCaptureManager() 101 : video_session_id_(kStartOpenSessionId), 102 device_name_("fake_device_0", "/dev/video0") {} 103 104 void Init() { 105 video_capture_device_.reset( 106 media::FakeVideoCaptureDevice::Create(device_name_)); 107 ASSERT_TRUE(video_capture_device_.get() != NULL); 108 } 109 110 MOCK_METHOD3(StartCapture, void(int, int, 111 media::VideoCaptureDevice::EventHandler*)); 112 MOCK_METHOD1(StopCapture, void(const media::VideoCaptureSessionId&)); 113 114 void Start(const media::VideoCaptureParams& capture_params, 115 media::VideoCaptureDevice::EventHandler* vc_receiver) OVERRIDE { 116 StartCapture(capture_params.width, capture_params.height, vc_receiver); 117 // TODO(mcasas): Add testing for variable resolution video capture devices, 118 // supported by FakeVideoCaptureDevice. See crbug.com/261410, second part. 119 media::VideoCaptureCapability capture_format( 120 capture_params.width, 121 capture_params.height, 122 capture_params.frame_per_second, 123 media::VideoCaptureCapability::kI420, 124 0, 125 false, 126 media::ConstantResolutionVideoCaptureDevice); 127 video_capture_device_->Allocate(capture_format, vc_receiver); 128 video_capture_device_->Start(); 129 } 130 131 void Stop(const media::VideoCaptureSessionId& capture_session_id, 132 base::Closure stopped_cb) OVERRIDE { 133 StopCapture(capture_session_id); 134 video_capture_device_->Stop(); 135 video_capture_device_->DeAllocate(); 136 } 137 138 int video_session_id_; 139 media::VideoCaptureDevice::Name device_name_; 140 scoped_ptr<media::VideoCaptureDevice> video_capture_device_; 141 142 private: 143 virtual ~MockVideoCaptureManager() {} 144 DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureManager); 145}; 146 147// Test class. 148class VideoCaptureControllerTest : public testing::Test { 149 public: 150 VideoCaptureControllerTest() {} 151 virtual ~VideoCaptureControllerTest() {} 152 153 protected: 154 virtual void SetUp() OVERRIDE { 155 message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO)); 156 file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE, 157 message_loop_.get())); 158 io_thread_.reset(new BrowserThreadImpl(BrowserThread::IO, 159 message_loop_.get())); 160 161 vcm_ = new MockVideoCaptureManager(); 162 vcm_->Init(); 163 controller_ = new VideoCaptureController(vcm_.get()); 164 controller_handler_.reset(new MockVideoCaptureControllerEventHandler( 165 controller_.get(), message_loop_.get())); 166 } 167 168 virtual void TearDown() OVERRIDE {} 169 170 scoped_ptr<base::MessageLoop> message_loop_; 171 scoped_ptr<BrowserThreadImpl> file_thread_; 172 scoped_ptr<BrowserThreadImpl> io_thread_; 173 scoped_refptr<MockVideoCaptureManager> vcm_; 174 scoped_ptr<MockVideoCaptureControllerEventHandler> controller_handler_; 175 scoped_refptr<VideoCaptureController> controller_; 176 177 private: 178 DISALLOW_COPY_AND_ASSIGN(VideoCaptureControllerTest); 179}; 180 181// Try to start and stop capture. 182TEST_F(VideoCaptureControllerTest, StartAndStop) { 183 media::VideoCaptureParams capture_params; 184 capture_params.session_id = vcm_->video_session_id_; 185 capture_params.width = 320; 186 capture_params.height = 240; 187 capture_params.frame_per_second = 30; 188 189 InSequence s; 190 EXPECT_CALL(*vcm_.get(), 191 StartCapture(capture_params.width, 192 capture_params.height, 193 controller_.get())).Times(1); 194 EXPECT_CALL(*controller_handler_, 195 DoFrameInfo(controller_handler_->controller_id_)) 196 .Times(AtLeast(1)); 197 EXPECT_CALL(*controller_handler_, 198 DoBufferCreated(controller_handler_->controller_id_)) 199 .Times(AtLeast(1)); 200 EXPECT_CALL(*controller_handler_, 201 DoBufferReady(controller_handler_->controller_id_)) 202 .Times(AtLeast(1)) 203 .WillOnce(StopCapture(controller_.get(), 204 controller_handler_->controller_id_, 205 controller_handler_.get(), 206 message_loop_.get())); 207 EXPECT_CALL(*vcm_.get(), StopCapture(vcm_->video_session_id_)).Times(1); 208 209 controller_->StartCapture(controller_handler_->controller_id_, 210 controller_handler_.get(), 211 controller_handler_->process_handle_, 212 capture_params); 213 message_loop_->Run(); 214} 215 216// Try to stop session before stopping capture. 217TEST_F(VideoCaptureControllerTest, StopSession) { 218 media::VideoCaptureParams capture_params; 219 capture_params.session_id = vcm_->video_session_id_; 220 capture_params.width = 320; 221 capture_params.height = 240; 222 capture_params.frame_per_second = 30; 223 224 InSequence s; 225 EXPECT_CALL(*vcm_.get(), 226 StartCapture(capture_params.width, 227 capture_params.height, 228 controller_.get())).Times(1); 229 EXPECT_CALL(*controller_handler_, 230 DoFrameInfo(controller_handler_->controller_id_)) 231 .Times(AtLeast(1)); 232 EXPECT_CALL(*controller_handler_, 233 DoBufferCreated(controller_handler_->controller_id_)) 234 .Times(AtLeast(1)); 235 EXPECT_CALL(*controller_handler_, 236 DoBufferReady(controller_handler_->controller_id_)) 237 .Times(AtLeast(1)) 238 .WillOnce(StopSession(controller_.get(), 239 vcm_->video_session_id_, 240 message_loop_.get())); 241 EXPECT_CALL(*controller_handler_, 242 DoEnded(controller_handler_->controller_id_)) 243 .Times(1); 244 245 controller_->StartCapture(controller_handler_->controller_id_, 246 controller_handler_.get(), 247 controller_handler_->process_handle_, 248 capture_params); 249 message_loop_->Run(); 250 251 // The session is stopped now. There should be no buffer coming from 252 // controller. 253 EXPECT_CALL(*controller_handler_, 254 DoBufferReady(controller_handler_->controller_id_)) 255 .Times(0); 256 message_loop_->PostDelayedTask(FROM_HERE, 257 base::MessageLoop::QuitClosure(), base::TimeDelta::FromSeconds(1)); 258 message_loop_->Run(); 259 260 EXPECT_CALL(*vcm_.get(), StopCapture(vcm_->video_session_id_)).Times(1); 261 controller_->StopCapture(controller_handler_->controller_id_, 262 controller_handler_.get()); 263} 264 265} // namespace content 266