1use anyhow::{Error, format_err};
5use fidl::endpoints::create_proxy;
6use fidl_fuchsia_camera3::{
7 DeviceMarker, DeviceProxy as Camera3DeviceProxy, DeviceWatcherMarker,
8 DeviceWatcherProxy as Camera3DeviceWatcherProxy, WatchDevicesEvent,
9};
10use fuchsia_async::{self as fasync, DurationExt};
11use futures::FutureExt;
12use futures::future::Fuse;
13use settings_common::inspect::event::ExternalEventPublisher;
14use settings_common::service_context::{ExternalServiceProxy, ServiceContext};
15use settings_common::{call, call_async};
16use zx::MonotonicDuration;
17
18pub const CAMERA_WATCHER_TIMEOUT: i64 = 30_000;
20
21async fn get_camera_id(
23 camera_watcher_proxy: &ExternalServiceProxy<Camera3DeviceWatcherProxy, ExternalEventPublisher>,
24) -> Result<u64, Error> {
25 let timer =
31 fasync::Timer::new(MonotonicDuration::from_millis(CAMERA_WATCHER_TIMEOUT).after_now())
32 .fuse();
33 let camera_ids = call_async!(camera_watcher_proxy => watch_devices()).fuse();
34
35 let unfulfilled_future = Fuse::terminated();
37
38 futures::pin_mut!(timer, camera_ids, unfulfilled_future);
39 loop {
40 futures::select! {
41 ids_result = camera_ids => {
42 let ids = ids_result?;
43 if ids.is_empty() {
44 let next_camera_ids = call_async!(camera_watcher_proxy => watch_devices()).fuse();
47 unfulfilled_future.set(next_camera_ids);
48 } else {
49 return extract_cam_id(ids);
51 }
52 }
53 ids_result_second = unfulfilled_future => {
54 let ids = ids_result_second?;
55 return extract_cam_id(ids);
56 }
57 _ = timer => {
58 return Err(format_err!("Could not find a camera"));
59 }
60 }
61 }
62}
63
64fn extract_cam_id(ids: Vec<WatchDevicesEvent>) -> Result<u64, Error> {
66 let first_cam = ids.first();
67 if let Some(WatchDevicesEvent::Existing(id)) | Some(WatchDevicesEvent::Added(id)) = first_cam {
68 Ok(*id)
69 } else {
70 Err(format_err!("Could not find a camera"))
71 }
72}
73
74pub async fn connect_to_camera(
77 service_context: &ServiceContext,
78 external_publisher: ExternalEventPublisher,
79) -> Result<Camera3DeviceProxy, Error> {
80 let camera_watcher_proxy = service_context
83 .connect_with_publisher::<DeviceWatcherMarker, _>(external_publisher)
84 .await?;
85 let camera_id = get_camera_id(&camera_watcher_proxy).await?;
86
87 let (camera_proxy, device_server) = create_proxy::<DeviceMarker>();
89 if call!(camera_watcher_proxy => connect_to_device(camera_id, device_server)).is_err() {
90 return Err(format_err!("Could not connect to fuchsia.camera3.DeviceWatcher device"));
91 }
92 Ok(camera_proxy)
93}