blob: 9beb4f45da5c578e606404fff85a98d9cdd65231 [file] [log] [blame]
// 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