asio_sys/bindings/
mod.rs

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