From f29239119070be27c4bdef574aecf4fdd2f89cfb Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Tue, 28 Jan 2020 16:17:14 +0100 Subject: [PATCH] Update asio backend for stream format renaming --- src/host/asio/device.rs | 140 ++++++++++++++++++++-------------------- src/host/asio/mod.rs | 39 +++++------ src/host/asio/stream.rs | 66 ++++++++++--------- 3 files changed, 127 insertions(+), 118 deletions(-) diff --git a/src/host/asio/device.rs b/src/host/asio/device.rs index b0b6532..dee4df3 100644 --- a/src/host/asio/device.rs +++ b/src/host/asio/device.rs @@ -1,20 +1,20 @@ use std; -pub type SupportedInputFormats = std::vec::IntoIter; -pub type SupportedOutputFormats = std::vec::IntoIter; +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 DefaultFormatError; +use DefaultStreamConfigError; use DeviceNameError; use DevicesError; -use Format; use SampleFormat; use SampleRate; -use SupportedFormat; -use SupportedFormatsError; +use SupportedStreamConfig; +use SupportedStreamConfigRange; +use SupportedStreamConfigsError; /// A ASIO Device pub struct Device { @@ -52,52 +52,21 @@ impl Device { Ok(self.driver.name().to_string()) } - /// Gets the supported input formats. + /// Gets the supported input configs. /// TODO currently only supports the default. - /// Need to find all possible formats. - pub fn supported_input_formats(&self) -> Result { - // Retrieve the default format for the total supported channels and supported sample - // format. - let mut f = match self.default_input_format() { - Err(_) => return Err(SupportedFormatsError::DeviceNotAvailable), - Ok(f) => f, - }; - - // Collect a format for every combination of supported sample rate and number of channels. - let mut supported_formats = 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 { - f.channels = channels; - f.sample_rate = rate; - supported_formats.push(SupportedFormat::from(f.clone())); - } - } - Ok(supported_formats.into_iter()) - } - - /// Gets the supported output formats. - /// TODO currently only supports the default. - /// Need to find all possible formats. - pub fn supported_output_formats( + /// Need to find all possible configs. + pub fn supported_input_configs( &self, - ) -> Result { - // Retrieve the default format for the total supported channels and supported sample + ) -> Result { + // Retrieve the default config for the total supported channels and supported sample // format. - let mut f = match self.default_output_format() { - Err(_) => return Err(SupportedFormatsError::DeviceNotAvailable), + let mut f = match self.default_input_config() { + Err(_) => return Err(SupportedStreamConfigsError::DeviceNotAvailable), Ok(f) => f, }; - // Collect a format for every combination of supported sample rate and number of channels. - let mut supported_formats = vec![]; + // 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 @@ -110,38 +79,71 @@ impl Device { for channels in 1..f.channels + 1 { f.channels = channels; f.sample_rate = rate; - supported_formats.push(SupportedFormat::from(f.clone())); + supported_configs.push(SupportedStreamConfigRange::from(f.clone())); } } - Ok(supported_formats.into_iter()) + Ok(supported_configs.into_iter()) } - /// Returns the default input format - pub fn default_input_format(&self) -> Result { - let channels = self.driver.channels().map_err(default_format_err)?.ins as u16; - let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_format_err)? as _); + /// 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 { + f.channels = channels; + f.sample_rate = rate; + supported_configs.push(SupportedStreamConfigRange::from(f.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 _); // Map th ASIO sample type to a CPAL sample type - let data_type = self.driver.input_data_type().map_err(default_format_err)?; - let data_type = - convert_data_type(&data_type).ok_or(DefaultFormatError::StreamTypeNotSupported)?; - Ok(Format { + 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, - data_type, + sample_format, }) } - /// Returns the default output format - pub fn default_output_format(&self) -> Result { - let channels = self.driver.channels().map_err(default_format_err)?.outs as u16; - let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_format_err)? as _); - let data_type = self.driver.output_data_type().map_err(default_format_err)?; - let data_type = - convert_data_type(&data_type).ok_or(DefaultFormatError::StreamTypeNotSupported)?; - Ok(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 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, - data_type, + sample_format, }) } } @@ -202,12 +204,12 @@ pub(crate) fn convert_data_type(ty: &sys::AsioSampleType) -> Option DefaultFormatError { +fn default_config_err(e: sys::AsioError) -> DefaultStreamConfigError { match e { sys::AsioError::NoDrivers | sys::AsioError::HardwareMalfunction => { - DefaultFormatError::DeviceNotAvailable + DefaultStreamConfigError::DeviceNotAvailable } - sys::AsioError::NoRate => DefaultFormatError::StreamTypeNotSupported, + sys::AsioError::NoRate => DefaultStreamConfigError::StreamTypeNotSupported, err => { let description = format!("{}", err); BackendSpecificError { description }.into() diff --git a/src/host/asio/mod.rs b/src/host/asio/mod.rs index 24713a0..917b958 100644 --- a/src/host/asio/mod.rs +++ b/src/host/asio/mod.rs @@ -2,12 +2,13 @@ extern crate asio_sys as sys; extern crate parking_lot; use crate::{ - BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format, - PauseStreamError, PlayStreamError, StreamError, SupportedFormatsError, + BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, + PauseStreamError, PlayStreamError, StreamError, SupportedStreamConfig, + SupportedStreamConfigsError, }; use traits::{DeviceTrait, HostTrait, StreamTrait}; -pub use self::device::{Device, Devices, SupportedInputFormats, SupportedOutputFormats}; +pub use self::device::{Device, Devices, SupportedInputConfigs, SupportedOutputConfigs}; pub use self::stream::Stream; use std::sync::Arc; @@ -53,37 +54,37 @@ impl HostTrait for Host { } impl DeviceTrait for Device { - type SupportedInputFormats = SupportedInputFormats; - type SupportedOutputFormats = SupportedOutputFormats; + type SupportedInputConfigs = SupportedInputConfigs; + type SupportedOutputConfigs = SupportedOutputConfigs; type Stream = Stream; fn name(&self) -> Result { Device::name(self) } - fn supported_input_formats( + fn supported_input_configs( &self, - ) -> Result { - Device::supported_input_formats(self) + ) -> Result { + Device::supported_input_configs(self) } - fn supported_output_formats( + fn supported_output_configs( &self, - ) -> Result { - Device::supported_output_formats(self) + ) -> Result { + Device::supported_output_configs(self) } - fn default_input_format(&self) -> Result { - Device::default_input_format(self) + fn default_input_config(&self) -> Result { + Device::default_input_config(self) } - fn default_output_format(&self) -> Result { - Device::default_output_format(self) + fn default_output_config(&self) -> Result { + Device::default_output_config(self) } fn build_input_stream_raw( &self, - format: &Format, + config: &SupportedStreamConfig, data_callback: D, error_callback: E, ) -> Result @@ -91,12 +92,12 @@ impl DeviceTrait for Device { D: FnMut(&Data) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { - Device::build_input_stream_raw(self, format, data_callback, error_callback) + Device::build_input_stream_raw(self, config, data_callback, error_callback) } fn build_output_stream_raw( &self, - format: &Format, + config: &SupportedStreamConfig, data_callback: D, error_callback: E, ) -> Result @@ -104,7 +105,7 @@ impl DeviceTrait for Device { D: FnMut(&mut Data) + Send + 'static, E: FnMut(StreamError) + Send + 'static, { - Device::build_output_stream_raw(self, format, data_callback, error_callback) + Device::build_output_stream_raw(self, config, data_callback, error_callback) } } diff --git a/src/host/asio/stream.rs b/src/host/asio/stream.rs index e938b5f..7d339c1 100644 --- a/src/host/asio/stream.rs +++ b/src/host/asio/stream.rs @@ -10,12 +10,12 @@ use std::sync::Arc; use BackendSpecificError; use BuildStreamError; use Data; -use Format; use PauseStreamError; use PlayStreamError; use Sample; use SampleFormat; use StreamError; +use SupportedStreamConfig; /// Sample types whose constant silent value is known. trait Silence { @@ -59,7 +59,7 @@ impl Stream { impl Device { pub fn build_input_stream_raw( &self, - format: &Format, + config: &SupportedStreamConfig, mut data_callback: D, _error_callback: E, ) -> Result @@ -70,18 +70,18 @@ impl Device { let stream_type = self.driver.input_data_type().map_err(build_stream_err)?; // Ensure that the desired sample type is supported. - let data_type = super::device::convert_data_type(&stream_type) + let sample_format = super::device::convert_data_type(&stream_type) .ok_or(BuildStreamError::FormatNotSupported)?; - if format.data_type != data_type { + if config.sample_format != sample_format { return Err(BuildStreamError::FormatNotSupported); } - let num_channels = format.channels.clone(); - let buffer_size = self.get_or_create_input_stream(format)?; + let num_channels = config.channels.clone(); + let buffer_size = self.get_or_create_input_stream(config)?; let cpal_num_samples = buffer_size * num_channels as usize; // Create the buffer depending on the size of the data type. - let len_bytes = cpal_num_samples * data_type.sample_size(); + let len_bytes = cpal_num_samples * sample_format.sample_size(); let mut interleaved = vec![0u8; len_bytes]; let stream_playing = Arc::new(AtomicBool::new(false)); @@ -134,7 +134,7 @@ impl Device { callback(&data); } - match (&stream_type, data_type) { + match (&stream_type, sample_format) { (&sys::AsioSampleType::ASIOSTInt16LSB, SampleFormat::I16) => { process_input_callback::( &mut data_callback, @@ -225,7 +225,7 @@ impl Device { pub fn build_output_stream_raw( &self, - format: &Format, + config: &SupportedStreamConfig, mut data_callback: D, _error_callback: E, ) -> Result @@ -236,18 +236,18 @@ impl Device { let stream_type = self.driver.output_data_type().map_err(build_stream_err)?; // Ensure that the desired sample type is supported. - let data_type = super::device::convert_data_type(&stream_type) + let sample_format = super::device::convert_data_type(&stream_type) .ok_or(BuildStreamError::FormatNotSupported)?; - if format.data_type != data_type { + if config.sample_format != sample_format { return Err(BuildStreamError::FormatNotSupported); } - let num_channels = format.channels.clone(); - let buffer_size = self.get_or_create_output_stream(format)?; + let num_channels = config.channels.clone(); + let buffer_size = self.get_or_create_output_stream(config)?; let cpal_num_samples = buffer_size * num_channels as usize; // Create buffers depending on data type. - let len_bytes = cpal_num_samples * data_type.sample_size(); + let len_bytes = cpal_num_samples * sample_format.sample_size(); let mut interleaved = vec![0u8; len_bytes]; let mut silence_asio_buffer = SilenceAsioBuffer::default(); @@ -336,7 +336,7 @@ impl Device { } } - match (data_type, &stream_type) { + match (sample_format, &stream_type) { (SampleFormat::I16, &sys::AsioSampleType::ASIOSTInt16LSB) => { process_output_callback::( &mut data_callback, @@ -436,15 +436,18 @@ impl Device { /// If there is no existing ASIO Input Stream it will be created. /// /// On success, the buffer size of the stream is returned. - fn get_or_create_input_stream(&self, format: &Format) -> Result { - match self.default_input_format() { + fn get_or_create_input_stream( + &self, + config: &SupportedStreamConfig, + ) -> Result { + match self.default_input_config() { Ok(f) => { let num_asio_channels = f.channels; - check_format(&self.driver, format, num_asio_channels) + check_config(&self.driver, config, num_asio_channels) } Err(_) => Err(BuildStreamError::FormatNotSupported), }?; - let num_channels = format.channels as usize; + let num_channels = config.channels as usize; let ref mut streams = *self.asio_streams.lock(); // Either create a stream if thers none or had back the // size of the current one. @@ -473,15 +476,18 @@ impl Device { /// Create a new CPAL Output Stream. /// /// If there is no existing ASIO Output Stream it will be created. - fn get_or_create_output_stream(&self, format: &Format) -> Result { - match self.default_output_format() { + fn get_or_create_output_stream( + &self, + config: &SupportedStreamConfig, + ) -> Result { + match self.default_output_config() { Ok(f) => { let num_asio_channels = f.channels; - check_format(&self.driver, format, num_asio_channels) + check_config(&self.driver, config, num_asio_channels) } Err(_) => Err(BuildStreamError::FormatNotSupported), }?; - let num_channels = format.channels as usize; + let num_channels = config.channels as usize; let ref mut streams = *self.asio_streams.lock(); // Either create a stream if thers none or had back the // size of the current one. @@ -570,19 +576,19 @@ impl AsioSample for f64 { } } -/// Check whether or not the desired format is supported by the stream. +/// Check whether or not the desired config is supported by the stream. /// /// Checks sample rate, data type and then finally the number of channels. -fn check_format( +fn check_config( driver: &sys::Driver, - format: &Format, + config: &SupportedStreamConfig, num_asio_channels: u16, ) -> Result<(), BuildStreamError> { - let Format { + let SupportedStreamConfig { channels, sample_rate, - data_type, - } = format; + sample_format, + } = config; // Try and set the sample rate to what the user selected. let sample_rate = sample_rate.0.into(); if sample_rate != driver.sample_rate().map_err(build_stream_err)? { @@ -598,7 +604,7 @@ fn check_format( } } // unsigned formats are not supported by asio - match data_type { + match sample_format { SampleFormat::I16 | SampleFormat::F32 => (), SampleFormat::U16 => return Err(BuildStreamError::FormatNotSupported), }