| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef MEDIA_FUCHSIA_CAMERA_FAKE_FUCHSIA_CAMERA_H_ |
| #define MEDIA_FUCHSIA_CAMERA_FAKE_FUCHSIA_CAMERA_H_ |
| |
| #include <fuchsia/camera3/cpp/fidl.h> |
| #include <fuchsia/camera3/cpp/fidl_test_base.h> |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <lib/sys/cpp/outgoing_directory.h> |
| |
| #include <vector> |
| |
| #include "base/message_loop/message_pump_for_io.h" |
| #include "base/run_loop.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace media { |
| |
| class FakeCameraStream final |
| : public fuchsia::camera3::testing::Stream_TestBase, |
| public base::MessagePumpForIO::ZxHandleWatcher { |
| public: |
| static const gfx::Size kMaxFrameSize; |
| static const gfx::Size kDefaultFrameSize; |
| |
| // Enum used to specify how sysmem collection allocation is expected to fail. |
| enum class SysmemFailMode { |
| // Don't simulate sysmem failure. |
| kNone, |
| |
| // Force Sync() failure. Implemented by dropping one of sysmem collection |
| // tokens. |
| kFailSync, |
| |
| // Force buffer allocation failure. Implemented by setting incompatible |
| // constraints. |
| kFailAllocation, |
| }; |
| |
| // Verifies that the I420 image stored at |data| matches the frame produced |
| // by ProduceFrame(). |
| static void ValidateFrameData(const uint8_t* data, |
| gfx::Size size, |
| uint8_t salt); |
| |
| FakeCameraStream(); |
| ~FakeCameraStream() override; |
| |
| FakeCameraStream(const FakeCameraStream&) = delete; |
| FakeCameraStream& operator=(const FakeCameraStream&) = delete; |
| |
| void Bind(fidl::InterfaceRequest<fuchsia::camera3::Stream> request); |
| |
| // Forces the stream to simulate sysmem buffer collection failure for the |
| // first buffer collection. |
| void SetFirstBufferCollectionFailMode(SysmemFailMode fail_mode); |
| |
| void SetFakeResolution(gfx::Size resolution); |
| void SetFakeOrientation(fuchsia::camera3::Orientation orientation); |
| |
| // Waits for the buffer collection to be allocated. Returns true if the buffer |
| // collection was allocated successfully. |
| bool WaitBuffersAllocated(); |
| |
| // Waits until there is at least one free buffer that can be used for the next |
| // frame. |
| bool WaitFreeBuffer(); |
| |
| void ProduceFrame(base::TimeTicks timestamp, uint8_t salt); |
| |
| private: |
| struct Buffer; |
| |
| // fuchsia::camera3::Stream implementation. |
| void WatchResolution(WatchResolutionCallback callback) override; |
| void WatchOrientation(WatchOrientationCallback callback) override; |
| void SetBufferCollection( |
| fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> |
| token_handle) override; |
| void WatchBufferCollection(WatchBufferCollectionCallback callback) override; |
| void GetNextFrame(GetNextFrameCallback callback) override; |
| |
| // fuchsia::camera3::testing::Stream_TestBase override. |
| void NotImplemented_(const std::string& name) override; |
| |
| void OnBufferCollectionSyncDone( |
| fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> |
| token_for_client, |
| fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> |
| failed_token); |
| |
| void OnBufferCollectionError(zx_status_t status); |
| |
| void OnBufferCollectionAllocated( |
| zx_status_t status, |
| fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info); |
| |
| // Calls callback for the pending WatchResolution() if the call is pending and |
| // resolution has been updated. |
| void SendResolution(); |
| |
| // Calls callback for the pending WatchOrientation() if the call is pending |
| // and orientation has been updated. |
| void SendOrientation(); |
| |
| // Calls callback for the pending WatchBufferCollection() if we have a new |
| // token and the call is pending. |
| void SendBufferCollection(); |
| |
| // Calls callback for the pending GetNextFrame() if we have a new frame and |
| // the call is pending. |
| void SendNextFrame(); |
| |
| // ZxHandleWatcher interface. Used to wait for frame release_fences to get |
| // notified when the client releases a buffer. |
| void OnZxHandleSignalled(zx_handle_t handle, zx_signals_t signals) override; |
| |
| fidl::Binding<fuchsia::camera3::Stream> binding_; |
| |
| gfx::Size resolution_ = kDefaultFrameSize; |
| fuchsia::camera3::Orientation orientation_ = |
| fuchsia::camera3::Orientation::UP; |
| |
| absl::optional<fuchsia::math::Size> resolution_update_ = fuchsia::math::Size{ |
| kDefaultFrameSize.width(), kDefaultFrameSize.height()}; |
| WatchResolutionCallback watch_resolution_callback_; |
| |
| absl::optional<fuchsia::camera3::Orientation> orientation_update_ = |
| fuchsia::camera3::Orientation::UP; |
| WatchOrientationCallback watch_orientation_callback_; |
| |
| fuchsia::sysmem::BufferCollectionTokenPtr new_buffer_collection_token_; |
| |
| absl::optional<fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>> |
| new_buffer_collection_token_for_client_; |
| WatchBufferCollectionCallback watch_buffer_collection_callback_; |
| |
| absl::optional<fuchsia::camera3::FrameInfo> next_frame_; |
| GetNextFrameCallback get_next_frame_callback_; |
| |
| fuchsia::sysmem::AllocatorPtr sysmem_allocator_; |
| fuchsia::sysmem::BufferCollectionPtr buffer_collection_; |
| |
| absl::optional<base::RunLoop> wait_buffers_allocated_run_loop_; |
| absl::optional<base::RunLoop> wait_free_buffer_run_loop_; |
| |
| std::vector<std::unique_ptr<Buffer>> buffers_; |
| size_t num_used_buffers_ = 0; |
| |
| size_t frame_counter_ = 0; |
| |
| SysmemFailMode first_buffer_collection_fail_mode_ = SysmemFailMode::kNone; |
| }; |
| |
| class FakeCameraDevice final |
| : public fuchsia::camera3::testing::Device_TestBase { |
| public: |
| FakeCameraDevice(); |
| ~FakeCameraDevice() override; |
| |
| FakeCameraDevice(const FakeCameraDevice&) = delete; |
| FakeCameraDevice& operator=(const FakeCameraDevice&) = delete; |
| |
| void Bind(fidl::InterfaceRequest<fuchsia::camera3::Device> request); |
| |
| FakeCameraStream* stream() { return &stream_; } |
| |
| // Sets a custom handler for GetIdentifier() messages. |
| void SetGetIdentifierHandler( |
| base::RepeatingCallback<void(GetIdentifierCallback)> |
| get_identifier_handler); |
| |
| private: |
| // fuchsia::camera3::Device implementation. |
| void GetIdentifier(GetIdentifierCallback callback) override; |
| void GetConfigurations(GetConfigurationsCallback callback) override; |
| void ConnectToStream( |
| uint32_t index, |
| fidl::InterfaceRequest<fuchsia::camera3::Stream> request) override; |
| |
| // fuchsia::camera3::testing::Device_TestBase override. |
| void NotImplemented_(const std::string& name) override; |
| |
| fidl::BindingSet<fuchsia::camera3::Device> bindings_; |
| |
| FakeCameraStream stream_; |
| |
| base::RepeatingCallback<void(GetIdentifierCallback)> get_identifier_handler_; |
| }; |
| |
| class FakeCameraDeviceWatcher { |
| public: |
| using DevicesMap = std::map<uint64_t, std::unique_ptr<FakeCameraDevice>>; |
| |
| explicit FakeCameraDeviceWatcher(sys::OutgoingDirectory* outgoing_directory); |
| ~FakeCameraDeviceWatcher(); |
| |
| FakeCameraDeviceWatcher(const FakeCameraDeviceWatcher&) = delete; |
| FakeCameraDeviceWatcher& operator=(const FakeCameraDeviceWatcher&) = delete; |
| |
| void DisconnectClients(); |
| |
| const DevicesMap& devices() const { return devices_; } |
| |
| // Removes camera device from the list and returns the corresponding |
| // FakeCameraStream and FakeCameraDevice. The caller may want to hold the |
| // returned object, e.g. to ensure that the corresponding FIDL connections |
| // are not dropped. |
| std::unique_ptr<FakeCameraDevice> RemoveDevice(uint64_t device_id); |
| |
| private: |
| class Client final |
| : public fuchsia::camera3::testing::DeviceWatcher_TestBase { |
| public: |
| explicit Client(FakeCameraDeviceWatcher* device_watcher); |
| ~Client() override; |
| |
| Client(const Client&) = delete; |
| Client& operator=(const Client&) = delete; |
| |
| void QueueEvent(fuchsia::camera3::WatchDevicesEvent event); |
| |
| // fuchsia::camera3::testing::DeviceWatcher_TestBase override. |
| void NotImplemented_(const std::string& name) override; |
| |
| // fuchsia::camera3::DeviceWatcher implementation. |
| void WatchDevices(WatchDevicesCallback callback) override; |
| void ConnectToDevice( |
| uint64_t id, |
| fidl::InterfaceRequest<fuchsia::camera3::Device> request) override; |
| |
| private: |
| bool initial_list_sent_ = false; |
| std::vector<fuchsia::camera3::WatchDevicesEvent> event_queue_; |
| |
| WatchDevicesCallback watch_devices_callback_; |
| FakeCameraDeviceWatcher* const device_watcher_; |
| }; |
| |
| fidl::BindingSet<fuchsia::camera3::DeviceWatcher, std::unique_ptr<Client>> |
| bindings_; |
| |
| DevicesMap devices_; |
| |
| uint64_t next_device_id_ = 1; |
| }; |
| |
| } // namespace media |
| |
| #endif // MEDIA_FUCHSIA_CAMERA_FAKE_FUCHSIA_CAMERA_H_ |