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