use cpal::traits::{DeviceTrait, HostTrait};
use cpal::{Device, Error, ErrorKind, Host, HostId};
pub fn list_hosts() -> Vec<Host> {
cpal::available_hosts()
.into_iter()
.map(|host_id| cpal::host_from_id(host_id).unwrap())
.collect()
}
pub fn get_host_by_id(host_id: HostId) -> Result<Host, Error> {
cpal::host_from_id(host_id)
}
pub fn get_host_by_name(name: &str) -> Result<Host, Error> {
cpal::available_hosts()
.into_iter()
.find(|host_id| host_id.name() == name)
.map(|host_id| cpal::host_from_id(host_id).unwrap())
.ok_or_else(|| {
Error::with_message(
ErrorKind::DeviceNotAvailable,
format!("no host named {name:?}"),
)
})
}
pub fn get_host_in_name(name: &str) -> Result<Host, Error> {
cpal::available_hosts()
.into_iter()
.find(|host_id| host_id.name().to_lowercase().contains(&name.to_lowercase()))
.map(|host_id| cpal::host_from_id(host_id).unwrap())
.ok_or_else(|| {
Error::with_message(
ErrorKind::DeviceNotAvailable,
format!("no host named {name:?}"),
)
})
}
pub fn list_devices(host: Option<Host>) -> Result<Vec<Device>, Error> {
if let Some(host) = host {
Ok(host.output_devices()?.collect())
} else {
Ok(cpal::default_host().output_devices()?.collect())
}
}
pub fn list_device_names() -> Result<Vec<String>, Error> {
Ok(list_devices(None)?.iter().map(Device::to_string).collect())
}
pub fn find_device(name: &str) -> Result<Device, Error> {
let devices = list_devices(None)?;
devices
.iter()
.find(|device| device.to_string() == name)
.or_else(|| {
devices
.iter()
.find(|device| device.to_string().eq_ignore_ascii_case(name))
})
.cloned()
.ok_or_else(|| {
Error::with_message(
ErrorKind::DeviceNotAvailable,
format!("no output device named {name:?}"),
)
})
}
pub fn default_device() -> Option<Device> {
cpal::default_host().default_output_device()
}
pub fn device_name(device: &Device) -> String {
device
.description()
.map(|description| description.name().to_string())
.unwrap_or_else(|_| device.to_string())
}