cat / goq
clone

turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer

1-n-sigls
goq / crates / sigil-host / src / clock.rs
clock.rs 2.3K
1use std::time::{Duration, Instant};23/// One monotonic epoch shared by every media source in an active session.4#[derive(Clone, Copy, Debug, PartialEq, Eq)]5pub(crate) struct SessionClock {6 epoch: Instant,7}89impl SessionClock {10 pub(crate) fn start() -> Self {11 Self {12 epoch: Instant::now(),13 }14 }1516 pub(crate) fn now_micros(self) -> u64 {17 self.micros_at(Instant::now())18 }1920 pub(crate) fn micros_at(self, observed_at: Instant) -> u64 {21 duration_micros(22 observed_at23 .checked_duration_since(self.epoch)24 .unwrap_or(Duration::ZERO),25 )26 }27}2829fn duration_micros(duration: Duration) -> u64 {30 u64::try_from(duration.as_micros()).unwrap_or(u64::MAX)31}3233/// Add ticks from a fixed-rate media clock to a common-clock anchor.34pub(crate) fn anchored_timestamp_micros(35 anchor_micros: u64,36 elapsed_ticks: u64,37 ticks_per_second: u32,38) -> i64 {39 let elapsed_micros = elapsed_ticks40 .saturating_mul(1_000_000)41 .checked_div(u64::from(ticks_per_second))42 .unwrap_or(u64::MAX);43 i64::try_from(anchor_micros.saturating_add(elapsed_micros)).unwrap_or(i64::MAX)44}4546#[cfg(test)]47mod tests {48 use super::*;4950 #[test]51 fn session_clock_is_nondecreasing() {52 let clock = SessionClock::start();53 let first = clock.now_micros();54 let second = clock.now_micros();55 assert!(second >= first);56 }5758 #[test]59 fn session_clock_preserves_real_observation_gaps() {60 let epoch = Instant::now();61 let clock = SessionClock { epoch };62 assert_eq!(clock.micros_at(epoch), 0);63 assert_eq!(clock.micros_at(epoch + Duration::from_millis(750)), 750_000);64 }6566 #[test]67 fn anchored_timestamps_preserve_epoch_and_fixed_rate_cadence() {68 assert_eq!(anchored_timestamp_micros(2_000_000, 0, 60), 2_000_000);69 assert_eq!(anchored_timestamp_micros(2_000_000, 1, 60), 2_016_666);70 assert_eq!(anchored_timestamp_micros(2_000_000, 3, 60), 2_050_000);71 assert_eq!(anchored_timestamp_micros(2_000_000, 960, 48_000), 2_020_000);72 }7374 #[test]75 fn anchored_timestamp_conversion_saturates() {76 assert_eq!(anchored_timestamp_micros(u64::MAX, u64::MAX, 1), i64::MAX);77 assert_eq!(anchored_timestamp_micros(1, 1, 0), i64::MAX);78 }79}