@@ -96,6 +96,12 @@ impl Device {
9696 let playing = Arc :: clone ( & stream_playing) ;
9797 let asio_streams = self . asio_streams . clone ( ) ;
9898
99+ // Query hardware input latency (order matters: needs buffers created above).
100+ let hardware_input_latency = driver
101+ . latencies ( )
102+ . map ( |( input, _) | input. max ( 0 ) as usize )
103+ . unwrap_or ( 0 ) ;
104+
99105 // Set the input callback.
100106 // This is most performance critical part of the ASIO bindings.
101107 let callback_id = driver. add_callback ( move |callback_info| unsafe {
@@ -113,6 +119,7 @@ impl Device {
113119
114120 /// 1. Write from the ASIO buffer to the interleaved CPAL buffer.
115121 /// 2. Deliver the CPAL buffer to the user callback.
122+ #[ allow( clippy:: too_many_arguments) ]
116123 unsafe fn process_input_callback < A , D , F > (
117124 data_callback : & mut D ,
118125 interleaved : & mut [ u8 ] ,
@@ -121,6 +128,7 @@ impl Device {
121128 sample_rate : crate :: SampleRate ,
122129 format : SampleFormat ,
123130 from_endianness : F ,
131+ hardware_latency_frames : usize ,
124132 ) where
125133 A : Copy ,
126134 D : FnMut ( & Data , & InputCallbackInfo ) + Send + ' static ,
@@ -147,6 +155,7 @@ impl Device {
147155 asio_info,
148156 sample_rate,
149157 format,
158+ hardware_latency_frames,
150159 ) ;
151160 }
152161
@@ -160,6 +169,7 @@ impl Device {
160169 config. sample_rate ,
161170 SampleFormat :: I16 ,
162171 from_le,
172+ hardware_input_latency,
163173 ) ;
164174 }
165175 ( & sys:: AsioSampleType :: ASIOSTInt16MSB , SampleFormat :: I16 ) => {
@@ -171,6 +181,7 @@ impl Device {
171181 config. sample_rate ,
172182 SampleFormat :: I16 ,
173183 from_be,
184+ hardware_input_latency,
174185 ) ;
175186 }
176187
@@ -183,6 +194,7 @@ impl Device {
183194 config. sample_rate ,
184195 SampleFormat :: F32 ,
185196 from_le,
197+ hardware_input_latency,
186198 ) ;
187199 }
188200 ( & sys:: AsioSampleType :: ASIOSTFloat32MSB , SampleFormat :: F32 ) => {
@@ -194,6 +206,7 @@ impl Device {
194206 config. sample_rate ,
195207 SampleFormat :: F32 ,
196208 from_be,
209+ hardware_input_latency,
197210 ) ;
198211 }
199212
@@ -206,6 +219,7 @@ impl Device {
206219 config. sample_rate ,
207220 SampleFormat :: I32 ,
208221 from_le,
222+ hardware_input_latency,
209223 ) ;
210224 }
211225 ( & sys:: AsioSampleType :: ASIOSTInt32MSB , SampleFormat :: I32 ) => {
@@ -217,6 +231,7 @@ impl Device {
217231 config. sample_rate ,
218232 SampleFormat :: I32 ,
219233 from_be,
234+ hardware_input_latency,
220235 ) ;
221236 }
222237
@@ -229,6 +244,7 @@ impl Device {
229244 config. sample_rate ,
230245 SampleFormat :: F64 ,
231246 from_le,
247+ hardware_input_latency,
232248 ) ;
233249 }
234250 ( & sys:: AsioSampleType :: ASIOSTFloat64MSB , SampleFormat :: F64 ) => {
@@ -240,6 +256,7 @@ impl Device {
240256 config. sample_rate ,
241257 SampleFormat :: F64 ,
242258 from_be,
259+ hardware_input_latency,
243260 ) ;
244261 }
245262
@@ -251,6 +268,7 @@ impl Device {
251268 callback_info,
252269 config. sample_rate ,
253270 true ,
271+ hardware_input_latency,
254272 ) ;
255273 }
256274 ( & sys:: AsioSampleType :: ASIOSTInt24MSB , SampleFormat :: I24 ) => {
@@ -261,6 +279,7 @@ impl Device {
261279 callback_info,
262280 config. sample_rate ,
263281 false ,
282+ hardware_input_latency,
264283 ) ;
265284 }
266285
@@ -334,6 +353,12 @@ impl Device {
334353 let playing = Arc :: clone ( & stream_playing) ;
335354 let asio_streams = self . asio_streams . clone ( ) ;
336355
356+ // Query hardware input latency (order matters: needs buffers created above).
357+ let hardware_output_latency = driver
358+ . latencies ( )
359+ . map ( |( _, output) | output. max ( 0 ) as usize )
360+ . unwrap_or ( 0 ) ;
361+
337362 let callback_id = driver. add_callback ( move |callback_info| unsafe {
338363 // If not playing, return early.
339364 if !playing. load ( Ordering :: SeqCst ) {
@@ -372,6 +397,7 @@ impl Device {
372397 sample_rate : crate :: SampleRate ,
373398 format : SampleFormat ,
374399 mix_samples : F ,
400+ hardware_latency_frames : usize ,
375401 ) where
376402 A : Copy ,
377403 D : FnMut ( & mut Data , & OutputCallbackInfo ) + Send + ' static ,
@@ -385,6 +411,7 @@ impl Device {
385411 asio_info,
386412 sample_rate,
387413 format,
414+ hardware_latency_frames,
388415 ) ;
389416 let n_channels = interleaved. len ( ) / asio_stream. buffer_size as usize ;
390417 let buffer_index = asio_info. buffer_index as usize ;
@@ -415,6 +442,7 @@ impl Device {
415442 |old_sample, new_sample| {
416443 from_le ( old_sample) . saturating_add ( new_sample) . to_le ( )
417444 } ,
445+ hardware_output_latency,
418446 ) ;
419447 }
420448 ( SampleFormat :: I16 , & sys:: AsioSampleType :: ASIOSTInt16MSB ) => {
@@ -429,6 +457,7 @@ impl Device {
429457 |old_sample, new_sample| {
430458 from_be ( old_sample) . saturating_add ( new_sample) . to_be ( )
431459 } ,
460+ hardware_output_latency,
432461 ) ;
433462 }
434463 ( SampleFormat :: F32 , & sys:: AsioSampleType :: ASIOSTFloat32LSB ) => {
@@ -445,6 +474,7 @@ impl Device {
445474 . to_bits ( )
446475 . to_le ( )
447476 } ,
477+ hardware_output_latency,
448478 ) ;
449479 }
450480
@@ -462,6 +492,7 @@ impl Device {
462492 . to_bits ( )
463493 . to_be ( )
464494 } ,
495+ hardware_output_latency,
465496 ) ;
466497 }
467498
@@ -477,6 +508,7 @@ impl Device {
477508 |old_sample, new_sample| {
478509 from_le ( old_sample) . saturating_add ( new_sample) . to_le ( )
479510 } ,
511+ hardware_output_latency,
480512 ) ;
481513 }
482514 ( SampleFormat :: I32 , & sys:: AsioSampleType :: ASIOSTInt32MSB ) => {
@@ -491,6 +523,7 @@ impl Device {
491523 |old_sample, new_sample| {
492524 from_be ( old_sample) . saturating_add ( new_sample) . to_be ( )
493525 } ,
526+ hardware_output_latency,
494527 ) ;
495528 }
496529
@@ -508,6 +541,7 @@ impl Device {
508541 . to_bits ( )
509542 . to_le ( )
510543 } ,
544+ hardware_output_latency,
511545 ) ;
512546 }
513547
@@ -525,6 +559,7 @@ impl Device {
525559 . to_bits ( )
526560 . to_be ( )
527561 } ,
562+ hardware_output_latency,
528563 ) ;
529564 }
530565
@@ -537,6 +572,7 @@ impl Device {
537572 asio_stream,
538573 callback_info,
539574 config. sample_rate ,
575+ hardware_output_latency,
540576 ) ;
541577 }
542578
@@ -549,6 +585,7 @@ impl Device {
549585 asio_stream,
550586 callback_info,
551587 config. sample_rate ,
588+ hardware_output_latency,
552589 ) ;
553590 }
554591
@@ -853,6 +890,7 @@ fn i24_bytes_to_i32(i24_bytes: &[u8; 3], little_endian: bool) -> i32 {
853890 }
854891}
855892
893+ #[ allow( clippy:: too_many_arguments) ]
856894unsafe fn process_output_callback_i24 < D > (
857895 data_callback : & mut D ,
858896 interleaved : & mut [ u8 ] ,
@@ -861,6 +899,7 @@ unsafe fn process_output_callback_i24<D>(
861899 asio_stream : & mut sys:: AsioStream ,
862900 asio_info : & sys:: CallbackInfo ,
863901 sample_rate : crate :: SampleRate ,
902+ hardware_latency_frames : usize ,
864903) where
865904 D : FnMut ( & mut Data , & OutputCallbackInfo ) + Send + ' static ,
866905{
@@ -873,6 +912,7 @@ unsafe fn process_output_callback_i24<D>(
873912 asio_info,
874913 sample_rate,
875914 format,
915+ hardware_latency_frames,
876916 ) ;
877917
878918 // Size of samples in the ASIO buffer (has to be 3 in this case)
@@ -930,6 +970,7 @@ unsafe fn process_input_callback_i24<D>(
930970 asio_info : & sys:: CallbackInfo ,
931971 sample_rate : crate :: SampleRate ,
932972 little_endian : bool ,
973+ hardware_latency_frames : usize ,
933974) where
934975 D : FnMut ( & Data , & InputCallbackInfo ) + Send + ' static ,
935976{
@@ -969,6 +1010,7 @@ unsafe fn process_input_callback_i24<D>(
9691010 asio_info,
9701011 sample_rate,
9711012 format,
1013+ hardware_latency_frames,
9721014 ) ;
9731015}
9741016
@@ -980,6 +1022,7 @@ unsafe fn apply_output_callback_to_data<A, D>(
9801022 asio_info : & sys:: CallbackInfo ,
9811023 sample_rate : crate :: SampleRate ,
9821024 sample_format : SampleFormat ,
1025+ hardware_latency_frames : usize ,
9831026) where
9841027 A : Copy ,
9851028 D : FnMut ( & mut Data , & OutputCallbackInfo ) + Send + ' static ,
@@ -990,7 +1033,10 @@ unsafe fn apply_output_callback_to_data<A, D>(
9901033 sample_format,
9911034 ) ;
9921035 let callback = system_time_to_stream_instant ( asio_info. system_time ) ;
993- let delay = frames_to_duration ( asio_stream. buffer_size as usize , sample_rate) ;
1036+ let delay = frames_to_duration (
1037+ asio_stream. buffer_size as usize + hardware_latency_frames,
1038+ sample_rate,
1039+ ) ;
9941040 let playback = callback
9951041 . add ( delay)
9961042 . expect ( "`playback` occurs beyond representation supported by `StreamInstant`" ) ;
@@ -1007,6 +1053,7 @@ unsafe fn apply_input_callback_to_data<A, D>(
10071053 asio_info : & sys:: CallbackInfo ,
10081054 sample_rate : crate :: SampleRate ,
10091055 format : SampleFormat ,
1056+ hardware_latency_frames : usize ,
10101057) where
10111058 A : Copy ,
10121059 D : FnMut ( & Data , & InputCallbackInfo ) + Send + ' static ,
@@ -1017,7 +1064,10 @@ unsafe fn apply_input_callback_to_data<A, D>(
10171064 format,
10181065 ) ;
10191066 let callback = system_time_to_stream_instant ( asio_info. system_time ) ;
1020- let delay = frames_to_duration ( asio_stream. buffer_size as usize , sample_rate) ;
1067+ let delay = frames_to_duration (
1068+ asio_stream. buffer_size as usize + hardware_latency_frames,
1069+ sample_rate,
1070+ ) ;
10211071 let capture = callback
10221072 . sub ( delay)
10231073 . expect ( "`capture` occurs before origin of alsa `StreamInstant`" ) ;
0 commit comments