diff --git a/src/lib.rs b/src/lib.rs index 31a6b45..9f2ada6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -158,6 +158,7 @@ pub use platform::{ SupportedInputConfigs, SupportedOutputConfigs, ALL_HOSTS, }; pub use samples_formats::{Sample, SampleFormat}; +use std::time::Duration; mod error; mod host; @@ -220,13 +221,53 @@ pub struct Data { sample_format: SampleFormat, } -/// Information relevant to a single call to the user's output stream data callback. -#[derive(Debug, Clone, PartialEq)] -pub struct OutputCallbackInfo {} +/// A monotonic time instance associated with a stream, retrieved from either: +/// +/// 1. A timestamp provided to the stream's underlying audio data callback or +/// 2. The same time source used to generate timestamps for a stream's underlying audio data +/// callback. +/// +/// **StreamInstant** represents a duration since some unspecified origin occurring either before +/// or equal to the moment the stream from which it was created begins. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +pub struct StreamInstant { + secs: u64, + nanos: u32, +} + +/// A timestamp associated with a call to an input stream's data callback. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] +pub struct InputStreamTimestamp { + /// The instant the stream's data callback was invoked. + pub callback: StreamInstant, + /// The instant that data was captured from the device. + /// + /// E.g. The instant data was read from an ADC. + pub capture: StreamInstant, +} + +/// A timestamp associated with a call to an output stream's data callback. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] +pub struct OutputStreamTimestamp { + /// The instant the stream's data callback was invoked. + pub callback: StreamInstant, + /// The predicted instant that data written will be delivered to the device for playback. + /// + /// E.g. The instant data will be played by a DAC. + pub playback: StreamInstant, +} /// Information relevant to a single call to the user's input stream data callback. #[derive(Debug, Clone, PartialEq)] -pub struct InputCallbackInfo {} +pub struct InputCallbackInfo { + timestamp: InputStreamTimestamp, +} + +/// Information relevant to a single call to the user's output stream data callback. +#[derive(Debug, Clone, PartialEq)] +pub struct OutputCallbackInfo { + timestamp: OutputStreamTimestamp, +} impl SupportedStreamConfig { pub fn channels(&self) -> ChannelCount { @@ -249,6 +290,66 @@ impl SupportedStreamConfig { } } +impl StreamInstant { + /// The amount of time elapsed from another instant to this one. + /// + /// Returns `None` if `earlier` is later than self. + pub fn duration_since(&self, earlier: &Self) -> Option { + if self < earlier { + None + } else { + Some(self.as_duration() - earlier.as_duration()) + } + } + + /// Returns the instant in time after the given duration has passed. + /// + /// Returns `None` if the resulting instant would exceed the bounds of the underlying data + /// structure. + pub fn add(&self, duration: Duration) -> Option { + self.as_duration() + .checked_add(duration) + .map(Self::from_duration) + } + + /// Returns the instant in time one `duration` ago. + /// + /// Returns `None` if the resulting instant would underflow. As a result, it is important to + /// consider that on some platforms the `StreamInstant` may begin at `0` from the moment the + /// source stream is created. + pub fn sub(&self, duration: Duration) -> Option { + self.as_duration() + .checked_sub(duration) + .map(Self::from_duration) + } + + fn new(secs: u64, nanos: u32) -> Self { + StreamInstant { secs, nanos } + } + + fn as_duration(&self) -> Duration { + Duration::new(self.secs, self.nanos) + } + + fn from_duration(d: Duration) -> Self { + Self::new(d.as_secs(), d.subsec_nanos()) + } +} + +impl InputCallbackInfo { + /// The timestamp associated with the call to an input stream's data callback. + pub fn timestamp(&self) -> InputStreamTimestamp { + self.timestamp + } +} + +impl OutputCallbackInfo { + /// The timestamp associated with the call to an output stream's data callback. + pub fn timestamp(&self) -> OutputStreamTimestamp { + self.timestamp + } +} + impl Data { // Internal constructor for host implementations to use. //