1use std::time::{Duration, Instant};
4
5pub type AudioDuration = Duration;
7
8pub type AudioInstant = Instant;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
17pub struct AudioTimestamp(u64);
18
19impl AudioTimestamp {
20 pub const ZERO: Self = Self(0);
21 pub const EPOCH: Self = Self(0);
22
23 pub fn from_secs(secs: f64) -> Self {
24 if !secs.is_finite() || secs <= 0.0 {
25 return Self::ZERO;
26 }
27
28 let nanos = (secs * 1_000_000_000.0).min(u64::MAX as f64);
29 Self(nanos as u64)
30 }
31
32 pub fn from_nanos(nanos: u64) -> Self {
33 Self(nanos)
34 }
35
36 pub fn from_samples(samples: u64, sample_rate: u32) -> Self {
37 if sample_rate == 0 {
38 return Self::ZERO;
39 }
40
41 Self(samples.saturating_mul(1_000_000_000) / sample_rate as u64)
42 }
43
44 pub fn as_secs(&self) -> f64 {
45 self.0 as f64 / 1_000_000_000.0
46 }
47
48 pub fn as_millis(&self) -> f64 {
49 self.0 as f64 / 1_000_000.0
50 }
51
52 pub fn nanos(&self) -> u64 {
53 self.0
54 }
55
56 pub fn add_duration(&self, d: Duration) -> Self {
57 let nanos = d.as_nanos().min(u128::from(u64::MAX)) as u64;
58 Self(self.0.saturating_add(nanos))
59 }
60
61 pub fn duration_since(&self, earlier: Self) -> Option<Duration> {
62 self.0.checked_sub(earlier.0).map(Duration::from_nanos)
63 }
64}
65
66impl std::ops::Add<Duration> for AudioTimestamp {
67 type Output = Self;
68 fn add(self, rhs: Duration) -> Self {
69 self.add_duration(rhs)
70 }
71}
72
73impl std::ops::Sub for AudioTimestamp {
74 type Output = Duration;
75 fn sub(self, rhs: Self) -> Duration {
76 Duration::from_nanos(self.0.saturating_sub(rhs.0))
77 }
78}
79
80impl std::fmt::Display for AudioTimestamp {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 write!(f, "{:.3}s", self.as_secs())
83 }
84}
85
86pub(crate) fn validate_in_range<T: PartialOrd + std::fmt::Display>(
88 value: T,
89 min: T,
90 max: T,
91 name: &str,
92) -> crate::error::Result<()> {
93 if value < min || value > max {
94 return Err(crate::error::Error::configuration(format!(
95 "{name} = {value} is outside valid range [{min}, {max}]"
96 )));
97 }
98 Ok(())
99}