Merge pull request #350 from jiminycrick/fix-stream-panic

Better error handling for stream creation
This commit is contained in:
est31 2021-05-02 13:33:22 +02:00 committed by GitHub
commit e2a3a0b81f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 38 deletions

View file

@ -97,8 +97,8 @@
//! //!
#![cfg_attr(test, deny(missing_docs))] #![cfg_attr(test, deny(missing_docs))]
pub use cpal::{ pub use cpal::{
traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices, self, traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices,
SupportedStreamConfig, self, SupportedStreamConfig,
}; };
mod conversions; mod conversions;

View file

@ -105,9 +105,30 @@ impl error::Error for PlayError {
#[derive(Debug)] #[derive(Debug)]
pub enum StreamError { pub enum StreamError {
PlayStreamError(cpal::PlayStreamError), PlayStreamError(cpal::PlayStreamError),
DefaultStreamConfigError(cpal::DefaultStreamConfigError),
BuildStreamError(cpal::BuildStreamError),
SupportedStreamConfigsError(cpal::SupportedStreamConfigsError),
NoDevice, NoDevice,
} }
impl From<cpal::DefaultStreamConfigError> for StreamError {
fn from(err: cpal::DefaultStreamConfigError) -> Self {
Self::DefaultStreamConfigError(err)
}
}
impl From<cpal::SupportedStreamConfigsError> for StreamError {
fn from(err: cpal::SupportedStreamConfigsError) -> Self {
Self::SupportedStreamConfigsError(err)
}
}
impl From<cpal::BuildStreamError> for StreamError {
fn from(err: cpal::BuildStreamError) -> Self {
Self::BuildStreamError(err)
}
}
impl From<cpal::PlayStreamError> for StreamError { impl From<cpal::PlayStreamError> for StreamError {
fn from(err: cpal::PlayStreamError) -> Self { fn from(err: cpal::PlayStreamError) -> Self {
Self::PlayStreamError(err) Self::PlayStreamError(err)
@ -118,6 +139,9 @@ impl fmt::Display for StreamError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Self::PlayStreamError(e) => e.fmt(f), Self::PlayStreamError(e) => e.fmt(f),
Self::BuildStreamError(e) => e.fmt(f),
Self::DefaultStreamConfigError(e) => e.fmt(f),
Self::SupportedStreamConfigsError(e) => e.fmt(f),
Self::NoDevice => write!(f, "NoDevice"), Self::NoDevice => write!(f, "NoDevice"),
} }
} }
@ -127,6 +151,9 @@ impl error::Error for StreamError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> { fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self { match self {
Self::PlayStreamError(e) => Some(e), Self::PlayStreamError(e) => Some(e),
Self::BuildStreamError(e) => Some(e),
Self::DefaultStreamConfigError(e) => Some(e),
Self::SupportedStreamConfigsError(e) => Some(e),
Self::NoDevice => None, Self::NoDevice => None,
} }
} }
@ -142,7 +169,6 @@ pub(crate) trait CpalDeviceExt {
fn try_new_output_stream( fn try_new_output_stream(
&self, &self,
) -> Result<(Arc<DynamicMixerController<f32>>, cpal::Stream), StreamError>; ) -> Result<(Arc<DynamicMixerController<f32>>, cpal::Stream), StreamError>;
fn new_output_stream(&self) -> (Arc<DynamicMixerController<f32>>, cpal::Stream);
} }
impl CpalDeviceExt for cpal::Device { impl CpalDeviceExt for cpal::Device {
@ -192,37 +218,16 @@ impl CpalDeviceExt for cpal::Device {
&self, &self,
) -> Result<(Arc<DynamicMixerController<f32>>, cpal::Stream), StreamError> { ) -> Result<(Arc<DynamicMixerController<f32>>, cpal::Stream), StreamError> {
// Determine the format to use for the new stream. // Determine the format to use for the new stream.
let default_format = match self.default_output_config() { let default_format = self.default_output_config()?;
Ok(f) => f,
Err(_) => return Err(StreamError::NoDevice),
};
Ok(self
.new_output_stream_with_format(default_format)
.unwrap_or_else(|err| {
// look through all supported formats to see if another works
supported_output_formats(self)
.filter_map(|format| self.new_output_stream_with_format(format).ok())
.next()
.ok_or(err)
.expect("build_output_stream failed with all supported formats")
}))
}
fn new_output_stream(&self) -> (Arc<DynamicMixerController<f32>>, cpal::Stream) {
// Determine the format to use for the new stream.
let default_format = self
.default_output_config()
.expect("The device doesn't support any format!?");
self.new_output_stream_with_format(default_format) self.new_output_stream_with_format(default_format)
.unwrap_or_else(|err| { .or_else(|err| {
// look through all supported formats to see if another works // look through all supported formats to see if another works
supported_output_formats(self) supported_output_formats(self)?
.filter_map(|format| self.new_output_stream_with_format(format).ok()) .filter_map(|format| self.new_output_stream_with_format(format).ok())
.next() .next()
.ok_or(err) // return original error if nothing works
.expect("build_output_stream failed with all supported formats") .ok_or(StreamError::BuildStreamError(err))
}) })
} }
} }
@ -230,16 +235,13 @@ impl CpalDeviceExt for cpal::Device {
/// All the supported output formats with sample rates /// All the supported output formats with sample rates
fn supported_output_formats( fn supported_output_formats(
device: &cpal::Device, device: &cpal::Device,
) -> impl Iterator<Item = cpal::SupportedStreamConfig> { ) -> Result<impl Iterator<Item = cpal::SupportedStreamConfig>, StreamError> {
const HZ_44100: cpal::SampleRate = cpal::SampleRate(44_100); const HZ_44100: cpal::SampleRate = cpal::SampleRate(44_100);
let mut supported: Vec<_> = device let mut supported: Vec<_> = device.supported_output_configs()?.collect();
.supported_output_configs()
.expect("No supported output formats")
.collect();
supported.sort_by(|a, b| b.cmp_default_heuristics(a)); supported.sort_by(|a, b| b.cmp_default_heuristics(a));
supported.into_iter().flat_map(|sf| { Ok(supported.into_iter().flat_map(|sf| {
let max_rate = sf.max_sample_rate(); let max_rate = sf.max_sample_rate();
let min_rate = sf.min_sample_rate(); let min_rate = sf.min_sample_rate();
let mut formats = vec![sf.clone().with_max_sample_rate()]; let mut formats = vec![sf.clone().with_max_sample_rate()];
@ -248,5 +250,5 @@ fn supported_output_formats(
} }
formats.push(sf.with_sample_rate(min_rate)); formats.push(sf.with_sample_rate(min_rate));
formats formats
}) }))
} }