blob: 74b021698f261e7ce22298f0eeb745096867c500 [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 SRC_CAMERA_CAMERA_MANAGER_VIDEO_DEVICE_CLIENT_H_
#define SRC_CAMERA_CAMERA_MANAGER_VIDEO_DEVICE_CLIENT_H_
#include <fuchsia/camera/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/wait.h>
#include <lib/component/cpp/startup_context.h>
#include <lib/fidl/cpp/binding.h>
#include <list>
namespace camera {
// Client class for cameras and other video devices. This class is intended to
// be used by the CameraManager, not applications.
class VideoDeviceClient : public fbl::RefCounted<VideoDeviceClient> {
class VideoStream;
public:
using StartupCallback = ::fbl::Function<void(zx_status_t status)>;
// The destructor signals all the connected drivers to close their
// connections.
~VideoDeviceClient();
// Create a VideoDeviceClient from a folder and filename. This should be
// by the CameraManagerImpl when it detects a new or existing device.
static std::unique_ptr<VideoDeviceClient> Create(int dir_fd,
const std::string &name);
// Load all information to identify the device, as well as available formats.
// Will call |callback| when everything is loaded.
void Startup(StartupCallback callback);
// Gets the device description that is published to the applications.
fuchsia::camera::DeviceInfo GetDeviceInfo() const { return device_info_; }
uint64_t id() const { return device_info_.camera_id; }
// Get the formats that this device supports. This is a local call.
const std::vector<fuchsia::camera::VideoFormat> *GetFormats() const;
// Attempt to establish a stream interface to the device.
// If a connection is not possible, |stream| will not be connected,
// and (because InterfaceRequest is move-only) the underlying channel
// handle will be deleted.
void CreateStream(fuchsia::sysmem::BufferCollectionInfo buffer_collection,
fuchsia::camera::FrameRate frame_rate,
fidl::InterfaceRequest<fuchsia::camera::Stream> stream,
zx::eventpair client_token);
private:
VideoDeviceClient() = default;
// Called asynchronously by the driver in response to GetFormats.
// Because GetFormats has a paginated response, OnGetFormatsResp may be
// called multiple times.
void OnGetFormatsResp(std::vector<fuchsia::camera::VideoFormat> formats,
uint32_t total_format_count, zx_status_t device_status);
// Global counter to keep camera ids unique:
static uint64_t camera_id_counter_;
// All the formats this device supports.
std::vector<fuchsia::camera::VideoFormat> formats_;
// VideoStream is a book-keeping class to keep track of the streams that
// this video device has created. This class currently just tracks the
// stream token, which can be used to kill the stream, but will TODO(CAM-15)
// also contain the format and buffer information, so other applications
// can attach to an active stream, and more detailed resource management
// can be performed.
class VideoStream {
public:
// Creates a VideoStream and initializes the eventpair and the async
// waiter. If anything fails, nullptr is returned. Otherwise,
// |driver_token| contains the peer to this class's internal token.
static std::unique_ptr<VideoStream> Create(VideoDeviceClient *owner,
zx::eventpair *driver_token);
private:
VideoStream() = default;
zx::eventpair stream_token_;
std::unique_ptr<async::Wait> stream_token_waiter_;
};
// VideoStream is the only one who should have access to RemoveActiveStream.
friend class VideoStream;
// Kill a specific stream, using a pointer to that stream, |stream_ptr|.
// This function is only called when the stream token is closed, meaning that
// the stream was shut down in the driver.
void RemoveActiveStream(VideoStream *stream_ptr);
// Device_info_ contains identifying information about the physical device.
// It also contains the camera_id which uniquely identifies this instance.
fuchsia::camera::DeviceInfo device_info_;
// When we connect to a device, we query multiple bits of information.
// This class keeps track of when we have gotten all the information we need
// from the device driver, and calls back to the Camera Manager when the
// device is ready to be used.
class ReadyCallbackHandler {
public:
static constexpr int kFormatsReady = 1;
static constexpr int kDeviceInfoReady = 2;
// |callback| is called when either |timeout| is reached, or when
// Signal is called with both values: kFormatsReady and kDeviceInfoReady.
ReadyCallbackHandler(StartupCallback callback, zx::duration timeout)
: callback_(std::move(callback)), timeout_task_([this]() {
if (callback_) {
callback_(ZX_ERR_TIMED_OUT);
callback_ = nullptr;
}
}) {
timeout_task_.PostDelayed(async_get_default_dispatcher(), timeout);
}
// Called to signal that a portion of the information has been received.
void Signal(int signal);
private:
bool has_device_info_ = false;
bool has_formats_ = false;
StartupCallback callback_;
// This timeout task will be cancel the task upon destruction.
async::TaskClosure timeout_task_;
};
// When the driver is starting up, allow a reasonably large amount of time
// to communicate driver information. This timeout is mostly to make sure
// that if the driver hangs, it will get dropped in a timely manner.
// TODO(CAM-18): Remove this when we switch to a dynamic detection model.
static constexpr uint32_t kDriverStartupTimeoutSec = 10;
std::unique_ptr<ReadyCallbackHandler> ready_callback_;
// Depending on the device, multiple concurrent streams may be allowed:
// The list of streams created for this device.
std::list<std::unique_ptr<VideoStream>> active_streams_;
// The connection to the device driver.
fuchsia::camera::ControlPtr camera_control_;
};
} // namespace camera
#endif // SRC_CAMERA_CAMERA_MANAGER_VIDEO_DEVICE_CLIENT_H_