Improve handling of `BuildStreamError` throughout crate.
This commit is contained in:
parent
f0e4e312c1
commit
ba8d354e93
126
src/alsa/mod.rs
126
src/alsa/mod.rs
|
@ -690,29 +690,41 @@ impl EventLoop {
|
||||||
) {
|
) {
|
||||||
-16 /* determined empirically */ => return Err(BuildStreamError::DeviceNotAvailable),
|
-16 /* determined empirically */ => return Err(BuildStreamError::DeviceNotAvailable),
|
||||||
-22 => return Err(BuildStreamError::InvalidArgument),
|
-22 => return Err(BuildStreamError::InvalidArgument),
|
||||||
e => if check_errors(e).is_err() {
|
e => if let Err(description) = check_errors(e) {
|
||||||
return Err(BuildStreamError::Unknown);
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let hw_params = HwParams::alloc();
|
let hw_params = HwParams::alloc();
|
||||||
|
|
||||||
set_hw_params_from_format(capture_handle, &hw_params, format);
|
set_hw_params_from_format(capture_handle, &hw_params, format)
|
||||||
|
.map_err(|description| BackendSpecificError { description })?;
|
||||||
|
|
||||||
let can_pause = alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1;
|
let can_pause = alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1;
|
||||||
|
|
||||||
let (buffer_len, period_len) = set_sw_params_from_format(capture_handle, format);
|
let (buffer_len, period_len) = set_sw_params_from_format(capture_handle, format)
|
||||||
|
.map_err(|description| BackendSpecificError { description })?;
|
||||||
|
|
||||||
check_errors(alsa::snd_pcm_prepare(capture_handle))
|
if let Err(desc) = check_errors(alsa::snd_pcm_prepare(capture_handle)) {
|
||||||
.expect("could not get playback handle");
|
let description = format!("could not get capture handle: {}", desc);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
|
||||||
let num_descriptors = {
|
let num_descriptors = {
|
||||||
let num_descriptors = alsa::snd_pcm_poll_descriptors_count(capture_handle);
|
let num_descriptors = alsa::snd_pcm_poll_descriptors_count(capture_handle);
|
||||||
debug_assert!(num_descriptors >= 1);
|
if num_descriptors == 0 {
|
||||||
|
let description = "poll descriptor count for capture stream was 0".to_string();
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
num_descriptors as usize
|
num_descriptors as usize
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_stream_id = StreamId(self.next_stream_id.fetch_add(1, Ordering::Relaxed));
|
let new_stream_id = StreamId(self.next_stream_id.fetch_add(1, Ordering::Relaxed));
|
||||||
assert_ne!(new_stream_id.0, usize::max_value()); // check for overflows
|
if new_stream_id.0 == usize::max_value() {
|
||||||
|
return Err(BuildStreamError::StreamIdOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
let stream_inner = StreamInner {
|
let stream_inner = StreamInner {
|
||||||
id: new_stream_id.clone(),
|
id: new_stream_id.clone(),
|
||||||
|
@ -728,8 +740,11 @@ impl EventLoop {
|
||||||
buffer: None,
|
buffer: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
check_errors(alsa::snd_pcm_start(capture_handle))
|
if let Err(desc) = check_errors(alsa::snd_pcm_start(capture_handle)) {
|
||||||
.expect("could not start capture stream");
|
let description = format!("could not start capture stream: {}", desc);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
|
||||||
self.push_command(Command::NewStream(stream_inner));
|
self.push_command(Command::NewStream(stream_inner));
|
||||||
Ok(new_stream_id)
|
Ok(new_stream_id)
|
||||||
|
@ -754,29 +769,41 @@ impl EventLoop {
|
||||||
) {
|
) {
|
||||||
-16 /* determined empirically */ => return Err(BuildStreamError::DeviceNotAvailable),
|
-16 /* determined empirically */ => return Err(BuildStreamError::DeviceNotAvailable),
|
||||||
-22 => return Err(BuildStreamError::InvalidArgument),
|
-22 => return Err(BuildStreamError::InvalidArgument),
|
||||||
e => if check_errors(e).is_err() {
|
e => if let Err(description) = check_errors(e) {
|
||||||
return Err(BuildStreamError::Unknown);
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let hw_params = HwParams::alloc();
|
let hw_params = HwParams::alloc();
|
||||||
|
|
||||||
set_hw_params_from_format(playback_handle, &hw_params, format);
|
set_hw_params_from_format(playback_handle, &hw_params, format)
|
||||||
|
.map_err(|description| BackendSpecificError { description })?;
|
||||||
|
|
||||||
let can_pause = alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1;
|
let can_pause = alsa::snd_pcm_hw_params_can_pause(hw_params.0) == 1;
|
||||||
|
|
||||||
let (buffer_len, period_len) = set_sw_params_from_format(playback_handle, format);
|
let (buffer_len, period_len) = set_sw_params_from_format(playback_handle, format)
|
||||||
|
.map_err(|description| BackendSpecificError { description })?;
|
||||||
|
|
||||||
check_errors(alsa::snd_pcm_prepare(playback_handle))
|
if let Err(desc) = check_errors(alsa::snd_pcm_prepare(playback_handle)) {
|
||||||
.expect("could not get playback handle");
|
let description = format!("could not get playback handle: {}", desc);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
|
||||||
let num_descriptors = {
|
let num_descriptors = {
|
||||||
let num_descriptors = alsa::snd_pcm_poll_descriptors_count(playback_handle);
|
let num_descriptors = alsa::snd_pcm_poll_descriptors_count(playback_handle);
|
||||||
debug_assert!(num_descriptors >= 1);
|
if num_descriptors == 0 {
|
||||||
|
let description = "poll descriptor count for playback stream was 0".to_string();
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
num_descriptors as usize
|
num_descriptors as usize
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_stream_id = StreamId(self.next_stream_id.fetch_add(1, Ordering::Relaxed));
|
let new_stream_id = StreamId(self.next_stream_id.fetch_add(1, Ordering::Relaxed));
|
||||||
assert_ne!(new_stream_id.0, usize::max_value()); // check for overflows
|
if new_stream_id.0 == usize::max_value() {
|
||||||
|
return Err(BuildStreamError::StreamIdOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
let stream_inner = StreamInner {
|
let stream_inner = StreamInner {
|
||||||
id: new_stream_id.clone(),
|
id: new_stream_id.clone(),
|
||||||
|
@ -826,12 +853,12 @@ unsafe fn set_hw_params_from_format(
|
||||||
format: &Format,
|
format: &Format,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_any(pcm_handle, hw_params.0)) {
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_any(pcm_handle, hw_params.0)) {
|
||||||
return Err("Errors on pcm handle".to_string());
|
return Err(format!("errors on pcm handle: {}", e));
|
||||||
}
|
}
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_access(pcm_handle,
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_access(pcm_handle,
|
||||||
hw_params.0,
|
hw_params.0,
|
||||||
alsa::SND_PCM_ACCESS_RW_INTERLEAVED)) {
|
alsa::SND_PCM_ACCESS_RW_INTERLEAVED)) {
|
||||||
return Err("Handle not acessible".to_string());
|
return Err(format!("handle not acessible: {}", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
let data_type = if cfg!(target_endian = "big") {
|
let data_type = if cfg!(target_endian = "big") {
|
||||||
|
@ -851,29 +878,34 @@ unsafe fn set_hw_params_from_format(
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_format(pcm_handle,
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_format(pcm_handle,
|
||||||
hw_params.0,
|
hw_params.0,
|
||||||
data_type)) {
|
data_type)) {
|
||||||
return Err("Format could not be set".to_string());
|
return Err(format!("format could not be set: {}", e));
|
||||||
}
|
}
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_rate(pcm_handle,
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_rate(pcm_handle,
|
||||||
hw_params.0,
|
hw_params.0,
|
||||||
format.sample_rate.0 as libc::c_uint,
|
format.sample_rate.0 as libc::c_uint,
|
||||||
0)) {
|
0)) {
|
||||||
return Err("Sample rate could not be set".to_string());
|
return Err(format!("sample rate could not be set: {}", e));
|
||||||
}
|
}
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_channels(pcm_handle,
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_channels(pcm_handle,
|
||||||
hw_params.0,
|
hw_params.0,
|
||||||
format.channels as
|
format.channels as
|
||||||
libc::c_uint)) {
|
libc::c_uint)) {
|
||||||
return Err("Channel count could not be set".to_string());
|
return Err(format!("channel count could not be set: {}", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Review this. 200ms seems arbitrary...
|
||||||
let mut max_buffer_size = format.sample_rate.0 as alsa::snd_pcm_uframes_t /
|
let mut max_buffer_size = format.sample_rate.0 as alsa::snd_pcm_uframes_t /
|
||||||
format.channels as alsa::snd_pcm_uframes_t /
|
format.channels as alsa::snd_pcm_uframes_t /
|
||||||
5; // 200ms of buffer
|
5; // 200ms of buffer
|
||||||
check_errors(alsa::snd_pcm_hw_params_set_buffer_size_max(pcm_handle,
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params_set_buffer_size_max(pcm_handle,
|
||||||
hw_params.0,
|
hw_params.0,
|
||||||
&mut max_buffer_size))
|
&mut max_buffer_size))
|
||||||
.unwrap();
|
{
|
||||||
|
return Err(format!("max buffer size could not be set: {}", e));
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(e) = check_errors(alsa::snd_pcm_hw_params(pcm_handle, hw_params.0)) {
|
if let Err(e) = check_errors(alsa::snd_pcm_hw_params(pcm_handle, hw_params.0)) {
|
||||||
return Err("Hardware params could not be set.".to_string());
|
return Err(format!("hardware params could not be set: {}", e));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -882,34 +914,42 @@ unsafe fn set_hw_params_from_format(
|
||||||
unsafe fn set_sw_params_from_format(
|
unsafe fn set_sw_params_from_format(
|
||||||
pcm_handle: *mut alsa::snd_pcm_t,
|
pcm_handle: *mut alsa::snd_pcm_t,
|
||||||
format: &Format,
|
format: &Format,
|
||||||
) -> (usize, usize)
|
) -> Result<(usize, usize), String>
|
||||||
{
|
{
|
||||||
let mut sw_params = mem::uninitialized(); // TODO: RAII
|
let mut sw_params = mem::uninitialized(); // TODO: RAII
|
||||||
check_errors(alsa::snd_pcm_sw_params_malloc(&mut sw_params)).unwrap();
|
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_malloc(&mut sw_params)) {
|
||||||
check_errors(alsa::snd_pcm_sw_params_current(pcm_handle, sw_params)).unwrap();
|
return Err(format!("snd_pcm_sw_params_malloc failed: {}", e));
|
||||||
check_errors(alsa::snd_pcm_sw_params_set_start_threshold(pcm_handle,
|
}
|
||||||
sw_params,
|
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_current(pcm_handle, sw_params)) {
|
||||||
0))
|
return Err(format!("snd_pcm_sw_params_current failed: {}", e));
|
||||||
.unwrap();
|
}
|
||||||
|
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_set_start_threshold(pcm_handle, sw_params, 0)) {
|
||||||
|
return Err(format!("snd_pcm_sw_params_set_start_threshold failed: {}", e));
|
||||||
|
}
|
||||||
|
|
||||||
let (buffer_len, period_len) = {
|
let (buffer_len, period_len) = {
|
||||||
let mut buffer = mem::uninitialized();
|
let mut buffer = mem::uninitialized();
|
||||||
let mut period = mem::uninitialized();
|
let mut period = mem::uninitialized();
|
||||||
check_errors(alsa::snd_pcm_get_params(pcm_handle, &mut buffer, &mut period))
|
if let Err(e) = check_errors(alsa::snd_pcm_get_params(pcm_handle, &mut buffer, &mut period)) {
|
||||||
.expect("could not initialize buffer");
|
return Err(format!("failed to initialize buffer: {}", e));
|
||||||
assert!(buffer != 0);
|
}
|
||||||
check_errors(alsa::snd_pcm_sw_params_set_avail_min(pcm_handle,
|
if buffer == 0 {
|
||||||
sw_params,
|
return Err(format!("initialization resulted in a null buffer"));
|
||||||
period))
|
}
|
||||||
.unwrap();
|
if let Err(e) = check_errors(alsa::snd_pcm_sw_params_set_avail_min(pcm_handle, sw_params, period)) {
|
||||||
|
return Err(format!("snd_pcm_sw_params_set_avail_min failed: {}", e));
|
||||||
|
}
|
||||||
let buffer = buffer as usize * format.channels as usize;
|
let buffer = buffer as usize * format.channels as usize;
|
||||||
let period = period as usize * format.channels as usize;
|
let period = period as usize * format.channels as usize;
|
||||||
(buffer, period)
|
(buffer, period)
|
||||||
};
|
};
|
||||||
|
|
||||||
check_errors(alsa::snd_pcm_sw_params(pcm_handle, sw_params)).unwrap();
|
if let Err(e) = check_errors(alsa::snd_pcm_sw_params(pcm_handle, sw_params)) {
|
||||||
|
return Err(format!("snd_pcm_sw_params failed: {}", e));
|
||||||
|
}
|
||||||
|
|
||||||
alsa::snd_pcm_sw_params_free(sw_params);
|
alsa::snd_pcm_sw_params_free(sw_params);
|
||||||
(buffer_len, period_len)
|
Ok((buffer_len, period_len))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around `hw_params`.
|
/// Wrapper around `hw_params`.
|
||||||
|
@ -945,8 +985,6 @@ impl Drop for StreamInner {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn check_errors(err: libc::c_int) -> Result<(), String> {
|
fn check_errors(err: libc::c_int) -> Result<(), String> {
|
||||||
use std::ffi;
|
|
||||||
|
|
||||||
if err < 0 {
|
if err < 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
let s = ffi::CStr::from_ptr(alsa::snd_strerror(err))
|
let s = ffi::CStr::from_ptr(alsa::snd_strerror(err))
|
||||||
|
|
|
@ -513,13 +513,16 @@ impl EventLoop {
|
||||||
// If the requested sample rate is different to the device sample rate, update the device.
|
// If the requested sample rate is different to the device sample rate, update the device.
|
||||||
if sample_rate as u32 != format.sample_rate.0 {
|
if sample_rate as u32 != format.sample_rate.0 {
|
||||||
|
|
||||||
// In order to avoid breaking existing input streams we `panic!` if there is already an
|
// In order to avoid breaking existing input streams we return an error if there is
|
||||||
// active input stream for this device with the actual sample rate.
|
// already an active input stream for this device with the actual sample rate.
|
||||||
for stream in &*self.streams.lock().unwrap() {
|
for stream in &*self.streams.lock().unwrap() {
|
||||||
if let Some(stream) = stream.as_ref() {
|
if let Some(stream) = stream.as_ref() {
|
||||||
if stream.device_id == device.audio_device_id {
|
if stream.device_id == device.audio_device_id {
|
||||||
panic!("cannot change device sample rate for stream as an existing stream \
|
let description = "cannot change device sample rate for stream as an \
|
||||||
is already running at the current sample rate.");
|
existing stream is already running at the current sample rate"
|
||||||
|
.into();
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -618,7 +621,9 @@ impl EventLoop {
|
||||||
let timer = ::std::time::Instant::now();
|
let timer = ::std::time::Instant::now();
|
||||||
while sample_rate != reported_rate {
|
while sample_rate != reported_rate {
|
||||||
if timer.elapsed() > ::std::time::Duration::from_secs(1) {
|
if timer.elapsed() > ::std::time::Duration::from_secs(1) {
|
||||||
panic!("timeout waiting for sample rate update for device");
|
let description = "timeout waiting for sample rate update for device".into();
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
::std::thread::sleep(::std::time::Duration::from_millis(5));
|
::std::thread::sleep(::std::time::Duration::from_millis(5));
|
||||||
}
|
}
|
||||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -371,9 +371,15 @@ pub enum BuildStreamError {
|
||||||
/// Trying to use capture capabilities on an output only format yields this.
|
/// Trying to use capture capabilities on an output only format yields this.
|
||||||
#[fail(display = "The requested device does not support this capability (invalid argument)")]
|
#[fail(display = "The requested device does not support this capability (invalid argument)")]
|
||||||
InvalidArgument,
|
InvalidArgument,
|
||||||
/// The C-Layer returned an error we don't know about
|
/// Occurs if adding a new Stream ID would cause an integer overflow.
|
||||||
#[fail(display = "An unknown error in the Backend occured")]
|
#[fail(display = "Adding a new stream ID would cause an overflow")]
|
||||||
Unknown,
|
StreamIdOverflow,
|
||||||
|
/// See the `BackendSpecificError` docs for more information about this error variant.
|
||||||
|
#[fail(display = "{}", err)]
|
||||||
|
BackendSpecific {
|
||||||
|
#[fail(cause)]
|
||||||
|
err: BackendSpecificError,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator yielding all `Device`s currently available to the system.
|
/// An iterator yielding all `Device`s currently available to the system.
|
||||||
|
@ -777,6 +783,12 @@ impl From<BackendSpecificError> for DefaultFormatError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<BackendSpecificError> for BuildStreamError {
|
||||||
|
fn from(err: BackendSpecificError) -> Self {
|
||||||
|
BuildStreamError::BackendSpecific { err }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If a backend does not provide an API for retrieving supported formats, we query it with a bunch
|
// If a backend does not provide an API for retrieving supported formats, we query it with a bunch
|
||||||
// of commonly used rates. This is always the case for wasapi and is sometimes the case for alsa.
|
// of commonly used rates. This is always the case for wasapi and is sometimes the case for alsa.
|
||||||
//
|
//
|
||||||
|
|
|
@ -20,6 +20,7 @@ use std::sync::mpsc::{channel, Sender, Receiver};
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
use BackendSpecificError;
|
||||||
use BuildStreamError;
|
use BuildStreamError;
|
||||||
use Format;
|
use Format;
|
||||||
use SampleFormat;
|
use SampleFormat;
|
||||||
|
@ -123,9 +124,14 @@ impl EventLoop {
|
||||||
|
|
||||||
// Obtaining a `IAudioClient`.
|
// Obtaining a `IAudioClient`.
|
||||||
let audio_client = match device.build_audioclient() {
|
let audio_client = match device.build_audioclient() {
|
||||||
|
Ok(client) => client,
|
||||||
Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) =>
|
Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) =>
|
||||||
return Err(BuildStreamError::DeviceNotAvailable),
|
return Err(BuildStreamError::DeviceNotAvailable),
|
||||||
e => e.unwrap(),
|
Err(e) => {
|
||||||
|
let description = format!("{}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Computing the format and initializing the device.
|
// Computing the format and initializing the device.
|
||||||
|
@ -158,7 +164,9 @@ impl EventLoop {
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("{:?}", e);
|
let description = format!("{}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
},
|
},
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
};
|
};
|
||||||
|
@ -179,7 +187,9 @@ impl EventLoop {
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("{:?}", e);
|
let description = format!("{}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
},
|
},
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
};
|
};
|
||||||
|
@ -192,16 +202,17 @@ impl EventLoop {
|
||||||
let event = synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null());
|
let event = synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null());
|
||||||
if event == ptr::null_mut() {
|
if event == ptr::null_mut() {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("Failed to create event");
|
let description = format!("failed to create event");
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
match check_result((*audio_client).SetEventHandle(event)) {
|
if let Err(e) = check_result((*audio_client).SetEventHandle(event)) {
|
||||||
Err(_) => {
|
(*audio_client).Release();
|
||||||
(*audio_client).Release();
|
let description = format!("failed to call SetEventHandle: {}", e);
|
||||||
panic!("Failed to call SetEventHandle")
|
let err = BackendSpecificError { description };
|
||||||
},
|
return Err(err.into());
|
||||||
Ok(_) => (),
|
}
|
||||||
};
|
|
||||||
|
|
||||||
event
|
event
|
||||||
};
|
};
|
||||||
|
@ -222,7 +233,9 @@ impl EventLoop {
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("{:?}", e);
|
let description = format!("failed to build capture client: {}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
},
|
},
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
};
|
};
|
||||||
|
@ -231,7 +244,9 @@ impl EventLoop {
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_stream_id = StreamId(self.next_stream_id.fetch_add(1, Ordering::Relaxed));
|
let new_stream_id = StreamId(self.next_stream_id.fetch_add(1, Ordering::Relaxed));
|
||||||
assert_ne!(new_stream_id.0, usize::max_value()); // check for overflows
|
if new_stream_id.0 == usize::max_value() {
|
||||||
|
return Err(BuildStreamError::StreamIdOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
// Once we built the `StreamInner`, we add a command that will be picked up by the
|
// Once we built the `StreamInner`, we add a command that will be picked up by the
|
||||||
// `run()` method and added to the `RunContext`.
|
// `run()` method and added to the `RunContext`.
|
||||||
|
@ -270,9 +285,14 @@ impl EventLoop {
|
||||||
|
|
||||||
// Obtaining a `IAudioClient`.
|
// Obtaining a `IAudioClient`.
|
||||||
let audio_client = match device.build_audioclient() {
|
let audio_client = match device.build_audioclient() {
|
||||||
|
Ok(client) => client,
|
||||||
Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) =>
|
Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) =>
|
||||||
return Err(BuildStreamError::DeviceNotAvailable),
|
return Err(BuildStreamError::DeviceNotAvailable),
|
||||||
e => e.unwrap(),
|
Err(e) => {
|
||||||
|
let description = format!("{}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Computing the format and initializing the device.
|
// Computing the format and initializing the device.
|
||||||
|
@ -303,7 +323,9 @@ impl EventLoop {
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("{:?}", e);
|
let description = format!("{}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
},
|
},
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
};
|
};
|
||||||
|
@ -316,13 +338,17 @@ impl EventLoop {
|
||||||
let event = synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null());
|
let event = synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null());
|
||||||
if event == ptr::null_mut() {
|
if event == ptr::null_mut() {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("Failed to create event");
|
let description = format!("failed to create event");
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
match check_result((*audio_client).SetEventHandle(event)) {
|
match check_result((*audio_client).SetEventHandle(event)) {
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("Failed to call SetEventHandle")
|
let description = format!("failed to call SetEventHandle: {}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
},
|
},
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
};
|
};
|
||||||
|
@ -343,7 +369,9 @@ impl EventLoop {
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("{:?}", e);
|
let description = format!("failed to obtain buffer size: {}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
},
|
},
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
};
|
};
|
||||||
|
@ -367,7 +395,9 @@ impl EventLoop {
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
(*audio_client).Release();
|
(*audio_client).Release();
|
||||||
panic!("{:?}", e);
|
let description = format!("failed to build render client: {}", e);
|
||||||
|
let err = BackendSpecificError { description };
|
||||||
|
return Err(err.into());
|
||||||
},
|
},
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
};
|
};
|
||||||
|
@ -376,7 +406,9 @@ impl EventLoop {
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_stream_id = StreamId(self.next_stream_id.fetch_add(1, Ordering::Relaxed));
|
let new_stream_id = StreamId(self.next_stream_id.fetch_add(1, Ordering::Relaxed));
|
||||||
assert_ne!(new_stream_id.0, usize::max_value()); // check for overflows
|
if new_stream_id.0 == usize::max_value() {
|
||||||
|
return Err(BuildStreamError::StreamIdOverflow);
|
||||||
|
}
|
||||||
|
|
||||||
// Once we built the `StreamInner`, we add a command that will be picked up by the
|
// Once we built the `StreamInner`, we add a command that will be picked up by the
|
||||||
// `run()` method and added to the `RunContext`.
|
// `run()` method and added to the `RunContext`.
|
||||||
|
|
Loading…
Reference in New Issue