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) => { debug!(" Default config:");
warn!("Error getting default rodio::Sink config: {}", e); debug!(" {:?}", cfg);
return;
} }
};
debug!(" Default config:");
debug!(" {:?}", default_fmt);
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() {
debug!(" Available configs:"); Ok(mut cfgs) => {
for format in output_configs { if let Some(first) = cfgs.next() {
debug!(" {:?}", format); debug!(" Available configs:");
debug!(" {:?}", first);
} 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);
list_formats(&default_device);
println!("Other Available Audio Devices:"); if let Some(default_device) = get_default_device() {
for device in cpal::default_host() default_device_name = default_device.name().ok();
.output_devices() println!(
.expect("cannot get list of output devices") "Default Audio Device:\n {}",
{ default_device_name.as_deref().unwrap_or("[unknown name]")
let device_name = device.name().expect("cannot get output name"); );
if device_name != default_device_name {
println!(" {}", device_name); list_formats(&default_device);
list_formats(&device);
println!("Other Available Audio Devices:");
} else {
warn!("No default device was found");
}
for device in cpal::default_host().output_devices()? {
match 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);
}
} }
} }
exit(0) Ok(())
} }
fn get_default_device() -> Result<rodio::Device, RodioError> { fn get_default_device() -> Option<rodio::Device> {
cpal::default_host() cpal::default_host().default_output_device()
.default_output_device()
.ok_or(RodioError::NoDeviceAvailable)
} }
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)?;