blob: 5bab5a59fba6fd0ac2f0841a562d6efe4b5d058c [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.
#include <fidl/fuchsia.hardware.camera/cpp/wire.h>
#include <fuchsia/camera/cpp/fidl.h>
#include <fuchsia/hardware/camera/cpp/fidl.h>
#include <fuchsia/ui/policy/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/executor.h>
#include <lib/async/cpp/wait.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/result.h>
#include <zircon/processargs.h>
#include <string>
#include "src/camera/bin/usb_device/device_impl.h"
zx::result<fuchsia::camera::ControlSyncPtr> OpenCamera(
fidl::ClientEnd<fuchsia_hardware_camera::Device> client_end) {
fuchsia::camera::ControlSyncPtr ctrl;
zx_status_t status =
fidl::WireCall(client_end)->GetChannel(ctrl.NewRequest().TakeChannel()).status();
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Call to GetChannel failed";
return zx::error(status);
}
fuchsia::camera::DeviceInfo info_return;
status = ctrl->GetDeviceInfo(&info_return);
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Call to GetDeviceInfo failed";
return zx::error(status);
}
FX_LOGS(INFO) << "Got Device Info:";
FX_LOGS(INFO) << "Vendor: " << info_return.vendor_name << " (" << info_return.vendor_id << ")";
return zx::ok(std::move(ctrl));
}
int main(int argc, char* argv[]) {
fuchsia_logging::SetLogSettings({.min_log_level = CAMERA_MIN_LOG_LEVEL},
{"camera", "camera_device"});
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
async::Executor executor(loop.dispatcher());
auto context = sys::ComponentContext::Create();
// Removed argument parsing.
// TODO(ernesthua) - Need to bring back argument parsing on merge back.
std::string outgoing_service_name("fuchsia.camera3.Device");
// We receive a channel that we interpret as a fuchsia.camera.Control
// connection.
zx::channel camera_channel(zx_take_startup_handle(PA_HND(PA_USER0, 0)));
if (!camera_channel.is_valid()) {
FX_LOGS(FATAL) << "Received invalid camera handle";
return EXIT_FAILURE;
}
// Connect to USB camera device.
zx::result status_or =
OpenCamera(fidl::ClientEnd<fuchsia_hardware_camera::Device>{std::move(camera_channel)});
if (status_or.is_error()) {
FX_PLOGS(FATAL, status_or.error_value())
<< "Failed to request camera device: error: " << status_or.error_value();
return EXIT_FAILURE;
}
auto control_sync_ptr = std::move(*(status_or));
// Connect to required environment services.
fuchsia::sysmem::AllocatorHandle allocator_handle;
fuchsia::sysmem::AllocatorPtr allocator_ptr;
zx_status_t status = context->svc()->Connect(allocator_handle.NewRequest());
if (status != ZX_OK) {
FX_PLOGS(FATAL, status) << "Failed to request allocator service.";
return EXIT_FAILURE;
}
allocator_ptr = allocator_handle.Bind();
// Post a quit task in the event the device enters a bad state.
zx::event event;
FX_CHECK(zx::event::create(0, &event) == ZX_OK);
async::Wait wait(event.get(), ZX_EVENT_SIGNALED, 0,
[&](async_dispatcher_t* dispatcher, async::Wait* wait, zx_status_t status,
const zx_packet_signal_t* signal) {
FX_LOGS(FATAL) << "Device signaled bad state.";
loop.Quit();
});
ZX_ASSERT(wait.Begin(loop.dispatcher()) == ZX_OK);
// Create the device and publish its service.
std::unique_ptr<camera::DeviceImpl> device;
auto create_device_and_add_service =
camera::DeviceImpl::Create(loop.dispatcher(), std::move(control_sync_ptr),
std::move(allocator_ptr), std::move(event))
.and_then([&](std::unique_ptr<camera::DeviceImpl>& dev) {
device = std::move(dev);
// TODO(https://fxbug.dev/42121063): publish discoverable service name once
// supported
zx_status_t status =
context->outgoing()->AddPublicService(device->GetHandler(), outgoing_service_name);
if (status != ZX_OK) {
FX_PLOGS(FATAL, status) << "Failed to publish service.";
loop.Quit();
return;
}
context->outgoing()->ServeFromStartupInfo();
})
.or_else([&loop](zx_status_t& error) {
FX_PLOGS(FATAL, error) << "Failed to create device.";
loop.Quit();
});
executor.schedule_task(std::move(create_device_and_add_service));
loop.Run();
return EXIT_SUCCESS;
}