mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Improved error handling in rodio backend
This commit is contained in:
parent
b2f1be4374
commit
689415a6f1
1 changed files with 64 additions and 39 deletions
|
@ -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)?;
|
||||||
|
|
Loading…
Reference in a new issue