use serde::Serialize; const DEFAULT_AUDIO_WINDOW_MS: u32 = 5; const DEFAULT_MAX_PAIR_GAP_S: f64 = 0.5; const DEFAULT_PULSE_PERIOD_S: f64 = 1.0; const DEFAULT_PULSE_WIDTH_S: f64 = 0.12; const DEFAULT_MARKER_TICK_PERIOD: u32 = 5; #[derive(Clone, Debug, PartialEq, Serialize)] pub struct SyncAnalysisReport { pub video_event_count: usize, pub audio_event_count: usize, pub paired_event_count: usize, pub first_skew_ms: f64, pub last_skew_ms: f64, pub mean_skew_ms: f64, pub median_skew_ms: f64, pub max_abs_skew_ms: f64, pub drift_ms: f64, pub skews_ms: Vec, pub video_onsets_s: Vec, pub audio_onsets_s: Vec, } #[derive(Clone, Debug, PartialEq)] pub struct SyncAnalysisOptions { pub audio_window_ms: u32, pub max_pair_gap_s: f64, pub pulse_period_s: f64, pub pulse_width_s: f64, pub marker_tick_period: u32, } impl Default for SyncAnalysisOptions { fn default() -> Self { Self { audio_window_ms: DEFAULT_AUDIO_WINDOW_MS, max_pair_gap_s: DEFAULT_MAX_PAIR_GAP_S, pulse_period_s: DEFAULT_PULSE_PERIOD_S, pulse_width_s: DEFAULT_PULSE_WIDTH_S, marker_tick_period: DEFAULT_MARKER_TICK_PERIOD, } } } #[cfg(test)] mod tests { use super::SyncAnalysisOptions; #[test] fn default_options_match_live_probe_expectations() { let options = SyncAnalysisOptions::default(); assert_eq!(options.audio_window_ms, 5); assert!((options.max_pair_gap_s - 0.5).abs() < f64::EPSILON); assert!((options.pulse_period_s - 1.0).abs() < f64::EPSILON); assert!((options.pulse_width_s - 0.12).abs() < f64::EPSILON); assert_eq!(options.marker_tick_period, 5); } }