Skip to content

Device not always Send? ASIO Device causes access violation #517

@Boscop

Description

@Boscop

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:

image

(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
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions