blob: 94860ae3466ebc1b4328c365978e47d968c81360 [file] [log] [blame]
// Copyright 2020 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_BIN_DEVICE_STREAM_IMPL_H_
#define SRC_CAMERA_BIN_DEVICE_STREAM_IMPL_H_
#include <fuchsia/camera2/cpp/fidl.h>
#include <fuchsia/camera2/hal/cpp/fidl.h>
#include <fuchsia/camera3/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/wait.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fit/result.h>
#include <zircon/status.h>
#include <memory>
#include <queue>
#include <set>
#include <vector>
#include "src/camera/bin/device/util.h"
#include "src/camera/lib/hanging_get_helper/hanging_get_helper.h"
// Represents a specific stream in a camera device's configuration. Serves multiple clients of the
// camera3.Stream protocol.
class StreamImpl {
public:
// Called by the stream on its thread when it needs to connect to its associated legacy stream.
using StreamRequestedCallback = fit::function<void(
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>,
fidl::InterfaceRequest<fuchsia::camera2::Stream>, fit::function<void(uint32_t)>, uint32_t)>;
// Called by the stream on its thread when it receives a new BufferCollectionToken, passing the
// server-side koid of the token and a callback function that receives the token validity. The
// parent should check the token validity and invoke the callback to inform the client. The
// callback may be invoked from any thread.
using CheckTokenCallback = fit::function<void(zx_koid_t, fit::function<void(bool)>)>;
StreamImpl(const fuchsia::camera3::StreamProperties2& properties,
const fuchsia::camera2::hal::StreamConfig& legacy_config,
fidl::InterfaceRequest<fuchsia::camera3::Stream> request,
CheckTokenCallback check_token, StreamRequestedCallback on_stream_requested,
fit::closure on_no_clients);
~StreamImpl();
void PostSetMuteState(MuteState mute_state, fit::closure completed);
private:
// Called when a client calls Rebind.
void OnNewRequest(fidl::InterfaceRequest<fuchsia::camera3::Stream> request);
// Called if the underlying legacy stream disconnects.
void OnLegacyStreamDisconnected(zx_status_t status);
// Posts a task to remove the client with the given id.
void PostRemoveClient(uint64_t id);
// Posts a task to add the client with the given id to the queue of frame recipients.
void PostAddFrameSink(uint64_t id);
// Called when the legacy stream's OnFrameAvailable event fires.
void OnFrameAvailable(fuchsia::camera2::FrameAvailableInfo info);
// Posts a task from the client with the given id to renegotiate buffers or opt out of buffer
// renegotiation.
void PostSetBufferCollection(uint64_t id,
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token);
// Sends pending frames to waiting recipients.
void SendFrames();
// Posts a task from the client with the given id to change the resolution of the stream.
void PostSetResolution(uint32_t id, fuchsia::math::Size coded_size);
// Posts a task from the client with the given id to change the crop region of the stream.
void PostSetCropRegion(uint32_t id, std::unique_ptr<fuchsia::math::RectF> region);
// Represents a single client connection to the StreamImpl class.
class Client : public fuchsia::camera3::Stream {
public:
Client(StreamImpl& stream, uint64_t id,
fidl::InterfaceRequest<fuchsia::camera3::Stream> request);
~Client() override;
// Posts a task to transfer ownership of the given frame to this client.
void PostSendFrame(fuchsia::camera3::FrameInfo frame);
// Posts a task to close the client connection with the given epitaph.
void PostCloseConnection(zx_status_t epitaph);
// Posts a task to add the given token to the client's token queue.
void PostReceiveBufferCollection(
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token);
// Posts a task to update the client's resolution.
void PostReceiveResolution(fuchsia::math::Size coded_size);
// Posts a task to update the client's crop region.
void PostReceiveCropRegion(std::unique_ptr<fuchsia::math::RectF> region);
// Returns a mutable reference to this client's state as a participant in buffer renegotiation.
// This state must be managed by the parent stream's thread, not the client thread.
bool& Participant();
private:
// Closes |binding_| with the provided |status| epitaph, and removes the client instance from
// the parent |clients_| map.
void CloseConnection(zx_status_t status);
// Called when the client endpoint of |binding_| is closed.
void OnClientDisconnected(zx_status_t status);
// |fuchsia::camera3::Stream|
void GetProperties(GetPropertiesCallback callback) override;
void GetProperties2(GetProperties2Callback callback) override;
void SetCropRegion(std::unique_ptr<fuchsia::math::RectF> region) override;
void WatchCropRegion(WatchCropRegionCallback callback) override;
void SetResolution(fuchsia::math::Size coded_size) override;
void WatchResolution(WatchResolutionCallback callback) override;
void SetBufferCollection(
fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken> token) override;
void WatchBufferCollection(WatchBufferCollectionCallback callback) override;
void WatchOrientation(WatchOrientationCallback callback) override;
void GetNextFrame(GetNextFrameCallback callback) override;
void Rebind(fidl::InterfaceRequest<Stream> request) override;
StreamImpl& stream_;
uint64_t id_;
async::Loop loop_;
fidl::Binding<fuchsia::camera3::Stream> binding_;
camera::HangingGetHelper<fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>>
buffers_;
camera::HangingGetHelper<fuchsia::math::Size,
fit::function<bool(fuchsia::math::Size, fuchsia::math::Size)>>
resolution_;
camera::HangingGetHelper<std::unique_ptr<fuchsia::math::RectF>> crop_region_;
GetNextFrameCallback frame_callback_;
bool participant_;
};
async::Loop loop_;
const fuchsia::camera3::StreamProperties2& properties_;
const fuchsia::camera2::hal::StreamConfig& legacy_config_;
fuchsia::camera2::StreamPtr legacy_stream_;
uint32_t legacy_stream_format_index_ = 0;
std::map<uint64_t, std::unique_ptr<Client>> clients_;
uint64_t client_id_next_ = 1;
CheckTokenCallback check_token_;
StreamRequestedCallback on_stream_requested_;
fit::closure on_no_clients_;
uint32_t max_camping_buffers_ = 0;
uint64_t frame_counter_ = 0;
std::queue<uint64_t> frame_sinks_;
bool frame_sink_warning_sent_ = false;
std::queue<fuchsia::camera3::FrameInfo> frames_;
std::map<uint32_t, std::unique_ptr<FrameWaiter>> frame_waiters_;
fuchsia::math::Size current_resolution_;
MuteState mute_state_;
std::unique_ptr<fuchsia::math::RectF> current_crop_region_;
friend class Client;
};
#endif // SRC_CAMERA_BIN_DEVICE_STREAM_IMPL_H_