1 // Copyright 2017 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 "media/capture/video/chromeos/camera_device_delegate.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <memory>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/run_loop.h"
16 #include "base/test/task_environment.h"
17 #include "media/base/bind_to_current_loop.h"
18 #include "media/capture/video/chromeos/camera_buffer_factory.h"
19 #include "media/capture/video/chromeos/camera_device_context.h"
20 #include "media/capture/video/chromeos/camera_hal_delegate.h"
21 #include "media/capture/video/chromeos/mock_camera_module.h"
22 #include "media/capture/video/chromeos/mock_vendor_tag_ops.h"
23 #include "media/capture/video/chromeos/mock_video_capture_client.h"
24 #include "media/capture/video/chromeos/video_capture_device_factory_chromeos.h"
25 #include "media/capture/video/mock_gpu_memory_buffer_manager.h"
26 #include "mojo/public/cpp/bindings/pending_receiver.h"
27 #include "mojo/public/cpp/bindings/pending_remote.h"
28 #include "mojo/public/cpp/bindings/receiver.h"
29 #include "mojo/public/cpp/bindings/remote.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 using testing::_;
34 using testing::A;
35 using testing::AtLeast;
36 using testing::AtMost;
37 using testing::Invoke;
38 using testing::InvokeWithoutArgs;
39
40 namespace media {
41
42 namespace {
43
44 class MockCameraDevice : public cros::mojom::Camera3DeviceOps {
45 public:
46 MockCameraDevice() = default;
47
48 ~MockCameraDevice() = default;
49
Initialize(mojo::PendingRemote<cros::mojom::Camera3CallbackOps> callback_ops,InitializeCallback callback)50 void Initialize(
51 mojo::PendingRemote<cros::mojom::Camera3CallbackOps> callback_ops,
52 InitializeCallback callback) override {
53 DoInitialize(std::move(callback_ops), callback);
54 }
55 MOCK_METHOD2(
56 DoInitialize,
57 void(mojo::PendingRemote<cros::mojom::Camera3CallbackOps> callback_ops,
58 InitializeCallback& callback));
59
ConfigureStreams(cros::mojom::Camera3StreamConfigurationPtr config,ConfigureStreamsCallback callback)60 void ConfigureStreams(cros::mojom::Camera3StreamConfigurationPtr config,
61 ConfigureStreamsCallback callback) override {
62 DoConfigureStreams(config, callback);
63 }
64 MOCK_METHOD2(DoConfigureStreams,
65 void(cros::mojom::Camera3StreamConfigurationPtr& config,
66 ConfigureStreamsCallback& callback));
67
ConstructDefaultRequestSettings(cros::mojom::Camera3RequestTemplate type,ConstructDefaultRequestSettingsCallback callback)68 void ConstructDefaultRequestSettings(
69 cros::mojom::Camera3RequestTemplate type,
70 ConstructDefaultRequestSettingsCallback callback) override {
71 DoConstructDefaultRequestSettings(type, callback);
72 }
73 MOCK_METHOD2(DoConstructDefaultRequestSettings,
74 void(cros::mojom::Camera3RequestTemplate type,
75 ConstructDefaultRequestSettingsCallback& callback));
76
ProcessCaptureRequest(cros::mojom::Camera3CaptureRequestPtr request,ProcessCaptureRequestCallback callback)77 void ProcessCaptureRequest(cros::mojom::Camera3CaptureRequestPtr request,
78 ProcessCaptureRequestCallback callback) override {
79 DoProcessCaptureRequest(request, callback);
80 }
81 MOCK_METHOD2(DoProcessCaptureRequest,
82 void(cros::mojom::Camera3CaptureRequestPtr& request,
83 ProcessCaptureRequestCallback& callback));
84
Dump(mojo::ScopedHandle fd)85 void Dump(mojo::ScopedHandle fd) override { DoDump(fd); }
86 MOCK_METHOD1(DoDump, void(mojo::ScopedHandle& fd));
87
Flush(FlushCallback callback)88 void Flush(FlushCallback callback) override { DoFlush(callback); }
89 MOCK_METHOD1(DoFlush, void(FlushCallback& callback));
90
RegisterBuffer(uint64_t buffer_id,cros::mojom::Camera3DeviceOps::BufferType type,std::vector<mojo::ScopedHandle> fds,uint32_t drm_format,cros::mojom::HalPixelFormat hal_pixel_format,uint32_t width,uint32_t height,const std::vector<uint32_t> & strides,const std::vector<uint32_t> & offsets,RegisterBufferCallback callback)91 void RegisterBuffer(uint64_t buffer_id,
92 cros::mojom::Camera3DeviceOps::BufferType type,
93 std::vector<mojo::ScopedHandle> fds,
94 uint32_t drm_format,
95 cros::mojom::HalPixelFormat hal_pixel_format,
96 uint32_t width,
97 uint32_t height,
98 const std::vector<uint32_t>& strides,
99 const std::vector<uint32_t>& offsets,
100 RegisterBufferCallback callback) override {}
101
Close(CloseCallback callback)102 void Close(CloseCallback callback) override { DoClose(callback); }
103 MOCK_METHOD1(DoClose, void(CloseCallback& callback));
104
105 private:
106 DISALLOW_COPY_AND_ASSIGN(MockCameraDevice);
107 };
108
109 constexpr int32_t kJpegMaxBufferSize = 1024;
110 constexpr size_t kDefaultWidth = 1280, kDefaultHeight = 720;
111 constexpr int32_t kDefaultMinFrameRate = 1, kDefaultMaxFrameRate = 30;
112
GetDefaultCaptureParams()113 VideoCaptureParams GetDefaultCaptureParams() {
114 VideoCaptureParams params;
115 params.requested_format = {gfx::Size(kDefaultWidth, kDefaultHeight),
116 float{kDefaultMaxFrameRate}, PIXEL_FORMAT_I420};
117 return params;
118 }
119
120 } // namespace
121
122 class CameraDeviceDelegateTest : public ::testing::Test {
123 public:
CameraDeviceDelegateTest()124 CameraDeviceDelegateTest()
125 : mock_camera_device_receiver_(&mock_camera_device_),
126 device_delegate_thread_("DeviceDelegateThread"),
127 hal_delegate_thread_("HalDelegateThread") {}
128
SetUp()129 void SetUp() override {
130 VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager(
131 &mock_gpu_memory_buffer_manager_);
132 hal_delegate_thread_.Start();
133 camera_hal_delegate_ =
134 new CameraHalDelegate(hal_delegate_thread_.task_runner());
135 auto get_camera_info = base::BindRepeating(
136 &CameraHalDelegate::GetCameraInfoFromDeviceId, camera_hal_delegate_);
137 camera_hal_delegate_->SetCameraModule(
138 mock_camera_module_.GetPendingRemote());
139 }
140
TearDown()141 void TearDown() override {
142 camera_hal_delegate_->Reset();
143 hal_delegate_thread_.Stop();
144 }
145
AllocateDevice()146 void AllocateDevice() {
147 ASSERT_FALSE(device_delegate_thread_.IsRunning());
148 ASSERT_FALSE(camera_device_delegate_);
149 VideoCaptureDeviceDescriptors descriptors;
150 camera_hal_delegate_->GetDeviceDescriptors(&descriptors);
151 ASSERT_EQ(descriptors.size(), 1u);
152 device_delegate_thread_.Start();
153
154 camera_device_delegate_ = std::make_unique<CameraDeviceDelegate>(
155 descriptors[0], camera_hal_delegate_,
156 device_delegate_thread_.task_runner(), nullptr);
157 }
158
GetNumberOfFakeCameras(cros::mojom::CameraModule::GetNumberOfCamerasCallback & cb)159 void GetNumberOfFakeCameras(
160 cros::mojom::CameraModule::GetNumberOfCamerasCallback& cb) {
161 std::move(cb).Run(1);
162 }
163
GetFakeVendorTagOps(mojo::PendingReceiver<cros::mojom::VendorTagOps> vendor_tag_ops_receiver,cros::mojom::CameraModule::GetVendorTagOpsCallback & cb)164 void GetFakeVendorTagOps(
165 mojo::PendingReceiver<cros::mojom::VendorTagOps> vendor_tag_ops_receiver,
166 cros::mojom::CameraModule::GetVendorTagOpsCallback& cb) {
167 mock_vendor_tag_ops_.Bind(std::move(vendor_tag_ops_receiver));
168 }
169
GetFakeCameraInfo(uint32_t camera_id,cros::mojom::CameraModule::GetCameraInfoCallback & cb)170 void GetFakeCameraInfo(uint32_t camera_id,
171 cros::mojom::CameraModule::GetCameraInfoCallback& cb) {
172 cros::mojom::CameraInfoPtr camera_info = cros::mojom::CameraInfo::New();
173 cros::mojom::CameraMetadataPtr static_metadata =
174 cros::mojom::CameraMetadata::New();
175
176 static_metadata->entry_count = 5;
177 static_metadata->entry_capacity = 5;
178 static_metadata->entries =
179 std::vector<cros::mojom::CameraMetadataEntryPtr>();
180
181 cros::mojom::CameraMetadataEntryPtr entry =
182 cros::mojom::CameraMetadataEntry::New();
183 entry->index = 0;
184 entry->tag = cros::mojom::CameraMetadataTag::
185 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
186 entry->type = cros::mojom::EntryType::TYPE_INT32;
187 entry->count = 12;
188 std::vector<int32_t> stream_configurations(entry->count);
189 stream_configurations[0] = static_cast<int32_t>(
190 cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
191 stream_configurations[1] = kDefaultWidth;
192 stream_configurations[2] = kDefaultHeight;
193 stream_configurations[3] = static_cast<int32_t>(
194 cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT);
195 stream_configurations[4] = static_cast<int32_t>(
196 cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888);
197 stream_configurations[5] = kDefaultWidth;
198 stream_configurations[6] = kDefaultHeight;
199 stream_configurations[7] = static_cast<int32_t>(
200 cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT);
201 stream_configurations[8] = static_cast<int32_t>(
202 cros::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_BLOB);
203 stream_configurations[9] = kDefaultWidth;
204 stream_configurations[10] = kDefaultHeight;
205 stream_configurations[11] = static_cast<int32_t>(
206 cros::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT);
207 uint8_t* as_int8 = reinterpret_cast<uint8_t*>(stream_configurations.data());
208 entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t));
209 static_metadata->entries->push_back(std::move(entry));
210
211 entry = cros::mojom::CameraMetadataEntry::New();
212 entry->index = 1;
213 entry->tag = cros::mojom::CameraMetadataTag::ANDROID_SENSOR_ORIENTATION;
214 entry->type = cros::mojom::EntryType::TYPE_INT32;
215 entry->count = 1;
216 entry->data = std::vector<uint8_t>(4, 0);
217 static_metadata->entries->push_back(std::move(entry));
218
219 entry = cros::mojom::CameraMetadataEntry::New();
220 entry->index = 2;
221 entry->tag = cros::mojom::CameraMetadataTag::ANDROID_JPEG_MAX_SIZE;
222 entry->type = cros::mojom::EntryType::TYPE_INT32;
223 entry->count = 1;
224 int32_t jpeg_max_size = kJpegMaxBufferSize;
225 as_int8 = reinterpret_cast<uint8_t*>(&jpeg_max_size);
226 entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t));
227 static_metadata->entries->push_back(std::move(entry));
228
229 entry = cros::mojom::CameraMetadataEntry::New();
230 entry->index = 3;
231 entry->tag =
232 cros::mojom::CameraMetadataTag::ANDROID_REQUEST_PIPELINE_MAX_DEPTH;
233 entry->type = cros::mojom::EntryType::TYPE_BYTE;
234 entry->count = 1;
235 uint8_t pipeline_max_depth = 1;
236 entry->data.assign(&pipeline_max_depth,
237 &pipeline_max_depth + entry->count * sizeof(uint8_t));
238 static_metadata->entries->push_back(std::move(entry));
239
240 entry = cros::mojom::CameraMetadataEntry::New();
241 entry->index = 4;
242 entry->tag = cros::mojom::CameraMetadataTag::
243 ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES;
244 entry->type = cros::mojom::EntryType::TYPE_INT32;
245 entry->count = 2;
246 std::vector<int32_t> available_fps_ranges = {kDefaultMinFrameRate,
247 kDefaultMaxFrameRate};
248 as_int8 = reinterpret_cast<uint8_t*>(available_fps_ranges.data());
249 entry->data.assign(as_int8, as_int8 + entry->count * sizeof(int32_t));
250 static_metadata->entries->push_back(std::move(entry));
251
252 switch (camera_id) {
253 case 0:
254 camera_info->facing = cros::mojom::CameraFacing::CAMERA_FACING_FRONT;
255 camera_info->orientation = 0;
256 camera_info->static_camera_characteristics = std::move(static_metadata);
257 break;
258 default:
259 FAIL() << "Invalid camera id";
260 }
261 std::move(cb).Run(0, std::move(camera_info));
262 }
263
OpenMockCameraDevice(int32_t camera_id,mojo::PendingReceiver<cros::mojom::Camera3DeviceOps> device_ops_receiver,base::OnceCallback<void (int32_t)> & callback)264 void OpenMockCameraDevice(
265 int32_t camera_id,
266 mojo::PendingReceiver<cros::mojom::Camera3DeviceOps> device_ops_receiver,
267 base::OnceCallback<void(int32_t)>& callback) {
268 mock_camera_device_receiver_.Bind(std::move(device_ops_receiver));
269 std::move(callback).Run(0);
270 }
271
InitializeMockCameraDevice(mojo::PendingRemote<cros::mojom::Camera3CallbackOps> callback_ops,base::OnceCallback<void (int32_t)> & callback)272 void InitializeMockCameraDevice(
273 mojo::PendingRemote<cros::mojom::Camera3CallbackOps> callback_ops,
274 base::OnceCallback<void(int32_t)>& callback) {
275 callback_ops_.Bind(std::move(callback_ops));
276 std::move(callback).Run(0);
277 }
278
ConfigureFakeStreams(cros::mojom::Camera3StreamConfigurationPtr & config,base::OnceCallback<void (int32_t,cros::mojom::Camera3StreamConfigurationPtr)> & callback)279 void ConfigureFakeStreams(
280 cros::mojom::Camera3StreamConfigurationPtr& config,
281 base::OnceCallback<void(int32_t,
282 cros::mojom::Camera3StreamConfigurationPtr)>&
283 callback) {
284 ASSERT_GE(2u, config->streams.size());
285 ASSERT_LT(0u, config->streams.size());
286 for (size_t i = 0; i < config->streams.size(); ++i) {
287 config->streams[i]->usage = 0;
288 config->streams[i]->max_buffers = 1;
289 }
290 std::move(callback).Run(0, std::move(config));
291 }
292
ConstructFakeRequestSettings(cros::mojom::Camera3RequestTemplate type,base::OnceCallback<void (cros::mojom::CameraMetadataPtr)> & callback)293 void ConstructFakeRequestSettings(
294 cros::mojom::Camera3RequestTemplate type,
295 base::OnceCallback<void(cros::mojom::CameraMetadataPtr)>& callback) {
296 cros::mojom::CameraMetadataPtr fake_settings =
297 cros::mojom::CameraMetadata::New();
298 fake_settings->entry_count = 1;
299 fake_settings->entry_capacity = 1;
300 fake_settings->entries = std::vector<cros::mojom::CameraMetadataEntryPtr>();
301 std::move(callback).Run(std::move(fake_settings));
302 }
303
ProcessCaptureRequest(cros::mojom::Camera3CaptureRequestPtr & request,base::OnceCallback<void (int32_t)> & callback)304 void ProcessCaptureRequest(cros::mojom::Camera3CaptureRequestPtr& request,
305 base::OnceCallback<void(int32_t)>& callback) {
306 std::move(callback).Run(0);
307
308 cros::mojom::Camera3NotifyMsgPtr msg = cros::mojom::Camera3NotifyMsg::New();
309 msg->type = cros::mojom::Camera3MsgType::CAMERA3_MSG_SHUTTER;
310 msg->message = cros::mojom::Camera3NotifyMsgMessage::New();
311 cros::mojom::Camera3ShutterMsgPtr shutter_msg =
312 cros::mojom::Camera3ShutterMsg::New();
313 shutter_msg->timestamp = base::TimeTicks::Now().ToInternalValue();
314 msg->message->set_shutter(std::move(shutter_msg));
315 callback_ops_->Notify(std::move(msg));
316
317 cros::mojom::Camera3CaptureResultPtr result =
318 cros::mojom::Camera3CaptureResult::New();
319 result->frame_number = request->frame_number;
320 result->result = cros::mojom::CameraMetadata::New();
321 result->output_buffers = std::move(request->output_buffers);
322 result->partial_result = 1;
323 callback_ops_->ProcessCaptureResult(std::move(result));
324 }
325
CloseMockCameraDevice(base::OnceCallback<void (int32_t)> & callback)326 void CloseMockCameraDevice(base::OnceCallback<void(int32_t)>& callback) {
327 mock_camera_device_receiver_.reset();
328 callback_ops_.reset();
329 std::move(callback).Run(0);
330 }
331
SetUpExpectationForHalDelegate()332 void SetUpExpectationForHalDelegate() {
333 EXPECT_CALL(mock_camera_module_, DoGetNumberOfCameras(_))
334 .Times(1)
335 .WillOnce(
336 Invoke(this, &CameraDeviceDelegateTest::GetNumberOfFakeCameras));
337 EXPECT_CALL(mock_camera_module_, DoSetCallbacks(_, _)).Times(1);
338 EXPECT_CALL(mock_camera_module_, DoGetVendorTagOps(_, _))
339 .Times(1)
340 .WillOnce(Invoke(this, &CameraDeviceDelegateTest::GetFakeVendorTagOps));
341 EXPECT_CALL(mock_camera_module_, DoGetCameraInfo(0, _))
342 .Times(1)
343 .WillOnce(Invoke(this, &CameraDeviceDelegateTest::GetFakeCameraInfo));
344 }
345
SetUpExpectationUntilInitialized()346 void SetUpExpectationUntilInitialized() {
347 SetUpExpectationForHalDelegate();
348 EXPECT_CALL(mock_camera_module_, DoOpenDevice(0, _, _))
349 .Times(1)
350 .WillOnce(
351 Invoke(this, &CameraDeviceDelegateTest::OpenMockCameraDevice));
352 EXPECT_CALL(mock_camera_device_, DoInitialize(_, _))
353 .Times(1)
354 .WillOnce(Invoke(
355 this, &CameraDeviceDelegateTest::InitializeMockCameraDevice));
356 }
357
SetUpExpectationUntilStreamConfigured()358 void SetUpExpectationUntilStreamConfigured() {
359 SetUpExpectationUntilInitialized();
360 EXPECT_CALL(mock_camera_device_, DoConfigureStreams(_, _))
361 .Times(1)
362 .WillOnce(
363 Invoke(this, &CameraDeviceDelegateTest::ConfigureFakeStreams));
364 EXPECT_CALL(
365 mock_gpu_memory_buffer_manager_,
366 CreateGpuMemoryBuffer(_, gfx::BufferFormat::YUV_420_BIPLANAR,
367 gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE,
368 gpu::kNullSurfaceHandle))
369 .Times(1)
370 .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager::
371 CreateFakeGpuMemoryBuffer));
372 EXPECT_CALL(
373 mock_gpu_memory_buffer_manager_,
374 CreateGpuMemoryBuffer(_, gfx::BufferFormat::R_8,
375 gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE,
376 gpu::kNullSurfaceHandle))
377 .Times(AtMost(1))
378 .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager::
379 CreateFakeGpuMemoryBuffer));
380 EXPECT_CALL(
381 mock_gpu_memory_buffer_manager_,
382 CreateGpuMemoryBuffer(gfx::Size(kDefaultWidth, kDefaultHeight),
383 gfx::BufferFormat::YUV_420_BIPLANAR,
384 gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE,
385 gpu::kNullSurfaceHandle))
386 .Times(1)
387 .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager::
388 CreateFakeGpuMemoryBuffer));
389 EXPECT_CALL(mock_gpu_memory_buffer_manager_,
390 CreateGpuMemoryBuffer(
391 gfx::Size(kJpegMaxBufferSize, 1), gfx::BufferFormat::R_8,
392 gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE,
393 gpu::kNullSurfaceHandle))
394 .Times(AtMost(1))
395 .WillOnce(Invoke(&unittest_internal::MockGpuMemoryBufferManager::
396 CreateFakeGpuMemoryBuffer));
397 }
398
SetUpExpectationUntilCapturing(unittest_internal::MockVideoCaptureClient * mock_client)399 void SetUpExpectationUntilCapturing(
400 unittest_internal::MockVideoCaptureClient* mock_client) {
401 SetUpExpectationUntilStreamConfigured();
402 EXPECT_CALL(mock_camera_device_, DoConstructDefaultRequestSettings(_, _))
403 .Times(1)
404 .WillOnce(Invoke(
405 this, &CameraDeviceDelegateTest::ConstructFakeRequestSettings));
406 EXPECT_CALL(*mock_client, OnStarted()).Times(1);
407 }
408
SetUpExpectationForCaptureLoop()409 void SetUpExpectationForCaptureLoop() {
410 EXPECT_CALL(mock_camera_device_, DoProcessCaptureRequest(_, _))
411 .Times(AtLeast(1))
412 .WillOnce(
413 Invoke(this, &CameraDeviceDelegateTest::ProcessCaptureRequest))
414 .WillRepeatedly(
415 Invoke(this, &CameraDeviceDelegateTest::ProcessCaptureRequest));
416 }
417
SetUpExpectationForClose()418 void SetUpExpectationForClose() {
419 EXPECT_CALL(mock_camera_device_, DoClose(_))
420 .Times(1)
421 .WillOnce(
422 Invoke(this, &CameraDeviceDelegateTest::CloseMockCameraDevice));
423 }
424
WaitForDeviceToClose()425 void WaitForDeviceToClose() {
426 base::WaitableEvent device_closed(
427 base::WaitableEvent::ResetPolicy::MANUAL,
428 base::WaitableEvent::InitialState::NOT_SIGNALED);
429 device_delegate_thread_.task_runner()->PostTask(
430 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::StopAndDeAllocate,
431 camera_device_delegate_->GetWeakPtr(),
432 base::BindOnce(
433 [](base::WaitableEvent* device_closed) {
434 device_closed->Signal();
435 },
436 base::Unretained(&device_closed))));
437 base::TimeDelta kWaitTimeoutSecs = base::TimeDelta::FromSeconds(3);
438 EXPECT_TRUE(device_closed.TimedWait(kWaitTimeoutSecs));
439 EXPECT_EQ(CameraDeviceContext::State::kStopped, GetState());
440 }
441
ResetDeviceContext()442 unittest_internal::NiceMockVideoCaptureClient* ResetDeviceContext() {
443 auto mock_client =
444 std::make_unique<unittest_internal::NiceMockVideoCaptureClient>();
445 auto* client_ptr = mock_client.get();
446 device_context_ =
447 std::make_unique<CameraDeviceContext>(std::move(mock_client));
448 return client_ptr;
449 }
450
ResetDevice()451 void ResetDevice() {
452 ASSERT_TRUE(device_delegate_thread_.IsRunning());
453 ASSERT_TRUE(camera_device_delegate_);
454 ASSERT_TRUE(device_delegate_thread_.task_runner()->DeleteSoon(
455 FROM_HERE, std::move(camera_device_delegate_)));
456 device_delegate_thread_.Stop();
457 }
458
DoLoop()459 void DoLoop() {
460 run_loop_.reset(new base::RunLoop());
461 run_loop_->Run();
462 }
463
QuitRunLoop()464 void QuitRunLoop() {
465 VLOG(2) << "quit!";
466 if (run_loop_) {
467 run_loop_->Quit();
468 }
469 }
470
GetState()471 CameraDeviceContext::State GetState() {
472 if (camera_device_delegate_->device_context_) {
473 return camera_device_delegate_->device_context_->GetState();
474 } else {
475 // No device context means the VCD is either not started yet or already
476 // stopped.
477 return CameraDeviceContext::State::kStopped;
478 }
479 }
480
481 protected:
482 base::test::TaskEnvironment task_environment_;
483 scoped_refptr<CameraHalDelegate> camera_hal_delegate_;
484 std::unique_ptr<CameraDeviceDelegate> camera_device_delegate_;
485
486 testing::StrictMock<unittest_internal::MockCameraModule> mock_camera_module_;
487 testing::NiceMock<unittest_internal::MockVendorTagOps> mock_vendor_tag_ops_;
488 unittest_internal::MockGpuMemoryBufferManager mock_gpu_memory_buffer_manager_;
489
490 testing::StrictMock<MockCameraDevice> mock_camera_device_;
491 mojo::Receiver<cros::mojom::Camera3DeviceOps> mock_camera_device_receiver_;
492 mojo::Remote<cros::mojom::Camera3CallbackOps> callback_ops_;
493
494 base::Thread device_delegate_thread_;
495
496 std::unique_ptr<CameraDeviceContext> device_context_;
497
498 private:
499 base::Thread hal_delegate_thread_;
500 std::unique_ptr<base::RunLoop> run_loop_;
501 DISALLOW_COPY_AND_ASSIGN(CameraDeviceDelegateTest);
502 };
503
504 // Test the complete capture flow: initialize, configure stream, capture one
505 // frame, and close the device.
TEST_F(CameraDeviceDelegateTest,AllocateCaptureAndStop)506 TEST_F(CameraDeviceDelegateTest, AllocateCaptureAndStop) {
507 auto* mock_client = ResetDeviceContext();
508 mock_client->SetFrameCb(BindToCurrentLoop(base::BindOnce(
509 &CameraDeviceDelegateTest::QuitRunLoop, base::Unretained(this))));
510 mock_client->SetQuitCb(BindToCurrentLoop(base::BindOnce(
511 &CameraDeviceDelegateTest::QuitRunLoop, base::Unretained(this))));
512 SetUpExpectationUntilCapturing(mock_client);
513 SetUpExpectationForCaptureLoop();
514
515 AllocateDevice();
516
517 device_delegate_thread_.task_runner()->PostTask(
518 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::AllocateAndStart,
519 camera_device_delegate_->GetWeakPtr(),
520 GetDefaultCaptureParams(),
521 base::Unretained(device_context_.get())));
522
523 // Wait until a frame is received. MockVideoCaptureClient calls QuitRunLoop()
524 // to stop the run loop.
525 DoLoop();
526 EXPECT_EQ(CameraDeviceContext::State::kCapturing, GetState());
527
528 SetUpExpectationForClose();
529
530 WaitForDeviceToClose();
531
532 ResetDevice();
533 }
534
535 // Test that the camera device delegate closes properly when StopAndDeAllocate()
536 // is called when the device is opening. The timeline is roughly:
537 // 1. AllocateAndStart()
538 // 2. Async IPC call OpenDevice() started
539 // 3. StopAndDeAllocate()
540 // 4. Async IPC call OpenDevice() finished
TEST_F(CameraDeviceDelegateTest,StopBeforeOpened)541 TEST_F(CameraDeviceDelegateTest, StopBeforeOpened) {
542 auto* mock_client = ResetDeviceContext();
543 mock_client->SetQuitCb(BindToCurrentLoop(base::BindOnce(
544 &CameraDeviceDelegateTest::QuitRunLoop, base::Unretained(this))));
545 SetUpExpectationForHalDelegate();
546
547 AllocateDevice();
548
549 device_delegate_thread_.task_runner()->PostTask(
550 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::AllocateAndStart,
551 camera_device_delegate_->GetWeakPtr(),
552 GetDefaultCaptureParams(),
553 base::Unretained(device_context_.get())));
554
555 base::WaitableEvent stop_posted;
556 auto open_device_quit_loop_cb =
557 [&](int32_t camera_id,
558 mojo::PendingReceiver<cros::mojom::Camera3DeviceOps>
559 device_ops_receiver,
560 base::OnceCallback<void(int32_t)>& callback) {
561 QuitRunLoop();
562 // Make sure StopAndDeAllocate() is called before the device opened
563 // callback.
564 stop_posted.Wait();
565 OpenMockCameraDevice(camera_id, std::move(device_ops_receiver),
566 callback);
567 };
568 EXPECT_CALL(mock_camera_module_, DoOpenDevice(0, _, _))
569 .Times(1)
570 .WillOnce(Invoke(open_device_quit_loop_cb));
571
572 // Wait until the QuitRunLoop() call in |mock_camera_module_->OpenDevice()|.
573 DoLoop();
574
575 SetUpExpectationForClose();
576
577 base::WaitableEvent device_closed;
578 device_delegate_thread_.task_runner()->PostTask(
579 FROM_HERE,
580 base::BindOnce(&CameraDeviceDelegate::StopAndDeAllocate,
581 camera_device_delegate_->GetWeakPtr(),
582 base::BindOnce(&base::WaitableEvent::Signal,
583 base::Unretained(&device_closed))));
584 stop_posted.Signal();
585 EXPECT_TRUE(device_closed.TimedWait(base::TimeDelta::FromSeconds(3)));
586 EXPECT_EQ(CameraDeviceContext::State::kStopped, GetState());
587
588 ResetDevice();
589 }
590
591 // Test that the camera device delegate closes properly when StopAndDeAllocate
592 // is called right after the device is initialized.
TEST_F(CameraDeviceDelegateTest,StopAfterInitialized)593 TEST_F(CameraDeviceDelegateTest, StopAfterInitialized) {
594 auto* mock_client = ResetDeviceContext();
595 mock_client->SetQuitCb(BindToCurrentLoop(base::BindOnce(
596 &CameraDeviceDelegateTest::QuitRunLoop, base::Unretained(this))));
597 SetUpExpectationUntilInitialized();
598
599 AllocateDevice();
600
601 device_delegate_thread_.task_runner()->PostTask(
602 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::AllocateAndStart,
603 camera_device_delegate_->GetWeakPtr(),
604 GetDefaultCaptureParams(),
605 base::Unretained(device_context_.get())));
606
607 EXPECT_CALL(mock_camera_device_, DoConfigureStreams(_, _))
608 .Times(1)
609 .WillOnce(Invoke(
610 [this](cros::mojom::Camera3StreamConfigurationPtr& config,
611 base::OnceCallback<void(
612 int32_t, cros::mojom::Camera3StreamConfigurationPtr)>&
613 callback) {
614 EXPECT_EQ(CameraDeviceContext::State::kInitialized,
615 this->GetState());
616 std::move(callback).Run(-ENODEV, {});
617 this->QuitRunLoop();
618 }));
619
620 // Wait until the QuitRunLoop call in |mock_camera_device_->ConfigureStreams|.
621 DoLoop();
622
623 SetUpExpectationForClose();
624
625 WaitForDeviceToClose();
626
627 ResetDevice();
628 }
629
630 // Test that the camera device delegate closes properly when StopAndDeAllocate
631 // is called right after the stream is configured.
TEST_F(CameraDeviceDelegateTest,StopAfterStreamConfigured)632 TEST_F(CameraDeviceDelegateTest, StopAfterStreamConfigured) {
633 auto* mock_client = ResetDeviceContext();
634 mock_client->SetQuitCb(BindToCurrentLoop(base::BindOnce(
635 &CameraDeviceDelegateTest::QuitRunLoop, base::Unretained(this))));
636 SetUpExpectationUntilStreamConfigured();
637
638 AllocateDevice();
639
640 device_delegate_thread_.task_runner()->PostTask(
641 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::AllocateAndStart,
642 camera_device_delegate_->GetWeakPtr(),
643 GetDefaultCaptureParams(),
644 base::Unretained(device_context_.get())));
645
646 EXPECT_CALL(mock_camera_device_, DoConstructDefaultRequestSettings(_, _))
647 .Times(1)
648 .WillOnce(Invoke(
649 [this](cros::mojom::Camera3RequestTemplate type,
650 base::OnceCallback<void(cros::mojom::CameraMetadataPtr)>&
651 callback) {
652 EXPECT_EQ(CameraDeviceContext::State::kStreamConfigured,
653 this->GetState());
654 std::move(callback).Run({});
655 this->QuitRunLoop();
656 }));
657
658 // Wait until the QuitRunLoop call in |mock_camera_device_->ConfigureStreams|.
659 DoLoop();
660
661 SetUpExpectationForClose();
662
663 WaitForDeviceToClose();
664
665 ResetDevice();
666 }
667
668 // Test that the camera device delegate handles camera device open failures
669 // correctly.
TEST_F(CameraDeviceDelegateTest,FailToOpenDevice)670 TEST_F(CameraDeviceDelegateTest, FailToOpenDevice) {
671 SetUpExpectationForHalDelegate();
672
673 AllocateDevice();
674
675 auto* mock_client = ResetDeviceContext();
676
677 auto stop_on_error = [&]() {
678 device_delegate_thread_.task_runner()->PostTask(
679 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::StopAndDeAllocate,
680 camera_device_delegate_->GetWeakPtr(),
681 BindToCurrentLoop(base::BindOnce(
682 &CameraDeviceDelegateTest::QuitRunLoop,
683 base::Unretained(this)))));
684 };
685 EXPECT_CALL(*mock_client, OnError(_, _, _))
686 .Times(AtLeast(1))
687 .WillRepeatedly(InvokeWithoutArgs(stop_on_error));
688
689 // Hold the |device_ops_receiver| to make the behavior of CameraDeviceDelegate
690 // deterministic. Otherwise the connection error handler would race with the
691 // callback of OpenDevice(), because they are in different mojo channels.
692 mojo::PendingReceiver<cros::mojom::Camera3DeviceOps>
693 device_ops_receiver_holder;
694 auto open_device_with_error_cb =
695 [&](int32_t camera_id,
696 mojo::PendingReceiver<cros::mojom::Camera3DeviceOps>
697 device_ops_receiver,
698 base::OnceCallback<void(int32_t)>& callback) {
699 device_ops_receiver_holder = std::move(device_ops_receiver);
700 std::move(callback).Run(-ENODEV);
701 };
702 EXPECT_CALL(mock_camera_module_, DoOpenDevice(0, _, _))
703 .Times(1)
704 .WillOnce(Invoke(open_device_with_error_cb));
705
706 device_delegate_thread_.task_runner()->PostTask(
707 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::AllocateAndStart,
708 camera_device_delegate_->GetWeakPtr(),
709 GetDefaultCaptureParams(),
710 base::Unretained(device_context_.get())));
711
712 // Wait unitl |camera_device_delegate_->StopAndDeAllocate| calls the
713 // QuitRunLoop callback.
714 DoLoop();
715
716 ResetDevice();
717 }
718
719 // Test that the class handles it correctly when StopAndDeAllocate is called
720 // multiple times.
TEST_F(CameraDeviceDelegateTest,DoubleStopAndDeAllocate)721 TEST_F(CameraDeviceDelegateTest, DoubleStopAndDeAllocate) {
722 auto* mock_client = ResetDeviceContext();
723 mock_client->SetFrameCb(BindToCurrentLoop(base::BindOnce(
724 &CameraDeviceDelegateTest::QuitRunLoop, base::Unretained(this))));
725 mock_client->SetQuitCb(BindToCurrentLoop(base::BindOnce(
726 &CameraDeviceDelegateTest::QuitRunLoop, base::Unretained(this))));
727 SetUpExpectationUntilCapturing(mock_client);
728 SetUpExpectationForCaptureLoop();
729
730 AllocateDevice();
731
732 device_delegate_thread_.task_runner()->PostTask(
733 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::AllocateAndStart,
734 camera_device_delegate_->GetWeakPtr(),
735 GetDefaultCaptureParams(),
736 base::Unretained(device_context_.get())));
737
738 // Wait until a frame is received. MockVideoCaptureClient calls QuitRunLoop()
739 // to stop the run loop.
740 DoLoop();
741
742 EXPECT_EQ(CameraDeviceContext::State::kCapturing, GetState());
743
744 SetUpExpectationForClose();
745
746 WaitForDeviceToClose();
747
748 device_delegate_thread_.task_runner()->PostTask(
749 FROM_HERE, base::BindOnce(&CameraDeviceDelegate::StopAndDeAllocate,
750 camera_device_delegate_->GetWeakPtr(),
751 BindToCurrentLoop(base::BindOnce(
752 &CameraDeviceDelegateTest::QuitRunLoop,
753 base::Unretained(this)))));
754 DoLoop();
755
756 ResetDevice();
757 }
758
759 } // namespace media
760