Fixed driver bug

This commit is contained in:
Tom Gowan 2018-11-01 12:21:00 +11:00 committed by mitchmindtree
parent 6a71f0a801
commit 5ec6da3aad
5 changed files with 141 additions and 125 deletions

View File

@ -1,9 +1,20 @@
#include "helpers.hpp"
extern "C" void destruct_AsioDrivers(AsioDrivers * a){
a->~AsioDrivers();
}
extern "C" ASIOError get_sample_rate(double * rate){
return ASIOGetSampleRate(reinterpret_cast<ASIOSampleRate *>(rate));
}
extern AsioDrivers* asioDrivers;
bool loadAsioDriver(char *name);
extern "C" bool load_asio_driver(char * name){
return loadAsioDriver(name);
}
extern "C" void remove_current_driver() {
asioDrivers->removeCurrentDriver();
}
extern "C" long get_driver_names(char **names, long maxDrivers) {
AsioDrivers ad;
return ad.getDriverNames(names, maxDrivers);
}

View File

@ -2,9 +2,9 @@
#include "asiodrivers.h"
#include "asio.h"
// Helper function to call destructors from within library
extern "C" void destruct_AsioDrivers(AsioDrivers * a);
// Helper function to wrap confusing preprocessor
extern "C" ASIOError get_sample_rate(double * rate);
extern "C" bool load_asio_driver(char * name);
extern "C" void remove_current_driver();
extern "C" long get_driver_names(char **names, long maxDrivers);

View File

