| // 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 GARNET_BIN_MEDIA_CAMERA_MANAGER_VIDEO_DEVICE_CLIENT_H_ |
| #define GARNET_BIN_MEDIA_CAMERA_MANAGER_VIDEO_DEVICE_CLIENT_H_ |
| |
| #include <list> |
| |
| #include <fbl/unique_ptr.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> |
| |
| 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. |
| fidl::VectorPtr<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); |
| |
| 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(fidl::VectorPtr<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 // GARNET_BIN_MEDIA_CAMERA_MANAGER_VIDEO_DEVICE_CLIENT_H_ |