This commit is contained in:
Tom Gowan 2018-10-30 14:27:50 +11:00 committed by mitchmindtree
parent 93f75940d6
commit ff7fd62a2d
2 changed files with 210 additions and 94 deletions

View File

@ -21,6 +21,7 @@ use std::os::raw::c_long;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::sync::MutexGuard;
use asio_import as ai; use asio_import as ai;
@ -38,7 +39,10 @@ lazy_static! {
} }
lazy_static! { lazy_static! {
static ref ASIO_DRIVERS: Mutex<Option<DriverWrapper>> = Mutex::new(None); static ref ASIO_DRIVERS: Mutex<DriverWrapper> = Mutex::new(DriverWrapper{
drivers: None,
state: AsioState::Offline,
});
} }
static STREAM_DRIVER_COUNT: AtomicUsize = AtomicUsize::new(0); static STREAM_DRIVER_COUNT: AtomicUsize = AtomicUsize::new(0);
@ -59,7 +63,17 @@ pub struct Drivers;
#[derive(Debug)] #[derive(Debug)]
struct DriverWrapper { struct DriverWrapper {
pub drivers: ai::AsioDrivers, drivers: Option<ai::AsioDrivers>,
state: AsioState,
}
#[derive(Debug)]
enum AsioState {
Offline,
Loaded,
Initialized,
Prepared,
Running,
} }
pub struct AsioStreams { pub struct AsioStreams {
@ -156,15 +170,15 @@ extern "C" fn buffer_switch_time_info(
params params
} }
fn get_drivers() -> MutexGuard<'static, DriverWrapper> {
ASIO_DRIVERS.lock().unwrap()
}
impl Drivers { impl Drivers {
pub fn load(driver_name: &str) -> Result<Self, AsioDriverError> { pub fn load(driver_name: &str) -> Result<Self, AsioDriverError> {
let mut drivers = ASIO_DRIVERS.lock().unwrap(); let mut drivers = get_drivers();
match *drivers { match drivers.state {
Some(_) => { AsioState::Offline => {
STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
Ok(Drivers {})
},
None => {
// Make owned CString to send to load driver // Make owned CString to send to load driver
let mut my_driver_name = let mut my_driver_name =
CString::new(driver_name).expect("Can't go from str to CString"); CString::new(driver_name).expect("Can't go from str to CString");
@ -175,21 +189,24 @@ impl Drivers {
unsafe { unsafe {
let mut asio_drivers = ai::AsioDrivers::new(); let mut asio_drivers = ai::AsioDrivers::new();
let load_result = asio_drivers.loadDriver(raw); let load_result = asio_drivers.loadDriver(raw);
let init_result = asio_init(&mut driver_info); if load_result { drivers.state = AsioState::Loaded; }
let init_result = drivers.asio_init(&mut driver_info);
// Take back ownership // Take back ownership
my_driver_name = CString::from_raw(raw); my_driver_name = CString::from_raw(raw);
if load_result && init_result.is_ok() { if load_result && init_result.is_ok() {
println!("Creating drivers"); println!("Creating drivers");
*drivers = Some(DriverWrapper { drivers.drivers = Some(asio_drivers);
drivers: asio_drivers,
});
STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst); STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
Ok(Drivers {}) Ok(Drivers)
} else { } else {
Err(AsioDriverError::DriverLoadError) Err(AsioDriverError::DriverLoadError)
} }
} }
}, },
_ => {
STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
Ok(Drivers)
},
} }
} }
@ -207,7 +224,7 @@ impl Drivers {
let mut ins: c_long = 0; let mut ins: c_long = 0;
let mut outs: c_long = 0; let mut outs: c_long = 0;
unsafe { unsafe {
asio_get_channels(&mut ins, &mut outs).expect("failed to get channels"); get_drivers().asio_get_channels(&mut ins, &mut outs).expect("failed to get channels");
channel = Channel { channel = Channel {
ins: ins as i64, ins: ins as i64,
outs: outs as i64, outs: outs as i64,
@ -224,7 +241,7 @@ impl Drivers {
let mut rate: c_double = 0.0f64; let mut rate: c_double = 0.0f64;
unsafe { unsafe {
asio_get_sample_rate(&mut rate).expect("failed to get sample rate"); get_drivers().asio_get_sample_rate(&mut rate).expect("failed to get sample rate");
sample_rate = SampleRate { rate: rate as u32 }; sample_rate = SampleRate { rate: rate as u32 };
} }
@ -242,7 +259,7 @@ impl Drivers {
name: [0 as c_char; 32], name: [0 as c_char; 32],
}; };
unsafe { unsafe {
match asio_get_channel_info(&mut channel_info) { match get_drivers().asio_get_channel_info(&mut channel_info) {
Ok(_) => { Ok(_) => {
num::FromPrimitive::from_i32(channel_info.type_) num::FromPrimitive::from_i32(channel_info.type_)
.map_or(Err(AsioDriverError::TypeError), |t| Ok(t)) .map_or(Err(AsioDriverError::TypeError), |t| Ok(t))
@ -312,22 +329,28 @@ impl Drivers {
}, },
(Some(input), None) => { (Some(input), None) => {
self.create_buffers(input.buffer_infos) self.create_buffers(input.buffer_infos)
.map(|(buffer_infos, buffer_size)| AsioStreams{ .map(|(buffer_infos, buffer_size)| {
input: Some(AsioStream{ STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
buffer_infos, AsioStreams{
buffer_size, input: Some(AsioStream{
}), buffer_infos,
output: None, buffer_size,
}),
output: None,
}
}) })
}, },
(None, Some(output)) => { (None, Some(output)) => {
self.create_buffers(output.buffer_infos) self.create_buffers(output.buffer_infos)
.map(|(buffer_infos, buffer_size)| AsioStreams{ .map(|(buffer_infos, buffer_size)| {
output: Some(AsioStream{ STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
buffer_infos, AsioStreams{
buffer_size, output: Some(AsioStream{
}), buffer_infos,
input: None, buffer_size,
}),
input: None,
}
}) })
}, },
(None, None) => panic!("Trying to create streams without preparing"), (None, None) => panic!("Trying to create streams without preparing"),
@ -350,7 +373,7 @@ impl Drivers {
let mut pref_b_size: c_long = 0; let mut pref_b_size: c_long = 0;
let mut grans: c_long = 0; let mut grans: c_long = 0;
//let mut result = Err(AsioDriverError::NoResult("not implimented".to_owned())); let mut drivers = get_drivers();
unsafe { unsafe {
// Get the buffer sizes // Get the buffer sizes
@ -358,7 +381,7 @@ impl Drivers {
// max possible size // max possible size
// preferred size // preferred size
// granularity // granularity
asio_get_buffer_size( drivers.asio_get_buffer_size(
&mut min_b_size, &mut min_b_size,
&mut max_b_size, &mut max_b_size,
&mut pref_b_size, &mut pref_b_size,
@ -371,7 +394,7 @@ impl Drivers {
.collect(); .collect();
let mut callbacks_convert = let mut callbacks_convert =
mem::transmute::<AsioCallbacks, ai::ASIOCallbacks>(callbacks); mem::transmute::<AsioCallbacks, ai::ASIOCallbacks>(callbacks);
asio_create_buffers( drivers.asio_create_buffers(
buffer_info_convert.as_mut_ptr(), buffer_info_convert.as_mut_ptr(),
num_channels as i32, num_channels as i32,
pref_b_size, pref_b_size,
@ -386,7 +409,6 @@ impl Drivers {
} }
println!("channels: {:?}", num_channels); println!("channels: {:?}", num_channels);
STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
(buffer_infos, pref_b_size) (buffer_infos, pref_b_size)
}).map_err(|e|{ }).map_err(|e|{
AsioDriverError::BufferError(format!( AsioDriverError::BufferError(format!(
@ -407,30 +429,10 @@ impl Drop for Drivers {
let count = STREAM_DRIVER_COUNT.fetch_sub(1, Ordering::SeqCst); let count = STREAM_DRIVER_COUNT.fetch_sub(1, Ordering::SeqCst);
if count == 1 { if count == 1 {
println!("Destroying driver"); println!("Destroying driver");
unsafe { clean_up();
if let Some(mut asio_drivers) = (*ASIO_DRIVERS.lock().unwrap()).take() {
ai::destruct_AsioDrivers(&mut asio_drivers.drivers);
}
}
} }
} }
} }
/* TODO this should be tied to cpal streams and not AsioStreams
impl Drop for AsioStream {
fn drop(&mut self) {
println!("dropping stream");
let count = STREAM_DRIVER_COUNT.fetch_sub(1, Ordering::SeqCst);
if count == 1 {
println!("Destroying driver");
unsafe {
if let Some(mut asio_drivers) = (*ASIO_DRIVERS.lock().unwrap()).take() {
ai::destruct_AsioDrivers(&mut asio_drivers.drivers);
}
}
}
}
}
*/
unsafe impl Send for DriverWrapper {} unsafe impl Send for DriverWrapper {}
@ -489,63 +491,135 @@ pub fn get_driver_list() -> Vec<String> {
driver_list driver_list
} }
pub fn destroy_stream(stream: AsioStream) { pub fn clean_up() {
unsafe { let mut drivers = get_drivers();
asio_dispose_buffers().expect("Failed to dispose buffers"); match drivers.state {
asio_exit().expect("Failed to exit asio"); AsioState::Offline => (),
AsioState::Loaded => {
unsafe {
let mut old_drivers = drivers.drivers.take().unwrap();
ai::destruct_AsioDrivers(&mut old_drivers);
}
drivers.state = AsioState::Offline;
},
AsioState::Initialized => {
unsafe {
drivers.asio_exit().expect("Failed to exit asio");
let mut old_drivers = drivers.drivers.take().unwrap();
ai::destruct_AsioDrivers(&mut old_drivers);
}
drivers.state = AsioState::Offline;
},
AsioState::Prepared => {
unsafe {
drivers.asio_dispose_buffers().expect("Failed to dispose buffers");
drivers.asio_exit().expect("Failed to exit asio");
let mut old_drivers = drivers.drivers.take().unwrap();
ai::destruct_AsioDrivers(&mut old_drivers);
}
drivers.state = AsioState::Offline;
},
AsioState::Running => {
unsafe {
drivers.asio_stop();
drivers.asio_dispose_buffers().expect("Failed to dispose buffers");
drivers.asio_exit().expect("Failed to exit asio");
let mut old_drivers = drivers.drivers.take().unwrap();
ai::destruct_AsioDrivers(&mut old_drivers);
}
drivers.state = AsioState::Offline;
},
} }
} }
pub fn play() { pub fn play() {
unsafe { unsafe {
let result = asio_start(); let result = get_drivers().asio_start();
println!("start result: {:?}", result); println!("start result: {:?}", result);
} }
} }
pub fn stop() { pub fn stop() {
unsafe { unsafe {
let result = asio_stop(); let result = get_drivers().asio_stop();
println!("stop result: {:?}", result); println!("stop result: {:?}", result);
} }
} }
unsafe fn asio_init(di: &mut ai::ASIODriverInfo) -> Result<(), AsioError> { impl DriverWrapper {
let result = ai::ASIOInit(di); unsafe fn asio_init(&mut self, di: &mut ai::ASIODriverInfo) -> Result<(), AsioError> {
asio_result!(result) if let AsioState::Loaded = self.state {
let result = ai::ASIOInit(di);
asio_result!(result)
.map(|_| self.state = AsioState::Initialized)
}else{
Ok(())
}
} }
unsafe fn asio_get_channels(ins: &mut c_long, outs: &mut c_long) -> Result<(), AsioError> { unsafe fn asio_get_channels(&mut self, ins: &mut c_long, outs: &mut c_long) -> Result<(), AsioError> {
let result = ai::ASIOGetChannels(ins, outs); if let AsioState::Offline = self.state {
asio_result!(result) Err(AsioError::NoDrivers)
} else {
let result = ai::ASIOGetChannels(ins, outs);
asio_result!(result)
}
} }
unsafe fn asio_get_sample_rate(rate: &mut c_double) -> Result<(), AsioError> { unsafe fn asio_get_sample_rate(&mut self, rate: &mut c_double) -> Result<(), AsioError> {
let result = ai::get_sample_rate(rate); if let AsioState::Offline = self.state {
asio_result!(result) Err(AsioError::NoDrivers)
} else {
let result = ai::get_sample_rate(rate);
asio_result!(result)
}
} }
unsafe fn asio_get_channel_info(ci: &mut ai::ASIOChannelInfo) -> Result<(), AsioError> { unsafe fn asio_get_channel_info(&mut self, ci: &mut ai::ASIOChannelInfo) -> Result<(), AsioError> {
let result = ai::ASIOGetChannelInfo(ci); if let AsioState::Offline = self.state {
asio_result!(result) Err(AsioError::NoDrivers)
} else {
let result = ai::ASIOGetChannelInfo(ci);
asio_result!(result)
}
} }
unsafe fn asio_get_buffer_size( unsafe fn asio_get_buffer_size(
&mut self,
min_b_size: &mut c_long, max_b_size: &mut c_long, pref_b_size: &mut c_long, grans: &mut c_long, min_b_size: &mut c_long, max_b_size: &mut c_long, pref_b_size: &mut c_long, grans: &mut c_long,
) -> Result<(), AsioError> { ) -> Result<(), AsioError> {
let result = ai::ASIOGetBufferSize( if let AsioState::Offline = self.state {
min_b_size, Err(AsioError::NoDrivers)
max_b_size, } else {
pref_b_size, let result = ai::ASIOGetBufferSize(
grans, min_b_size,
); max_b_size,
asio_result!(result) pref_b_size,
grans,
);
asio_result!(result)
}
} }
unsafe fn asio_create_buffers( unsafe fn asio_create_buffers(
&mut self,
buffer_info_convert: *mut ai::ASIOBufferInfo, num_channels: i32, pref_b_size: c_long, buffer_info_convert: *mut ai::ASIOBufferInfo, num_channels: i32, pref_b_size: c_long,
callbacks_convert: &mut ai::ASIOCallbacks, callbacks_convert: &mut ai::ASIOCallbacks,
) -> Result<(), AsioError> { ) -> Result<(), AsioError> {
use AsioState::*;
match self.state {
Offline | Loaded => return Err(AsioError::NoDrivers),
Running => {
self.asio_stop();
self.asio_dispose_buffers().expect("Failed to dispose buffers");
self.state = Initialized;
},
Prepared => {
self.asio_dispose_buffers().expect("Failed to dispose buffers");
self.state = Initialized;
},
_ => (),
}
let result = ai::ASIOCreateBuffers( let result = ai::ASIOCreateBuffers(
buffer_info_convert, buffer_info_convert,
num_channels, num_channels,
@ -553,24 +627,53 @@ unsafe fn asio_create_buffers(
callbacks_convert, callbacks_convert,
); );
asio_result!(result) asio_result!(result)
.map(|_| self.state = AsioState::Prepared)
} }
unsafe fn asio_dispose_buffers() -> Result<(), AsioError> { unsafe fn asio_dispose_buffers(&mut self) -> Result<(), AsioError> {
use AsioState::*;
match self.state {
Offline | Loaded => return Err(AsioError::NoDrivers),
Running | Prepared => (),
Initialized => return Ok(()),
}
let result = ai::ASIODisposeBuffers(); let result = ai::ASIODisposeBuffers();
asio_result!(result) asio_result!(result)
.map(|_| self.state = AsioState::Initialized)
} }
unsafe fn asio_exit() -> Result<(), AsioError> { unsafe fn asio_exit(&mut self) -> Result<(), AsioError> {
use AsioState::*;
match self.state {
Offline | Loaded => return Err(AsioError::NoDrivers),
_ => (),
}
let result = ai::ASIOExit(); let result = ai::ASIOExit();
asio_result!(result) asio_result!(result)
.map(|_| self.state = AsioState::Loaded)
} }
unsafe fn asio_start() -> Result<(), AsioError> { unsafe fn asio_start(&mut self) -> Result<(), AsioError> {
use AsioState::*;
match self.state {
Offline | Loaded | Initialized => return Err(AsioError::NoDrivers),
Running => return Ok(()),
Prepared => (),
}
let result = ai::ASIOStart(); let result = ai::ASIOStart();
asio_result!(result) asio_result!(result)
.map(|_| self.state = AsioState::Running)
} }
unsafe fn asio_stop() -> Result<(), AsioError> { unsafe fn asio_stop(&mut self) -> Result<(), AsioError> {
use AsioState::*;
match self.state {
Offline | Loaded => return Err(AsioError::NoDrivers),
Running => (),
Initialized | Prepared => return Ok(()),
}
let result = ai::ASIOStop(); let result = ai::ASIOStop();
asio_result!(result) asio_result!(result)
.map(|_| self.state = AsioState::Prepared)
}
} }

View File

@ -17,6 +17,7 @@ use SampleFormat;
pub struct EventLoop { pub struct EventLoop {
asio_streams: Arc<Mutex<sys::AsioStreams>>, asio_streams: Arc<Mutex<sys::AsioStreams>>,
cpal_streams: Arc<Mutex<Vec<Option<Stream>>>>,
stream_count: AtomicUsize, stream_count: AtomicUsize,
callbacks: Arc<Mutex<Vec<&'static mut (FnMut(StreamId, StreamData) + Send)>>>, callbacks: Arc<Mutex<Vec<&'static mut (FnMut(StreamId, StreamData) + Send)>>>,
} }
@ -31,6 +32,11 @@ pub struct OutputBuffer<'a, T: 'a> {
buffer: &'a mut [T], buffer: &'a mut [T],
} }
enum Stream{
Input,
Output,
}
#[derive(Default)] #[derive(Default)]
struct I16Buffer{ struct I16Buffer{
cpal: Vec<i16>, cpal: Vec<i16>,
@ -56,6 +62,7 @@ impl EventLoop {
pub fn new() -> EventLoop { pub fn new() -> EventLoop {
EventLoop { EventLoop {
asio_streams: Arc::new(Mutex::new(sys::AsioStreams{input: None, output: None})), asio_streams: Arc::new(Mutex::new(sys::AsioStreams{input: None, output: None})),
cpal_streams: Arc::new(Mutex::new(Vec::new())),
stream_count: AtomicUsize::new(0), stream_count: AtomicUsize::new(0),
callbacks: Arc::new(Mutex::new(Vec::new())), callbacks: Arc::new(Mutex::new(Vec::new())),
} }
@ -259,6 +266,7 @@ impl EventLoop {
} }
} }
}); });
self.cpal_streams.lock().unwrap().push(Some(Stream::Input));
StreamId(count) StreamId(count)
}) })
} }
@ -414,10 +422,12 @@ pub fn build_output_stream(
} }
} }
}); });
self.cpal_streams.lock().unwrap().push(Some(Stream::Output));
StreamId(count) StreamId(count)
}) })
} }
pub fn play_stream(&self, stream: StreamId) { pub fn play_stream(&self, stream: StreamId) {
sys::play(); sys::play();
} }
@ -426,20 +436,17 @@ pub fn pause_stream(&self, stream: StreamId) {
sys::stop(); sys::stop();
} }
// TODO the logic for this is wrong
// We are not destroying AsioStreams but CPAL streams
// Asio Streams should only be destroyed if there are no
// CPAL streams left
pub fn destroy_stream(&self, stream_id: StreamId) { pub fn destroy_stream(&self, stream_id: StreamId) {
/* let mut streams = self.cpal_streams.lock().unwrap();
let mut asio_streams_lock = self.asio_streams.lock().unwrap(); streams.get_mut(stream_id.0 - 1).take();
let old_stream = mem::replace(asio_streams_lock.get_mut(stream_id.0 - 1).expect("stream count out of bounds"), None); let count = self.stream_count.load(Ordering::SeqCst);
if let Some(old_stream) = old_stream { self.stream_count.store(count - 1, Ordering::SeqCst);
sys::destroy_stream(old_stream); if count == 1 {
*self.asio_streams.lock().unwrap() = sys::AsioStreams{ output: None, input: None };
sys::clean_up();
} }
*/
unimplemented!()
} }
pub fn run<F>(&self, mut callback: F) -> ! pub fn run<F>(&self, mut callback: F) -> !
where where
F: FnMut(StreamId, StreamData) + Send, F: FnMut(StreamId, StreamData) + Send,
@ -456,6 +463,12 @@ F: FnMut(StreamId, StreamData) + Send,
} }
} }
impl Drop for EventLoop {
fn drop(&mut self) {
sys::clean_up();
}
}
impl<'a, T> InputBuffer<'a, T> { impl<'a, T> InputBuffer<'a, T> {
pub fn buffer(&self) -> &[T] { pub fn buffer(&self) -> &[T] {
&self.buffer &self.buffer