asio_sys/bindings/mod.rs
1pub(crate) mod asio_import;
2#[macro_use]
3pub mod errors;
4
5// On Windows (where ASIO actually runs), c_long is i32.
6// On non-Windows platforms (for docs.rs and local testing), redefine c_long as i32 to match.
7#[cfg(target_os = "windows")]
8use std::os::raw::c_long;
9use std::{
10 ffi::{CStr, CString},
11 os::raw::{c_char, c_double, c_void},
12 ptr::null_mut,
13 sync::{
14 atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering},
15 Arc, Mutex, MutexGuard, Weak,
16 },
17 time::Duration,
18};
19
20use num_traits::FromPrimitive;
21
22use self::errors::{AsioError, AsioErrorWrapper, LoadDriverError};
23#[cfg(not(target_os = "windows"))]
24type c_long = i32;
25
26// Bindings import
27use self::asio_import as ai;
28
29/// A handle to the ASIO API.
30///
31/// There should only be one instance of this type at any point in time.
32#[derive(Debug, Default)]
33pub struct Asio {
34 // Keeps track of whether or not a driver is already loaded.
35 //
36 // This is necessary as ASIO only supports one `Driver` at a time.
37 loaded_driver: Mutex<Weak<DriverInner>>,
38}
39
40/// A handle to a single ASIO driver.
41///
42/// Creating an instance of this type loads and initialises the driver.
43///
44/// Dropping all `Driver` instances will automatically dispose of any resources and de-initialise
45/// the driver.
46#[derive(Clone, Debug)]
47pub struct Driver {
48 inner: Arc<DriverInner>,
49}
50
51// Contains the state associated with a `Driver`.
52//
53// This state may be shared between multiple `Driver` handles representing the same underlying
54// driver. Only when the last `Driver` is dropped will the `Drop` implementation for this type run
55// and the necessary driver resources will be de-allocated and unloaded.
56//
57// The same could be achieved by returning an `Arc<Driver>` from the `Host::load_driver` API,
58// however the `DriverInner` abstraction is required in order to allow for the `Driver::destroy`
59// method to exist safely. By wrapping the `Arc<DriverInner>` in the `Driver` type, we can make
60// sure the user doesn't `try_unwrap` the `Arc` and invalidate the `Asio` instance's weak pointer.
61// This would allow for instantiation of a separate driver before the existing one is destroyed,
62// which is disallowed by ASIO.
63#[derive(Debug)]
64struct DriverInner {
65 state: Mutex<DriverState>,
66 // Input/output buffer state, shared across every `Driver` handle for this driver.
67 streams: Arc<Mutex<AsioStreams>>,
68 // The unique name associated with this driver.
69 name: String,
70 // Track whether or not the driver has been destroyed.
71 //
72 // This allows for the user to manually destroy the driver and handle any errors if they wish.
73 //
74 // In the case that the driver has been manually destroyed this flag will be set to `true`
75 // indicating to the `drop` implementation that there is nothing to be done.
76 destroyed: bool,
77}
78
79/// All possible states of an ASIO `Driver` instance.
80///
81/// Mapped to the finite state machine in the ASIO SDK docs.
82#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
83pub(crate) enum DriverState {
84 Initialized,
85 Prepared,
86 Running,
87}
88
89/// Amount of input and output channels available.
90#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
91pub struct Channels {
92 pub ins: i32,
93 pub outs: i32,
94}
95
96/// Hardware latency in frames for the input and output streams.
97#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
98pub struct Latencies {
99 pub input: i32,
100 pub output: i32,
101}
102
103/// Hardware buffer size preferences and constraints.
104#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
105pub enum BufferPreference {
106 Only(u32),
107 Preferred(u32),
108 Stepped { preferred: u32, step: u32 },
109}
110
111/// Minimum and maximum supported buffer sizes in frames.
112#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
113pub struct BufferSizeRange {
114 pub min: i32,
115 pub max: i32,
116 pub preferred: BufferPreference,
117}
118
119/// Information provided to the BufferCallback.
120#[derive(Debug)]
121pub struct CallbackInfo {
122 pub buffer_index: i32,
123 /// System time at the start of this buffer period, in nanoseconds.
124 pub system_time: u64,
125 pub callback_flag: u32,
126}
127
128/// Holds the pointer to the callbacks that come from cpal
129struct BufferCallback(Box<dyn FnMut(&CallbackInfo) + Send>);
130
131/// Input and Output streams.
132///
133/// There is only ever max one input and one output.
134///
135/// Only one is required.
136#[derive(Debug)]
137pub struct AsioStreams {
138 pub input: Option<AsioStream>,
139 pub output: Option<AsioStream>,
140}
141
142/// A stream to ASIO.
143///
144/// Contains the buffers.
145#[derive(Debug)]
146pub struct AsioStream {
147 /// A Double buffer per channel
148 pub buffer_infos: Vec<AsioBufferInfo>,
149 /// Size of each buffer
150 pub buffer_size: i32,
151}
152
153/// All the possible types from ASIO.
154/// This is a direct copy of the ASIOSampleType
155/// inside ASIO SDK.
156#[derive(Debug, FromPrimitive)]
157#[repr(C)]
158pub enum AsioSampleType {
159 ASIOSTInt16MSB = 0,
160 ASIOSTInt24MSB = 1, // used for 20 bits as well
161 ASIOSTInt32MSB = 2,
162 ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float
163 ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float
164
165 // these are used for 32 bit data buffer, with different alignment of the data inside
166 // 32 bit PCI bus systems can be more easily used with these
167 ASIOSTInt32MSB16 = 8, // 32 bit data with 16 bit alignment
168 ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment
169 ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment
170 ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment
171
172 ASIOSTInt16LSB = 16,
173 ASIOSTInt24LSB = 17, // used for 20 bits as well
174 ASIOSTInt32LSB = 18,
175 ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture
176 ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture
177
178 // these are used for 32 bit data buffer, with different alignment of the data inside
179 // 32 bit PCI bus systems can more easily used with these
180 ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment
181 ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment
182 ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment
183 ASIOSTInt32LSB24 = 27, // 32 bit data with 24 bit alignment
184
185 // ASIO DSD format.
186 ASIOSTDSDInt8LSB1 = 32, // DSD 1 bit data, 8 samples per byte. First sample in Least significant bit.
187 ASIOSTDSDInt8MSB1 = 33, // DSD 1 bit data, 8 samples per byte. First sample in Most significant bit.
188 ASIOSTDSDInt8NER8 = 40, // DSD 8 bit data, 1 sample per byte. No Endianness required.
189
190 ASIOSTLastEntry,
191}
192
193/// Gives information about buffers
194/// Receives pointers to buffers
195#[derive(Debug, Copy, Clone)]
196#[repr(C, packed(4))]
197pub struct AsioBufferInfo {
198 /// 0 for output 1 for input
199 pub is_input: i32,
200 /// Which channel. Starts at 0
201 pub channel_num: i32,
202 /// Pointer to each half of the double buffer.
203 pub buffers: [*mut c_void; 2],
204}
205
206/// Callbacks that ASIO calls
207#[repr(C, packed(4))]
208struct AsioCallbacks {
209 buffer_switch: extern "C" fn(double_buffer_index: c_long, direct_process: c_long) -> (),
210 sample_rate_did_change: extern "C" fn(s_rate: c_double) -> (),
211 asio_message: extern "C" fn(
212 selector: c_long,
213 value: c_long,
214 message: *mut (),
215 opt: *mut c_double,
216 ) -> c_long,
217 buffer_switch_time_info: extern "C" fn(
218 params: *mut ai::ASIOTime,
219 double_buffer_index: c_long,
220 direct_process: c_long,
221 ) -> *mut ai::ASIOTime,
222}
223
224static ASIO_CALLBACKS: AsioCallbacks = AsioCallbacks {
225 buffer_switch,
226 sample_rate_did_change,
227 asio_message,
228 buffer_switch_time_info,
229};
230
231/// All the possible types from ASIO.
232/// This is a direct copy of the asioMessage selectors
233/// inside ASIO SDK.
234#[rustfmt::skip]
235#[derive(Clone, Copy, Debug, FromPrimitive)]
236#[repr(C)]
237pub enum AsioMessageSelectors {
238 kAsioSelectorSupported = 1, // selector in <value>, returns 1L if supported,
239 // 0 otherwise
240 kAsioEngineVersion, // returns engine (host) asio implementation version,
241 // 2 or higher
242 kAsioResetRequest, // request driver reset. if accepted, this
243 // will close the driver (ASIO_Exit() ) and
244 // re-open it again (ASIO_Init() etc). some
245 // drivers need to reconfigure for instance
246 // when the sample rate changes, or some basic
247 // changes have been made in ASIO_ControlPanel().
248 // returns 1L; note the request is merely passed
249 // to the application, there is no way to determine
250 // if it gets accepted at this time (but it usually
251 // will be).
252 kAsioBufferSizeChange, // not yet supported, will currently always return 0L.
253 // for now, use kAsioResetRequest instead.
254 // once implemented, the new buffer size is expected
255 // in <value>, and on success returns 1L
256 kAsioResyncRequest, // the driver went out of sync, such that
257 // the timestamp is no longer valid. this
258 // is a request to re-start the engine and
259 // slave devices (sequencer). returns 1 for ok,
260 // 0 if not supported.
261 kAsioLatenciesChanged, // the drivers latencies have changed. The engine
262 // will refetch the latencies.
263 kAsioSupportsTimeInfo, // if host returns true here, it will expect the
264 // callback bufferSwitchTimeInfo to be called instead
265 // of bufferSwitch
266 kAsioSupportsTimeCode, //
267 kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands
268 kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this
269 kAsioSupportsInputGain, // unused and undefined
270 kAsioSupportsInputMeter, // unused and undefined
271 kAsioSupportsOutputGain, // unused and undefined
272 kAsioSupportsOutputMeter, // unused and undefined
273 kAsioOverload, // driver detected an overload
274 kAsioNumMessageSelectors, // sentinel value equal to the number of defined selectors
275}
276
277/// Events dispatched to registered driver event callbacks.
278#[derive(Clone, Copy, Debug)]
279pub enum AsioDriverEvent {
280 /// A message from the ASIO driver's `asioMessage` callback.
281 ///
282 /// `selector` identifies the message type; `value` is the raw payload passed by the driver.
283 /// For [`AsioMessageSelectors::kAsioSelectorSupported`] queries, `value` is the selector being
284 /// queried. Return `true` to advertise support for it, `false` to decline. For other selectors,
285 /// the return value is ignored.
286 Message {
287 selector: AsioMessageSelectors,
288 value: i32,
289 },
290
291 /// The ASIO driver reported a sample rate change.
292 ///
293 /// Only dispatched when the reported rate differs from the last known rate, so spurious
294 /// `sampleRateDidChange` calls (e.g. on AES/EBU sync status changes where the rate has not
295 /// actually changed) are suppressed.
296 SampleRateChanged(f64),
297}
298
299/// A rust-usable version of the `ASIOTime` type that does not contain a binary blob for fields.
300#[repr(C, packed(4))]
301pub struct AsioTime {
302 /// Must be `0`.
303 reserved: [i32; 4],
304 /// Required.
305 pub time_info: AsioTimeInfo,
306 /// Optional, evaluated if (time_code.flags & ktcValid).
307 pub time_code: AsioTimeCode,
308}
309
310/// A rust-compatible version of the `ASIOTimeInfo` type that does not contain a binary blob for
311/// fields.
312#[repr(C, packed(4))]
313pub struct AsioTimeInfo {
314 /// Absolute speed (1. = nominal).
315 pub speed: c_double,
316 /// System time related to sample_position, in nanoseconds.
317 ///
318 /// On Windows, must be derived from timeGetTime().
319 pub system_time: ai::ASIOTimeStamp,
320 /// Sample position since `ASIOStart()`.
321 pub sample_position: ai::ASIOSamples,
322 /// Current rate, unsigned.
323 pub sample_rate: AsioSampleRate,
324 /// See `AsioTimeInfoFlags`.
325 pub flags: i32,
326 /// Must be `0`.
327 reserved: [c_char; 12],
328}
329
330/// A rust-compatible version of the `ASIOTimeCode` type that does not use a binary blob for its
331/// fields.
332#[repr(C, packed(4))]
333pub struct AsioTimeCode {
334 /// Speed relation (fraction of nominal speed) optional.
335 ///
336 /// Set to 0. or 1. if not supported.
337 pub speed: c_double,
338 /// Time in samples unsigned.
339 pub time_code_samples: ai::ASIOSamples,
340 /// See `ASIOTimeCodeFlags`.
341 pub flags: i32,
342 /// Set to `0`.
343 future: [c_char; 64],
344}
345
346/// A rust-compatible version of the `ASIOSampleRate` type that does not use a binary blob for its
347/// fields.
348pub type AsioSampleRate = f64;
349
350// A helper type to simplify retrieval of available buffer sizes.
351#[derive(Default)]
352struct BufferSizes {
353 min: c_long,
354 max: c_long,
355 pref: c_long,
356 grans: c_long,
357}
358
359/// Identifies a buffer callback registered via [`Driver::add_callback`].
360#[derive(Clone, Copy, Debug, PartialEq, Eq)]
361pub struct BufferCallbackId(usize);
362
363/// A global way to access all the callbacks.
364///
365/// This is required because of how ASIO calls the `buffer_switch` function with no data
366/// parameters.
367static BUFFER_CALLBACK: Mutex<Vec<(BufferCallbackId, BufferCallback)>> = Mutex::new(Vec::new());
368
369/// Used to identify when to clear buffers.
370static CALLBACK_FLAG: AtomicU32 = AtomicU32::new(0);
371
372/// Indicates that ASIOOutputReady should be called
373static CALL_OUTPUT_READY: AtomicBool = AtomicBool::new(false);
374static CURRENT_SAMPLE_RATE: AtomicU64 = AtomicU64::new(0);
375
376/// Identifies a driver event callback registered via [`Driver::add_event_callback`].
377#[derive(Clone, Copy, Debug, PartialEq, Eq)]
378pub struct DriverEventCallbackId(usize);
379
380struct DriverEventCallback(Arc<dyn Fn(AsioDriverEvent) -> bool + Send + Sync>);
381
382/// A global registry for ASIO driver event callbacks.
383static DRIVER_EVENT_CALLBACKS: Mutex<Vec<(DriverEventCallbackId, DriverEventCallback)>> =
384 Mutex::new(Vec::new());
385
386impl Asio {
387 /// Initialise the ASIO API.
388 pub fn new() -> Self {
389 Self::default()
390 }
391
392 /// Returns the name for each available driver.
393 ///
394 /// This is used at the start to allow the user to choose which driver they want.
395 pub fn driver_names(&self) -> Vec<String> {
396 // The most drivers we can take
397 const MAX_DRIVERS: usize = 100;
398 // Max length for divers name
399 const MAX_DRIVER_NAME_LEN: usize = 32;
400
401 // 2D array of driver names set to 0.
402 let mut driver_names: [[c_char; MAX_DRIVER_NAME_LEN]; MAX_DRIVERS] =
403 [[0; MAX_DRIVER_NAME_LEN]; MAX_DRIVERS];
404 // Pointer to each driver name.
405 let mut driver_name_ptrs: [*mut c_char; MAX_DRIVERS] = [null_mut(); MAX_DRIVERS];
406 for (ptr, name) in driver_name_ptrs.iter_mut().zip(&mut driver_names[..]) {
407 *ptr = (*name).as_mut_ptr();
408 }
409
410 unsafe {
411 let num_drivers =
412 ai::get_driver_names(driver_name_ptrs.as_mut_ptr(), MAX_DRIVERS as i32);
413 (0..num_drivers)
414 .map(|i| driver_name_to_utf8(&driver_names[i as usize]).to_string())
415 .collect()
416 }
417 }
418
419 /// If a driver has already been loaded, this will return that driver.
420 ///
421 /// Returns `None` if no driver is currently loaded.
422 ///
423 /// This can be useful to check before calling `load_driver` as ASIO only supports loading a
424 /// single driver at a time.
425 pub fn loaded_driver(&self) -> Option<Driver> {
426 self.loaded_driver
427 .lock()
428 .expect("failed to acquire loaded driver lock")
429 .upgrade()
430 .map(|inner| Driver { inner })
431 }
432
433 /// Load a driver from the given name.
434 ///
435 /// Driver names compatible with this method can be produced via the `asio.driver_names()`
436 /// method.
437 ///
438 /// NOTE: Despite many requests from users, ASIO only supports loading a single driver at a
439 /// time. Calling this method while a previously loaded `Driver` instance exists will result in
440 /// an error. That said, if this method is called with the name of a driver that has already
441 /// been loaded, that driver will be returned successfully.
442 pub fn load_driver(&self, driver_name: &str) -> Result<Driver, LoadDriverError> {
443 // Hold the lock for the entire operation to prevent a TOCTOU race where two threads
444 // both pass the "no driver loaded" check and then both call load_asio_driver.
445 let mut loaded = self
446 .loaded_driver
447 .lock()
448 .expect("failed to acquire loaded driver lock");
449
450 // Check whether or not a driver is already loaded.
451 if let Some(inner) = loaded.upgrade() {
452 let driver = Driver { inner };
453 if driver.name() == driver_name {
454 return Ok(driver);
455 } else {
456 return Err(LoadDriverError::DriverAlreadyExists);
457 }
458 }
459
460 // Make owned CString to send to load driver
461 let driver_name_cstring =
462 CString::new(driver_name).map_err(|_| LoadDriverError::LoadDriverFailed)?;
463 let mut driver_info = std::mem::MaybeUninit::<ai::ASIODriverInfo>::uninit();
464
465 unsafe {
466 match ai::load_asio_driver(driver_name_cstring.as_ptr() as *mut c_char) {
467 false => Err(LoadDriverError::LoadDriverFailed),
468 true => {
469 // Initialize ASIO.
470 asio_result!(ai::ASIOInit(driver_info.as_mut_ptr()))?;
471 let _driver_info = driver_info.assume_init();
472 let mut rate: c_double = 0.0;
473 let _ = asio_result!(ai::get_sample_rate(&mut rate));
474 if rate > 0.0 {
475 CURRENT_SAMPLE_RATE.store(rate.to_bits(), Ordering::Release);
476 }
477 let state = Mutex::new(DriverState::Initialized);
478 let streams = Arc::new(Mutex::new(AsioStreams {
479 input: None,
480 output: None,
481 }));
482 let name = driver_name.to_string();
483 let destroyed = false;
484 let inner = Arc::new(DriverInner {
485 name,
486 state,
487 streams,
488 destroyed,
489 });
490 *loaded = Arc::downgrade(&inner);
491 let driver = Driver { inner };
492 Ok(driver)
493 }
494 }
495 }
496 }
497}
498
499impl BufferCallback {
500 /// Calls the inner callback.
501 fn run(&mut self, callback_info: &CallbackInfo) {
502 let cb = &mut self.0;
503 cb(callback_info);
504 }
505}
506
507impl Driver {
508 /// The name used to uniquely identify this driver.
509 pub fn name(&self) -> &str {
510 &self.inner.name
511 }
512
513 /// The shared input/output buffer state for this driver.
514 pub fn streams(&self) -> Arc<Mutex<AsioStreams>> {
515 self.inner.streams.clone()
516 }
517
518 /// Returns the number of input and output channels available on the driver.
519 pub fn channels(&self) -> Result<Channels, AsioError> {
520 let _guard = self.inner.lock_state();
521 let mut ins: c_long = 0;
522 let mut outs: c_long = 0;
523 unsafe {
524 asio_result!(ai::ASIOGetChannels(&mut ins, &mut outs))?;
525 }
526 Ok(Channels { ins, outs })
527 }
528
529 /// Get the input and output hardware latency in frames.
530 pub fn latencies(&self) -> Result<Latencies, AsioError> {
531 let _guard = self.inner.lock_state();
532 let mut input_latency: c_long = 0;
533 let mut output_latency: c_long = 0;
534 unsafe {
535 asio_result!(ai::ASIOGetLatencies(
536 &mut input_latency,
537 &mut output_latency
538 ))?;
539 }
540 Ok(Latencies {
541 input: input_latency,
542 output: output_latency,
543 })
544 }
545
546 /// Get the min and max supported buffersize of the driver.
547 pub fn buffersize_range(&self) -> Result<BufferSizeRange, AsioError> {
548 let _guard = self.inner.lock_state();
549 let buffer_sizes = asio_get_buffer_sizes()?;
550 Ok(BufferSizeRange {
551 min: buffer_sizes.min,
552 max: buffer_sizes.max,
553 preferred: match buffer_sizes.grans {
554 -1 => BufferPreference::Only(buffer_sizes.pref as u32),
555 0 => BufferPreference::Preferred(buffer_sizes.pref as u32),
556 granularity => BufferPreference::Stepped {
557 preferred: buffer_sizes.pref as u32,
558 step: granularity as u32,
559 },
560 },
561 })
562 }
563
564 /// Get current sample rate of the driver.
565 pub fn sample_rate(&self) -> Result<f64, AsioError> {
566 let _guard = self.inner.lock_state();
567 let mut rate: c_double = 0.0;
568 unsafe {
569 asio_result!(ai::get_sample_rate(&mut rate))?;
570 }
571 Ok(rate)
572 }
573
574 /// Can the driver accept the given sample rate.
575 pub fn can_sample_rate(&self, sample_rate: f64) -> Result<bool, AsioError> {
576 let _guard = self.inner.lock_state();
577 unsafe {
578 match asio_result!(ai::can_sample_rate(sample_rate)) {
579 Ok(()) => Ok(true),
580 Err(AsioError::NoRate) => Ok(false),
581 Err(err) => Err(err),
582 }
583 }
584 }
585
586 /// Set the sample rate for the driver.
587 pub fn set_sample_rate(&self, sample_rate: f64) -> Result<(), AsioError> {
588 let actual = {
589 let _guard = self.inner.lock_state();
590 unsafe { asio_result!(ai::set_sample_rate(sample_rate))? };
591 let mut actual: c_double = 0.0;
592 unsafe { asio_result!(ai::get_sample_rate(&mut actual))? };
593 actual
594 };
595
596 // Check whether the driver applied the rate immediately.
597 if (actual - sample_rate).abs() < 1.0 {
598 CURRENT_SAMPLE_RATE.store(actual.to_bits(), Ordering::Release);
599 return Ok(());
600 }
601
602 // Some ASIO drivers (e.g. Steinberg) do not apply a rate change until after a
603 // complete buffer-creation cycle (CreateBuffers -> Start -> Stop -> DisposeBuffers),
604 // followed by a full driver teardown and reload.
605 let mut dummy_infos = prepare_buffer_infos(false, 1);
606 let buffer_size = self.create_buffers(&mut dummy_infos, None)?;
607
608 // Start briefly so the driver reconfigures its hardware clock.
609 self.start()?;
610
611 // Wait for one full buffer to be processed: this guarantees the driver has
612 // applied the rate change to the hardware clock before we stop it.
613 let buffer_duration = Duration::from_secs_f64(buffer_size as f64 / sample_rate);
614 std::thread::sleep(buffer_duration);
615
616 self.stop()?;
617 self.dispose_buffers()?;
618
619 // Full teardown so the driver is reset to a clean state. Some drivers
620 // (e.g. Steinberg) return errors from ASIOGetChannels after DisposeBuffers
621 // unless the driver is fully exited and reloaded.
622 {
623 let mut state = self.inner.lock_state();
624 unsafe {
625 let _ = asio_result!(ai::ASIOExit());
626 ai::remove_current_driver();
627 }
628 std::thread::sleep(buffer_duration);
629
630 // Safety: the name was validated as null-free when the driver was first loaded.
631 let name_cstring = CString::new(self.inner.name.as_str())
632 .expect("driver name already stored must not contain null bytes");
633 unsafe {
634 if !ai::load_asio_driver(name_cstring.as_ptr() as *mut c_char) {
635 return Err(AsioError::NoDrivers);
636 }
637 let mut driver_info = std::mem::MaybeUninit::<ai::ASIODriverInfo>::uninit();
638 asio_result!(ai::ASIOInit(driver_info.as_mut_ptr()))?;
639 }
640 *state = DriverState::Initialized;
641
642 // Set the rate again on the freshly initialized driver.
643 unsafe { asio_result!(ai::set_sample_rate(sample_rate))? };
644
645 let mut actual: c_double = 0.0;
646 unsafe { asio_result!(ai::get_sample_rate(&mut actual))? };
647 if (actual - sample_rate).abs() >= 1.0 {
648 return Err(AsioError::NoRate);
649 }
650
651 CURRENT_SAMPLE_RATE.store(actual.to_bits(), Ordering::Release);
652 }
653 Ok(())
654 }
655
656 /// Get the current data type of the driver's input stream.
657 ///
658 /// This queries a single channel's type assuming all channels have the same sample type.
659 pub fn input_data_type(&self) -> Result<AsioSampleType, AsioError> {
660 let _guard = self.inner.lock_state();
661 stream_data_type(true)
662 }
663
664 /// Get the current data type of the driver's output stream.
665 ///
666 /// This queries a single channel's type assuming all channels have the same sample type.
667 pub fn output_data_type(&self) -> Result<AsioSampleType, AsioError> {
668 let _guard = self.inner.lock_state();
669 stream_data_type(false)
670 }
671
672 /// Ask ASIO to allocate the buffers and give the callback pointers.
673 ///
674 /// This will destroy any already allocated buffers.
675 ///
676 /// If buffersize is None then the preferred buffer size from ASIO is used,
677 /// otherwise the desired buffersize is used if the requested size is within
678 /// the range of accepted buffersizes for the device.
679 fn create_buffers(
680 &self,
681 buffer_infos: &mut [AsioBufferInfo],
682 buffer_size: Option<i32>,
683 ) -> Result<c_long, AsioError> {
684 let num_channels = buffer_infos.len();
685
686 let mut state = self.inner.lock_state();
687
688 // Retrieve the available buffer sizes.
689 let buffer_sizes = asio_get_buffer_sizes()?;
690 if buffer_sizes.pref <= 0 {
691 panic!(
692 "`ASIOGetBufferSize` produced unusable preferred buffer size of {}",
693 buffer_sizes.pref,
694 );
695 }
696
697 let buffer_size = match buffer_size {
698 Some(v) => {
699 if v <= buffer_sizes.max {
700 v
701 } else {
702 return Err(AsioError::InvalidBufferSize);
703 }
704 }
705 None => buffer_sizes.pref,
706 };
707
708 CALL_OUTPUT_READY.store(
709 asio_result!(unsafe { ai::ASIOOutputReady() }).is_ok(),
710 Ordering::Release,
711 );
712
713 // Ensure the driver is in the `Initialized` state.
714 if let DriverState::Running = *state {
715 state.stop()?;
716 }
717 if let DriverState::Prepared = *state {
718 state.dispose_buffers()?;
719 }
720 unsafe {
721 asio_result!(ai::ASIOCreateBuffers(
722 buffer_infos.as_mut_ptr() as *mut _,
723 num_channels as i32,
724 buffer_size,
725 &ASIO_CALLBACKS as *const _ as *mut _,
726 ))?;
727 }
728 *state = DriverState::Prepared;
729
730 Ok(buffer_size)
731 }
732
733 /// Creates the streams.
734 ///
735 /// `buffer_size` sets the desired buffer_size. If None is passed in, then the
736 /// default buffersize for the device is used.
737 ///
738 /// Both input and output streams need to be created together as a single slice of
739 /// `ASIOBufferInfo`.
740 fn create_streams(
741 &self,
742 mut input_buffer_infos: Vec<AsioBufferInfo>,
743 mut output_buffer_infos: Vec<AsioBufferInfo>,
744 buffer_size: Option<i32>,
745 ) -> Result<AsioStreams, AsioError> {
746 let (input, output) = match (
747 input_buffer_infos.is_empty(),
748 output_buffer_infos.is_empty(),
749 ) {
750 // Both stream exist.
751 (false, false) => {
752 // Create one continuous slice of buffers.
753 let split_point = input_buffer_infos.len();
754 let mut all_buffer_infos = input_buffer_infos;
755 all_buffer_infos.append(&mut output_buffer_infos);
756 // Create the buffers. On success, split the output and input again.
757 let buffer_size = self.create_buffers(&mut all_buffer_infos, buffer_size)?;
758 let output_buffer_infos = all_buffer_infos.split_off(split_point);
759 let input_buffer_infos = all_buffer_infos;
760 let input = Some(AsioStream {
761 buffer_infos: input_buffer_infos,
762 buffer_size,
763 });
764 let output = Some(AsioStream {
765 buffer_infos: output_buffer_infos,
766 buffer_size,
767 });
768 (input, output)
769 }
770 // Just input
771 (false, true) => {
772 let buffer_size = self.create_buffers(&mut input_buffer_infos, buffer_size)?;
773 let input = Some(AsioStream {
774 buffer_infos: input_buffer_infos,
775 buffer_size,
776 });
777 let output = None;
778 (input, output)
779 }
780 // Just output
781 (true, false) => {
782 let buffer_size = self.create_buffers(&mut output_buffer_infos, buffer_size)?;
783 let input = None;
784 let output = Some(AsioStream {
785 buffer_infos: output_buffer_infos,
786 buffer_size,
787 });
788 (input, output)
789 }
790 // Impossible
791 (true, true) => unreachable!("Trying to create streams without preparing"),
792 };
793 Ok(AsioStreams { input, output })
794 }
795
796 /// Prepare the input stream.
797 ///
798 /// Because only the latest call to ASIOCreateBuffers is relevant this call will destroy all
799 /// past active buffers and recreate them.
800 ///
801 /// For this reason we take the output stream if it exists.
802 ///
803 /// `num_channels` is the desired number of input channels.
804 ///
805 /// `buffer_size` sets the desired buffer_size. If None is passed in, then the
806 /// default buffersize for the device is used.
807 ///
808 /// This returns a full AsioStreams with both input and output if output was active.
809 pub fn prepare_input_stream(
810 &self,
811 output: Option<AsioStream>,
812 num_channels: usize,
813 buffer_size: Option<i32>,
814 ) -> Result<AsioStreams, AsioError> {
815 let input_buffer_infos = prepare_buffer_infos(true, num_channels);
816 let output_buffer_infos = output.map(|output| output.buffer_infos).unwrap_or_default();
817 self.create_streams(input_buffer_infos, output_buffer_infos, buffer_size)
818 }
819
820 /// Prepare the output stream.
821 ///
822 /// Because only the latest call to ASIOCreateBuffers is relevant this call will destroy all
823 /// past active buffers and recreate them.
824 ///
825 /// For this reason we take the input stream if it exists.
826 ///
827 /// `num_channels` is the desired number of output channels.
828 ///
829 /// `buffer_size` sets the desired buffer_size. If None is passed in, then the
830 /// default buffersize for the device is used.
831 ///
832 /// This returns a full AsioStreams with both input and output if input was active.
833 pub fn prepare_output_stream(
834 &self,
835 input: Option<AsioStream>,
836 num_channels: usize,
837 buffer_size: Option<i32>,
838 ) -> Result<AsioStreams, AsioError> {
839 let input_buffer_infos = input.map(|input| input.buffer_infos).unwrap_or_default();
840 let output_buffer_infos = prepare_buffer_infos(false, num_channels);
841 self.create_streams(input_buffer_infos, output_buffer_infos, buffer_size)
842 }
843
844 /// Releases buffers allocations.
845 ///
846 /// This will `stop` the stream if the driver is `Running`.
847 ///
848 /// No-op if no buffers are allocated.
849 pub fn dispose_buffers(&self) -> Result<(), AsioError> {
850 self.inner.dispose_buffers_inner()
851 }
852
853 /// Starts ASIO streams playing.
854 ///
855 /// The driver must be in the `Prepared` state
856 ///
857 /// If called successfully, the driver will be in the `Running` state.
858 ///
859 /// No-op if already `Running`.
860 pub fn start(&self) -> Result<(), AsioError> {
861 let mut state = self.inner.lock_state();
862 if let DriverState::Running = *state {
863 return Ok(());
864 }
865 unsafe {
866 asio_result!(ai::ASIOStart())?;
867 }
868 *state = DriverState::Running;
869 Ok(())
870 }
871
872 /// Stops ASIO streams playing.
873 ///
874 /// No-op if the state is not `Running`.
875 ///
876 /// If the state was `Running` and the stream is stopped successfully, the driver will be in
877 /// the `Prepared` state.
878 pub fn stop(&self) -> Result<(), AsioError> {
879 self.inner.stop_inner()
880 }
881
882 /// Adds a callback to the list of active callbacks.
883 ///
884 /// The given function receives the index of the buffer currently ready for processing.
885 ///
886 /// Returns an ID uniquely associated with the given callback so that it may be removed later.
887 pub fn add_callback<F>(&self, callback: F) -> BufferCallbackId
888 where
889 F: 'static + FnMut(&CallbackInfo) + Send,
890 {
891 let mut bc = BUFFER_CALLBACK.lock().unwrap();
892 let id = bc
893 .last()
894 .map(|&(id, _)| BufferCallbackId(id.0.checked_add(1).expect("stream ID overflowed")))
895 .unwrap_or(BufferCallbackId(0));
896 let cb = BufferCallback(Box::new(callback));
897 bc.push((id, cb));
898 id
899 }
900
901 /// Remove the callback with the given ID.
902 pub fn remove_callback(&self, rem_id: BufferCallbackId) {
903 let mut bc = BUFFER_CALLBACK.lock().unwrap();
904 bc.retain(|&(id, _)| id != rem_id);
905 }
906
907 /// Consumes and destroys the `Driver`, stopping the streams if they are running and releasing
908 /// any associated resources.
909 ///
910 /// Returns `Ok(true)` if the driver was successfully destroyed.
911 ///
912 /// Returns `Ok(false)` if the driver was not destroyed because another handle to the driver
913 /// still exists.
914 ///
915 /// Returns `Err` if some switching driver states failed or if ASIO returned an error on exit.
916 pub fn destroy(self) -> Result<bool, AsioError> {
917 let Driver { inner } = self;
918 match Arc::try_unwrap(inner) {
919 Err(_) => Ok(false),
920 Ok(mut inner) => {
921 inner.destroy_inner()?;
922 Ok(true)
923 }
924 }
925 }
926
927 /// Register a callback to receive ASIO driver events.
928 ///
929 /// The callback receives an [`AsioDriverEvent`] and returns a `bool`. The return value is
930 /// meaningful only for [`AsioDriverEvent::Message`] with selector
931 /// [`AsioMessageSelectors::kAsioSelectorSupported`]: return `true` to advertise support for
932 /// the queried selector, `false` to decline. For all other events the return value is ignored.
933 ///
934 /// Returns an ID uniquely associated with the given callback so that it may be removed later.
935 pub fn add_event_callback<F>(&self, callback: F) -> DriverEventCallbackId
936 where
937 F: Fn(AsioDriverEvent) -> bool + Send + Sync + 'static,
938 {
939 let mut dcb = DRIVER_EVENT_CALLBACKS.lock().unwrap();
940 let id = dcb
941 .last()
942 .map(|&(id, _)| {
943 DriverEventCallbackId(
944 id.0.checked_add(1)
945 .expect("DriverEventCallbackId overflowed"),
946 )
947 })
948 .unwrap_or(DriverEventCallbackId(0));
949
950 let cb = DriverEventCallback(Arc::new(callback));
951 dcb.push((id, cb));
952 id
953 }
954
955 /// Remove the event callback with the given ID.
956 pub fn remove_event_callback(&self, rem_id: DriverEventCallbackId) {
957 let mut dcb = DRIVER_EVENT_CALLBACKS.lock().unwrap();
958 dcb.retain(|&(id, _)| id != rem_id);
959 }
960}
961
962impl DriverState {
963 fn stop(&mut self) -> Result<(), AsioError> {
964 if let DriverState::Running = *self {
965 unsafe {
966 asio_result!(ai::ASIOStop())?;
967 }
968 *self = DriverState::Prepared;
969 }
970 Ok(())
971 }
972
973 fn dispose_buffers(&mut self) -> Result<(), AsioError> {
974 if let DriverState::Initialized = *self {
975 return Ok(());
976 }
977 if let DriverState::Running = *self {
978 self.stop()?;
979 }
980 unsafe {
981 asio_result!(ai::ASIODisposeBuffers())?;
982 }
983 *self = DriverState::Initialized;
984 Ok(())
985 }
986
987 fn destroy(&mut self) -> Result<(), AsioError> {
988 if let DriverState::Running = *self {
989 self.stop()?;
990 }
991 if let DriverState::Prepared = *self {
992 self.dispose_buffers()?;
993 }
994 unsafe {
995 asio_result!(ai::ASIOExit())?;
996 ai::remove_current_driver();
997 }
998 Ok(())
999 }
1000}
1001
1002impl DriverInner {
1003 fn lock_state(&self) -> MutexGuard<'_, DriverState> {
1004 self.state.lock().expect("failed to lock `DriverState`")
1005 }
1006
1007 fn stop_inner(&self) -> Result<(), AsioError> {
1008 let mut state = self.lock_state();
1009 state.stop()
1010 }
1011
1012 fn dispose_buffers_inner(&self) -> Result<(), AsioError> {
1013 let mut state = self.lock_state();
1014 state.dispose_buffers()
1015 }
1016
1017 fn destroy_inner(&mut self) -> Result<(), AsioError> {
1018 {
1019 let mut state = self.lock_state();
1020 state.destroy()?;
1021
1022 // Clear any existing stream callbacks.
1023 if let Ok(mut bcs) = BUFFER_CALLBACK.lock() {
1024 bcs.clear();
1025 }
1026 }
1027
1028 // Signal that the driver has been destroyed.
1029 self.destroyed = true;
1030
1031 Ok(())
1032 }
1033}
1034
1035impl Drop for DriverInner {
1036 fn drop(&mut self) {
1037 if !self.destroyed {
1038 // We probably shouldn't `panic!` in the destructor? We also shouldn't ignore errors
1039 // though either.
1040 self.destroy_inner().ok();
1041 }
1042 }
1043}
1044
1045unsafe impl Send for AsioStream {}
1046
1047/// Used by the input and output stream creation process.
1048fn prepare_buffer_infos(is_input: bool, n_channels: usize) -> Vec<AsioBufferInfo> {
1049 let is_input = if is_input { 1 } else { 0 };
1050 (0..n_channels)
1051 .map(|ch| AsioBufferInfo {
1052 is_input,
1053 channel_num: ch as i32,
1054 // To be filled by ASIOCreateBuffers.
1055 buffers: [std::ptr::null_mut(); 2],
1056 })
1057 .collect()
1058}
1059
1060/// Retrieve the minimum, maximum and preferred buffer sizes along with the available
1061/// buffer size granularity.
1062fn asio_get_buffer_sizes() -> Result<BufferSizes, AsioError> {
1063 let mut b = BufferSizes::default();
1064 unsafe {
1065 let res = ai::ASIOGetBufferSize(&mut b.min, &mut b.max, &mut b.pref, &mut b.grans);
1066 asio_result!(res)?;
1067 }
1068 Ok(b)
1069}
1070
1071/// Retrieve the `ASIOChannelInfo` associated with the channel at the given index on either the
1072/// input or output stream (`true` for input).
1073fn asio_channel_info(channel: c_long, is_input: bool) -> Result<ai::ASIOChannelInfo, AsioError> {
1074 let mut channel_info = ai::ASIOChannelInfo {
1075 // Which channel we are querying
1076 channel,
1077 // Was it input or output
1078 isInput: if is_input { 1 } else { 0 },
1079 // Was it active
1080 isActive: 0,
1081 channelGroup: 0,
1082 // The sample type
1083 type_: 0,
1084 name: [0 as c_char; 32],
1085 };
1086 unsafe {
1087 asio_result!(ai::ASIOGetChannelInfo(&mut channel_info))?;
1088 Ok(channel_info)
1089 }
1090}
1091
1092/// Retrieve the data type of either the input or output stream.
1093///
1094/// If `is_input` is true, this will be queried on the input stream.
1095fn stream_data_type(is_input: bool) -> Result<AsioSampleType, AsioError> {
1096 let channel_info = asio_channel_info(0, is_input)?;
1097 Ok(FromPrimitive::from_i32(channel_info.type_).expect("unknown `ASIOSampletype` value"))
1098}
1099
1100/// ASIO uses null terminated c strings for driver names.
1101///
1102/// This converts to utf8.
1103fn driver_name_to_utf8(bytes: &[c_char]) -> std::borrow::Cow<'_, str> {
1104 unsafe { CStr::from_ptr(bytes.as_ptr()).to_string_lossy() }
1105}
1106
1107/// Convert an `ASIOTimeStamp` (high and low 32-bit halves) to a `u64` nanosecond value.
1108#[inline]
1109fn asio_timestamp_to_nanos(ts: ai::ASIOTimeStamp) -> u64 {
1110 (ts.hi as u64) << 32 | ts.lo as u64
1111}
1112
1113/// Indicates the stream sample rate has changed.
1114extern "C" fn sample_rate_did_change(s_rate: c_double) {
1115 let old_bits = CURRENT_SAMPLE_RATE.load(Ordering::Acquire);
1116 if s_rate.to_bits() != old_bits {
1117 CURRENT_SAMPLE_RATE.store(s_rate.to_bits(), Ordering::Release);
1118 dispatch_event(AsioDriverEvent::SampleRateChanged(s_rate));
1119 }
1120}
1121
1122const ASIO_VERSION: c_long = 2;
1123
1124/// Dispatch `event` to all registered driver event callbacks.
1125///
1126/// Returns `true` if any callback returns `true`. All callbacks are always called so that
1127/// notification side-effects (e.g. stream invalidation) reach every registered listener.
1128fn dispatch_event(event: AsioDriverEvent) -> bool {
1129 let callbacks: Vec<_> = {
1130 let lock = DRIVER_EVENT_CALLBACKS.lock().unwrap();
1131 lock.iter().map(|(_, cb)| cb.0.clone()).collect()
1132 };
1133 callbacks
1134 .iter()
1135 .fold(false, |handled, cb| cb(event) || handled)
1136}
1137
1138/// Message callback for ASIO to notify of certain events.
1139extern "C" fn asio_message(
1140 selector: c_long,
1141 value: c_long,
1142 _message: *mut (),
1143 _opt: *mut c_double,
1144) -> c_long {
1145 match AsioMessageSelectors::from_i64(selector as i64) {
1146 Some(AsioMessageSelectors::kAsioSelectorSupported) => {
1147 // For selectors that asio-sys itself always handles, advertise support
1148 // unconditionally. For all others, delegate to registered callbacks so
1149 // each host can opt-in.
1150 match AsioMessageSelectors::from_i64(value as i64) {
1151 Some(AsioMessageSelectors::kAsioSelectorSupported)
1152 | Some(AsioMessageSelectors::kAsioResetRequest)
1153 | Some(AsioMessageSelectors::kAsioEngineVersion)
1154 | Some(AsioMessageSelectors::kAsioResyncRequest)
1155 | Some(AsioMessageSelectors::kAsioLatenciesChanged)
1156 | Some(AsioMessageSelectors::kAsioSupportsTimeInfo) => true as c_long,
1157 _ => dispatch_event(AsioDriverEvent::Message {
1158 selector: AsioMessageSelectors::kAsioSelectorSupported,
1159 value,
1160 }) as c_long,
1161 }
1162 }
1163
1164 Some(AsioMessageSelectors::kAsioResetRequest) => {
1165 // The driver requests a full teardown and reinitialisation. Cannot be performed
1166 // here as this callback is invoked from within the driver; notify the host to
1167 // defer the reset to a safe point.
1168 dispatch_event(AsioDriverEvent::Message {
1169 selector: AsioMessageSelectors::kAsioResetRequest,
1170 value,
1171 });
1172 true as c_long
1173 }
1174
1175 Some(AsioMessageSelectors::kAsioResyncRequest) => {
1176 // The driver encountered non-fatal data loss (e.g. a timestamp discontinuity).
1177 // Notify the host so it can handle the gap appropriately.
1178 dispatch_event(AsioDriverEvent::Message {
1179 selector: AsioMessageSelectors::kAsioResyncRequest,
1180 value,
1181 });
1182 true as c_long
1183 }
1184
1185 Some(AsioMessageSelectors::kAsioLatenciesChanged) => {
1186 // The driver latencies have changed; have them re-queried.
1187 dispatch_event(AsioDriverEvent::Message {
1188 selector: AsioMessageSelectors::kAsioLatenciesChanged,
1189 value,
1190 });
1191 true as c_long
1192 }
1193
1194 Some(AsioMessageSelectors::kAsioEngineVersion) => {
1195 // Return the supported ASIO version of the host application. If a host application
1196 // does not implement this selector, ASIO 1.0 is assumed by the driver.
1197 ASIO_VERSION
1198 }
1199
1200 Some(AsioMessageSelectors::kAsioSupportsTimeInfo) => {
1201 // Informs the driver whether the asioCallbacks.bufferSwitchTimeInfo() callback is
1202 // supported. For compatibility with ASIO 1.0 drivers the host application should
1203 // always support the "old" bufferSwitch method, too, which we do.
1204 true as c_long
1205 }
1206
1207 // For all other selectors, delegate to registered callbacks.
1208 Some(other) => dispatch_event(AsioDriverEvent::Message {
1209 selector: other,
1210 value,
1211 }) as c_long,
1212
1213 None => false as c_long, // Unrecognised selector.
1214 }
1215}
1216
1217/// Similar to buffer switch but with time info.
1218///
1219/// If only `buffer_switch` is called by the driver instead, the `buffer_switch` callback will
1220/// create the necessary timing info and call this function.
1221///
1222/// TODO: Provide some access to `ai::ASIOTime` once CPAL gains support for time stamps.
1223extern "C" fn buffer_switch_time_info(
1224 time: *mut ai::ASIOTime,
1225 double_buffer_index: c_long,
1226 _direct_process: c_long,
1227) -> *mut ai::ASIOTime {
1228 // This lock is probably unavoidable, but locks in the audio stream are not great.
1229 let mut bcs = BUFFER_CALLBACK.lock().unwrap();
1230 let asio_time: &mut AsioTime = unsafe { &mut *(time as *mut AsioTime) };
1231 // Alternates: 0, 1, 0, 1, ...
1232 let callback_flag = CALLBACK_FLAG.fetch_xor(1, Ordering::Relaxed);
1233
1234 let callback_info = CallbackInfo {
1235 buffer_index: double_buffer_index,
1236 system_time: asio_timestamp_to_nanos(asio_time.time_info.system_time),
1237 callback_flag,
1238 };
1239 for &mut (_, ref mut bc) in bcs.iter_mut() {
1240 bc.run(&callback_info);
1241 }
1242
1243 if CALL_OUTPUT_READY.load(Ordering::Acquire) {
1244 unsafe { ai::ASIOOutputReady() };
1245 }
1246
1247 time
1248}
1249
1250/// This is called by ASIO.
1251///
1252/// Here we run the callback for each stream.
1253///
1254/// `double_buffer_index` is either `0` or `1` indicating which buffer to fill.
1255extern "C" fn buffer_switch(double_buffer_index: c_long, direct_process: c_long) {
1256 // Emulate the time info provided by the `buffer_switch_time_info` callback.
1257 // This is an attempt at matching the behaviour in `hostsample.cpp` from the SDK.
1258 let mut time = unsafe {
1259 let mut time: AsioTime = std::mem::zeroed();
1260 let res = ai::ASIOGetSamplePosition(
1261 &mut time.time_info.sample_position,
1262 &mut time.time_info.system_time,
1263 );
1264 if let Ok(()) = asio_result!(res) {
1265 time.time_info.flags = (ai::AsioTimeInfoFlags::kSystemTimeValid
1266 | ai::AsioTimeInfoFlags::kSamplePositionValid)
1267 // Context about the cast:
1268 //
1269 // Cast was required to successfully compile with MinGW-w64.
1270 //
1271 // The flags defined will not create a value that exceeds the maximum value of an i32.
1272 // The flags are intended to be non-negative, so the sign bit will not be used.
1273 // The c_uint (flags) is being cast to i32 which is safe as long as the actual value fits within the i32 range, which is true in this case.
1274 //
1275 // The actual flags in asio sdk are defined as:
1276 // typedef enum AsioTimeInfoFlags
1277 // {
1278 // kSystemTimeValid = 1, // must always be valid
1279 // kSamplePositionValid = 1 << 1, // must always be valid
1280 // kSampleRateValid = 1 << 2,
1281 // kSpeedValid = 1 << 3,
1282 //
1283 // kSampleRateChanged = 1 << 4,
1284 // kClockSourceChanged = 1 << 5
1285 // } AsioTimeInfoFlags;
1286 .0 as _;
1287 }
1288 time
1289 };
1290
1291 // Actual processing happens within the `buffer_switch_time_info` callback.
1292 let asio_time_ptr = &mut time as *mut AsioTime as *mut ai::ASIOTime;
1293 buffer_switch_time_info(asio_time_ptr, double_buffer_index, direct_process);
1294}
1295
1296#[test]
1297fn check_type_sizes() {
1298 assert_eq!(
1299 std::mem::size_of::<AsioSampleRate>(),
1300 std::mem::size_of::<ai::ASIOSampleRate>()
1301 );
1302 assert_eq!(
1303 std::mem::size_of::<AsioTimeCode>(),
1304 std::mem::size_of::<ai::ASIOTimeCode>()
1305 );
1306 assert_eq!(
1307 std::mem::size_of::<AsioTimeInfo>(),
1308 std::mem::size_of::<ai::AsioTimeInfo>(),
1309 );
1310 assert_eq!(
1311 std::mem::size_of::<AsioTime>(),
1312 std::mem::size_of::<ai::ASIOTime>()
1313 );
1314}