| // 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_UTIL_H_ |
| #define SRC_CAMERA_BIN_DEVICE_UTIL_H_ |
| |
| #include <fuchsia/camera2/hal/cpp/fidl.h> |
| #include <fuchsia/camera3/cpp/fidl.h> |
| #include <lib/async/cpp/task.h> |
| #include <lib/async/cpp/wait.h> |
| #include <lib/async/default.h> |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/fidl/cpp/interface_ptr.h> |
| #include <lib/fpromise/promise.h> |
| #include <lib/fpromise/result.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/trace/event.h> |
| #include <zircon/status.h> |
| #include <zircon/types.h> |
| |
| #include "src/lib/fsl/handles/object_info.h" |
| |
| namespace camera { |
| |
| // Safely unbinds a client connection, doing so on the connection's thread if it differs from the |
| // caller's thread. |
| template <class T> |
| inline void Unbind(fidl::InterfacePtr<T>& p) { |
| if (!p) { |
| return; |
| } |
| |
| if (p.dispatcher() == async_get_default_dispatcher()) { |
| p.Unbind(); |
| return; |
| } |
| |
| async::PostTask(p.dispatcher(), [&]() { p.Unbind(); }); |
| } |
| |
| // Converts a camera2.hal.Config to a camera3.Configuration |
| inline fpromise::result<fuchsia::camera3::Configuration2, zx_status_t> Convert( |
| const fuchsia::camera2::hal::Config& config) { |
| if (config.stream_configs.empty()) { |
| FX_LOGS(ERROR) << "Config reported no streams."; |
| return fpromise::error(ZX_ERR_INTERNAL); |
| } |
| std::vector<fuchsia::camera3::StreamProperties2> streams; |
| for (const auto& stream_config : config.stream_configs) { |
| if (stream_config.image_formats.empty()) { |
| FX_LOGS(ERROR) << "Stream reported no image formats."; |
| return fpromise::error(ZX_ERR_INTERNAL); |
| } |
| fuchsia::camera3::StreamProperties2 stream_properties; |
| stream_properties.set_frame_rate( |
| {.numerator = stream_config.frame_rate.frames_per_sec_numerator, |
| .denominator = stream_config.frame_rate.frames_per_sec_denominator}); |
| stream_properties.set_image_format(stream_config.image_formats[0]); |
| // TODO(fxbug.dev/50908): Detect ROI support during initialization. |
| stream_properties.set_supports_crop_region(true); |
| std::vector<fuchsia::math::Size> supported_resolutions; |
| for (const auto& format : stream_config.image_formats) { |
| supported_resolutions.push_back({.width = static_cast<int32_t>(format.coded_width), |
| .height = static_cast<int32_t>(format.coded_height)}); |
| } |
| stream_properties.set_supported_resolutions(std::move(supported_resolutions)); |
| streams.push_back(std::move(stream_properties)); |
| } |
| fuchsia::camera3::Configuration2 ret; |
| ret.set_streams(std::move(streams)); |
| return fpromise::ok(std::move(ret)); |
| } |
| |
| // Converts a valid camera3.StreamProperties2 to a camera3.StreamProperties, dropping the |
| // |supported_resolutions| field. |
| inline fuchsia::camera3::StreamProperties Convert( |
| const fuchsia::camera3::StreamProperties2& properties) { |
| return {.image_format = properties.image_format(), |
| .frame_rate = properties.frame_rate(), |
| .supports_crop_region = properties.supports_crop_region()}; |
| } |
| |
| // Represents the mute state of a device as defined by the Device.WatchMuteState API. |
| struct MuteState { |
| bool software_muted = false; |
| bool hardware_muted = false; |
| // Returns true iff any mute is active. |
| bool muted() const { return software_muted || hardware_muted; } |
| bool operator==(const MuteState& other) const { |
| return other.software_muted == software_muted && other.hardware_muted == hardware_muted; |
| } |
| }; |
| |
| // Wraps an async::Wait and frame release fence such that object lifetime requirements are enforced |
| // automatically, namely that the waited-upon object must outlive the wait object. |
| class FrameWaiter { |
| public: |
| FrameWaiter(async_dispatcher_t* dispatcher, std::vector<zx::eventpair> fences, |
| fit::closure signaled) |
| : fences_(std::move(fences)), |
| pending_fences_(fences_.size()), |
| signaled_(std::move(signaled)) { |
| for (auto& fence : fences_) { |
| waits_.push_back(std::make_unique<async::WaitOnce>(fence.get(), ZX_EVENTPAIR_PEER_CLOSED, 0)); |
| waits_.back()->Begin(dispatcher, fit::bind_member(this, &FrameWaiter::Handler)); |
| } |
| } |
| ~FrameWaiter() { |
| for (auto& wait : waits_) { |
| wait->Cancel(); |
| } |
| signaled_ = nullptr; |
| fences_.clear(); |
| } |
| |
| private: |
| void Handler(async_dispatcher_t* dispatcher, async::WaitOnce* wait, zx_status_t status, |
| const zx_packet_signal_t* signal) { |
| if (status != ZX_OK) { |
| return; |
| } |
| if (--pending_fences_ > 0) { |
| return; |
| } |
| // |signaled_| may delete |this|, so move it to a local before calling it. This ensures captures |
| // are persisted for the duration of the callback. |
| auto signaled = std::move(signaled_); |
| signaled(); |
| } |
| std::vector<zx::eventpair> fences_; |
| std::vector<std::unique_ptr<async::WaitOnce>> waits_; |
| size_t pending_fences_; |
| fit::closure signaled_; |
| }; |
| |
| template <typename T, typename Enable = void> |
| struct IsFidlChannelWrapper : std::false_type {}; |
| |
| template <typename T> |
| struct IsFidlChannelWrapper<fidl::InterfaceHandle<T>> : std::true_type {}; |
| |
| template <typename T> |
| struct IsFidlChannelWrapper<fidl::InterfacePtr<T>> : std::true_type {}; |
| |
| template <typename T> |
| struct IsFidlChannelWrapper<fidl::SynchronousInterfacePtr<T>> : std::true_type {}; |
| |
| template <typename T> |
| struct IsFidlChannelWrapper<fidl::InterfaceRequest<T>> : std::true_type {}; |
| |
| template <typename T> |
| struct IsFidlChannelWrapper<fidl::Binding<T>> : std::true_type {}; |
| |
| template <typename T> |
| inline constexpr bool IsFidlChannelWrapperV = IsFidlChannelWrapper<T>::value; |
| |
| template <typename T> |
| inline zx_handle_t GetFidlChannelHandle(const T& fidl) { |
| static_assert(IsFidlChannelWrapperV<T>, "'fidl' must be one one of the fidl channel wrappers"); |
| return fidl.channel().get(); |
| } |
| |
| template <typename T> |
| inline zx_koid_t GetKoid(const T& fidl) { |
| return fsl::GetKoid(GetFidlChannelHandle(fidl)); |
| } |
| |
| template <typename T> |
| inline zx_koid_t GetRelatedKoid(const T& fidl) { |
| return fsl::GetRelatedKoid(GetFidlChannelHandle(fidl)); |
| } |
| |
| template <typename T> |
| inline std::pair<zx_koid_t, zx_koid_t> GetKoids(const T& fidl) { |
| return fsl::GetKoids(GetFidlChannelHandle(fidl)); |
| } |
| |
| } // namespace camera |
| |
| #endif // SRC_CAMERA_BIN_DEVICE_UTIL_H_ |