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