Skip to content

Commit b169a68

Browse files
committed
Implement pause/resume
closes #14
1 parent 2848647 commit b169a68

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- Pause/resume camera stream
12+
913
## [0.2.0] - 2025-02-19
1014

1115
### Added

src/camera.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use nokhwa::utils::{
99
CameraFormat, CameraIndex, ControlValueSetter, FrameFormat, KnownCameraControl,
1010
RequestedFormat, RequestedFormatType, Resolution,
1111
};
12-
use std::sync::{Arc, Mutex};
12+
use std::sync::{Arc, Condvar, Mutex};
1313

1414
#[derive(Debug, Clone)]
1515
pub struct CameraInfo {
@@ -41,6 +41,8 @@ pub enum CameraEvent {
4141
StopStream,
4242
Config(ImageConfig),
4343
Controls(Vec<(KnownCameraControl, ControlValueSetter)>),
44+
Pause,
45+
Resume,
4446
}
4547

4648
struct Exit {}
@@ -75,7 +77,11 @@ impl CameraThread {
7577
#[allow(clippy::type_complexity)]
7678
let controls: Arc<Mutex<Option<Vec<(KnownCameraControl, ControlValueSetter)>>>> =
7779
Arc::new(Mutex::new(None));
80+
81+
let pause = Arc::new((Mutex::new(false), Condvar::new()));
82+
7883
let mut join_handle = None;
84+
7985
while let Ok(event) = self.config_rx.recv() {
8086
match event {
8187
CameraEvent::StartStream { id, format } => {
@@ -86,6 +92,8 @@ impl CameraThread {
8692
let window_tx = self.window_tx.clone();
8793
let result_tx = self.result_tx.clone();
8894
let exit_rx = exit_rx.clone();
95+
let pause_thread = Arc::clone(&pause);
96+
8997
let hdl = std::thread::spawn(move || {
9098
let mut camera = match CallbackCamera::new(
9199
id,
@@ -127,7 +135,15 @@ impl CameraThread {
127135

128136
let mut inner_config = None;
129137

138+
let (pause_lock, pause_cvar) = &*pause_thread;
139+
130140
loop {
141+
// Check pause request
142+
let guard = pause_cvar
143+
.wait_while(pause_lock.lock().unwrap(), |paused| *paused)
144+
.unwrap();
145+
drop(guard);
146+
131147
// Check exit request
132148
if exit_rx.try_recv().is_ok() {
133149
return;
@@ -208,6 +224,18 @@ impl CameraThread {
208224
CameraEvent::Controls(ctrls) => {
209225
*controls.lock().unwrap() = Some(ctrls);
210226
}
227+
CameraEvent::Pause => {
228+
let (pause_lock, pause_cvar) = &*pause;
229+
let mut paused = pause_lock.lock().unwrap();
230+
*paused = true;
231+
pause_cvar.notify_one();
232+
}
233+
CameraEvent::Resume => {
234+
let (pause_lock, pause_cvar) = &*pause;
235+
let mut paused = pause_lock.lock().unwrap();
236+
*paused = false;
237+
pause_cvar.notify_one();
238+
}
211239
}
212240
}
213241
log::debug!("Camera thread exiting");

src/gui/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub struct SpectrometerGui {
3131
camera_control_window: camera_control::CameraControlWindow,
3232
import_export_window: import_export::ImportExportWindow,
3333
running: bool,
34+
paused: bool,
3435
camera_info: IndexMap<CameraIndex, crate::camera::CameraInfo>,
3536
camera_controls: Vec<CameraControl>,
3637
spectrum_container: SpectrumContainer,
@@ -61,6 +62,7 @@ impl SpectrometerGui {
6162
camera_control_window: camera_control::CameraControlWindow::new(),
6263
import_export_window: import_export::ImportExportWindow::new(),
6364
running: false,
65+
paused: false,
6466
camera_info: Default::default(),
6567
camera_controls: Default::default(),
6668
spectrum_container: SpectrumContainer::new(spectrum_rx),
@@ -166,7 +168,17 @@ impl SpectrometerGui {
166168
}
167169
}
168170

171+
fn pause_stream(&mut self) {
172+
self.camera_config_tx.send(CameraEvent::Pause).unwrap();
173+
}
174+
175+
fn resume_stream(&mut self) {
176+
self.camera_config_tx.send(CameraEvent::Resume).unwrap();
177+
}
178+
169179
fn stop_stream(&mut self) {
180+
// First resume stream, otherwise the camera thread will not continue
181+
self.resume_stream();
170182
self.camera_config_tx.send(CameraEvent::StopStream).unwrap();
171183
}
172184

@@ -451,6 +463,7 @@ impl SpectrometerGui {
451463
.clamp(camera_format.width() as f32, camera_format.height() as f32);
452464

453465
self.running = !self.running;
466+
self.paused = false;
454467
if self.running {
455468
self.start_stream();
456469
} else {
@@ -463,6 +476,18 @@ impl SpectrometerGui {
463476
});
464477
}
465478
};
479+
if self.running {
480+
let pause_resume_button =
481+
ui.button(if self.paused { "Resume" } else { "Pause" });
482+
if pause_resume_button.clicked() {
483+
if self.paused {
484+
self.resume_stream();
485+
} else {
486+
self.pause_stream();
487+
}
488+
self.paused = !self.paused;
489+
}
490+
}
466491
});
467492
});
468493
}

0 commit comments

Comments
 (0)