Skip to content

Commit ae8bd29

Browse files
Merge pull request #1436 from CapSoftware/camera-fix
feat: Add camera preview timeout and improve camera cleanup
2 parents fabd186 + fdad15c commit ae8bd29

File tree

2 files changed

+46
-8
lines changed

2 files changed

+46
-8
lines changed

apps/desktop/src-tauri/src/camera.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ use tokio::{
1717
runtime::Runtime,
1818
sync::{broadcast, oneshot},
1919
task::LocalSet,
20+
time::{Duration, Instant},
2021
};
21-
use tracing::{error, info, trace};
22+
use tracing::{error, info, trace, warn};
2223
use wgpu::{CompositeAlphaMode, SurfaceTexture};
2324

2425
static TOOLBAR_HEIGHT: f32 = 56.0; // also defined in Typescript
@@ -496,8 +497,23 @@ impl Renderer {
496497
return;
497498
};
498499

500+
let start_time = Instant::now();
501+
let startup_timeout = Duration::from_secs(5);
502+
let mut received_first_frame = false;
503+
499504
let mut state = default_state;
500505
while let Some(event) = loop {
506+
let timeout_remaining = if received_first_frame {
507+
Duration::MAX
508+
} else {
509+
startup_timeout.saturating_sub(start_time.elapsed())
510+
};
511+
512+
if timeout_remaining.is_zero() {
513+
warn!("Camera preview timed out waiting for first frame, closing window");
514+
break None;
515+
}
516+
501517
tokio::select! {
502518
frame = camera_rx.recv_async() => break frame.ok().map(Ok),
503519
result = reconfigure.recv() => {
@@ -507,10 +523,15 @@ impl Renderer {
507523
continue;
508524
}
509525
},
526+
_ = tokio::time::sleep(timeout_remaining) => {
527+
warn!("Camera preview timed out waiting for first frame, closing window");
528+
break None;
529+
}
510530
}
511531
} {
512532
match event {
513533
Ok(frame) => {
534+
received_first_frame = true;
514535
let aspect_ratio = frame.inner.width() as f32 / frame.inner.height() as f32;
515536
self.sync_ratio_uniform_and_resize_window_to_it(&window, &state, aspect_ratio);
516537

apps/desktop/src-tauri/src/lib.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,17 @@ async fn set_camera_input(
457457
.map_err(|e| e.to_string())?;
458458
}
459459
Some(id) => {
460+
{
461+
let app = &mut *state.write().await;
462+
app.selected_camera_id = Some(id.clone());
463+
app.camera_in_use = true;
464+
app.camera_cleanup_done = false;
465+
}
466+
460467
let mut attempts = 0;
461-
loop {
468+
let init_result: Result<(), String> = loop {
462469
attempts += 1;
463470

464-
// We first ask the actor to set the input
465-
// This returns a future that resolves when the camera is actually ready
466471
let request = camera_feed
467472
.ask(feeds::camera::SetInput { id: id.clone() })
468473
.await
@@ -474,10 +479,10 @@ async fn set_camera_input(
474479
};
475480

476481
match result {
477-
Ok(_) => break,
482+
Ok(_) => break Ok(()),
478483
Err(e) => {
479484
if attempts >= 3 {
480-
return Err(format!(
485+
break Err(format!(
481486
"Failed to initialize camera after {} attempts: {}",
482487
attempts, e
483488
));
@@ -489,6 +494,13 @@ async fn set_camera_input(
489494
tokio::time::sleep(Duration::from_millis(500)).await;
490495
}
491496
}
497+
};
498+
499+
if let Err(e) = init_result {
500+
let app = &mut *state.write().await;
501+
app.selected_camera_id = None;
502+
app.camera_in_use = false;
503+
return Err(e);
492504
}
493505

494506
ShowCapWindow::Camera
@@ -2765,7 +2777,13 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
27652777
let state = app.state::<ArcLock<App>>();
27662778
let app_state = &mut *state.write().await;
27672779

2768-
if !app_state.is_recording_active_or_pending() {
2780+
let camera_window_open =
2781+
CapWindowId::Camera.get(&app).is_some();
2782+
2783+
if !app_state.is_recording_active_or_pending()
2784+
&& !camera_window_open
2785+
&& !app_state.camera_in_use
2786+
{
27692787
let _ =
27702788
app_state.mic_feed.ask(microphone::RemoveInput).await;
27712789
let _ = app_state
@@ -2775,7 +2793,6 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
27752793

27762794
app_state.selected_mic_label = None;
27772795
app_state.selected_camera_id = None;
2778-
app_state.camera_in_use = false;
27792796
}
27802797
});
27812798
}

0 commit comments

Comments
 (0)