Update asio backend for stream format renaming
This commit is contained in:
parent
3a692f8bca
commit
f292391190
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue