| // 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 <fuchsia/camera/test/cpp/fidl.h> |
| #include <fuchsia/camera3/cpp/fidl.h> |
| #include <fuchsia/hardware/camera/cpp/fidl.h> |
| #include <fuchsia/sys/cpp/fidl.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/fidl/cpp/binding_set.h> |
| #include <lib/sys/cpp/component_context.h> |
| #include <lib/syslog/cpp/log_settings.h> |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "src/camera/bin/device_watcher/device_watcher_impl.h" |
| #include "src/lib/fsl/io/device_watcher.h" |
| |
| constexpr auto kCameraPath = "/dev/class/camera"; |
| |
| static fpromise::result<fuchsia::hardware::camera::DeviceHandle, zx_status_t> GetCamera( |
| std::string path) { |
| fuchsia::hardware::camera::DeviceHandle camera; |
| zx_status_t status = |
| fdio_service_connect(path.c_str(), camera.NewRequest().TakeChannel().release()); |
| if (status != ZX_OK) { |
| FX_PLOGS(ERROR, status); |
| return fpromise::error(status); |
| } |
| |
| return fpromise::ok(std::move(camera)); |
| } |
| |
| class DeviceWatcherTesterImpl : public fuchsia::camera::test::DeviceWatcherTester { |
| public: |
| using InjectDeviceCallback = fit::function<void(fuchsia::hardware::camera::DeviceHandle)>; |
| explicit DeviceWatcherTesterImpl(InjectDeviceCallback callback) |
| : callback_(std::move(callback)) {} |
| fidl::InterfaceRequestHandler<fuchsia::camera::test::DeviceWatcherTester> GetHandler() { |
| return fit::bind_member(this, &DeviceWatcherTesterImpl::OnNewRequest); |
| } |
| |
| private: |
| void OnNewRequest(fidl::InterfaceRequest<fuchsia::camera::test::DeviceWatcherTester> request) { |
| bindings_.AddBinding(this, std::move(request)); |
| } |
| |
| // |fuchsia::camera::test::DeviceWatcherTester| |
| void InjectDevice(fuchsia::hardware::camera::DeviceHandle camera) override { |
| callback_(std::move(camera)); |
| } |
| |
| fidl::BindingSet<fuchsia::camera::test::DeviceWatcherTester> bindings_; |
| InjectDeviceCallback callback_; |
| }; |
| |
| int main(int argc, char* argv[]) { |
| syslog::SetLogSettings({.min_log_level = CAMERA_MIN_LOG_LEVEL}, |
| {"camera", "camera_device_watcher"}); |
| |
| async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); |
| auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory(); |
| |
| fuchsia::sys::LauncherHandle launcher; |
| zx_status_t status = context->svc()->Connect(launcher.NewRequest()); |
| if (status != ZX_OK) { |
| FX_PLOGS(FATAL, status) << "Failed to connect to launcher service."; |
| return EXIT_FAILURE; |
| } |
| |
| auto result = DeviceWatcherImpl::Create(std::move(launcher), loop.dispatcher()); |
| if (result.is_error()) { |
| FX_PLOGS(FATAL, result.error()); |
| return EXIT_FAILURE; |
| } |
| |
| auto server = result.take_value(); |
| |
| auto watcher = fsl::DeviceWatcher::CreateWithIdleCallback( |
| kCameraPath, |
| [&](int dir_fd, std::string path) { |
| auto full_path = std::string(kCameraPath) + "/" + path; |
| auto result = GetCamera(full_path); |
| if (result.is_error()) { |
| FX_PLOGS(INFO, result.error()) << "Couldn't get camera from " << full_path |
| << ". This device will not be exposed to clients."; |
| return; |
| } |
| auto add_result = server->AddDevice(result.take_value()); |
| if (add_result.is_error()) { |
| FX_PLOGS(WARNING, add_result.error()) << "Failed to add camera from " << full_path |
| << ". This device will not be exposed to clients."; |
| return; |
| } |
| }, |
| [&]() { server->UpdateClients(); }); |
| if (!watcher) { |
| FX_LOGS(FATAL); |
| return EXIT_FAILURE; |
| } |
| |
| context->outgoing()->AddPublicService(server->GetHandler()); |
| |
| DeviceWatcherTesterImpl tester([&](fuchsia::hardware::camera::DeviceHandle device) { |
| auto result = server->AddDevice(std::move(device)); |
| if (result.is_error()) { |
| FX_PLOGS(ERROR, result.error()) << "Failed to add test device."; |
| return; |
| } |
| server->UpdateClients(); |
| }); |
| |
| context->outgoing()->AddPublicService(tester.GetHandler()); |
| |
| loop.Run(); |
| return EXIT_SUCCESS; |
| } |