use crate::error::{RtAudioError, RtAudioErrorType};
use crate::wrapper::RtAudioWrapper;
use crate::{Api, DeviceID, DeviceInfo, SessionID, StreamConfig, StreamHandle};
#[cfg(all(feature = "log", not(feature = "tracing")))]
use log::warn;
#[cfg(feature = "tracing")]
use tracing::warn;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FindDeviceInfo {
pub index: usize,
pub session_id: SessionID,
}
pub struct Host {
pub(crate) wrapper: RtAudioWrapper,
pub(crate) devices: Vec<DeviceInfo>,
}
impl Host {
pub fn new(api: Api) -> Result<Self, RtAudioError> {
let mut new_self = Self {
wrapper: RtAudioWrapper::new(api)?,
devices: Vec::new(),
};
new_self.refresh_devices();
Ok(new_self)
}
pub fn show_warnings(&mut self, show: bool) {
self.wrapper.show_warnings(show);
}
pub fn api(&self) -> Api {
self.wrapper.api()
}
pub fn refresh_devices(&mut self) {
let num_devices = self.wrapper.num_devices();
self.devices.clear();
for i in 0..num_devices {
let session_id = self.wrapper.get_device_session_id_at_index(i);
let info = if session_id.is_none() {
Err(RtAudioError {
type_: RtAudioErrorType::InvalidParamter,
msg: Some(format!("Could not find device at index {}", i)),
})
} else if let Err(e) = self.wrapper.check_for_error() {
Err(e)
} else {
self.wrapper.get_device_info(session_id.unwrap())
};
match info {
Ok(info) => self.devices.push(info),
Err(e) => {
#[cfg(not(any(feature = "tracing", feature = "log")))]
let _ = e;
#[cfg(any(feature = "tracing", feature = "log"))]
warn!("Error while scanning audio device at index {}: {}", i, e);
}
}
}
}
pub fn find_device(&self, id: &DeviceID) -> Option<FindDeviceInfo> {
let mut first_matching_name_idx = None;
for (i, device_info) in self.devices.iter().enumerate() {
let name_matches = device_info.name() == &id.name;
if first_matching_name_idx.is_none() && name_matches {
first_matching_name_idx = Some(i);
}
if name_matches && device_info.id.session_id == id.session_id {
return Some(FindDeviceInfo {
index: i,
session_id: id.session_id,
});
}
}
first_matching_name_idx.map(|i| FindDeviceInfo {
index: i,
session_id: self.devices[i].id.session_id,
})
}
pub fn devices(&self) -> &[DeviceInfo] {
&self.devices
}
pub fn iter_output_devices<'a>(&'a self) -> impl Iterator<Item = &'a DeviceInfo> {
self.devices.iter().filter(|d| d.output_channels > 0)
}
pub fn iter_input_devices<'a>(&'a self) -> impl Iterator<Item = &'a DeviceInfo> {
self.devices.iter().filter(|d| d.input_channels > 0)
}
pub fn iter_duplex_devices<'a>(&'a self) -> impl Iterator<Item = &'a DeviceInfo> {
self.devices.iter().filter(|d| d.duplex_channels > 0)
}
pub fn default_input_device_index(&self) -> Option<usize> {
self.devices
.iter()
.position(|d| d.is_default_input && d.input_channels > 0)
}
pub fn default_output_device_index(&self) -> Option<usize> {
self.devices
.iter()
.position(|d| d.is_default_output && d.output_channels > 0)
}
pub fn default_duplex_device_index(&self) -> Option<usize> {
self.devices
.iter()
.position(|d| (d.is_default_input || d.is_default_output) && d.duplex_channels > 0)
}
pub fn open_stream(self, config: &StreamConfig) -> Result<StreamHandle, (Self, RtAudioError)> {
StreamHandle::new(self, config)
}
}
impl Default for Host {
fn default() -> Self {
Self::new(Api::Unspecified).unwrap()
}
}
impl std::fmt::Debug for Host {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Host").finish()
}
}