@@ -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 {
@@ -121,6 +127,7 @@ impl Device {
121127 sample_rate : crate :: SampleRate ,
122128 format : SampleFormat ,
123129 from_endianness : F ,
130+ hardware_latency_frames : usize ,
124131 ) where
125132 A : Copy ,
126133 D : FnMut ( & Data , & InputCallbackInfo ) + Send + ' static ,
@@ -147,6 +154,7 @@ impl Device {
147154 asio_info,
148155 sample_rate,
149156 format,
157+ hardware_latency_frames,
150158 ) ;
151159 }
152160
@@ -160,6 +168,7 @@ impl Device {
160168 config. sample_rate ,
161169 SampleFormat :: I16 ,
162170 from_le,
171+ hardware_input_latency,
163172 ) ;
164173 }
165174 ( & sys:: AsioSampleType :: ASIOSTInt16MSB , SampleFormat :: I16 ) => {
@@ -171,6 +180,7 @@ impl Device {
171180 config. sample_rate ,
172181 SampleFormat :: I16 ,
173182 from_be,
183+ hardware_input_latency,
174184 ) ;
175185 }
176186
@@ -183,6 +193,7 @@ impl Device {
183193 config. sample_rate ,
184194 SampleFormat :: F32 ,
185195 from_le,
196+ hardware_input_latency,
186197 ) ;
187198 }
188199 ( & sys:: AsioSampleType :: ASIOSTFloat32MSB , SampleFormat :: F32 ) => {
@@ -194,6 +205,7 @@ impl Device {
194205 config. sample_rate ,
195206 SampleFormat :: F32 ,
196207 from_be,
208+ hardware_input_latency,
197209 ) ;
198210 }
199211
@@ -206,6 +218,7 @@ impl Device {
206218 config. sample_rate ,
207219 SampleFormat :: I32 ,
208220 from_le,
221+ hardware_input_latency,
209222 ) ;
210223 }
211224 ( & sys:: AsioSampleType :: ASIOSTInt32MSB , SampleFormat :: I32 ) => {
@@ -217,6 +230,7 @@ impl Device {
217230 config. sample_rate ,
218231 SampleFormat :: I32 ,
219232 from_be,
233+ hardware_input_latency,
220234 ) ;
221235 }
222236
@@ -229,6 +243,7 @@ impl Device {
229243 config. sample_rate ,
230244 SampleFormat :: F64 ,
231245 from_le,
246+ hardware_input_latency,
232247 ) ;
233248 }
234249 ( & sys:: AsioSampleType :: ASIOSTFloat64MSB , SampleFormat :: F64 ) => {
@@ -240,6 +255,7 @@ impl Device {
240255 config. sample_rate ,
241256 SampleFormat :: F64 ,
242257 from_be,
258+ hardware_input_latency,
243259 ) ;
244260 }
245261
@@ -251,6 +267,7 @@ impl Device {
251267 callback_info,
252268 config. sample_rate ,
253269 true ,
270+ hardware_input_latency,
254271 ) ;
255272 }
256273 ( & sys:: AsioSampleType :: ASIOSTInt24MSB , SampleFormat :: I24 ) => {
@@ -261,6 +278,7 @@ impl Device {
261278 callback_info,
262279 config. sample_rate ,
263280 false ,
281+ hardware_input_latency,
264282 ) ;
265283 }
266284
@@ -334,6 +352,12 @@ impl Device {
334352 let playing = Arc :: clone ( & stream_playing) ;
335353 let asio_streams = self . asio_streams . clone ( ) ;
336354
355+ // Query hardware input latency (order matters: needs buffers created above).
356+ let hardware_output_latency = driver
357+ . latencies ( )
358+ . map ( |( _, output) | output. max ( 0 ) as usize )
359+ . unwrap_or ( 0 ) ;
360+
337361 let callback_id = driver. add_callback ( move |callback_info| unsafe {
338362 // If not playing, return early.
339363 if !playing. load ( Ordering :: SeqCst ) {
@@ -372,6 +396,7 @@ impl Device {
372396 sample_rate : crate :: SampleRate ,
373397 format : SampleFormat ,
374398 mix_samples : F ,
399+ hardware_latency_frames : usize ,
375400 ) where
376401 A : Copy ,
377402 D : FnMut ( & mut Data , & OutputCallbackInfo ) + Send + ' static ,
@@ -385,6 +410,7 @@ impl Device {
385410 asio_info,
386411 sample_rate,
387412 format,
413+ hardware_latency_frames,
388414 ) ;
389415 let n_channels = interleaved. len ( ) / asio_stream. buffer_size as usize ;
390416 let buffer_index = asio_info. buffer_index as usize ;
@@ -415,6 +441,7 @@ impl Device {
415441 |old_sample, new_sample| {
416442 from_le ( old_sample) . saturating_add ( new_sample) . to_le ( )
417443 } ,
444+ hardware_output_latency,
418445 ) ;
419446 }
420447 ( SampleFormat :: I16 , & sys:: AsioSampleType :: ASIOSTInt16MSB ) => {
@@ -429,6 +456,7 @@ impl Device {
429456 |old_sample, new_sample| {
430457 from_be ( old_sample) . saturating_add ( new_sample) . to_be ( )
431458 } ,
459+ hardware_output_latency,
432460 ) ;
433461 }
434462 ( SampleFormat :: F32 , & sys:: AsioSampleType :: ASIOSTFloat32LSB ) => {
@@ -445,6 +473,7 @@ impl Device {
445473 . to_bits ( )
446474 . to_le ( )
447475 } ,
476+ hardware_output_latency,
448477 ) ;
449478 }
450479
@@ -462,6 +491,7 @@ impl Device {
462491 . to_bits ( )
463492 . to_be ( )
464493 } ,
494+ hardware_output_latency,
465495 ) ;
466496 }
467497
@@ -477,6 +507,7 @@ impl Device {
477507 |old_sample, new_sample| {
478508 from_le ( old_sample) . saturating_add ( new_sample) . to_le ( )
479509 } ,
510+ hardware_output_latency,
480511 ) ;
481512 }
482513 ( SampleFormat :: I32 , & sys:: AsioSampleType :: ASIOSTInt32MSB ) => {
@@ -491,6 +522,7 @@ impl Device {
491522 |old_sample, new_sample| {
492523 from_be ( old_sample) . saturating_add ( new_sample) . to_be ( )
493524 } ,
525+ hardware_output_latency,
494526 ) ;
495527 }
496528
@@ -508,6 +540,7 @@ impl Device {
508540 . to_bits ( )
509541 . to_le ( )
510542 } ,
543+ hardware_output_latency,
511544 ) ;
512545 }
513546
@@ -525,6 +558,7 @@ impl Device {
525558 . to_bits ( )
526559 . to_be ( )
527560 } ,
561+ hardware_output_latency,
528562 ) ;
529563 }
530564
@@ -537,6 +571,7 @@ impl Device {
537571 asio_stream,
538572 callback_info,
539573 config. sample_rate ,
574+ hardware_output_latency,
540575 ) ;
541576 }
542577
@@ -549,6 +584,7 @@ impl Device {
549584 asio_stream,
550585 callback_info,
551586 config. sample_rate ,
587+ hardware_output_latency,
552588 ) ;
553589 }
554590
@@ -861,6 +897,7 @@ unsafe fn process_output_callback_i24<D>(
861897 asio_stream : & mut sys:: AsioStream ,
862898 asio_info : & sys:: CallbackInfo ,
863899 sample_rate : crate :: SampleRate ,
900+ hardware_latency_frames : usize ,
864901) where
865902 D : FnMut ( & mut Data , & OutputCallbackInfo ) + Send + ' static ,
866903{
@@ -873,6 +910,7 @@ unsafe fn process_output_callback_i24<D>(
873910 asio_info,
874911 sample_rate,
875912 format,
913+ hardware_latency_frames,
876914 ) ;
877915
878916 // Size of samples in the ASIO buffer (has to be 3 in this case)
@@ -930,6 +968,7 @@ unsafe fn process_input_callback_i24<D>(
930968 asio_info : & sys:: CallbackInfo ,
931969 sample_rate : crate :: SampleRate ,
932970 little_endian : bool ,
971+ hardware_latency_frames : usize ,
933972) where
934973 D : FnMut ( & Data , & InputCallbackInfo ) + Send + ' static ,
935974{
@@ -969,6 +1008,7 @@ unsafe fn process_input_callback_i24<D>(
9691008 asio_info,
9701009 sample_rate,
9711010 format,
1011+ hardware_latency_frames,
9721012 ) ;
9731013}
9741014
@@ -980,6 +1020,7 @@ unsafe fn apply_output_callback_to_data<A, D>(
9801020 asio_info : & sys:: CallbackInfo ,
9811021 sample_rate : crate :: SampleRate ,
9821022 sample_format : SampleFormat ,
1023+ hardware_latency_frames : usize ,
9831024) where
9841025 A : Copy ,
9851026 D : FnMut ( & mut Data , & OutputCallbackInfo ) + Send + ' static ,
@@ -990,7 +1031,10 @@ unsafe fn apply_output_callback_to_data<A, D>(
9901031 sample_format,
9911032 ) ;
9921033 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) ;
1034+ let delay = frames_to_duration (
1035+ asio_stream. buffer_size as usize + hardware_latency_frames,
1036+ sample_rate,
1037+ ) ;
9941038 let playback = callback
9951039 . add ( delay)
9961040 . expect ( "`playback` occurs beyond representation supported by `StreamInstant`" ) ;
@@ -1007,6 +1051,7 @@ unsafe fn apply_input_callback_to_data<A, D>(
10071051 asio_info : & sys:: CallbackInfo ,
10081052 sample_rate : crate :: SampleRate ,
10091053 format : SampleFormat ,
1054+ hardware_latency_frames : usize ,
10101055) where
10111056 A : Copy ,
10121057 D : FnMut ( & Data , & InputCallbackInfo ) + Send + ' static ,
@@ -1017,7 +1062,10 @@ unsafe fn apply_input_callback_to_data<A, D>(
10171062 format,
10181063 ) ;
10191064 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) ;
1065+ let delay = frames_to_duration (
1066+ asio_stream. buffer_size as usize + hardware_latency_frames,
1067+ sample_rate,
1068+ ) ;
10211069 let capture = callback
10221070 . sub ( delay)
10231071 . expect ( "`capture` occurs before origin of alsa `StreamInstant`" ) ;
0 commit comments