blob: 31e309ea17f61f795dde59fb9248be9c55ccdac0 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// 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/optional.h"
#include "base/run_loop.h"
#include "ui/gfx/geometry/size.h"
namespace media {
class FakeCameraStream : 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() final;
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) final;
void WatchOrientation(WatchOrientationCallback callback) final;
void SetBufferCollection(
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
token_handle) final;
void WatchBufferCollection(WatchBufferCollectionCallback callback) final;
void GetNextFrame(GetNextFrameCallback callback) final;
// fuchsia::camera3::testing::Stream_TestBase override.
void NotImplemented_(const std::string& name) override;
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) final;
fidl::Binding<fuchsia::camera3::Stream> binding_;
gfx::Size resolution_ = kDefaultFrameSize;
fuchsia::camera3::Orientation orientation_ =
fuchsia::camera3::Orientation::UP;
base::Optional<fuchsia::math::Size> resolution_update_ = fuchsia::math::Size{
kDefaultFrameSize.width(), kDefaultFrameSize.height()};
WatchResolutionCallback watch_resolution_callback_;
base::Optional<fuchsia::camera3::Orientation> orientation_update_ =
fuchsia::camera3::Orientation::UP;
WatchOrientationCallback watch_orientation_callback_;
base::Optional<fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>>
new_buffer_collection_token_;
WatchBufferCollectionCallback watch_buffer_collection_callback_;
base::Optional<fuchsia::camera3::FrameInfo> next_frame_;
GetNextFrameCallback get_next_frame_callback_;
fuchsia::sysmem::AllocatorPtr sysmem_allocator_;
fuchsia::sysmem::BufferCollectionPtr buffer_collection_;
base::Optional<base::RunLoop> wait_buffers_allocated_run_loop_;
base::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 : public fuchsia::camera3::testing::Device_TestBase {
public:
explicit FakeCameraDevice(FakeCameraStream* stream);
~FakeCameraDevice() final;
FakeCameraDevice(const FakeCameraDevice&) = delete;
FakeCameraDevice& operator=(const FakeCameraDevice&) = delete;
void Bind(fidl::InterfaceRequest<fuchsia::camera3::Device> request);
private:
// fuchsia::camera3::Device implementation.
void GetIdentifier(GetIdentifierCallback callback) final;
void GetConfigurations(GetConfigurationsCallback callback) final;
void ConnectToStream(
uint32_t index,
fidl::InterfaceRequest<fuchsia::camera3::Stream> request) final;
// fuchsia::camera3::testing::Device_TestBase override.
void NotImplemented_(const std::string& name) override;
fidl::BindingSet<fuchsia::camera3::Device> bindings_;
FakeCameraStream* const stream_;
};
class FakeCameraDeviceWatcher {
public:
explicit FakeCameraDeviceWatcher(sys::OutgoingDirectory* outgoing_directory);
~FakeCameraDeviceWatcher();
FakeCameraDeviceWatcher(const FakeCameraDeviceWatcher&) = delete;
FakeCameraDeviceWatcher& operator=(const FakeCameraDeviceWatcher&) = delete;
void DisconnectClients();
FakeCameraStream* stream() { return &stream_; }
private:
class Client : public fuchsia::camera3::testing::DeviceWatcher_TestBase {
public:
explicit Client(FakeCameraDevice* device);
~Client() final;
Client(const Client&) = delete;
Client& operator=(const Client&) = delete;
// fuchsia::camera3::testing::DeviceWatcher_TestBase override.
void NotImplemented_(const std::string& name) final;
// fuchsia::camera3::DeviceWatcher implementation.
void WatchDevices(WatchDevicesCallback callback) final;
void ConnectToDevice(
uint64_t id,
fidl::InterfaceRequest<fuchsia::camera3::Device> request) final;
private:
bool devices_sent_ = false;
FakeCameraDevice* const device_;
};
fidl::BindingSet<fuchsia::camera3::DeviceWatcher, std::unique_ptr<Client>>
bindings_;
FakeCameraStream stream_;
FakeCameraDevice device_{&stream_};
};
} // namespace media
#endif // MEDIA_FUCHSIA_CAMERA_FAKE_FUCHSIA_CAMERA_H_