blob: 65c7271f3ff5d74adfaa48306ab208e0b0897afb [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 <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;
}