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