Improved error handling in rodio backend

This commit is contained in:
johannesd3 2021-02-12 19:31:41 +01:00
parent b2f1be4374
commit 689415a6f1

View file

@ -29,75 +29,100 @@ pub struct RodioSink {
} }
fn list_formats(device: &rodio::Device) { fn list_formats(device: &rodio::Device) {
let default_fmt = match device.default_output_config() { match device.default_output_config() {
Ok(fmt) => fmt, Ok(cfg) => {
Err(e) => {
warn!("Error getting default rodio::Sink config: {}", e);
return;
}
};
debug!(" Default config:"); debug!(" Default config:");
debug!(" {:?}", default_fmt); debug!(" {:?}", cfg);
}
let mut output_configs = match device.supported_output_configs() {
Ok(f) => f.peekable(),
Err(e) => { Err(e) => {
warn!("Error getting supported rodio::Sink configs: {}", e); // Use loglevel debug, since even the output is only debug
return; debug!("Error getting default rodio::Sink config: {}", e);
} }
}; };
if output_configs.peek().is_some() { match device.supported_output_configs() {
Ok(mut cfgs) => {
if let Some(first) = cfgs.next() {
debug!(" Available configs:"); debug!(" Available configs:");
for format in output_configs { debug!(" {:?}", first);
debug!(" {:?}", format); } else {
return;
}
for cfg in cfgs {
debug!(" {:?}", cfg);
}
}
Err(e) => {
debug!("Error getting supported rodio::Sink configs: {}", e);
} }
} }
} }
fn list_outputs_and_exit() -> ! { fn list_outputs() -> Result<(), cpal::DevicesError> {
let default_device = get_default_device().unwrap(); let mut default_device_name = None;
let default_device_name = default_device.name().expect("cannot get output name");
println!("Default Audio Device:\n {}", default_device_name); if let Some(default_device) = get_default_device() {
default_device_name = default_device.name().ok();
println!(
"Default Audio Device:\n {}",
default_device_name.as_deref().unwrap_or("[unknown name]")
);
list_formats(&default_device); list_formats(&default_device);
println!("Other Available Audio Devices:"); println!("Other Available Audio Devices:");
for device in cpal::default_host() } else {
.output_devices() warn!("No default device was found");
.expect("cannot get list of output devices") }
{
let device_name = device.name().expect("cannot get output name"); for device in cpal::default_host().output_devices()? {
if device_name != default_device_name { match device.name() {
println!(" {}", device_name); Ok(name) if Some(&name) == default_device_name.as_ref() => (),
Ok(name) => {
println!(" {}", name);
list_formats(&device);
}
Err(e) => {
warn!("Cannot get device name: {}", e);
println!(" [unknown name]");
list_formats(&device); list_formats(&device);
} }
} }
exit(0)
} }
fn get_default_device() -> Result<rodio::Device, RodioError> { Ok(())
cpal::default_host() }
.default_output_device()
.ok_or(RodioError::NoDeviceAvailable) fn get_default_device() -> Option<rodio::Device> {
cpal::default_host().default_output_device()
} }
fn create_sink(device: Option<String>) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> { fn create_sink(device: Option<String>) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> {
let rodio_device = match device { let rodio_device = match device {
Some(ask) if &ask == "?" => list_outputs_and_exit(), Some(ask) if &ask == "?" => {
let exit_code = match list_outputs() {
Ok(()) => 0,
Err(e) => {
error!("{}", e);
1
}
};
exit(exit_code)
}
Some(device_name) => { Some(device_name) => {
cpal::default_host() cpal::default_host()
.output_devices()? .output_devices()?
.find(|d| d.name().ok().map_or(false, |name| name == device_name)) // Ignore devices for which getting name fails .find(|d| d.name().ok().map_or(false, |name| name == device_name)) // Ignore devices for which getting name fails
.ok_or(RodioError::DeviceNotAvailable(device_name))? .ok_or(RodioError::DeviceNotAvailable(device_name))?
} }
None => get_default_device()?, None => get_default_device().ok_or(RodioError::NoDeviceAvailable)?,
}; };
let name = rodio_device.name().ok(); let name = rodio_device.name().ok();
info!( info!(
"Using audio device: {}", "Using audio device: {}",
name.as_deref().unwrap_or("(unknown name)") name.as_deref().unwrap_or("[unknown name]")
); );
let (stream, handle) = rodio::OutputStream::try_from_device(&rodio_device)?; let (stream, handle) = rodio::OutputStream::try_from_device(&rodio_device)?;