mirror of
https://github.com/RustAudio/rodio
synced 2024-11-10 06:04:16 +00:00
Merge pull request #350 from jiminycrick/fix-stream-panic
Better error handling for stream creation
This commit is contained in:
commit
e2a3a0b81f
2 changed files with 40 additions and 38 deletions
|
@ -97,8 +97,8 @@
|
|||
//!
|
||||
#![cfg_attr(test, deny(missing_docs))]
|
||||
pub use cpal::{
|
||||
traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices,
|
||||
SupportedStreamConfig, self,
|
||||
self, traits::DeviceTrait, Device, Devices, DevicesError, InputDevices, OutputDevices,
|
||||
SupportedStreamConfig,
|
||||
};
|
||||
|
||||
mod conversions;
|
||||
|
|
|
@ -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
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue