1pub fn now_usec() -> i64 {
8 monotonic_usec()
9}
10
11#[allow(unsafe_code)]
13fn monotonic_usec() -> i64 {
14 #[cfg(target_os = "macos")]
15 {
16 unsafe extern "C" {
17 fn mach_continuous_time() -> u64;
18 fn mach_timebase_info(info: *mut MachTimebaseInfo) -> i32;
19 }
20 #[repr(C)]
21 struct MachTimebaseInfo {
22 numer: u32,
23 denom: u32,
24 }
25 static TIMEBASE: std::sync::OnceLock<(u32, u32)> = std::sync::OnceLock::new();
26 let (numer, denom) = *TIMEBASE.get_or_init(|| {
27 let mut info = MachTimebaseInfo { numer: 0, denom: 0 };
28 unsafe {
29 mach_timebase_info(&mut info);
30 }
31 (info.numer, info.denom)
32 });
33 let ticks = unsafe { mach_continuous_time() };
34 let nanos = ticks as i128 * numer as i128 / denom as i128;
35 (nanos / 1_000) as i64
36 }
37 #[cfg(all(unix, not(target_os = "macos")))]
38 {
39 let mut ts = libc::timespec {
40 tv_sec: 0,
41 tv_nsec: 0,
42 };
43 unsafe {
44 libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts);
45 }
46 ts.tv_sec * 1_000_000 + ts.tv_nsec / 1_000
47 }
48 #[cfg(not(unix))]
49 {
50 use std::time::{SystemTime, UNIX_EPOCH};
51 SystemTime::now()
52 .duration_since(UNIX_EPOCH)
53 .unwrap_or_default()
54 .as_micros() as i64
55 }
56}
57
58pub struct ChunkTimestamper {
62 start_usec: i64,
63 samples_written: u64,
64 rate: u32,
65}
66
67impl ChunkTimestamper {
68 pub fn new(rate: u32) -> Self {
70 Self {
71 start_usec: now_usec(),
72 samples_written: 0,
73 rate,
74 }
75 }
76
77 pub fn next(&mut self, frames: u32) -> i64 {
79 let ts = self.start_usec + (self.samples_written as i64 * 1_000_000) / self.rate as i64;
80 self.samples_written += frames as u64;
81 ts
82 }
83
84 pub fn reset(&mut self) {
86 self.start_usec = now_usec();
87 self.samples_written = 0;
88 }
89}