fix: asio-sys build failure, Segmentation fault (#775)

This commit is contained in:
mizuki0629
2023-04-14 17:12:55 +09:00
committed by GitHub
parent 848abf256f
commit 7d40371785
3 changed files with 107 additions and 75 deletions

View File

@@ -10,7 +10,7 @@ keywords = ["audio", "sound", "asio", "steinberg"]
build = "build.rs"
[target.'cfg(any(target_os = "windows"))'.build-dependencies]
bindgen = "0.56.0"
bindgen = "0.64"
walkdir = "2"
cc = "1.0.25"

View File

@@ -164,50 +164,35 @@ fn create_bindings(cpal_asio_dir: &PathBuf) {
.clang_arg(format!("-I{}/{}", cpal_asio_dir.display(), "host"))
.clang_arg(format!("-I{}/{}", cpal_asio_dir.display(), "common"))
// Need to whitelist to avoid binding tp c++ std::*
.whitelist_type("AsioDrivers")
.whitelist_type("AsioDriver")
.whitelist_type("ASIOTime")
.whitelist_type("ASIOTimeInfo")
.whitelist_type("ASIODriverInfo")
.whitelist_type("ASIOBufferInfo")
.whitelist_type("ASIOCallbacks")
.whitelist_type("ASIOSamples")
.whitelist_type("ASIOSampleType")
.whitelist_type("ASIOSampleRate")
.whitelist_type("ASIOChannelInfo")
.whitelist_type("AsioTimeInfoFlags")
.whitelist_type("ASIOTimeCodeFlags")
.whitelist_var("kAsioSelectorSupported")
.whitelist_var("kAsioEngineVersion")
.whitelist_var("kAsioResetRequest")
.whitelist_var("kAsioBufferSizeChange")
.whitelist_var("kAsioResyncRequest")
.whitelist_var("kAsioLatenciesChanged")
.whitelist_var("kAsioSupportsTimeInfo")
.whitelist_var("kAsioSupportsTimeCode")
.whitelist_var("kAsioMMCCommand")
.whitelist_var("kAsioSupportsInputMonitor")
.whitelist_var("kAsioSupportsInputGain")
.whitelist_var("kAsioSupportsInputMeter")
.whitelist_var("kAsioSupportsOutputGain")
.whitelist_var("kAsioSupportsOutputMeter")
.whitelist_var("kAsioOverload")
.whitelist_function("ASIOGetChannels")
.whitelist_function("ASIOGetChannelInfo")
.whitelist_function("ASIOGetBufferSize")
.whitelist_function("ASIOGetSamplePosition")
.whitelist_function("get_sample_rate")
.whitelist_function("set_sample_rate")
.whitelist_function("can_sample_rate")
.whitelist_function("ASIOInit")
.whitelist_function("ASIOCreateBuffers")
.whitelist_function("ASIOStart")
.whitelist_function("ASIOStop")
.whitelist_function("ASIODisposeBuffers")
.whitelist_function("ASIOExit")
.whitelist_function("load_asio_driver")
.whitelist_function("remove_current_driver")
.whitelist_function("get_driver_names")
.allowlist_type("AsioDrivers")
.allowlist_type("AsioDriver")
.allowlist_type("ASIOTime")
.allowlist_type("ASIOTimeInfo")
.allowlist_type("ASIODriverInfo")
.allowlist_type("ASIOBufferInfo")
.allowlist_type("ASIOCallbacks")
.allowlist_type("ASIOSamples")
.allowlist_type("ASIOSampleType")
.allowlist_type("ASIOSampleRate")
.allowlist_type("ASIOChannelInfo")
.allowlist_type("AsioTimeInfoFlags")
.allowlist_type("ASIOTimeCodeFlags")
.allowlist_function("ASIOGetChannels")
.allowlist_function("ASIOGetChannelInfo")
.allowlist_function("ASIOGetBufferSize")
.allowlist_function("ASIOGetSamplePosition")
.allowlist_function("get_sample_rate")
.allowlist_function("set_sample_rate")
.allowlist_function("can_sample_rate")
.allowlist_function("ASIOInit")
.allowlist_function("ASIOCreateBuffers")
.allowlist_function("ASIOStart")
.allowlist_function("ASIOStop")
.allowlist_function("ASIODisposeBuffers")
.allowlist_function("ASIOExit")
.allowlist_function("load_asio_driver")
.allowlist_function("remove_current_driver")
.allowlist_function("get_driver_names")
.bitfield_enum("AsioTimeInfoFlags")
.bitfield_enum("ASIOTimeCodeFlags")
// Finish the builder and generate the bindings.

View File

@@ -186,6 +186,62 @@ struct AsioCallbacks {
) -> *mut ai::ASIOTime,
}
static ASIO_CALLBACKS: Lazy<Mutex<AsioCallbacks>> = Lazy::new(|| {
Mutex::new(AsioCallbacks {
buffer_switch,
sample_rate_did_change,
asio_message,
buffer_switch_time_info,
})
});
/// All the possible types from ASIO.
/// This is a direct copy of the asioMessage selectors
/// inside ASIO SDK.
#[rustfmt::skip]
#[derive(Debug, FromPrimitive)]
#[repr(C)]
pub enum AsioMessageSelectors {
kAsioSelectorSupported = 1, // selector in <value>, returns 1L if supported,
// 0 otherwise
kAsioEngineVersion, // returns engine (host) asio implementation version,
// 2 or higher
kAsioResetRequest, // request driver reset. if accepted, this
// will close the driver (ASIO_Exit() ) and
// re-open it again (ASIO_Init() etc). some
// drivers need to reconfigure for instance
// when the sample rate changes, or some basic
// changes have been made in ASIO_ControlPanel().
// returns 1L; note the request is merely passed
// to the application, there is no way to determine
// if it gets accepted at this time (but it usually
// will be).
kAsioBufferSizeChange, // not yet supported, will currently always return 0L.
// for now, use kAsioResetRequest instead.
// once implemented, the new buffer size is expected
// in <value>, and on success returns 1L
kAsioResyncRequest, // the driver went out of sync, such that
// the timestamp is no longer valid. this
// is a request to re-start the engine and
// slave devices (sequencer). returns 1 for ok,
// 0 if not supported.
kAsioLatenciesChanged, // the drivers latencies have changed. The engine
// will refetch the latencies.
kAsioSupportsTimeInfo, // if host returns true here, it will expect the
// callback bufferSwitchTimeInfo to be called instead
// of bufferSwitch
kAsioSupportsTimeCode, //
kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands
kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this
kAsioSupportsInputGain, // unused and undefined
kAsioSupportsInputMeter, // unused and undefined
kAsioSupportsOutputGain, // unused and undefined
kAsioSupportsOutputMeter, // unused and undefined
kAsioOverload, // driver detected an overload
kAsioNumMessageSelectors
}
/// A rust-usable version of the `ASIOTime` type that does not contain a binary blob for fields.
#[repr(C)]
pub struct AsioTime {
@@ -449,9 +505,6 @@ impl Driver {
) -> Result<c_long, AsioError> {
let num_channels = buffer_infos.len();
// To pass as ai::ASIOCallbacks
let mut callbacks = create_asio_callbacks();
let mut state = self.inner.lock_state();
// Retrieve the available buffer sizes.
@@ -481,12 +534,16 @@ impl Driver {
if let DriverState::Prepared = *state {
state.dispose_buffers()?;
}
// To pass as ai::ASIOCallbacks
let callbacks = &mut (*ASIO_CALLBACKS.lock().unwrap());
unsafe {
asio_result!(ai::ASIOCreateBuffers(
buffer_infos.as_mut_ptr() as *mut _,
num_channels as i32,
buffer_size,
&mut callbacks as *mut _ as *mut _,
callbacks as *mut _ as *mut _,
))?;
}
*state = DriverState::Prepared;
@@ -795,16 +852,6 @@ fn prepare_buffer_infos(is_input: bool, n_channels: usize) -> Vec<AsioBufferInfo
.collect()
}
/// The set of callbacks passed to `ASIOCreateBuffers`.
fn create_asio_callbacks() -> AsioCallbacks {
AsioCallbacks {
buffer_switch: buffer_switch,
sample_rate_did_change: sample_rate_did_change,
asio_message: asio_message,
buffer_switch_time_info: buffer_switch_time_info,
}
}
/// Retrieve the minimum, maximum and preferred buffer sizes along with the available
/// buffer size granularity.
fn asio_get_buffer_sizes() -> Result<BufferSizes, AsioError> {
@@ -873,23 +920,23 @@ extern "C" fn asio_message(
_message: *mut (),
_opt: *mut c_double,
) -> c_long {
match selector {
ai::kAsioSelectorSupported => {
match AsioMessageSelectors::from_i64(selector as i64) {
Some(AsioMessageSelectors::kAsioSelectorSupported) => {
// Indicate what message selectors are supported.
match value {
| ai::kAsioResetRequest
| ai::kAsioEngineVersion
| ai::kAsioResyncRequest
| ai::kAsioLatenciesChanged
match AsioMessageSelectors::from_i64(value as i64) {
| Some(AsioMessageSelectors::kAsioResetRequest)
| Some(AsioMessageSelectors::kAsioEngineVersion)
| Some(AsioMessageSelectors::kAsioResyncRequest)
| Some(AsioMessageSelectors::kAsioLatenciesChanged)
// Following added in ASIO 2.0.
| ai::kAsioSupportsTimeInfo
| ai::kAsioSupportsTimeCode
| ai::kAsioSupportsInputMonitor => 1,
| Some(AsioMessageSelectors::kAsioSupportsTimeInfo)
| Some(AsioMessageSelectors::kAsioSupportsTimeCode)
| Some(AsioMessageSelectors::kAsioSupportsInputMonitor) => 1,
_ => 0,
}
}
ai::kAsioResetRequest => {
Some(AsioMessageSelectors::kAsioResetRequest) => {
// Defer the task and perform the reset of the driver during the next "safe" situation
// You cannot reset the driver right now, as this code is called from the driver. Reset
// the driver is done by completely destruct it. I.e. ASIOStop(), ASIODisposeBuffers(),
@@ -898,7 +945,7 @@ extern "C" fn asio_message(
1
}
ai::kAsioResyncRequest => {
Some(AsioMessageSelectors::kAsioResyncRequest) => {
// This informs the application, that the driver encountered some non fatal data loss.
// It is used for synchronization purposes of different media. Added mainly to work
// around the Win16Mutex problems in Windows 95/98 with the Windows Multimedia system,
@@ -908,7 +955,7 @@ extern "C" fn asio_message(
1
}
ai::kAsioLatenciesChanged => {
Some(AsioMessageSelectors::kAsioLatenciesChanged) => {
// This will inform the host application that the drivers were latencies changed.
// Beware, it this does not mean that the buffer sizes have changed! You might need to
// update internal delay data.
@@ -916,20 +963,20 @@ extern "C" fn asio_message(
1
}
ai::kAsioEngineVersion => {
Some(AsioMessageSelectors::kAsioEngineVersion) => {
// Return the supported ASIO version of the host application If a host applications
// does not implement this selector, ASIO 1.0 is assumed by the driver
2
}
ai::kAsioSupportsTimeInfo => {
Some(AsioMessageSelectors::kAsioSupportsTimeInfo) => {
// Informs the driver whether the asioCallbacks.bufferSwitchTimeInfo() callback is
// supported. For compatibility with ASIO 1.0 drivers the host application should
// always support the "old" bufferSwitch method, too, which we do.
1
}
ai::kAsioSupportsTimeCode => {
Some(AsioMessageSelectors::kAsioSupportsTimeCode) => {
// Informs the driver whether the application is interested in time code info. If an
// application does not need to know about time code, the driver has less work to do.
// TODO: Provide an option for this?