use std; pub type SupportedInputConfigs = std::vec::IntoIter; pub type SupportedOutputConfigs = std::vec::IntoIter; use super::parking_lot::Mutex; use super::sys; use std::hash::{Hash, Hasher}; use std::sync::Arc; use BackendSpecificError; use DefaultStreamConfigError; use DeviceNameError; use DevicesError; use SampleFormat; use SampleRate; use SupportedBufferSizeRange; use SupportedStreamConfig; use SupportedStreamConfigRange; use SupportedStreamConfigsError; /// A ASIO Device pub struct Device { /// The driver represented by this device. pub driver: Arc, // Input and/or Output stream. // An driver can only have one of each. // They need to be created at the same time. pub asio_streams: Arc>, } /// All available devices. pub struct Devices { asio: Arc, drivers: std::vec::IntoIter, } impl PartialEq for Device { fn eq(&self, other: &Self) -> bool { self.driver.name() == other.driver.name() } } impl Eq for Device {} impl Hash for Device { fn hash(&self, state: &mut H) { self.driver.name().hash(state); } } impl Device { pub fn name(&self) -> Result { Ok(self.driver.name().to_string()) } /// Gets the supported input configs. /// TODO currently only supports the default. /// Need to find all possible configs. pub fn supported_input_configs( &self, ) -> Result { // Retrieve the default config for the total supported channels and supported sample // format. let mut f = match self.default_input_config() { Err(_) => return Err(SupportedStreamConfigsError::DeviceNotAvailable), Ok(f) => f, }; // Collect a config for every combination of supported sample rate and number of channels. let mut supported_configs = vec![]; for &rate in ::COMMON_SAMPLE_RATES { if !self .driver .can_sample_rate(rate.0.into()) .ok() .unwrap_or(false) { continue; } for channels in 1..f.channels + 1 { supported_configs.push(SupportedStreamConfigRange { channels, min_sample_rate: rate, max_sample_rate: rate, buffer_size: f.buffer_size.clone(), sample_format: f.sample_format.clone(), }) } } Ok(supported_configs.into_iter()) } /// Gets the supported output configs. /// TODO currently only supports the default. /// Need to find all possible configs. pub fn supported_output_configs( &self, ) -> Result { // Retrieve the default config for the total supported channels and supported sample // format. let mut f = match self.default_output_config() { Err(_) => return Err(SupportedStreamConfigsError::DeviceNotAvailable), Ok(f) => f, }; // Collect a config for every combination of supported sample rate and number of channels. let mut supported_configs = vec![]; for &rate in ::COMMON_SAMPLE_RATES { if !self .driver .can_sample_rate(rate.0.into()) .ok() .unwrap_or(false) { continue; } for channels in 1..f.channels + 1 { supported_configs.push(SupportedStreamConfigRange { channels, min_sample_rate: rate, max_sample_rate: rate, buffer_size: f.buffer_size.clone(), sample_format: f.sample_format.clone(), }) } } Ok(supported_configs.into_iter()) } /// Returns the default input config pub fn default_input_config(&self) -> Result { let channels = self.driver.channels().map_err(default_config_err)?.ins as u16; let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_config_err)? as _); let (min, max) = self.driver.buffersize_range().map_err(default_config_err)?; let buffer_size = SupportedBufferSizeRange { min: min as u32, max: max as u32, requires_power_of_two: false, }; // Map th ASIO sample type to a CPAL sample type let data_type = self.driver.input_data_type().map_err(default_config_err)?; let sample_format = convert_data_type(&data_type) .ok_or(DefaultStreamConfigError::StreamTypeNotSupported)?; Ok(SupportedStreamConfig { channels, sample_rate, buffer_size, sample_format, }) } /// Returns the default output config pub fn default_output_config(&self) -> Result { let channels = self.driver.channels().map_err(default_config_err)?.outs as u16; let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_config_err)? as _); let (min, max) = self.driver.buffersize_range().map_err(default_config_err)?; let buffer_size = SupportedBufferSizeRange { min: min as u32, max: max as u32, requires_power_of_two: false, }; let data_type = self.driver.output_data_type().map_err(default_config_err)?; let sample_format = convert_data_type(&data_type) .ok_or(DefaultStreamConfigError::StreamTypeNotSupported)?; Ok(SupportedStreamConfig { channels, sample_rate, buffer_size, sample_format, }) } } impl Devices { pub fn new(asio: Arc) -> Result { let drivers = asio.driver_names().into_iter(); Ok(Devices { asio, drivers }) } } impl Iterator for Devices { type Item = Device; /// Load drivers and return device fn next(&mut self) -> Option { loop { match self.drivers.next() { Some(name) => match self.asio.load_driver(&name) { Ok(driver) => { let driver = Arc::new(driver); let asio_streams = Arc::new(Mutex::new(sys::AsioStreams { input: None, output: None, })); return Some(Device { driver, asio_streams, }); } Err(_) => continue, }, None => return None, } } } fn size_hint(&self) -> (usize, Option) { unimplemented!() } } pub(crate) fn convert_data_type(ty: &sys::AsioSampleType) -> Option { let fmt = match *ty { sys::AsioSampleType::ASIOSTInt16MSB => SampleFormat::I16, sys::AsioSampleType::ASIOSTInt16LSB => SampleFormat::I16, sys::AsioSampleType::ASIOSTFloat32MSB => SampleFormat::F32, sys::AsioSampleType::ASIOSTFloat32LSB => SampleFormat::F32, // NOTE: While ASIO does not support these formats directly, the stream callback created by // CPAL supports converting back and forth between the following. This is because many ASIO // drivers only support `Int32` formats, while CPAL does not support this format at all. We // allow for this implicit conversion temporarily until CPAL gets support for an `I32` // format. sys::AsioSampleType::ASIOSTInt32MSB => SampleFormat::I16, sys::AsioSampleType::ASIOSTInt32LSB => SampleFormat::I16, _ => return None, }; Some(fmt) } fn default_config_err(e: sys::AsioError) -> DefaultStreamConfigError { match e { sys::AsioError::NoDrivers | sys::AsioError::HardwareMalfunction => { DefaultStreamConfigError::DeviceNotAvailable } sys::AsioError::NoRate => DefaultStreamConfigError::StreamTypeNotSupported, err => { let description = format!("{}", err); BackendSpecificError { description }.into() } } }