Better error handling for stream creation

This commit is contained in:
jiminycrick 2021-01-01 22:13:18 -08:00 committed by James Melkonian
parent a6f50364b0
commit 3ad927886c

View file

@ -105,9 +105,30 @@ impl error::Error for PlayError {
#[derive(Debug)]
pub enum StreamError {
PlayStreamError(cpal::PlayStreamError),
DefaultStreamConfigError(cpal::DefaultStreamConfigError),
BuildStreamError(cpal::BuildStreamError),
SupportedStreamConfigsError(cpal::SupportedStreamConfigsError),
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 {
fn from(err: cpal::PlayStreamError) -> Self {
Self::PlayStreamError(err)
@ -118,6 +139,9 @@ impl fmt::Display for StreamError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
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"),
}
}
@ -127,6 +151,9 @@ impl error::Error for StreamError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::PlayStreamError(e) => Some(e),
Self::BuildStreamError(e) => Some(e),
Self::DefaultStreamConfigError(e) => Some(e),
Self::SupportedStreamConfigsError(e) => Some(e),
Self::NoDevice => None,
}
}
@ -142,7 +169,6 @@ pub(crate) trait CpalDeviceExt {
fn try_new_output_stream(
&self,
) -> Result<(Arc<DynamicMixerController<f32>>, cpal::Stream), StreamError>;
fn new_output_stream(&self) -> (Arc<DynamicMixerController<f32>>, cpal::Stream);
}
impl CpalDeviceExt for cpal::Device {
@ -192,37 +218,16 @@ impl CpalDeviceExt for cpal::Device {
&self,
) -> Result<(Arc<DynamicMixerController<f32>>, cpal::Stream), StreamError> {
// Determine the format to use for the new stream.
let default_format = match 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!?");
let default_format = self.default_output_config()?;
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
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")
supported_output_formats(self)?
.filter_map(|format| self.new_output_stream_with_format(format).ok())
.next()
// return original error if nothing works
.ok_or(StreamError::BuildStreamError(err))
})
}
}
@ -230,16 +235,13 @@ impl CpalDeviceExt for cpal::Device {
/// All the supported output formats with sample rates
fn supported_output_formats(
device: &cpal::Device,
) -> impl Iterator<Item = cpal::SupportedStreamConfig> {
) -> Result<impl Iterator<Item = cpal::SupportedStreamConfig>, StreamError> {
const HZ_44100: cpal::SampleRate = cpal::SampleRate(44_100);
let mut supported: Vec<_> = device
.supported_output_configs()
.expect("No supported output formats")
.collect();
let mut supported: Vec<_> = device.supported_output_configs()?.collect();
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 min_rate = sf.min_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
})
}))
}