use std::{
fmt::{Debug, Display},
hash::Hash,
time::Duration,
};
use crate::{
Data, DeviceDescription, DeviceId, Error, InputCallbackInfo, InputDevices, OutputCallbackInfo,
OutputDevices, SampleFormat, SizedSample, StreamConfig, StreamInstant, SupportedStreamConfig,
SupportedStreamConfigRange,
};
pub trait HostTrait {
type Devices: Iterator<Item = Self::Device>;
type Device: DeviceTrait;
fn is_available() -> bool;
fn devices(&self) -> Result<Self::Devices, Error>;
fn device_by_id(&self, id: &DeviceId) -> Option<Self::Device> {
self.devices()
.ok()?
.find(|device| device.id().ok().as_ref() == Some(id))
}
fn default_input_device(&self) -> Option<Self::Device>;
fn default_output_device(&self) -> Option<Self::Device>;
fn input_devices(&self) -> Result<InputDevices<Self::Devices>, Error> {
Ok(self.devices()?.filter(DeviceTrait::supports_input))
}
fn output_devices(&self) -> Result<OutputDevices<Self::Devices>, Error> {
Ok(self.devices()?.filter(DeviceTrait::supports_output))
}
}
pub trait DeviceTrait: PartialEq + Eq + Hash + Debug + Display {
type SupportedInputConfigs: Iterator<Item = SupportedStreamConfigRange>;
type SupportedOutputConfigs: Iterator<Item = SupportedStreamConfigRange>;
type Stream: StreamTrait;
fn description(&self) -> Result<DeviceDescription, Error>;
fn id(&self) -> Result<DeviceId, Error>;
fn supports_input(&self) -> bool {
self.supported_input_configs()
.is_ok_and(|mut iter| iter.next().is_some())
}
fn supports_output(&self) -> bool {
self.supported_output_configs()
.is_ok_and(|mut iter| iter.next().is_some())
}
fn supported_input_configs(&self) -> Result<Self::SupportedInputConfigs, Error>;
fn supported_output_configs(&self) -> Result<Self::SupportedOutputConfigs, Error>;
fn default_input_config(&self) -> Result<SupportedStreamConfig, Error>;
fn default_output_config(&self) -> Result<SupportedStreamConfig, Error>;
fn build_input_stream<T, D, E>(
&self,
config: StreamConfig,
mut data_callback: D,
error_callback: E,
timeout: Option<Duration>,
) -> Result<Self::Stream, Error>
where
T: SizedSample,
D: FnMut(&[T], &InputCallbackInfo) + Send + 'static,
E: FnMut(Error) + Send + 'static,
{
self.build_input_stream_raw(
config,
T::FORMAT,
move |data, info| {
data_callback(
data.as_slice()
.expect("host supplied incorrect sample type"),
info,
)
},
error_callback,
timeout,
)
}
fn build_output_stream<T, D, E>(
&self,
config: StreamConfig,
mut data_callback: D,
error_callback: E,
timeout: Option<Duration>,
) -> Result<Self::Stream, Error>
where
T: SizedSample,
D: FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static,
E: FnMut(Error) + Send + 'static,
{
self.build_output_stream_raw(
config,
T::FORMAT,
move |data, info| {
data_callback(
data.as_slice_mut()
.expect("host supplied incorrect sample type"),
info,
)
},
error_callback,
timeout,
)
}
fn build_input_stream_raw<D, E>(
&self,
config: StreamConfig,
sample_format: SampleFormat,
data_callback: D,
error_callback: E,
timeout: Option<Duration>,
) -> Result<Self::Stream, Error>
where
D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
E: FnMut(Error) + Send + 'static;
fn build_output_stream_raw<D, E>(
&self,
config: StreamConfig,
sample_format: SampleFormat,
data_callback: D,
error_callback: E,
timeout: Option<Duration>,
) -> Result<Self::Stream, Error>
where
D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
E: FnMut(Error) + Send + 'static;
}
pub trait StreamTrait {
fn play(&self) -> Result<(), Error>;
fn pause(&self) -> Result<(), Error>;
fn buffer_size(&self) -> Result<crate::FrameCount, Error>;
fn now(&self) -> StreamInstant;
}
#[macro_export]
macro_rules! assert_stream_send {
($t:ty) => {
const fn _assert_stream_send<T: Send>() {}
const _: () = _assert_stream_send::<$t>();
};
}
#[macro_export]
macro_rules! assert_stream_sync {
($t:ty) => {
const fn _assert_stream_sync<T: Sync>() {}
const _: () = _assert_stream_sync::<$t>();
};
}