-
Notifications
You must be signed in to change notification settings - Fork 433
Open
Description
cpal's Device
claims to be Send
but when I enable the asio
feature and enumerate devices in another thread, after the thread returns, I get access violation in the asio driver:
(exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)
Details (see comments in code):
// spawn new thread as workaround: https://github.com/RustAudio/rodio/issues/214
pub fn call_in_new_thread<R: Send + 'static, F: FnOnce() -> R + Send + 'static>(new_thread: bool, f: F) -> R {
if new_thread {
thread::Builder::new().name("tmp".to_string()).spawn(f).expect("spawn").join().expect("join")
} else {
f()
}
}
pub fn get_audio_output_devices() -> Vec<cpal::Device> {
let mut result = vec![];
debug!("Supported hosts:\n {:?}", cpal::ALL_HOSTS);
let available_hosts = cpal::available_hosts();
debug!("Available hosts:\n {:?}", available_hosts);
for host_id in available_hosts {
#[cfg(windows)]
let new_thread = host_id == HostId::Wasapi;
#[cfg(not(windows))]
let new_thread = false;
// NOTE: If I run the code like this (i.e. only spawning a new thread for accessing wasapi),
// it lists both wasapi and asio devices without crash.
// BUT:
// If I always pass `true` for `new_thread`, it causes access violation in asio driver AFTER having enumerated & printed all devices (when the asio device is dropped).
// If I always pass `false` for `new_thread`, it causes a crash in wasapi:
// Os { code: -2147417850, kind: Other, message: "Cannot change thread mode after it is set." }', C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\cpal-0.13.1\src\host\wasapi\com.rs:13:77
// It's a known issue: https://github.com/RustAudio/rodio/issues/214
result.extend(call_in_new_thread(new_thread, move || {
let mut r = vec![];
debug!("{}", host_id.name());
let host = cpal::host_from_id(host_id).unwrap();
let default_out = host.default_output_device().map(|e| e.name().unwrap());
debug!(" Default Output Device:\n {:?}", default_out);
let devices = host.devices().unwrap();
debug!(" Devices: ");
for (device_index, device) in devices.enumerate() {
debug!(" {}. \"{}\"", device_index + 1, device.name().unwrap());
// Output configs
let mut output_configs = match device.supported_output_configs() {
Ok(f) => f.peekable(),
Err(e) => {
debug!("Error: {:?}", e);
continue;
}
};
if output_configs.peek().is_some() {
debug!(" All supported output stream configs:");
for (config_index, config) in output_configs.enumerate() {
debug!(" {}.{}. {:?}", device_index + 1, config_index + 1, config);
}
}
// use only device with default config
if let Ok(conf) = device.default_output_config() {
debug!(" Default output stream config:\n {:?}", conf);
r.push(device);
}
}
r
}));
}
result
}