Update asio backend for stream format renaming

This commit is contained in:
mitchmindtree 2020-01-28 16:17:14 +01:00
parent 3a692f8bca
commit f292391190
3 changed files with 127 additions and 118 deletions

View File

@ -1,20 +1,20 @@
use std; use std;
pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedInputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedOutputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
use super::parking_lot::Mutex; use super::parking_lot::Mutex;
use super::sys; use super::sys;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::sync::Arc; use std::sync::Arc;
use BackendSpecificError; use BackendSpecificError;
use DefaultFormatError; use DefaultStreamConfigError;
use DeviceNameError; use DeviceNameError;
use DevicesError; use DevicesError;
use Format;
use SampleFormat; use SampleFormat;
use SampleRate; use SampleRate;
use SupportedFormat; use SupportedStreamConfig;
use SupportedFormatsError; use SupportedStreamConfigRange;
use SupportedStreamConfigsError;
/// A ASIO Device /// A ASIO Device
pub struct Device { pub struct Device {
@ -52,52 +52,21 @@ impl Device {
Ok(self.driver.name().to_string()) Ok(self.driver.name().to_string())
} }
/// Gets the supported input formats. /// Gets the supported input configs.
/// TODO currently only supports the default. /// TODO currently only supports the default.
/// Need to find all possible formats. /// Need to find all possible configs.
pub fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> { pub fn supported_input_configs(
// 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(
&self, &self,
) -> Result<SupportedOutputFormats, SupportedFormatsError> { ) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
// Retrieve the default format for the total supported channels and supported sample // Retrieve the default config for the total supported channels and supported sample
// format. // format.
let mut f = match self.default_output_format() { let mut f = match self.default_input_config() {
Err(_) => return Err(SupportedFormatsError::DeviceNotAvailable), Err(_) => return Err(SupportedStreamConfigsError::DeviceNotAvailable),
Ok(f) => f, Ok(f) => f,
}; };
// Collect a format for every combination of supported sample rate and number of channels. // Collect a config for every combination of supported sample rate and number of channels.
let mut supported_formats = vec![]; let mut supported_configs = vec![];
for &rate in ::COMMON_SAMPLE_RATES { for &rate in ::COMMON_SAMPLE_RATES {
if !self if !self
.driver .driver
@ -110,38 +79,71 @@ impl Device {
for channels in 1..f.channels + 1 { for channels in 1..f.channels + 1 {
f.channels = channels; f.channels = channels;
f.sample_rate = rate; 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 /// Gets the supported output configs.
pub fn default_input_format(&self) -> Result<Format, DefaultFormatError> { /// TODO currently only supports the default.
let channels = self.driver.channels().map_err(default_format_err)?.ins as u16; /// Need to find all possible configs.
let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_format_err)? as _); pub fn supported_output_configs(
&self,
) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
// 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<SupportedStreamConfig, DefaultStreamConfigError> {
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 // 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 = self.driver.input_data_type().map_err(default_config_err)?;
let data_type = let sample_format = convert_data_type(&data_type)
convert_data_type(&data_type).ok_or(DefaultFormatError::StreamTypeNotSupported)?; .ok_or(DefaultStreamConfigError::StreamTypeNotSupported)?;
Ok(Format { Ok(SupportedStreamConfig {
channels, channels,
sample_rate, sample_rate,
data_type, sample_format,
}) })
} }
/// Returns the default output format /// Returns the default output config
pub fn default_output_format(&self) -> Result<Format, DefaultFormatError> { pub fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
let channels = self.driver.channels().map_err(default_format_err)?.outs as u16; let channels = self.driver.channels().map_err(default_config_err)?.outs as u16;
let sample_rate = SampleRate(self.driver.sample_rate().map_err(default_format_err)? as _); 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_format_err)?; let data_type = self.driver.output_data_type().map_err(default_config_err)?;
let data_type = let sample_format = convert_data_type(&data_type)
convert_data_type(&data_type).ok_or(DefaultFormatError::StreamTypeNotSupported)?; .ok_or(DefaultStreamConfigError::StreamTypeNotSupported)?;
Ok(Format { Ok(SupportedStreamConfig {
channels, channels,
sample_rate, sample_rate,
data_type, sample_format,
}) })
} }
} }
@ -202,12 +204,12 @@ pub(crate) fn convert_data_type(ty: &sys::AsioSampleType) -> Option<SampleFormat
Some(fmt) Some(fmt)
} }
fn default_format_err(e: sys::AsioError) -> DefaultFormatError { fn default_config_err(e: sys::AsioError) -> DefaultStreamConfigError {
match e { match e {
sys::AsioError::NoDrivers | sys::AsioError::HardwareMalfunction => { sys::AsioError::NoDrivers | sys::AsioError::HardwareMalfunction => {
DefaultFormatError::DeviceNotAvailable DefaultStreamConfigError::DeviceNotAvailable
} }
sys::AsioError::NoRate => DefaultFormatError::StreamTypeNotSupported, sys::AsioError::NoRate => DefaultStreamConfigError::StreamTypeNotSupported,
err => { err => {
let description = format!("{}", err); let description = format!("{}", err);
BackendSpecificError { description }.into() BackendSpecificError { description }.into()

View File

@ -2,12 +2,13 @@ extern crate asio_sys as sys;
extern crate parking_lot; extern crate parking_lot;
use crate::{ use crate::{
BuildStreamError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format, BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
PauseStreamError, PlayStreamError, StreamError, SupportedFormatsError, PauseStreamError, PlayStreamError, StreamError, SupportedStreamConfig,
SupportedStreamConfigsError,
}; };
use traits::{DeviceTrait, HostTrait, StreamTrait}; 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; pub use self::stream::Stream;
use std::sync::Arc; use std::sync::Arc;
@ -53,37 +54,37 @@ impl HostTrait for Host {
} }
impl DeviceTrait for Device { impl DeviceTrait for Device {
type SupportedInputFormats = SupportedInputFormats; type SupportedInputConfigs = SupportedInputConfigs;
type SupportedOutputFormats = SupportedOutputFormats; type SupportedOutputConfigs = SupportedOutputConfigs;
type Stream = Stream; type Stream = Stream;
fn name(&self) -> Result<String, DeviceNameError> { fn name(&self) -> Result<String, DeviceNameError> {
Device::name(self) Device::name(self)
} }
fn supported_input_formats( fn supported_input_configs(
&self, &self,
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> { ) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError> {
Device::supported_input_formats(self) Device::supported_input_configs(self)
} }
fn supported_output_formats( fn supported_output_configs(
&self, &self,
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> { ) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError> {
Device::supported_output_formats(self) Device::supported_output_configs(self)
} }
fn default_input_format(&self) -> Result<Format, DefaultFormatError> { fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
Device::default_input_format(self) Device::default_input_config(self)
} }
fn default_output_format(&self) -> Result<Format, DefaultFormatError> { fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
Device::default_output_format(self) Device::default_output_config(self)
} }
fn build_input_stream_raw<D, E>( fn build_input_stream_raw<D, E>(
&self, &self,
format: &Format, config: &SupportedStreamConfig,
data_callback: D, data_callback: D,
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
@ -91,12 +92,12 @@ impl DeviceTrait for Device {
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data) + Send + 'static,
E: FnMut(StreamError) + 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<D, E>( fn build_output_stream_raw<D, E>(
&self, &self,
format: &Format, config: &SupportedStreamConfig,
data_callback: D, data_callback: D,
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
@ -104,7 +105,7 @@ impl DeviceTrait for Device {
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data) + Send + 'static,
E: FnMut(StreamError) + 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)
} }
} }

View File

@ -10,12 +10,12 @@ use std::sync::Arc;
use BackendSpecificError; use BackendSpecificError;
use BuildStreamError; use BuildStreamError;
use Data; use Data;
use Format;
use PauseStreamError; use PauseStreamError;
use PlayStreamError; use PlayStreamError;
use Sample; use Sample;
use SampleFormat; use SampleFormat;
use StreamError; use StreamError;
use SupportedStreamConfig;
/// Sample types whose constant silent value is known. /// Sample types whose constant silent value is known.
trait Silence { trait Silence {
@ -59,7 +59,7 @@ impl Stream {
impl Device { impl Device {
pub fn build_input_stream_raw<D, E>( pub fn build_input_stream_raw<D, E>(
&self, &self,
format: &Format, config: &SupportedStreamConfig,
mut data_callback: D, mut data_callback: D,
_error_callback: E, _error_callback: E,
) -> Result<Stream, BuildStreamError> ) -> Result<Stream, BuildStreamError>
@ -70,18 +70,18 @@ impl Device {
let stream_type = self.driver.input_data_type().map_err(build_stream_err)?; let stream_type = self.driver.input_data_type().map_err(build_stream_err)?;
// Ensure that the desired sample type is supported. // 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)?; .ok_or(BuildStreamError::FormatNotSupported)?;
if format.data_type != data_type { if config.sample_format != sample_format {
return Err(BuildStreamError::FormatNotSupported); return Err(BuildStreamError::FormatNotSupported);
} }
let num_channels = format.channels.clone(); let num_channels = config.channels.clone();
let buffer_size = self.get_or_create_input_stream(format)?; let buffer_size = self.get_or_create_input_stream(config)?;
let cpal_num_samples = buffer_size * num_channels as usize; let cpal_num_samples = buffer_size * num_channels as usize;
// Create the buffer depending on the size of the data type. // 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 mut interleaved = vec![0u8; len_bytes];
let stream_playing = Arc::new(AtomicBool::new(false)); let stream_playing = Arc::new(AtomicBool::new(false));
@ -134,7 +134,7 @@ impl Device {
callback(&data); callback(&data);
} }
match (&stream_type, data_type) { match (&stream_type, sample_format) {
(&sys::AsioSampleType::ASIOSTInt16LSB, SampleFormat::I16) => { (&sys::AsioSampleType::ASIOSTInt16LSB, SampleFormat::I16) => {
process_input_callback::<i16, i16, _, _>( process_input_callback::<i16, i16, _, _>(
&mut data_callback, &mut data_callback,
@ -225,7 +225,7 @@ impl Device {
pub fn build_output_stream_raw<D, E>( pub fn build_output_stream_raw<D, E>(
&self, &self,
format: &Format, config: &SupportedStreamConfig,
mut data_callback: D, mut data_callback: D,
_error_callback: E, _error_callback: E,
) -> Result<Stream, BuildStreamError> ) -> Result<Stream, BuildStreamError>
@ -236,18 +236,18 @@ impl Device {
let stream_type = self.driver.output_data_type().map_err(build_stream_err)?; let stream_type = self.driver.output_data_type().map_err(build_stream_err)?;
// Ensure that the desired sample type is supported. // 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)?; .ok_or(BuildStreamError::FormatNotSupported)?;
if format.data_type != data_type { if config.sample_format != sample_format {
return Err(BuildStreamError::FormatNotSupported); return Err(BuildStreamError::FormatNotSupported);
} }
let num_channels = format.channels.clone(); let num_channels = config.channels.clone();
let buffer_size = self.get_or_create_output_stream(format)?; let buffer_size = self.get_or_create_output_stream(config)?;
let cpal_num_samples = buffer_size * num_channels as usize; let cpal_num_samples = buffer_size * num_channels as usize;
// Create buffers depending on data type. // 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 interleaved = vec![0u8; len_bytes];
let mut silence_asio_buffer = SilenceAsioBuffer::default(); 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) => { (SampleFormat::I16, &sys::AsioSampleType::ASIOSTInt16LSB) => {
process_output_callback::<i16, i16, _, _>( process_output_callback::<i16, i16, _, _>(
&mut data_callback, &mut data_callback,
@ -436,15 +436,18 @@ impl Device {
/// If there is no existing ASIO Input Stream it will be created. /// If there is no existing ASIO Input Stream it will be created.
/// ///
/// On success, the buffer size of the stream is returned. /// On success, the buffer size of the stream is returned.
fn get_or_create_input_stream(&self, format: &Format) -> Result<usize, BuildStreamError> { fn get_or_create_input_stream(
match self.default_input_format() { &self,
config: &SupportedStreamConfig,
) -> Result<usize, BuildStreamError> {
match self.default_input_config() {
Ok(f) => { Ok(f) => {
let num_asio_channels = f.channels; 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), 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(); let ref mut streams = *self.asio_streams.lock();
// Either create a stream if thers none or had back the // Either create a stream if thers none or had back the
// size of the current one. // size of the current one.
@ -473,15 +476,18 @@ impl Device {
/// Create a new CPAL Output Stream. /// Create a new CPAL Output Stream.
/// ///
/// If there is no existing ASIO Output Stream it will be created. /// If there is no existing ASIO Output Stream it will be created.
fn get_or_create_output_stream(&self, format: &Format) -> Result<usize, BuildStreamError> { fn get_or_create_output_stream(
match self.default_output_format() { &self,
config: &SupportedStreamConfig,
) -> Result<usize, BuildStreamError> {
match self.default_output_config() {
Ok(f) => { Ok(f) => {
let num_asio_channels = f.channels; 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), 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(); let ref mut streams = *self.asio_streams.lock();
// Either create a stream if thers none or had back the // Either create a stream if thers none or had back the
// size of the current one. // 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. /// Checks sample rate, data type and then finally the number of channels.
fn check_format( fn check_config(
driver: &sys::Driver, driver: &sys::Driver,
format: &Format, config: &SupportedStreamConfig,
num_asio_channels: u16, num_asio_channels: u16,
) -> Result<(), BuildStreamError> { ) -> Result<(), BuildStreamError> {
let Format { let SupportedStreamConfig {
channels, channels,
sample_rate, sample_rate,
data_type, sample_format,
} = format; } = config;
// Try and set the sample rate to what the user selected. // Try and set the sample rate to what the user selected.
let sample_rate = sample_rate.0.into(); let sample_rate = sample_rate.0.into();
if sample_rate != driver.sample_rate().map_err(build_stream_err)? { 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 // unsigned formats are not supported by asio
match data_type { match sample_format {
SampleFormat::I16 | SampleFormat::F32 => (), SampleFormat::I16 | SampleFormat::F32 => (),
SampleFormat::U16 => return Err(BuildStreamError::FormatNotSupported), SampleFormat::U16 => return Err(BuildStreamError::FormatNotSupported),
} }