blob: 7abeb41e90bdc39df9c303fcf2553f87a2a82c83 [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/camera3/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <fuchsia/ui/policy/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/task.h>
#include <lib/fit/bridge.h>
#include <lib/fit/single_threaded_executor.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace-provider/provider.h>
#include <set>
#include "src/camera/bin/camera-gym/buffer_collage.h"
#include "src/camera/bin/camera-gym/lifecycle_impl.h"
#include "src/camera/bin/camera-gym/stream_cycler.h"
#include "src/lib/fxl/command_line.h"
int main(int argc, char* argv[]) {
auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
// Default must match existing behavior as started from UI.
bool manual_mode = command_line.HasOption("manual");
syslog::SetLogSettings({.min_log_level = CAMERA_MIN_LOG_LEVEL}, {"camera-gym"});
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
trace::TraceProviderWithFdio trace_provider(loop.dispatcher());
auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
// Connect to required services for the collage.
fuchsia::sysmem::AllocatorHandle allocator;
zx_status_t status = context->svc()->Connect(allocator.NewRequest());
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to request Allocator service.";
return EXIT_FAILURE;
}
fuchsia::ui::scenic::ScenicHandle scenic;
status = context->svc()->Connect(scenic.NewRequest());
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to request Scenic service.";
return EXIT_FAILURE;
}
fuchsia::ui::policy::PresenterHandle presenter;
context->svc()->Connect(presenter.NewRequest());
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to request Presenter service.";
return EXIT_FAILURE;
}
// Create the collage.
auto collage_result = camera::BufferCollage::Create(std::move(scenic), std::move(allocator),
std::move(presenter), [&] { loop.Quit(); });
if (collage_result.is_error()) {
FX_PLOGS(ERROR, collage_result.error()) << "Failed to create BufferCollage.";
return EXIT_FAILURE;
}
auto collage = collage_result.take_value();
// Connect to required services for the cycler.
fuchsia::camera3::DeviceWatcherHandle watcher;
status = context->svc()->Connect(watcher.NewRequest());
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to request DeviceWatcher service.";
return EXIT_FAILURE;
}
allocator = nullptr;
status = context->svc()->Connect(allocator.NewRequest());
if (status != ZX_OK) {
FX_PLOGS(ERROR, status) << "Failed to request Allocator service.";
return EXIT_FAILURE;
}
// Create the cycler and attach it to the collage.
auto cycler_result =
camera::StreamCycler::Create(std::move(watcher), std::move(allocator), manual_mode);
if (cycler_result.is_error()) {
FX_PLOGS(ERROR, cycler_result.error()) << "Failed to create StreamCycler.";
return EXIT_FAILURE;
}
auto cycler = cycler_result.take_value();
bool device_muted = false;
std::set<uint32_t> collection_ids;
camera::StreamCycler::AddCollectionHandler add_collection_handler =
[&](fuchsia::sysmem::BufferCollectionTokenHandle token,
fuchsia::sysmem::ImageFormat_2 image_format, std::string description) -> uint32_t {
auto result = fit::run_single_threaded(
collage->AddCollection(std::move(token), image_format, description));
if (result.is_error()) {
FX_LOGS(FATAL) << "Failed to add collection to collage.";
return 0;
}
collection_ids.insert(result.value());
return result.value();
};
camera::StreamCycler::RemoveCollectionHandler remove_collection_handler = [&](uint32_t id) {
collection_ids.erase(id);
collage->RemoveCollection(id);
};
camera::StreamCycler::ShowBufferHandler show_buffer_handler =
[&](uint32_t collection_id, uint32_t buffer_index, zx::eventpair release_fence,
std::optional<fuchsia::math::RectF> subregion) {
collage->PostShowBuffer(collection_id, buffer_index, std::move(release_fence),
std::move(subregion));
if (!device_muted) {
// Only make the collection visible after we have shown an unmuted frame.
collage->PostSetCollectionVisibility(collection_id, true);
}
};
camera::StreamCycler::MuteStateHandler mute_handler = [&](bool muted) {
collage->PostSetMuteIconVisibility(muted);
if (muted) {
// Immediately hide all collections on mute.
for (auto id : collection_ids) {
collage->PostSetCollectionVisibility(id, false);
}
}
device_muted = muted;
};
cycler->SetHandlers(std::move(add_collection_handler), std::move(remove_collection_handler),
std::move(show_buffer_handler), std::move(mute_handler));
if (manual_mode) {
FX_LOGS(INFO) << "Running in manual mode.";
FX_LOGS(INFO) << "This is a placeholder. Dropping through to automatic mode for now.";
} else {
FX_LOGS(INFO) << "Running in automatic mode.";
}
// Publish the view service.
context->outgoing()->AddPublicService(collage->GetHandler());
// Publish a handler for the Lifecycle protocol that cleanly quits the component.
LifecycleImpl lifecycle([&] { loop.Quit(); });
context->outgoing()->AddPublicService(lifecycle.GetHandler());
loop.Run();
return EXIT_SUCCESS;
}