blob: 769bc7cd1b23e36bbb9f32240746a56f7000bf86 [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_CAMERA_GYM_STREAM_CYCLER_H_
#define SRC_CAMERA_BIN_CAMERA_GYM_STREAM_CYCLER_H_
#include <fuchsia/camera3/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/fit/function.h>
#include <lib/fpromise/result.h>
#include <gtest/gtest_prod.h>
#include "fuchsia/camera/gym/cpp/fidl.h"
#include "fuchsia/math/cpp/fidl.h"
#include "src/camera/bin/camera-gym/moving_window.h"
namespace camera {
// This class is responsible for exercising the camera APIs to cycle between the various streams and
// configurations reported by a camera.
class StreamCycler {
public:
~StreamCycler();
static fpromise::result<std::unique_ptr<StreamCycler>, zx_status_t> Create(
fuchsia::camera3::DeviceWatcherHandle watcher, fuchsia::sysmem::AllocatorHandle allocator,
async_dispatcher_t* dispatcher, bool manual_mode);
using AddCollectionHandler = fit::function<uint32_t(fuchsia::sysmem::BufferCollectionTokenHandle,
fuchsia::sysmem::ImageFormat_2, std::string)>;
using RemoveCollectionHandler = fit::function<void(uint32_t)>;
using ShowBufferHandler =
fit::function<void(uint32_t, uint32_t, zx::eventpair, std::optional<fuchsia::math::RectF>)>;
using MuteStateHandler = fit::function<void(bool)>;
// Registers handlers that are called when the cycler adds or removes a buffer collection. The
// value returned by |on_add_collection| will be subsequently passed to |on_remove_collection|.
void SetHandlers(AddCollectionHandler on_add_collection,
RemoveCollectionHandler on_remove_collection, ShowBufferHandler on_show_buffer,
MuteStateHandler on_mute_changed);
using CommandStatusHandler =
fit::function<void(fuchsia::camera::gym::Controller_SendCommand_Result)>;
void set_controller_dispatcher(async_dispatcher_t* dispatcher) {
controller_dispatcher_ = dispatcher;
}
// Manual mode entry points:
void ExecuteCommand(fuchsia::camera::gym::Command command, CommandStatusHandler handler);
void set_auto_cycle_interval(std::optional<zx::duration> interval) {
auto_cycle_interval_ = interval;
}
private:
explicit StreamCycler(async_dispatcher_t* dispatcher, bool manual_mode = false);
// Notification to camera-gym that the camera device is present.
void WatchDevicesCallback(std::vector<fuchsia::camera3::WatchDevicesEvent> events);
// Notification to camera-gym that the mute state has changed.
void WatchMuteStateHandler(bool software_muted, bool hardware_muted);
// Forcibly select the stream config for the next demo cycle. This has an intended side effect of
// disconnecting all current streams, which should trigger the RemoveCollectionHandler's for the
// existing streams.
void ForceNextStreamConfiguration();
// Notification to camera-gym that the stream configuration has changed.
void WatchCurrentConfigurationCallback(uint32_t config_index);
// Kick off the sequence to connect all of the streams for this demo cycle.
void ConnectToAllStreams();
// Kick off the sequence to connect a single stream.
void ConnectToStream(uint32_t config_index, uint32_t stream_index);
// Notification to camera-gym that the crop region has been set.
void WatchCropRegionCallback(uint32_t stream_index, std::unique_ptr<fuchsia::math::RectF> region);
// Next camera frame on given stream is available.
void OnNextFrame(uint32_t stream_index, fuchsia::camera3::FrameInfo frame_info);
// Disconnect a single stream.
void DisconnectStream(uint32_t stream_index);
// Utility to return what the next config_index should be.
uint32_t NextConfigIndex();
// LateChecker: Update the timestamp because a new frame arrived.
void ResetStreamWatchdog(uint32_t stream_index);
// LateChecker: Restart all watchdog timers
// For purposes like the start of streaming, etc.
void ResetAllWatchdogs();
// LateChecker: See if any frame arrival deadlines expired.
void CheckAllWatchdogs();
// Manual mode entry points:
void PostedExecuteCommand(fuchsia::camera::gym::Command command, CommandStatusHandler handler);
void ExecuteSetConfigCommand(fuchsia::camera::gym::SetConfigCommand& command);
void ExecuteAddStreamCommand(fuchsia::camera::gym::AddStreamCommand& command);
void ExecuteSetCropCommand(fuchsia::camera::gym::SetCropCommand& command);
void ExecuteSetResolutionCommand(fuchsia::camera::gym::SetResolutionCommand& command);
// When a command successfully executes, CommandSuccessNotify must be called.
void CommandSuccessNotify();
// When a command experiences any failure in execution, CommandFailureNotify must be called.
void CommandFailureNotify(::fuchsia::camera::gym::CommandError status);
async_dispatcher_t* dispatcher_;
async_dispatcher_t* controller_dispatcher_;
fuchsia::camera3::DeviceWatcherPtr watcher_;
fuchsia::sysmem::AllocatorPtr allocator_;
fuchsia::camera3::DevicePtr device_;
std::vector<fuchsia::camera3::Configuration> configurations_;
bool manual_mode_;
std::optional<zx::duration> auto_cycle_interval_;
// Are the camera streams currently muted?
bool muted_ = false;
// Only set by WatchCurrentConfigurationCallback().
// Only used by ConnectToAllStreams() and NextConfigIndex().
// Set to the config_index AFTER being notified that the config was set by the driver stack.
uint32_t current_config_index_;
AddCollectionHandler add_collection_handler_;
RemoveCollectionHandler remove_collection_handler_;
ShowBufferHandler show_buffer_handler_;
MuteStateHandler mute_state_handler_;
// TODO(?????) - Is this really the ideal way to communicate status back?
CommandStatusHandler command_status_handler_;
// Track the moving region of interest
MovingWindow moving_window_;
// stream_infos_ uses the same index as the corresponding stream index in configurations_.
struct StreamInfo {
fuchsia::camera3::StreamPtr stream;
fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection_info;
std::optional<uint32_t> add_collection_handler_returned_value;
std::optional<uint32_t>
source_highlight; // Stream on which to highlight this stream's crop region.
std::optional<fuchsia::math::RectF> highlight;
fuchsia::sysmem::ImageFormat_2 image_format;
zx::time last_received; // Last timestamp this stream received a frame.
};
std::map<uint32_t, StreamInfo> stream_infos_;
friend class CameraGymTest;
friend class CameraGymStreamCyclerTest;
FRIEND_TEST(CameraGymTest, PendingCollectionId);
FRIEND_TEST(StreamCyclerTest, SimpleConfiguration_ManualMode_ConnectToStream);
FRIEND_TEST(StreamCyclerTest, ComplexConfiguration_ManualMode_WatchCurrentConfigurationCallback);
FRIEND_TEST(StreamCyclerTest, ComplexConfiguration_ManualMode_ExecuteSetConfigCommand_SameConfig);
FRIEND_TEST(StreamCyclerTest,
ComplexConfiguration_ManualMode_ExecuteSetConfigCommand_DifferentConfig);
FRIEND_TEST(StreamCyclerTest, ComplexConfiguration_ManualMode_ExecuteAddStreamCommand);
FRIEND_TEST(StreamCyclerTest, ComplexConfiguration_ManualMode_ExecuteSetCropCommand);
FRIEND_TEST(StreamCyclerTest, CommandSuccessNotify);
};
} // namespace camera
#endif // SRC_CAMERA_BIN_CAMERA_GYM_STREAM_CYCLER_H_