@@ -2,7 +2,7 @@ use std::{thread::JoinHandle, time::Instant};
22
33use crate :: {
44 traits:: StreamTrait , BackendSpecificError , InputCallbackInfo , OutputCallbackInfo , SampleFormat ,
5- StreamConfig , StreamError ,
5+ StreamConfig , StreamError , StreamInstant ,
66} ;
77use pipewire:: {
88 self as pw,
@@ -149,9 +149,19 @@ where
149149 }
150150}
151151
152+ /// Hardware timestamp from a PipeWire graph cycle.
153+ struct PwTime {
154+ /// CLOCK_MONOTONIC nanoseconds, stamped at the start of the graph cycle.
155+ now_ns : i64 ,
156+ /// Pipeline delay converted to nanoseconds.
157+ /// For output: how far ahead of the driver our next sample will be played.
158+ /// For input: how long ago the data in the buffer was captured.
159+ delay_ns : i64 ,
160+ }
161+
152162/// Returns a hardware timestamp for the current graph cycle, or `None` if
153163/// the driver has not started yet or the rate is unavailable.
154- fn pw_stream_time ( stream : & pw:: stream:: Stream ) -> Option < crate :: StreamInstant > {
164+ fn pw_stream_time ( stream : & pw:: stream:: Stream ) -> Option < ( StreamInstant , PwTime ) > {
155165 use pw:: sys as pw_sys;
156166 use std:: mem;
157167 let mut t: pw_sys:: pw_time = unsafe { mem:: zeroed ( ) } ;
@@ -166,7 +176,15 @@ fn pw_stream_time(stream: &pw::stream::Stream) -> Option<crate::StreamInstant> {
166176 return None ;
167177 }
168178 debug_assert_eq ! ( t. rate. num, 1 , "unexpected pw_time rate.num" ) ;
169- Some ( crate :: StreamInstant :: from_nanos ( t. now ) )
179+ let delay_ns = t. delay * 1_000_000_000i64 / t. rate . denom as i64 ;
180+ let callback = crate :: StreamInstant :: from_nanos ( t. now ) ;
181+ Some ( (
182+ callback,
183+ PwTime {
184+ now_ns : t. now ,
185+ delay_ns,
186+ } ,
187+ ) )
170188}
171189
172190impl < D , E > UserData < D , E >
@@ -180,15 +198,22 @@ where
180198 frames : usize ,
181199 data : & Data ,
182200 ) -> Result < ( ) , BackendSpecificError > {
183- let callback =
184- pw_stream_time ( stream) . unwrap_or ( stream_timestamp_fallback ( self . created_instance ) ?) ;
185- let delay_duration = frames_to_duration ( frames, self . format . rate ( ) ) ;
186- let capture = callback
187- . add ( delay_duration)
188- . ok_or_else ( || BackendSpecificError {
189- description : "`playback` occurs beyond representation supported by `StreamInstant`"
190- . to_string ( ) ,
191- } ) ?;
201+ let ( callback, capture) = match pw_stream_time ( stream) {
202+ Some ( ( cb, PwTime { now_ns, delay_ns } ) ) => {
203+ ( cb, crate :: StreamInstant :: from_nanos ( now_ns - delay_ns) )
204+ }
205+ None => {
206+ let cb = stream_timestamp_fallback ( self . created_instance ) ?;
207+ let pl = cb
208+ . sub ( frames_to_duration ( frames, self . format . rate ( ) ) )
209+ . ok_or_else ( || BackendSpecificError {
210+ description :
211+ "`capture` occurs beyond representation supported by `StreamInstant`"
212+ . to_string ( ) ,
213+ } ) ?;
214+ ( cb, pl)
215+ }
216+ } ;
192217 let timestamp = crate :: InputStreamTimestamp { callback, capture } ;
193218 let info = crate :: InputCallbackInfo { timestamp } ;
194219 ( self . data_callback ) ( data, & info) ;
@@ -206,15 +231,22 @@ where
206231 frames : usize ,
207232 data : & mut Data ,
208233 ) -> Result < ( ) , BackendSpecificError > {
209- let callback =
210- pw_stream_time ( stream) . unwrap_or ( stream_timestamp_fallback ( self . created_instance ) ?) ;
211- let delay_duration = frames_to_duration ( frames, self . format . rate ( ) ) ;
212- let playback = callback
213- . add ( delay_duration)
214- . ok_or_else ( || BackendSpecificError {
215- description : "`playback` occurs beyond representation supported by `StreamInstant`"
216- . to_string ( ) ,
217- } ) ?;
234+ let ( callback, playback) = match pw_stream_time ( stream) {
235+ Some ( ( cb, PwTime { now_ns, delay_ns } ) ) => {
236+ ( cb, crate :: StreamInstant :: from_nanos ( now_ns + delay_ns) )
237+ }
238+ None => {
239+ let cb = stream_timestamp_fallback ( self . created_instance ) ?;
240+ let pl = cb
241+ . add ( frames_to_duration ( frames, self . format . rate ( ) ) )
242+ . ok_or_else ( || BackendSpecificError {
243+ description :
244+ "`playback` occurs beyond representation supported by `StreamInstant`"
245+ . to_string ( ) ,
246+ } ) ?;
247+ ( cb, pl)
248+ }
249+ } ;
218250 let timestamp = crate :: OutputStreamTimestamp { callback, playback } ;
219251 let info = crate :: OutputCallbackInfo { timestamp } ;
220252 ( self . data_callback ) ( data, & info) ;
0 commit comments