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;
pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>;
pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>;
pub type SupportedInputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
pub type SupportedOutputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
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<SupportedInputFormats, SupportedFormatsError> {
// 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<SupportedOutputFormats, SupportedFormatsError> {
// Retrieve the default format for the total supported channels and supported sample
) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
// 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<Format, DefaultFormatError> {
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<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
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<Format, DefaultFormatError> {
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<SupportedStreamConfig, DefaultStreamConfigError> {
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<SampleFormat
Some(fmt)
}
fn default_format_err(e: sys::AsioError) -> 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()

View File

@ -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<String, DeviceNameError> {
Device::name(self)
}
fn supported_input_formats(
fn supported_input_configs(
&self,
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
Device::supported_input_formats(self)
) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError> {
Device::supported_input_configs(self)
}
fn supported_output_formats(
fn supported_output_configs(
&self,
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
Device::supported_output_formats(self)
) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError> {
Device::supported_output_configs(self)
}
fn default_input_format(&self) -> Result<Format, DefaultFormatError> {
Device::default_input_format(self)
fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
Device::default_input_config(self)
}
fn default_output_format(&self) -> Result<Format, DefaultFormatError> {
Device::default_output_format(self)
fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
Device::default_output_config(self)
}
fn build_input_stream_raw<D, E>(
&self,
format: &Format,
config: &SupportedStreamConfig,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -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<D, E>(
&self,
format: &Format,
config: &SupportedStreamConfig,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
@ -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)
}
}

View File

@ -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<D, E>(
&self,
format: &Format,
config: &SupportedStreamConfig,
mut data_callback: D,
_error_callback: E,
) -> Result<Stream, BuildStreamError>
@ -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::<i16, i16, _, _>(
&mut data_callback,
@ -225,7 +225,7 @@ impl Device {
pub fn build_output_stream_raw<D, E>(
&self,
format: &Format,
config: &SupportedStreamConfig,
mut data_callback: D,
_error_callback: E,
) -> Result<Stream, BuildStreamError>
@ -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::<i16, i16, _, _>(
&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<usize, BuildStreamError> {
match self.default_input_format() {
fn get_or_create_input_stream(
&self,
config: &SupportedStreamConfig,
) -> Result<usize, BuildStreamError> {
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<usize, BuildStreamError> {
match self.default_output_format() {
fn get_or_create_output_stream(
&self,
config: &SupportedStreamConfig,
) -> Result<usize, BuildStreamError> {
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),
}