| // 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; |
| } |