implemented buffersizes for asio
This commit is contained in:
parent
6edee6c6c2
commit
9e660da433
|
@ -19,6 +19,7 @@ pub enum AsioError {
|
||||||
HardwareStuck,
|
HardwareStuck,
|
||||||
NoRate,
|
NoRate,
|
||||||
ASE_NoMemory,
|
ASE_NoMemory,
|
||||||
|
InvalidBufferSize,
|
||||||
UnknownError,
|
UnknownError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ impl fmt::Display for AsioError {
|
||||||
"sample clock or rate cannot be determined or is not present"
|
"sample clock or rate cannot be determined or is not present"
|
||||||
),
|
),
|
||||||
AsioError::ASE_NoMemory => write!(f, "not enough memory for completing the request"),
|
AsioError::ASE_NoMemory => write!(f, "not enough memory for completing the request"),
|
||||||
|
AsioError::InvalidBufferSize => write!(f, "buffersize out of range for device"),
|
||||||
AsioError::UnknownError => write!(f, "Error not in SDK"),
|
AsioError::UnknownError => write!(f, "Error not in SDK"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +96,7 @@ impl Error for AsioError {
|
||||||
AsioError::HardwareStuck => "hardware is not running when sample position is inquired",
|
AsioError::HardwareStuck => "hardware is not running when sample position is inquired",
|
||||||
AsioError::NoRate => "sample clock or rate cannot be determined or is not present",
|
AsioError::NoRate => "sample clock or rate cannot be determined or is not present",
|
||||||
AsioError::ASE_NoMemory => "not enough memory for completing the request",
|
AsioError::ASE_NoMemory => "not enough memory for completing the request",
|
||||||
|
AsioError::InvalidBufferSize => "buffersize out of range for device",
|
||||||
AsioError::UnknownError => "Error not in SDK",
|
AsioError::UnknownError => "Error not in SDK",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -385,6 +385,14 @@ impl Driver {
|
||||||
Ok(channel)
|
Ok(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the min and max supported buffersize of the driver.
|
||||||
|
pub fn buffersize_range(&self) -> Result<(c_long, c_long), AsioError> {
|
||||||
|
let buffer_sizes = asio_get_buffer_sizes()?;
|
||||||
|
let min = buffer_sizes.min;
|
||||||
|
let max = buffer_sizes.max;
|
||||||
|
Ok((min, max))
|
||||||
|
}
|
||||||
|
|
||||||
/// Get current sample rate of the driver.
|
/// Get current sample rate of the driver.
|
||||||
pub fn sample_rate(&self) -> Result<c_double, AsioError> {
|
pub fn sample_rate(&self) -> Result<c_double, AsioError> {
|
||||||
let mut rate: c_double = 0.0;
|
let mut rate: c_double = 0.0;
|
||||||
|
@ -431,8 +439,10 @@ impl Driver {
|
||||||
///
|
///
|
||||||
/// This will destroy any already allocated buffers.
|
/// This will destroy any already allocated buffers.
|
||||||
///
|
///
|
||||||
/// The preferred buffer size from ASIO is used.
|
/// If buffersize is None then the preferred buffer size from ASIO is used,
|
||||||
fn create_buffers(&self, buffer_infos: &mut [AsioBufferInfo]) -> Result<c_long, AsioError> {
|
/// otherwise the desired buffersize is used if the requeted size is within
|
||||||
|
/// the range of accepted buffersizes for the device.
|
||||||
|
fn create_buffers(&self, buffer_infos: &mut [AsioBufferInfo], buffer_size: Option<i32>) -> Result<c_long, AsioError> {
|
||||||
let num_channels = buffer_infos.len();
|
let num_channels = buffer_infos.len();
|
||||||
|
|
||||||
// To pass as ai::ASIOCallbacks
|
// To pass as ai::ASIOCallbacks
|
||||||
|
@ -449,6 +459,17 @@ impl Driver {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let buffer_size = match buffer_size {
|
||||||
|
Some(v) => {
|
||||||
|
if v <= buffer_sizes.max {
|
||||||
|
v
|
||||||
|
} else {
|
||||||
|
return Err(AsioError::InvalidBufferSize)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => buffer_sizes.pref,
|
||||||
|
};
|
||||||
|
|
||||||
// Ensure the driver is in the `Initialized` state.
|
// Ensure the driver is in the `Initialized` state.
|
||||||
if let DriverState::Running = *state {
|
if let DriverState::Running = *state {
|
||||||
state.stop()?;
|
state.stop()?;
|
||||||
|
@ -460,23 +481,27 @@ impl Driver {
|
||||||
asio_result!(ai::ASIOCreateBuffers(
|
asio_result!(ai::ASIOCreateBuffers(
|
||||||
buffer_infos.as_mut_ptr() as *mut _,
|
buffer_infos.as_mut_ptr() as *mut _,
|
||||||
num_channels as i32,
|
num_channels as i32,
|
||||||
buffer_sizes.pref,
|
buffer_size,
|
||||||
&mut callbacks as *mut _ as *mut _,
|
&mut callbacks as *mut _ as *mut _,
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
*state = DriverState::Prepared;
|
*state = DriverState::Prepared;
|
||||||
|
|
||||||
Ok(buffer_sizes.pref)
|
Ok(buffer_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the streams.
|
/// Creates the streams.
|
||||||
///
|
///
|
||||||
|
/// `buffer_size` sets the desired buffer_size. If None is passed in, then the
|
||||||
|
/// default buffersize for the device is used.
|
||||||
|
///
|
||||||
/// Both input and output streams need to be created together as a single slice of
|
/// Both input and output streams need to be created together as a single slice of
|
||||||
/// `ASIOBufferInfo`.
|
/// `ASIOBufferInfo`.
|
||||||
fn create_streams(
|
fn create_streams(
|
||||||
&self,
|
&self,
|
||||||
mut input_buffer_infos: Vec<AsioBufferInfo>,
|
mut input_buffer_infos: Vec<AsioBufferInfo>,
|
||||||
mut output_buffer_infos: Vec<AsioBufferInfo>,
|
mut output_buffer_infos: Vec<AsioBufferInfo>,
|
||||||
|
buffer_size: Option<i32>,
|
||||||
) -> Result<AsioStreams, AsioError> {
|
) -> Result<AsioStreams, AsioError> {
|
||||||
let (input, output) = match (
|
let (input, output) = match (
|
||||||
input_buffer_infos.is_empty(),
|
input_buffer_infos.is_empty(),
|
||||||
|
@ -489,7 +514,7 @@ impl Driver {
|
||||||
let mut all_buffer_infos = input_buffer_infos;
|
let mut all_buffer_infos = input_buffer_infos;
|
||||||
all_buffer_infos.append(&mut output_buffer_infos);
|
all_buffer_infos.append(&mut output_buffer_infos);
|
||||||
// Create the buffers. On success, split the output and input again.
|
// Create the buffers. On success, split the output and input again.
|
||||||
let buffer_size = self.create_buffers(&mut all_buffer_infos)?;
|
let buffer_size = self.create_buffers(&mut all_buffer_infos, buffer_size)?;
|
||||||
let output_buffer_infos = all_buffer_infos.split_off(split_point);
|
let output_buffer_infos = all_buffer_infos.split_off(split_point);
|
||||||
let input_buffer_infos = all_buffer_infos;
|
let input_buffer_infos = all_buffer_infos;
|
||||||
let input = Some(AsioStream {
|
let input = Some(AsioStream {
|
||||||
|
@ -504,7 +529,7 @@ impl Driver {
|
||||||
}
|
}
|
||||||
// Just input
|
// Just input
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
let buffer_size = self.create_buffers(&mut input_buffer_infos)?;
|
let buffer_size = self.create_buffers(&mut input_buffer_infos, buffer_size)?;
|
||||||
let input = Some(AsioStream {
|
let input = Some(AsioStream {
|
||||||
buffer_infos: input_buffer_infos,
|
buffer_infos: input_buffer_infos,
|
||||||
buffer_size,
|
buffer_size,
|
||||||
|
@ -514,7 +539,7 @@ impl Driver {
|
||||||
}
|
}
|
||||||
// Just output
|
// Just output
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
let buffer_size = self.create_buffers(&mut output_buffer_infos)?;
|
let buffer_size = self.create_buffers(&mut output_buffer_infos, buffer_size)?;
|
||||||
let input = None;
|
let input = None;
|
||||||
let output = Some(AsioStream {
|
let output = Some(AsioStream {
|
||||||
buffer_infos: output_buffer_infos,
|
buffer_infos: output_buffer_infos,
|
||||||
|
@ -537,17 +562,21 @@ impl Driver {
|
||||||
///
|
///
|
||||||
/// `num_channels` is the desired number of input channels.
|
/// `num_channels` is the desired number of input channels.
|
||||||
///
|
///
|
||||||
|
/// `buffer_size` sets the desired buffer_size. If None is passed in, then the
|
||||||
|
/// default buffersize for the device is used.
|
||||||
|
///
|
||||||
/// This returns a full AsioStreams with both input and output if output was active.
|
/// This returns a full AsioStreams with both input and output if output was active.
|
||||||
pub fn prepare_input_stream(
|
pub fn prepare_input_stream(
|
||||||
&self,
|
&self,
|
||||||
output: Option<AsioStream>,
|
output: Option<AsioStream>,
|
||||||
num_channels: usize,
|
num_channels: usize,
|
||||||
|
buffer_size: Option<i32>,
|
||||||
) -> Result<AsioStreams, AsioError> {
|
) -> Result<AsioStreams, AsioError> {
|
||||||
let input_buffer_infos = prepare_buffer_infos(true, num_channels);
|
let input_buffer_infos = prepare_buffer_infos(true, num_channels);
|
||||||
let output_buffer_infos = output
|
let output_buffer_infos = output
|
||||||
.map(|output| output.buffer_infos)
|
.map(|output| output.buffer_infos)
|
||||||
.unwrap_or_else(Vec::new);
|
.unwrap_or_else(Vec::new);
|
||||||
self.create_streams(input_buffer_infos, output_buffer_infos)
|
self.create_streams(input_buffer_infos, output_buffer_infos, buffer_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare the output stream.
|
/// Prepare the output stream.
|
||||||
|
@ -559,17 +588,21 @@ impl Driver {
|
||||||
///
|
///
|
||||||
/// `num_channels` is the desired number of output channels.
|
/// `num_channels` is the desired number of output channels.
|
||||||
///
|
///
|
||||||
|
/// `buffer_size` sets the desired buffer_size. If None is passed in, then the
|
||||||
|
/// default buffersize for the device is used.
|
||||||
|
///
|
||||||
/// This returns a full AsioStreams with both input and output if input was active.
|
/// This returns a full AsioStreams with both input and output if input was active.
|
||||||
pub fn prepare_output_stream(
|
pub fn prepare_output_stream(
|
||||||
&self,
|
&self,
|
||||||
input: Option<AsioStream>,
|
input: Option<AsioStream>,
|
||||||
num_channels: usize,
|
num_channels: usize,
|
||||||
|
buffer_size: Option<i32>,
|
||||||
) -> Result<AsioStreams, AsioError> {
|
) -> Result<AsioStreams, AsioError> {
|
||||||
let input_buffer_infos = input
|
let input_buffer_infos = input
|
||||||
.map(|input| input.buffer_infos)
|
.map(|input| input.buffer_infos)
|
||||||
.unwrap_or_else(Vec::new);
|
.unwrap_or_else(Vec::new);
|
||||||
let output_buffer_infos = prepare_buffer_infos(false, num_channels);
|
let output_buffer_infos = prepare_buffer_infos(false, num_channels);
|
||||||
self.create_streams(input_buffer_infos, output_buffer_infos)
|
self.create_streams(input_buffer_infos, output_buffer_infos, buffer_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Releases buffers allocations.
|
/// Releases buffers allocations.
|
||||||
|
|
|
@ -4,7 +4,9 @@ extern crate cpal;
|
||||||
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
|
|
||||||
fn main() -> Result<(), anyhow::Error> {
|
fn main() -> Result<(), anyhow::Error> {
|
||||||
let host = cpal::default_host();
|
//let host = cpal::default_host();
|
||||||
|
let host =
|
||||||
|
cpal::host_from_id(cpal::platform::HostId::Asio).expect("failed to initialise ASIO host");
|
||||||
let device = host
|
let device = host
|
||||||
.default_output_device()
|
.default_output_device()
|
||||||
.expect("failed to find a default output device");
|
.expect("failed to find a default output device");
|
||||||
|
@ -23,6 +25,9 @@ fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Result<(), anyh
|
||||||
where
|
where
|
||||||
T: cpal::Sample,
|
T: cpal::Sample,
|
||||||
{
|
{
|
||||||
|
let mut config: cpal::StreamConfig = config.clone();
|
||||||
|
config.buffer_size = cpal::BufferSize::Fixed(256);
|
||||||
|
|
||||||
let sample_rate = config.sample_rate.0 as f32;
|
let sample_rate = config.sample_rate.0 as f32;
|
||||||
let channels = config.channels as usize;
|
let channels = config.channels as usize;
|
||||||
|
|
||||||
|
@ -36,7 +41,7 @@ where
|
||||||
let err_fn = |err| eprintln!("an error occurred on stream: {}", err);
|
let err_fn = |err| eprintln!("an error occurred on stream: {}", err);
|
||||||
|
|
||||||
let stream = device.build_output_stream(
|
let stream = device.build_output_stream(
|
||||||
config,
|
&config,
|
||||||
move |data: &mut [T], _: &cpal::OutputCallbackInfo| {
|
move |data: &mut [T], _: &cpal::OutputCallbackInfo| {
|
||||||
write_data(data, channels, &mut next_value)
|
write_data(data, channels, &mut next_value)
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,6 +11,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
for host_id in available_hosts {
|
for host_id in available_hosts {
|
||||||
println!("{}", host_id.name());
|
println!("{}", host_id.name());
|
||||||
let host = cpal::host_from_id(host_id)?;
|
let host = cpal::host_from_id(host_id)?;
|
||||||
|
|
||||||
let default_in = host.default_input_device().map(|e| e.name().unwrap());
|
let default_in = host.default_input_device().map(|e| e.name().unwrap());
|
||||||
let default_out = host.default_output_device().map(|e| e.name().unwrap());
|
let default_out = host.default_output_device().map(|e| e.name().unwrap());
|
||||||
println!(" Default Input Device:\n {:?}", default_in);
|
println!(" Default Input Device:\n {:?}", default_in);
|
||||||
|
|
|
@ -16,8 +16,9 @@ use ringbuf::RingBuffer;
|
||||||
const LATENCY_MS: f32 = 150.0;
|
const LATENCY_MS: f32 = 150.0;
|
||||||
|
|
||||||
fn main() -> Result<(), anyhow::Error> {
|
fn main() -> Result<(), anyhow::Error> {
|
||||||
let host = cpal::default_host();
|
//let host = cpal::default_host();
|
||||||
|
let host =
|
||||||
|
cpal::host_from_id(cpal::platform::HostId::Asio).expect("failed to initialise ASIO host");
|
||||||
// Default devices.
|
// Default devices.
|
||||||
let input_device = host
|
let input_device = host
|
||||||
.default_input_device()
|
.default_input_device()
|
||||||
|
@ -30,7 +31,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
// We'll try and use the same configuration between streams to keep it simple.
|
// We'll try and use the same configuration between streams to keep it simple.
|
||||||
let mut config: cpal::StreamConfig = input_device.default_input_config()?.into();
|
let mut config: cpal::StreamConfig = input_device.default_input_config()?.into();
|
||||||
config.buffer_size = cpal::BufferSize::Fixed(1024);
|
//config.buffer_size = cpal::BufferSize::Fixed(1024);
|
||||||
|
|
||||||
// Create a delay in case the input and output devices aren't synced.
|
// Create a delay in case the input and output devices aren't synced.
|
||||||
let latency_frames = (LATENCY_MS / 1_000.0) * config.sample_rate.0 as f32;
|
let latency_frames = (LATENCY_MS / 1_000.0) * config.sample_rate.0 as f32;
|
||||||
|
@ -44,10 +45,10 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
for _ in 0..latency_samples {
|
for _ in 0..latency_samples {
|
||||||
// The ring buffer has twice as much space as necessary to add latency here,
|
// The ring buffer has twice as much space as necessary to add latency here,
|
||||||
// so this should never fail
|
// so this should never fail
|
||||||
producer.push(0.0).unwrap();
|
producer.push(0).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_data_fn = move |data: &[f32], _: &cpal::InputCallbackInfo| {
|
let input_data_fn = move |data: &[i16], _: &cpal::InputCallbackInfo| {
|
||||||
println!("data len = {}", data.len());
|
println!("data len = {}", data.len());
|
||||||
let mut output_fell_behind = false;
|
let mut output_fell_behind = false;
|
||||||
for &sample in data {
|
for &sample in data {
|
||||||
|
@ -60,14 +61,14 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let output_data_fn = move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
|
let output_data_fn = move |data: &mut [i16], _: &cpal::OutputCallbackInfo| {
|
||||||
let mut input_fell_behind = None;
|
let mut input_fell_behind = None;
|
||||||
for sample in data {
|
for sample in data {
|
||||||
*sample = match consumer.pop() {
|
*sample = match consumer.pop() {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
input_fell_behind = Some(err);
|
input_fell_behind = Some(err);
|
||||||
0.0
|
0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,11 @@ extern crate libc;
|
||||||
|
|
||||||
use self::alsa::poll::Descriptors;
|
use self::alsa::poll::Descriptors;
|
||||||
use crate::{
|
use crate::{
|
||||||
BackendSpecificError, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError,
|
BackendSpecificError, BufferSize, BuildStreamError, ChannelCount, Data,
|
||||||
BufferSize, DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError,
|
DefaultStreamConfigError, DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo,
|
||||||
PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedBufferSizeRange,
|
PauseStreamError, PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError,
|
||||||
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
|
SupportedBufferSizeRange, SupportedStreamConfig, SupportedStreamConfigRange,
|
||||||
|
SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
|
@ -12,6 +12,7 @@ use DeviceNameError;
|
||||||
use DevicesError;
|
use DevicesError;
|
||||||
use SampleFormat;
|
use SampleFormat;
|
||||||
use SampleRate;
|
use SampleRate;
|
||||||
|
use SupportedBufferSizeRange;
|
||||||
use SupportedStreamConfig;
|
use SupportedStreamConfig;
|
||||||
use SupportedStreamConfigRange;
|
use SupportedStreamConfigRange;
|
||||||
use SupportedStreamConfigsError;
|
use SupportedStreamConfigsError;
|
||||||
|
@ -77,9 +78,13 @@ impl Device {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for channels in 1..f.channels + 1 {
|
for channels in 1..f.channels + 1 {
|
||||||
f.channels = channels;
|
supported_configs.push(SupportedStreamConfigRange {
|
||||||
f.sample_rate = rate;
|
channels,
|
||||||
supported_configs.push(SupportedStreamConfigRange::from(f.clone()));
|
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())
|
Ok(supported_configs.into_iter())
|
||||||
|
@ -110,9 +115,13 @@ impl Device {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for channels in 1..f.channels + 1 {
|
for channels in 1..f.channels + 1 {
|
||||||
f.channels = channels;
|
supported_configs.push(SupportedStreamConfigRange {
|
||||||
f.sample_rate = rate;
|
channels,
|
||||||
supported_configs.push(SupportedStreamConfigRange::from(f.clone()));
|
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())
|
Ok(supported_configs.into_iter())
|
||||||
|
@ -122,6 +131,12 @@ impl Device {
|
||||||
pub fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
|
pub fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
|
||||||
let channels = self.driver.channels().map_err(default_config_err)?.ins as u16;
|
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 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
|
// Map th ASIO sample type to a CPAL sample type
|
||||||
let data_type = self.driver.input_data_type().map_err(default_config_err)?;
|
let data_type = self.driver.input_data_type().map_err(default_config_err)?;
|
||||||
let sample_format = convert_data_type(&data_type)
|
let sample_format = convert_data_type(&data_type)
|
||||||
|
@ -129,6 +144,7 @@ impl Device {
|
||||||
Ok(SupportedStreamConfig {
|
Ok(SupportedStreamConfig {
|
||||||
channels,
|
channels,
|
||||||
sample_rate,
|
sample_rate,
|
||||||
|
buffer_size,
|
||||||
sample_format,
|
sample_format,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -137,12 +153,19 @@ impl Device {
|
||||||
pub fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
|
pub fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
|
||||||
let channels = self.driver.channels().map_err(default_config_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_config_err)? as _);
|
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 data_type = self.driver.output_data_type().map_err(default_config_err)?;
|
||||||
let sample_format = convert_data_type(&data_type)
|
let sample_format = convert_data_type(&data_type)
|
||||||
.ok_or(DefaultStreamConfigError::StreamTypeNotSupported)?;
|
.ok_or(DefaultStreamConfigError::StreamTypeNotSupported)?;
|
||||||
Ok(SupportedStreamConfig {
|
Ok(SupportedStreamConfig {
|
||||||
channels,
|
channels,
|
||||||
sample_rate,
|
sample_rate,
|
||||||
|
buffer_size,
|
||||||
sample_format,
|
sample_format,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@ use self::num_traits::PrimInt;
|
||||||
use super::parking_lot::Mutex;
|
use super::parking_lot::Mutex;
|
||||||
use super::Device;
|
use super::Device;
|
||||||
use crate::{
|
use crate::{
|
||||||
BackendSpecificError, BuildStreamError, Data, InputCallbackInfo, OutputCallbackInfo,
|
BackendSpecificError, BufferSize, BuildStreamError, Data, InputCallbackInfo,
|
||||||
PauseStreamError, PlayStreamError, Sample, SampleFormat, StreamConfig, StreamError,
|
OutputCallbackInfo, PauseStreamError, PlayStreamError, Sample, SampleFormat, StreamConfig,
|
||||||
SupportedStreamConfig,
|
StreamError,
|
||||||
};
|
};
|
||||||
use std;
|
use std;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
@ -482,6 +482,12 @@ impl Device {
|
||||||
}?;
|
}?;
|
||||||
let num_channels = config.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();
|
||||||
|
|
||||||
|
let buffer_size = match config.buffer_size {
|
||||||
|
BufferSize::Fixed(v) => Some(v as i32),
|
||||||
|
BufferSize::Default => None,
|
||||||
|
};
|
||||||
|
|
||||||
// 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.
|
||||||
match streams.input {
|
match streams.input {
|
||||||
|
@ -489,7 +495,7 @@ impl Device {
|
||||||
None => {
|
None => {
|
||||||
let output = streams.output.take();
|
let output = streams.output.take();
|
||||||
self.driver
|
self.driver
|
||||||
.prepare_input_stream(output, num_channels)
|
.prepare_input_stream(output, num_channels, buffer_size)
|
||||||
.map(|new_streams| {
|
.map(|new_streams| {
|
||||||
let bs = match new_streams.input {
|
let bs = match new_streams.input {
|
||||||
Some(ref inp) => inp.buffer_size as usize,
|
Some(ref inp) => inp.buffer_size as usize,
|
||||||
|
@ -523,6 +529,12 @@ impl Device {
|
||||||
}?;
|
}?;
|
||||||
let num_channels = config.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();
|
||||||
|
|
||||||
|
let buffer_size = match config.buffer_size {
|
||||||
|
BufferSize::Fixed(v) => Some(v as i32),
|
||||||
|
BufferSize::Default => None,
|
||||||
|
};
|
||||||
|
|
||||||
// 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.
|
||||||
match streams.output {
|
match streams.output {
|
||||||
|
@ -530,7 +542,7 @@ impl Device {
|
||||||
None => {
|
None => {
|
||||||
let output = streams.output.take();
|
let output = streams.output.take();
|
||||||
self.driver
|
self.driver
|
||||||
.prepare_output_stream(output, num_channels)
|
.prepare_output_stream(output, num_channels, buffer_size)
|
||||||
.map(|new_streams| {
|
.map(|new_streams| {
|
||||||
let bs = match new_streams.output {
|
let bs = match new_streams.output {
|
||||||
Some(ref out) => out.buffer_size as usize,
|
Some(ref out) => out.buffer_size as usize,
|
||||||
|
@ -645,6 +657,7 @@ fn check_config(
|
||||||
let StreamConfig {
|
let StreamConfig {
|
||||||
channels,
|
channels,
|
||||||
sample_rate,
|
sample_rate,
|
||||||
|
buffer_size,
|
||||||
} = config;
|
} = 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();
|
||||||
|
|
|
@ -5,9 +5,10 @@ use self::core_foundation_sys::string::{CFStringGetCString, CFStringGetCStringPt
|
||||||
use self::coreaudio::audio_unit::render_callback::{self, data};
|
use self::coreaudio::audio_unit::render_callback::{self, data};
|
||||||
use self::coreaudio::audio_unit::{AudioUnit, Element, Scope};
|
use self::coreaudio::audio_unit::{AudioUnit, Element, Scope};
|
||||||
use self::coreaudio::sys::{
|
use self::coreaudio::sys::{
|
||||||
kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyDeviceNameCFString,
|
kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyBufferFrameSize,
|
||||||
kAudioDevicePropertyBufferFrameSize, kAudioDevicePropertyBufferFrameSizeRange,kAudioDevicePropertyNominalSampleRate,
|
kAudioDevicePropertyBufferFrameSizeRange, kAudioDevicePropertyDeviceNameCFString,
|
||||||
kAudioDevicePropertyScopeOutput, kAudioDevicePropertyStreamConfiguration, kAudioDevicePropertyStreamFormat,
|
kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput,
|
||||||
|
kAudioDevicePropertyStreamConfiguration, kAudioDevicePropertyStreamFormat,
|
||||||
kAudioFormatFlagIsFloat, kAudioFormatFlagIsPacked, kAudioFormatLinearPCM,
|
kAudioFormatFlagIsFloat, kAudioFormatFlagIsPacked, kAudioFormatLinearPCM,
|
||||||
kAudioObjectPropertyElementMaster, kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyElementMaster, kAudioObjectPropertyScopeGlobal,
|
||||||
kAudioObjectPropertyScopeInput, kAudioObjectPropertyScopeOutput,
|
kAudioObjectPropertyScopeInput, kAudioObjectPropertyScopeOutput,
|
||||||
|
@ -20,10 +21,11 @@ use self::coreaudio::sys::{
|
||||||
};
|
};
|
||||||
use crate::traits::{DeviceTrait, HostTrait, StreamTrait};
|
use crate::traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
use crate::{
|
use crate::{
|
||||||
BackendSpecificError, BufferSize, BuildStreamError, ChannelCount, Data, DefaultStreamConfigError,
|
BackendSpecificError, BufferSize, BuildStreamError, ChannelCount, Data,
|
||||||
DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError,
|
DefaultStreamConfigError, DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo,
|
||||||
PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedBufferSizeRange,
|
PauseStreamError, PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError,
|
||||||
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
|
SupportedBufferSizeRange, SupportedStreamConfig, SupportedStreamConfigRange,
|
||||||
|
SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
@ -669,14 +671,12 @@ impl Device {
|
||||||
|
|
||||||
// Set the buffersize
|
// Set the buffersize
|
||||||
match config.buffer_size {
|
match config.buffer_size {
|
||||||
BufferSize::Fixed(v) => {
|
BufferSize::Fixed(v) => audio_unit.set_property(
|
||||||
audio_unit.set_property(
|
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
kAudioDevicePropertyBufferFrameSize,
|
||||||
scope,
|
scope,
|
||||||
element,
|
element,
|
||||||
Some(&v),
|
Some(&v),
|
||||||
)?
|
)?,
|
||||||
},
|
|
||||||
BufferSize::Default => (),
|
BufferSize::Default => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,14 +753,12 @@ impl Device {
|
||||||
|
|
||||||
// Set the buffersize
|
// Set the buffersize
|
||||||
match config.buffer_size {
|
match config.buffer_size {
|
||||||
BufferSize::Fixed(v) => {
|
BufferSize::Fixed(v) => audio_unit.set_property(
|
||||||
audio_unit.set_property(
|
|
||||||
kAudioDevicePropertyBufferFrameSize,
|
kAudioDevicePropertyBufferFrameSize,
|
||||||
scope,
|
scope,
|
||||||
element,
|
element,
|
||||||
Some(&v),
|
Some(&v),
|
||||||
)?
|
)?,
|
||||||
},
|
|
||||||
BufferSize::Default => (),
|
BufferSize::Default => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -319,6 +319,7 @@ unsafe fn format_from_waveformatex_ptr(
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let format = SupportedStreamConfig {
|
let format = SupportedStreamConfig {
|
||||||
|
buffer_size: unimplemented!(),
|
||||||
channels: (*waveformatex_ptr).nChannels as _,
|
channels: (*waveformatex_ptr).nChannels as _,
|
||||||
sample_rate: SampleRate((*waveformatex_ptr).nSamplesPerSec),
|
sample_rate: SampleRate((*waveformatex_ptr).nSamplesPerSec),
|
||||||
sample_format,
|
sample_format,
|
||||||
|
@ -526,7 +527,8 @@ impl Device {
|
||||||
let mut supported_formats = Vec::with_capacity(supported_sample_rates.len());
|
let mut supported_formats = Vec::with_capacity(supported_sample_rates.len());
|
||||||
for rate in supported_sample_rates {
|
for rate in supported_sample_rates {
|
||||||
format.sample_rate = SampleRate(rate as _);
|
format.sample_rate = SampleRate(rate as _);
|
||||||
supported_formats.push(SupportedStreamConfigRange::from(format.clone()));
|
unimplemented!();
|
||||||
|
//supported_formats.push(SupportedStreamConfigRange::from(format.clone()));
|
||||||
}
|
}
|
||||||
Ok(supported_formats.into_iter())
|
Ok(supported_formats.into_iter())
|
||||||
}
|
}
|
||||||
|
|
|
@ -531,10 +531,7 @@ impl SupportedStreamConfigRange {
|
||||||
///
|
///
|
||||||
/// **panic!**s if the given `sample_rate` is outside the range specified within this
|
/// **panic!**s if the given `sample_rate` is outside the range specified within this
|
||||||
/// `SupportedStreamConfigRange` instance.
|
/// `SupportedStreamConfigRange` instance.
|
||||||
pub fn with_sample_rate(
|
pub fn with_sample_rate(self, sample_rate: SampleRate) -> SupportedStreamConfig {
|
||||||
self,
|
|
||||||
sample_rate: SampleRate,
|
|
||||||
) -> SupportedStreamConfig {
|
|
||||||
assert!(self.min_sample_rate <= sample_rate && sample_rate <= self.max_sample_rate);
|
assert!(self.min_sample_rate <= sample_rate && sample_rate <= self.max_sample_rate);
|
||||||
SupportedStreamConfig {
|
SupportedStreamConfig {
|
||||||
channels: self.channels,
|
channels: self.channels,
|
||||||
|
|
Loading…
Reference in New Issue