mirror of
https://github.com/RustAudio/rodio
synced 2024-12-13 21:52:38 +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))]
|
#![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;
|
||||||
|
|
|
@ -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
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue