asio: Re-add possibility to create stream individually
This commit is contained in:
parent
bfda575218
commit
972cce0f8c
|
@ -24,6 +24,7 @@ ringbuf = "0.1.6"
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["audiosessiontypes", "audioclient", "coml2api", "combaseapi", "debug", "devpkey", "handleapi", "ksmedia", "mmdeviceapi", "objbase", "std", "synchapi", "winbase", "winuser"] }
|
winapi = { version = "0.3", features = ["audiosessiontypes", "audioclient", "coml2api", "combaseapi", "debug", "devpkey", "handleapi", "ksmedia", "mmdeviceapi", "objbase", "std", "synchapi", "winbase", "winuser"] }
|
||||||
asio-sys = { version = "0.1", path = "asio-sys", optional = true }
|
asio-sys = { version = "0.1", path = "asio-sys", optional = true }
|
||||||
|
parking_lot = "0.9"
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))'.dependencies]
|
||||||
alsa-sys = { version = "0.1", path = "alsa-sys" }
|
alsa-sys = { version = "0.1", path = "alsa-sys" }
|
||||||
|
|
|
@ -3,7 +3,7 @@ pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>;
|
||||||
pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>;
|
pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>;
|
||||||
|
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::sync::{Mutex, Arc};
|
use std::sync::{Arc};
|
||||||
use BackendSpecificError;
|
use BackendSpecificError;
|
||||||
use DefaultFormatError;
|
use DefaultFormatError;
|
||||||
use DeviceNameError;
|
use DeviceNameError;
|
||||||
|
@ -14,6 +14,7 @@ use SampleRate;
|
||||||
use SupportedFormat;
|
use SupportedFormat;
|
||||||
use SupportedFormatsError;
|
use SupportedFormatsError;
|
||||||
use super::sys;
|
use super::sys;
|
||||||
|
use super::parking_lot::Mutex;
|
||||||
|
|
||||||
/// A ASIO Device
|
/// A ASIO Device
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
|
@ -23,7 +24,7 @@ pub struct Device {
|
||||||
// Input and/or Output stream.
|
// Input and/or Output stream.
|
||||||
// An driver can only have one of each.
|
// An driver can only have one of each.
|
||||||
// They need to be created at the same time.
|
// They need to be created at the same time.
|
||||||
pub asio_streams: Arc<Mutex<Option<sys::AsioStreams>>>,
|
pub asio_streams: Arc<Mutex<sys::AsioStreams>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All available devices.
|
/// All available devices.
|
||||||
|
@ -154,7 +155,10 @@ impl Iterator for Devices {
|
||||||
Some(name) => match self.asio.load_driver(&name) {
|
Some(name) => match self.asio.load_driver(&name) {
|
||||||
Ok(driver) => {
|
Ok(driver) => {
|
||||||
let driver = Arc::new(driver);
|
let driver = Arc::new(driver);
|
||||||
let asio_streams = Arc::new(Mutex::new(None));
|
let asio_streams = Arc::new(Mutex::new(sys::AsioStreams {
|
||||||
|
input: None,
|
||||||
|
output: None,
|
||||||
|
}));
|
||||||
return Some(Device { driver, asio_streams });
|
return Some(Device { driver, asio_streams });
|
||||||
}
|
}
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
extern crate asio_sys as sys;
|
extern crate asio_sys as sys;
|
||||||
|
extern crate parking_lot;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
BuildStreamError,
|
BuildStreamError,
|
||||||
|
|
|
@ -78,8 +78,8 @@ impl Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_channels = format.channels.clone();
|
let num_channels = format.channels.clone();
|
||||||
let asio_stream = self.get_or_create_input_stream(format)?;
|
let buffer_size = self.get_or_create_input_stream(format)?;
|
||||||
let cpal_num_samples = asio_stream.buffer_size as usize * 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 * data_type.sample_size();
|
||||||
|
@ -87,6 +87,7 @@ impl Device {
|
||||||
|
|
||||||
let stream_playing = Arc::new(AtomicBool::new(false));
|
let stream_playing = Arc::new(AtomicBool::new(false));
|
||||||
let playing = Arc::clone(&stream_playing);
|
let playing = Arc::clone(&stream_playing);
|
||||||
|
let asio_streams = self.asio_streams.clone();
|
||||||
|
|
||||||
// Set the input callback.
|
// Set the input callback.
|
||||||
// This is most performance critical part of the ASIO bindings.
|
// This is most performance critical part of the ASIO bindings.
|
||||||
|
@ -96,6 +97,13 @@ impl Device {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There is 0% chance of lock contention the host only locks when recreating streams.
|
||||||
|
let stream_lock = asio_streams.lock();
|
||||||
|
let ref asio_stream = match stream_lock.input {
|
||||||
|
Some(ref asio_stream) => asio_stream,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
/// 1. Write from the ASIO buffer to the interleaved CPAL buffer.
|
/// 1. Write from the ASIO buffer to the interleaved CPAL buffer.
|
||||||
/// 2. Deliver the CPAL buffer to the user callback.
|
/// 2. Deliver the CPAL buffer to the user callback.
|
||||||
unsafe fn process_input_callback<A, B, D, F, G>(
|
unsafe fn process_input_callback<A, B, D, F, G>(
|
||||||
|
@ -134,7 +142,7 @@ impl Device {
|
||||||
process_input_callback::<i16, i16, _, _, _>(
|
process_input_callback::<i16, i16, _, _, _>(
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
from_le,
|
from_le,
|
||||||
std::convert::identity::<i16>,
|
std::convert::identity::<i16>,
|
||||||
|
@ -144,7 +152,7 @@ impl Device {
|
||||||
process_input_callback::<i16, i16, _, _, _>(
|
process_input_callback::<i16, i16, _, _, _>(
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
from_be,
|
from_be,
|
||||||
std::convert::identity::<i16>,
|
std::convert::identity::<i16>,
|
||||||
|
@ -158,7 +166,7 @@ impl Device {
|
||||||
process_input_callback::<f32, f32, _, _, _>(
|
process_input_callback::<f32, f32, _, _, _>(
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
std::convert::identity::<f32>,
|
std::convert::identity::<f32>,
|
||||||
std::convert::identity::<f32>,
|
std::convert::identity::<f32>,
|
||||||
|
@ -172,7 +180,7 @@ impl Device {
|
||||||
process_input_callback::<i32, i16, _, _, _>(
|
process_input_callback::<i32, i16, _, _, _>(
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
from_le,
|
from_le,
|
||||||
|s| (s >> 16) as i16,
|
|s| (s >> 16) as i16,
|
||||||
|
@ -182,7 +190,7 @@ impl Device {
|
||||||
process_input_callback::<i32, i16, _, _, _>(
|
process_input_callback::<i32, i16, _, _, _>(
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
from_be,
|
from_be,
|
||||||
|s| (s >> 16) as i16,
|
|s| (s >> 16) as i16,
|
||||||
|
@ -195,7 +203,7 @@ impl Device {
|
||||||
process_input_callback::<f64, f32, _, _, _>(
|
process_input_callback::<f64, f32, _, _, _>(
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
std::convert::identity::<f64>,
|
std::convert::identity::<f64>,
|
||||||
|s| s as f32,
|
|s| s as f32,
|
||||||
|
@ -235,8 +243,8 @@ impl Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_channels = format.channels.clone();
|
let num_channels = format.channels.clone();
|
||||||
let asio_stream = self.get_or_create_output_stream(format)?;
|
let buffer_size = self.get_or_create_output_stream(format)?;
|
||||||
let cpal_num_samples = asio_stream.buffer_size as usize * 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 * data_type.sample_size();
|
||||||
|
@ -245,6 +253,7 @@ impl Device {
|
||||||
|
|
||||||
let stream_playing = Arc::new(AtomicBool::new(false));
|
let stream_playing = Arc::new(AtomicBool::new(false));
|
||||||
let playing = Arc::clone(&stream_playing);
|
let playing = Arc::clone(&stream_playing);
|
||||||
|
let asio_streams = self.asio_streams.clone();
|
||||||
|
|
||||||
self.driver.set_callback(move |buffer_index| unsafe {
|
self.driver.set_callback(move |buffer_index| unsafe {
|
||||||
// If not playing, return early.
|
// If not playing, return early.
|
||||||
|
@ -252,6 +261,13 @@ impl Device {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There is 0% chance of lock contention the host only locks when recreating streams.
|
||||||
|
let stream_lock = asio_streams.lock();
|
||||||
|
let ref asio_stream = match stream_lock.output {
|
||||||
|
Some(ref asio_stream) => asio_stream,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
// Silence the ASIO buffer that is about to be used.
|
// Silence the ASIO buffer that is about to be used.
|
||||||
//
|
//
|
||||||
// This checks if any other callbacks have already silenced the buffer associated with
|
// This checks if any other callbacks have already silenced the buffer associated with
|
||||||
|
@ -325,7 +341,7 @@ impl Device {
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
silence,
|
silence,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
std::convert::identity::<i16>,
|
std::convert::identity::<i16>,
|
||||||
to_le,
|
to_le,
|
||||||
|
@ -336,7 +352,7 @@ impl Device {
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
silence,
|
silence,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
std::convert::identity::<i16>,
|
std::convert::identity::<i16>,
|
||||||
to_be,
|
to_be,
|
||||||
|
@ -351,7 +367,7 @@ impl Device {
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
silence,
|
silence,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
std::convert::identity::<f32>,
|
std::convert::identity::<f32>,
|
||||||
std::convert::identity::<f32>,
|
std::convert::identity::<f32>,
|
||||||
|
@ -366,7 +382,7 @@ impl Device {
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
silence,
|
silence,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
|s| (s as i32) << 16,
|
|s| (s as i32) << 16,
|
||||||
to_le,
|
to_le,
|
||||||
|
@ -377,7 +393,7 @@ impl Device {
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
silence,
|
silence,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
|s| (s as i32) << 16,
|
|s| (s as i32) << 16,
|
||||||
to_be,
|
to_be,
|
||||||
|
@ -391,7 +407,7 @@ impl Device {
|
||||||
&mut data_callback,
|
&mut data_callback,
|
||||||
&mut interleaved,
|
&mut interleaved,
|
||||||
silence,
|
silence,
|
||||||
&asio_stream,
|
asio_stream,
|
||||||
buffer_index as usize,
|
buffer_index as usize,
|
||||||
|s| s as f64,
|
|s| s as f64,
|
||||||
std::convert::identity::<f64>,
|
std::convert::identity::<f64>,
|
||||||
|
@ -419,7 +435,7 @@ impl Device {
|
||||||
fn get_or_create_input_stream(
|
fn get_or_create_input_stream(
|
||||||
&self,
|
&self,
|
||||||
format: &Format,
|
format: &Format,
|
||||||
) -> Result<sys::AsioStream, BuildStreamError> {
|
) -> Result<usize, BuildStreamError> {
|
||||||
match self.default_input_format() {
|
match self.default_input_format() {
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
let num_asio_channels = f.channels;
|
let num_asio_channels = f.channels;
|
||||||
|
@ -428,27 +444,26 @@ impl Device {
|
||||||
Err(_) => Err(BuildStreamError::FormatNotSupported),
|
Err(_) => Err(BuildStreamError::FormatNotSupported),
|
||||||
}?;
|
}?;
|
||||||
let num_channels = format.channels as usize;
|
let num_channels = format.channels as usize;
|
||||||
let ref mut streams = *self.asio_streams.lock().unwrap();
|
let ref mut streams = *self.asio_streams.lock();
|
||||||
match streams {
|
// Either create a stream if thers none or had back the
|
||||||
Some(streams) => match streams.input.take() {
|
// size of the current one.
|
||||||
Some(input) => Ok(input),
|
match streams.input {
|
||||||
|
Some(ref input) => Ok(input.buffer_size as usize),
|
||||||
None => {
|
None => {
|
||||||
println!("ASIO streams have been already created");
|
let output = streams.output.take();
|
||||||
Err(BuildStreamError::DeviceNotAvailable)
|
self.driver
|
||||||
}
|
.prepare_input_stream(output, num_channels)
|
||||||
},
|
.map(|new_streams| {
|
||||||
None => {
|
let bs = match new_streams.input {
|
||||||
match self.driver.prepare_input_stream(None, num_channels) {
|
Some(ref inp) => inp.buffer_size as usize,
|
||||||
Ok(mut new_streams) => {
|
None => unreachable!(),
|
||||||
let input = new_streams.input.take().expect("missing input stream");
|
};
|
||||||
*streams = Some(new_streams);
|
*streams = new_streams;
|
||||||
Ok(input)
|
bs
|
||||||
}
|
}).map_err(|ref e| {
|
||||||
Err(e) => {
|
|
||||||
println!("Error preparing stream: {}", e);
|
println!("Error preparing stream: {}", e);
|
||||||
Err(BuildStreamError::DeviceNotAvailable)
|
BuildStreamError::DeviceNotAvailable
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,7 +474,7 @@ impl Device {
|
||||||
fn get_or_create_output_stream(
|
fn get_or_create_output_stream(
|
||||||
&self,
|
&self,
|
||||||
format: &Format,
|
format: &Format,
|
||||||
) -> Result<sys::AsioStream, BuildStreamError> {
|
) -> Result<usize, BuildStreamError> {
|
||||||
match self.default_output_format() {
|
match self.default_output_format() {
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
let num_asio_channels = f.channels;
|
let num_asio_channels = f.channels;
|
||||||
|
@ -468,27 +483,26 @@ impl Device {
|
||||||
Err(_) => Err(BuildStreamError::FormatNotSupported),
|
Err(_) => Err(BuildStreamError::FormatNotSupported),
|
||||||
}?;
|
}?;
|
||||||
let num_channels = format.channels as usize;
|
let num_channels = format.channels as usize;
|
||||||
let ref mut streams = *self.asio_streams.lock().unwrap();
|
let ref mut streams = *self.asio_streams.lock();
|
||||||
match streams {
|
// Either create a stream if thers none or had back the
|
||||||
Some(streams) => match streams.output.take() {
|
// size of the current one.
|
||||||
Some(output) => Ok(output),
|
match streams.output {
|
||||||
|
Some(ref output) => Ok(output.buffer_size as usize),
|
||||||
None => {
|
None => {
|
||||||
println!("ASIO streams have been already created");
|
let output = streams.output.take();
|
||||||
Err(BuildStreamError::DeviceNotAvailable)
|
self.driver
|
||||||
}
|
.prepare_output_stream(output, num_channels)
|
||||||
},
|
.map(|new_streams| {
|
||||||
None => {
|
let bs = match new_streams.output {
|
||||||
match self.driver.prepare_output_stream(None, num_channels) {
|
Some(ref out) => out.buffer_size as usize,
|
||||||
Ok(mut new_streams) => {
|
None => unreachable!(),
|
||||||
let output = new_streams.output.take().expect("missing output stream");
|
};
|
||||||
*streams = Some(new_streams);
|
*streams = new_streams;
|
||||||
Ok(output)
|
bs
|
||||||
}
|
}).map_err(|ref e| {
|
||||||
Err(e) => {
|
|
||||||
println!("Error preparing stream: {}", e);
|
println!("Error preparing stream: {}", e);
|
||||||
Err(BuildStreamError::DeviceNotAvailable)
|
BuildStreamError::DeviceNotAvailable
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue