Skip to main content

proteus_lib/diagnostics/
reporter.rs

1//! Periodic playback state reporter for UI updates.
2
3use std::{
4    sync::{Arc, Mutex},
5    time::Duration,
6};
7
8use crate::playback::player::Player;
9
10/// Snapshot of playback state sent to UI consumers.
11#[derive(Clone, PartialEq)]
12pub struct Report {
13    pub time: f64,
14    pub volume: f32,
15    pub duration: f64,
16    pub playing: bool,
17}
18
19/// Background reporter that polls the [`Player`] at fixed intervals.
20#[derive(Clone)]
21pub struct Reporter {
22    player: Arc<Mutex<Player>>,
23    report: Arc<Mutex<dyn Fn(Report) + Send>>,
24    interval: Duration,
25    finish: Arc<Mutex<bool>>,
26}
27
28impl Reporter {
29    /// Create a new reporter for the given player and callback.
30    pub fn new(
31        player: Arc<Mutex<Player>>,
32        report: Arc<Mutex<dyn Fn(Report) + Send>>,
33        interval: Duration,
34    ) -> Self {
35        Self {
36            player,
37            report,
38            interval,
39            finish: Arc::new(Mutex::new(false)),
40        }
41    }
42
43    fn run(&self) {
44        let mut last_report = Report {
45            time: 0.0,
46            volume: 0.0,
47            duration: 0.0,
48            playing: false,
49        };
50
51        loop {
52            let player = self.player.lock().unwrap();
53            let time = player.get_time();
54            let volume = player.get_volume();
55            let duration = player.get_duration();
56            let playing = player.is_playing();
57
58            let report = Report {
59                time,
60                volume,
61                duration,
62                playing,
63            };
64
65            drop(player);
66
67            if report != last_report {
68                (*self.report.lock().unwrap())(report.clone());
69                last_report = report;
70            }
71
72            if *self.finish.lock().unwrap() {
73                break;
74            }
75
76            std::thread::sleep(self.interval);
77        }
78    }
79
80    /// Start the background reporting thread.
81    pub fn start(&self) {
82        let this = self.clone();
83        Some(std::thread::spawn(move || this.run()));
84        *self.finish.lock().unwrap() = false;
85    }
86
87    /// Stop the background reporting thread.
88    pub fn stop(&self) {
89        *self.finish.lock().unwrap() = true;
90        // if let Some(child) = self.child.take() {
91        //     child.join().unwrap();
92        // }
93    }
94}