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}