| // Copyright 2019 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. |
| |
| #include "src/camera/drivers/controller/controller_protocol.h" |
| |
| #include <fuchsia/camera2/cpp/fidl.h> |
| #include <lib/fidl/cpp/optional.h> |
| #include <lib/fit/defer.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/trace/event.h> |
| |
| #include "src/camera/drivers/controller/configs/product_config.h" |
| |
| namespace camera { |
| |
| namespace { |
| constexpr auto kTag = "camera_controller"; |
| } // namespace |
| |
| ControllerImpl::ControllerImpl(zx_device_t* device, |
| fidl::InterfaceRequest<fuchsia::camera2::hal::Controller> control, |
| async_dispatcher_t* dispatcher, const ddk::IspProtocolClient& isp, |
| const ddk::GdcProtocolClient& gdc, |
| const ddk::Ge2dProtocolClient& ge2d, |
| fit::closure on_connection_closed, |
| fuchsia::sysmem::AllocatorSyncPtr sysmem_allocator, |
| const zx::event& shutdown_event) |
| : binding_(this), |
| pipeline_manager_(device, dispatcher, isp, gdc, ge2d, std::move(sysmem_allocator), |
| shutdown_event), |
| product_config_(ProductConfig::Create()) { |
| binding_.set_error_handler( |
| [occ = std::move(on_connection_closed)](zx_status_t /*status*/) { occ(); }); |
| PopulateConfigurations(); |
| binding_.Bind(std::move(control), dispatcher); |
| } |
| |
| zx_status_t ControllerImpl::GetInternalConfiguration(uint32_t config_index, |
| InternalConfigInfo** internal_config) { |
| if (config_index >= internal_configs_.configs_info.size() || internal_config == nullptr) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| *internal_config = &internal_configs_.configs_info[config_index]; |
| return ZX_OK; |
| } |
| |
| void ControllerImpl::GetNextConfig(GetNextConfigCallback callback) { |
| fuchsia::camera2::hal::Config config; |
| |
| if (config_count_ >= configs_.size()) { |
| callback(nullptr, ZX_ERR_STOP); |
| return; |
| } |
| config = fidl::Clone(configs_.at(config_count_)); |
| callback(fidl::MakeOptional(std::move(config)), ZX_OK); |
| config_count_++; |
| } |
| |
| static InternalConfigNode* GetStreamConfigNode( |
| InternalConfigInfo* internal_config, fuchsia::camera2::CameraStreamType stream_config_type) { |
| // Internal API, assuming the pointer will be valid always. |
| for (auto& stream_info : internal_config->streams_info) { |
| auto supported_streams = stream_info.supported_streams; |
| if (std::any_of(supported_streams.begin(), supported_streams.end(), |
| [stream_config_type](auto& supported_stream) { |
| return supported_stream.type == stream_config_type; |
| })) { |
| return &stream_info; |
| } |
| } |
| return nullptr; |
| } |
| |
| void ControllerImpl::CreateStream(uint32_t config_index, uint32_t stream_index, |
| uint32_t image_format_index, |
| fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection, |
| fidl::InterfaceRequest<fuchsia::camera2::Stream> stream) { |
| TRACE_DURATION("camera", "ControllerImpl::CreateStream"); |
| zx_status_t status = ZX_OK; |
| auto cleanup = fit::defer([&stream, &status]() { stream.Close(status); }); |
| auto external_configs = product_config_->ExternalConfigs(); |
| |
| // Input Validations |
| if (config_index >= configs_.size()) { |
| FX_LOGST(DEBUG, kTag) << "Invalid config index " << config_index; |
| status = ZX_ERR_INVALID_ARGS; |
| return; |
| } |
| const auto& config = configs_[config_index]; |
| |
| if (stream_index >= config.stream_configs.size()) { |
| FX_LOGST(DEBUG, kTag) << "Invalid stream index " << stream_index; |
| status = ZX_ERR_INVALID_ARGS; |
| return; |
| } |
| const auto& stream_config = config.stream_configs[stream_index]; |
| |
| if (image_format_index >= stream_config.image_formats.size()) { |
| FX_LOGST(DEBUG, kTag) << "Invalid image format index " << image_format_index; |
| status = ZX_ERR_INVALID_ARGS; |
| return; |
| } |
| |
| if (buffer_collection.buffer_count == 0) { |
| FX_LOGST(DEBUG, kTag) << "Invalid buffer count " << buffer_collection.buffer_count; |
| status = ZX_ERR_INVALID_ARGS; |
| return; |
| } |
| |
| // Get Internal Configuration |
| InternalConfigInfo* internal_config; |
| status = GetInternalConfiguration(config_index, &internal_config); |
| if (status != ZX_OK) { |
| FX_PLOGST(DEBUG, kTag, status) << "Unable to get Internal configuration"; |
| return; |
| } |
| |
| // Check the Input Stream Type and see if it is already created |
| auto* stream_config_node = |
| GetStreamConfigNode(internal_config, stream_config.properties.stream_type()); |
| if (stream_config_node == nullptr) { |
| FX_LOGST(DEBUG, kTag) << "Unable to get Internal stream config node"; |
| return; |
| } |
| |
| StreamCreationData info; |
| info.output_buffers = std::move(buffer_collection); |
| info.image_format_index = image_format_index; |
| info.node = *stream_config_node; |
| info.stream_config = fidl::Clone(stream_config); |
| info.frame_rate_range = internal_config->frame_rate_range; |
| |
| cleanup.cancel(); |
| |
| // We now have the stream_config_node which needs to be configured |
| // Configure the stream pipeline |
| pipeline_manager_.ConfigureStreamPipeline(std::move(info), std::move(stream)); |
| } |
| |
| void ControllerImpl::EnableStreaming() { pipeline_manager_.StartStreaming(); } |
| |
| void ControllerImpl::DisableStreaming() { pipeline_manager_.StopStreaming(); } |
| |
| void ControllerImpl::GetDeviceInfo(GetDeviceInfoCallback callback) { |
| fuchsia::camera2::DeviceInfo camera_device_info; |
| camera_device_info.set_vendor_name(kCameraVendorName); |
| camera_device_info.set_vendor_id(kCameraVendorId); |
| camera_device_info.set_product_name(kCameraProductName); |
| camera_device_info.set_product_id(kCameraProductId); |
| camera_device_info.set_type(fuchsia::camera2::DeviceType::BUILTIN); |
| callback(std::move(camera_device_info)); |
| } |
| |
| } // namespace camera |