@ -163,7 +163,6 @@ fn create_bindings(cpal_asio_dir: &PathBuf) {
.whitelist_type("ASIOCallbacks")
.whitelist_type("ASIOSampleType")
.whitelist_type("ASIOChannelInfo")
.whitelist_function("destruct_AsioDrivers")
.whitelist_function("ASIOGetChannels")
.whitelist_function("ASIOGetChannelInfo")
.whitelist_function("ASIOGetBufferSize")
@ -174,6 +173,9 @@ fn create_bindings(cpal_asio_dir: &PathBuf) {
.whitelist_function("ASIOStop")
.whitelist_function("ASIODisposeBuffers")
.whitelist_function("ASIOExit")
.whitelist_function("load_asio_driver")
.whitelist_function("remove_current_driver")
.whitelist_function("get_driver_names")
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.

View File

@ -15,17 +15,12 @@ use errors::{AsioError, AsioDriverError, AsioErrorWrapper};
use std::ffi::CStr;
use std::ffi::CString;
use std::mem;
use std::os::raw::c_char;
use std::os::raw::c_double;
use std::os::raw::c_long;
use std::os::raw::c_void;
use std::os::raw::{c_char, c_double, c_long, c_void};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::sync::MutexGuard;
use std::sync::{Mutex, MutexGuard};
use asio_import as ai;
const MAX_DRIVER: usize = 32;
pub struct CbArgs<S, D> {
pub stream_id: S,
@ -39,8 +34,7 @@ lazy_static! {
}
lazy_static! {
static ref ASIO_DRIVERS: Mutex<DriverWrapper> = Mutex::new(DriverWrapper{
drivers: None,
static ref ASIO_DRIVERS: Mutex<AsioWrapper> = Mutex::new(AsioWrapper{
state: AsioState::Offline,
});
}
@ -64,8 +58,7 @@ pub struct SampleRate {
pub struct Drivers;
#[derive(Debug)]
struct DriverWrapper {
drivers: Option<ai::AsioDrivers>,
struct AsioWrapper {
state: AsioState,
}
@ -78,6 +71,7 @@ enum AsioState {
Running,
}
pub struct AsioStreams {
pub input: Option<AsioStream>,
pub output: Option<AsioStream>,
@ -132,7 +126,7 @@ pub enum AsioSampleType {
pub struct AsioBufferInfo {
pub is_input: c_long,
pub channel_num: c_long,
pub buffers: [*mut std::os::raw::c_void; 2],
pub buffers: [*mut c_void; 2],
}
#[repr(C)]
@ -148,7 +142,7 @@ struct AsioCallbacks {
direct_process: c_long,
) -> *mut ai::ASIOTime,
}
extern "C" fn buffer_switch(double_buffer_index: c_long, direct_process: c_long) -> () {
extern "C" fn buffer_switch(double_buffer_index: c_long, _direct_process: c_long) -> () {
let mut bcs = buffer_callback.lock().unwrap();
for mut bc in bcs.iter_mut() {
@ -158,57 +152,52 @@ extern "C" fn buffer_switch(double_buffer_index: c_long, direct_process: c_long)
}
}
extern "C" fn sample_rate_did_change(s_rate: c_double) -> () {}
extern "C" fn sample_rate_did_change(_s_rate: c_double) -> () {}
extern "C" fn asio_message(
selector: c_long, value: c_long, message: *mut (), opt: *mut c_double,
_selector: c_long, _value: c_long, _message: *mut (), _opt: *mut c_double,
) -> c_long {
4 as c_long
}
extern "C" fn buffer_switch_time_info(
params: *mut ai::ASIOTime, double_buffer_index: c_long, direct_process: c_long,
params: *mut ai::ASIOTime, _double_buffer_index: c_long, _direct_process: c_long,
) -> *mut ai::ASIOTime {
params
}
fn get_drivers() -> MutexGuard<'static, DriverWrapper> {
fn get_drivers() -> MutexGuard<'static, AsioWrapper> {
ASIO_DRIVERS.lock().unwrap()
}
impl Drivers {
#[allow(unused_assignments)]
pub fn load(driver_name: &str) -> Result<Self, AsioDriverError> {
let mut drivers = get_drivers();
match drivers.state {
AsioState::Offline => {
// Make owned CString to send to load driver
let mut my_driver_name =
CString::new(driver_name).expect("Can't go from str to CString");
let raw = my_driver_name.into_raw();
let mut driver_info = ai::ASIODriverInfo {
_bindgen_opaque_blob: [0u32; 43],
};
unsafe {
let mut asio_drivers = ai::AsioDrivers::new();
let load_result = asio_drivers.loadDriver(raw);
if load_result { drivers.state = AsioState::Loaded; }
let init_result = drivers.asio_init(&mut driver_info);
// Take back ownership
my_driver_name = CString::from_raw(raw);
if load_result && init_result.is_ok() {
println!("Creating drivers");
drivers.drivers = Some(asio_drivers);
// Make owned CString to send to load driver
let mut my_driver_name =
CString::new(driver_name).expect("Can't go from str to CString");
let raw = my_driver_name.into_raw();
let mut driver_info = ai::ASIODriverInfo {
_bindgen_opaque_blob: [0u32; 43],
};
unsafe {
let load_result = drivers.load(raw);
// Take back ownership
my_driver_name = CString::from_raw(raw);
if load_result {
match drivers.asio_init(&mut driver_info) {
Ok(_) => {
STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
Ok(Drivers)
} else {
},
Err(_) => {
Err(AsioDriverError::DriverLoadError)
}
},
}
},
_ => {
STREAM_DRIVER_COUNT.fetch_add(1, Ordering::SeqCst);
Ok(Drivers)
},
} else {
Err(AsioDriverError::DriverLoadError)
}
}
}
@ -274,8 +263,8 @@ impl Drivers {
}
}
pub fn prepare_input_stream(&self, output: Option<AsioStream>, mut num_channels: usize) -> Result<AsioStreams, AsioDriverError> {
let mut buffer_infos = vec![
pub fn prepare_input_stream(&self, output: Option<AsioStream>, num_channels: usize) -> Result<AsioStreams, AsioDriverError> {
let buffer_infos = vec![
AsioBufferInfo {
is_input: 1,
channel_num: 0,
@ -291,7 +280,7 @@ impl Drivers {
/// Creates the output stream
pub fn prepare_output_stream(&self, input: Option<AsioStream>, num_channels: usize) -> Result<AsioStreams, AsioDriverError> {
// Initialize data for FFI
let mut buffer_infos = vec![
let buffer_infos = vec![
AsioBufferInfo {
is_input: 0,
channel_num: 0,
@ -363,7 +352,7 @@ impl Drivers {
fn create_buffers(&self, buffer_infos: Vec<AsioBufferInfo>)
-> Result<(Vec<AsioBufferInfo>, c_long), AsioDriverError>{
let num_channels = buffer_infos.len();
let mut callbacks = AsioCallbacks {
let callbacks = AsioCallbacks {
buffer_switch: buffer_switch,
sample_rate_did_change: sample_rate_did_change,
asio_message: asio_message,
@ -402,7 +391,7 @@ impl Drivers {
pref_b_size,
&mut callbacks_convert,
).map(|_|{
let mut buffer_infos: Vec<AsioBufferInfo> = buffer_info_convert
let buffer_infos: Vec<AsioBufferInfo> = buffer_info_convert
.into_iter()
.map(|bi| mem::transmute::<ai::ASIOBufferInfo, AsioBufferInfo>(bi))
.collect();
@ -427,27 +416,25 @@ impl Drivers {
impl Drop for Drivers {
fn drop(&mut self) {
println!("dropping drivers");
let count = STREAM_DRIVER_COUNT.fetch_sub(1, Ordering::SeqCst);
if count == 1 {
println!("Destroying driver");
clean_up();
}
}
}
unsafe impl Send for DriverWrapper {}
unsafe impl Send for AsioWrapper {}
impl BufferCallback {
fn run(&mut self, index: i32) {
let mut cb = &mut self.0;
let cb = &mut self.0;
cb(index);
}
}
unsafe impl Send for AsioStream {}
pub fn set_callback<F: 'static>(mut callback: F) -> ()
pub fn set_callback<F: 'static>(callback: F) -> ()
where
F: FnMut(i32) + Send,
{
@ -456,82 +443,36 @@ where
}
/// Returns a list of all the ASIO drivers
//TODO this needs to not create and remove drivers
#[allow(unused_assignments)]
pub fn get_driver_list() -> Vec<String> {
let mut driver_list: Vec<String> = Vec::new();
const MAX_DRIVERS: usize = 100;
const CHAR_LEN: usize = 32;
let mut driver_names: [[c_char; MAX_DRIVER]; MAX_DRIVER] = [[0; MAX_DRIVER]; MAX_DRIVER];
let mut p_driver_name: [*mut i8; MAX_DRIVER] = [0 as *mut i8; MAX_DRIVER];
let mut driver_names: [[c_char; CHAR_LEN]; MAX_DRIVERS] = [[0; CHAR_LEN]; MAX_DRIVERS];
let mut p_driver_name: [*mut i8; MAX_DRIVERS] = [0 as *mut i8; MAX_DRIVERS];
for i in 0 .. MAX_DRIVER {
for i in 0 .. MAX_DRIVERS {
p_driver_name[i] = driver_names[i].as_mut_ptr();
}
unsafe {
let mut asio_drivers = ai::AsioDrivers::new();
let num_drivers = ai::get_driver_names(p_driver_name.as_mut_ptr(), MAX_DRIVERS as i32);
let num_drivers =
asio_drivers.getDriverNames(p_driver_name.as_mut_ptr(), MAX_DRIVER as i32);
if num_drivers > 0 {
for i in 0 .. num_drivers {
(0..num_drivers)
.map(|i|{
let mut my_driver_name = CString::new("").unwrap();
let name = CStr::from_ptr(p_driver_name[i as usize]);
my_driver_name = name.to_owned();
match my_driver_name.into_string() {
Ok(s) => driver_list.push(s),
Err(_) => println!("Failed converting from CString"),
}
}
} else {
println!("No ASIO drivers found");
}
ai::destruct_AsioDrivers(&mut asio_drivers);
my_driver_name.into_string().expect("Failed to convert driver name")
})
.collect()
}
driver_list
}
pub fn clean_up() {
let mut drivers = get_drivers();
match drivers.state {
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;
},
}
drivers.clean_up();
}
pub fn play() {
@ -548,12 +489,32 @@ pub fn stop() {
}
}
impl DriverWrapper {
impl AsioWrapper {
unsafe fn load(&mut self, raw: *mut i8) -> bool {
use AsioState::*;
self.clean_up();
if ai::load_asio_driver(raw) {
self.state = Loaded;
true
} else {
false
}
}
unsafe fn unload(&mut self) {
ai::remove_current_driver();
}
unsafe fn asio_init(&mut self, di: &mut ai::ASIODriverInfo) -> Result<(), AsioError> {
if let AsioState::Loaded = self.state {
let result = ai::ASIOInit(di);
asio_result!(result)
.map(|_| self.state = AsioState::Initialized)
.map_err(|e| {
self.state = AsioState::Offline;
e
})
}else{
Ok(())
}
@ -612,7 +573,7 @@ unsafe fn asio_create_buffers(
match self.state {
Offline | Loaded => return Err(AsioError::NoDrivers),
Running => {
self.asio_stop();
self.asio_stop().expect("Asio failed to stop");
self.asio_dispose_buffers().expect("Failed to dispose buffers");
self.state = Initialized;
},
@ -652,7 +613,7 @@ unsafe fn asio_exit(&mut self) -> Result<(), AsioError> {
}
let result = ai::ASIOExit();
asio_result!(result)
.map(|_| self.state = AsioState::Loaded)
.map(|_| self.state = AsioState::Offline)
}
unsafe fn asio_start(&mut self) -> Result<(), AsioError> {
@ -678,4 +639,41 @@ unsafe fn asio_stop(&mut self) -> Result<(), AsioError> {
asio_result!(result)
.map(|_| self.state = AsioState::Prepared)
}
fn clean_up(&mut self) {
match self.state {
AsioState::Offline => (),
AsioState::Loaded => {
unsafe {
self.asio_exit().expect("Failed to exit asio");
self.unload();
}
self.state = AsioState::Offline;
},
AsioState::Initialized => {
unsafe {
self.asio_exit().expect("Failed to exit asio");
self.unload();
}
self.state = AsioState::Offline;
},
AsioState::Prepared => {
unsafe {
self.asio_dispose_buffers().expect("Failed to dispose buffers");
self.asio_exit().expect("Failed to exit asio");
self.unload();
}
self.state = AsioState::Offline;
},
AsioState::Running => {
unsafe {
self.asio_stop().expect("Asio failed to stop");
self.asio_dispose_buffers().expect("Failed to dispose buffers");
self.asio_exit().expect("Failed to exit asio");
self.unload();
}
self.state = AsioState::Offline;
},
}
}
}

View File

@ -96,7 +96,12 @@ impl Device {
impl Default for Devices {
fn default() -> Devices {
Devices{ drivers: sys::get_driver_list().into_iter() }
// Remove offline drivers
let driver_names: Vec<String> = sys::get_driver_list()
.into_iter()
.filter(|name| sys::Drivers::load(&name).is_ok())
.collect();
Devices{ drivers: driver_names.into_iter() }
}
}