use core::time::Duration;
use std::fmt;
use crate::{
traits::{DeviceTrait, HostTrait, StreamTrait},
Data, DeviceDescription, DeviceId, Error, ErrorKind, FrameCount, InputCallbackInfo,
OutputCallbackInfo, SampleFormat, StreamConfig, StreamInstant, SupportedStreamConfig,
SupportedStreamConfigRange,
};
pub struct Host(Box<dyn HostErased>);
impl Host {
pub(crate) fn new() -> Result<Self, Error> {
Err(Error::new(ErrorKind::HostUnavailable))
}
pub fn from_host<T>(host: T) -> Self
where
T: HostTrait + Send + Sync + 'static,
T::Device: Send + Sync + Clone,
<T::Device as DeviceTrait>::SupportedInputConfigs: Clone,
<T::Device as DeviceTrait>::SupportedOutputConfigs: Clone,
<T::Device as DeviceTrait>::Stream: Send + Sync,
{
Self(Box::new(host))
}
}
pub struct Device(Box<dyn DeviceErased>);
impl Device {
pub fn from_device<T>(device: T) -> Self
where
T: DeviceTrait + Send + Sync + Clone + 'static,
T::SupportedInputConfigs: Clone,
T::SupportedOutputConfigs: Clone,
T::Stream: Send + Sync,
{
Self(Box::new(device))
}
}
impl Clone for Device {
fn clone(&self) -> Self {
self.0.clone()
}
}
impl PartialEq for Device {
fn eq(&self, other: &Self) -> bool {
DeviceTrait::id(self).ok() == DeviceTrait::id(other).ok()
}
}
impl Eq for Device {}
impl std::hash::Hash for Device {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
DeviceTrait::id(self).ok().hash(state);
}
}
impl fmt::Display for Device {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let desc = DeviceTrait::description(self).map_err(|_| fmt::Error)?;
f.write_str(desc.name())
}
}
impl fmt::Debug for Device {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Device")
.field(&DeviceTrait::description(self).map(|d| d.name().to_owned()))
.finish()
}
}
pub struct Stream(Box<dyn StreamErased>);
impl Stream {
pub fn from_stream<T>(stream: T) -> Self
where
T: StreamTrait + Send + Sync + 'static,
{
Self(Box::new(stream))
}
}
type Devices = Box<dyn Iterator<Item = Device>>;
trait HostErased: Send + Sync {
fn devices(&self) -> Result<Devices, Error>;
fn default_input_device(&self) -> Option<Device>;
fn default_output_device(&self) -> Option<Device>;
}
pub struct SupportedConfigs(Box<dyn SupportedConfigsErased>);
trait SupportedConfigsErased: Iterator<Item = SupportedStreamConfigRange> {
fn clone(&self) -> SupportedConfigs;
}
impl<T> SupportedConfigsErased for T
where
T: Iterator<Item = SupportedStreamConfigRange> + Clone + 'static,
{
fn clone(&self) -> SupportedConfigs {
SupportedConfigs(Box::new(Clone::clone(self)))
}
}
impl Iterator for SupportedConfigs {
type Item = SupportedStreamConfigRange;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl Clone for SupportedConfigs {
fn clone(&self) -> Self {
self.0.clone()
}
}
type ErrorCallback = Box<dyn FnMut(Error) + Send + 'static>;
type InputCallback = Box<dyn FnMut(&Data, &InputCallbackInfo) + Send + 'static>;
type OutputCallback = Box<dyn FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static>;
trait DeviceErased: Send + Sync {
fn description(&self) -> Result<DeviceDescription, Error>;
fn id(&self) -> Result<DeviceId, Error>;
fn supports_input(&self) -> bool;
fn supports_output(&self) -> bool;
fn supported_input_configs(&self) -> Result<SupportedConfigs, Error>;
fn supported_output_configs(&self) -> Result<SupportedConfigs, Error>;
fn default_input_config(&self) -> Result<SupportedStreamConfig, Error>;
fn default_output_config(&self) -> Result<SupportedStreamConfig, Error>;
fn build_input_stream_raw(
&self,
config: StreamConfig,
sample_format: SampleFormat,
data_callback: InputCallback,
error_callback: ErrorCallback,
timeout: Option<Duration>,
) -> Result<Stream, Error>;
fn build_output_stream_raw(
&self,
config: StreamConfig,
sample_format: SampleFormat,
data_callback: OutputCallback,
error_callback: ErrorCallback,
timeout: Option<Duration>,
) -> Result<Stream, Error>;
fn clone(&self) -> Device;
}
trait StreamErased: Send + Sync {
fn play(&self) -> Result<(), Error>;
fn pause(&self) -> Result<(), Error>;
fn now(&self) -> StreamInstant;
fn buffer_size(&self) -> Result<FrameCount, Error>;
}
fn device_to_erased(d: impl DeviceErased + 'static) -> Device {
Device(Box::new(d))
}
impl<T> HostErased for T
where
T: HostTrait + Send + Sync,
T::Devices: 'static,
T::Device: DeviceErased + 'static,
{
fn devices(&self) -> Result<Devices, Error> {
let iter = <T as HostTrait>::devices(self)?;
let erased = Box::new(iter.map(device_to_erased));
Ok(erased)
}
fn default_input_device(&self) -> Option<Device> {
<T as HostTrait>::default_input_device(self).map(device_to_erased)
}
fn default_output_device(&self) -> Option<Device> {
<T as HostTrait>::default_output_device(self).map(device_to_erased)
}
}
fn supported_configs_to_erased(
i: impl Iterator<Item = SupportedStreamConfigRange> + Clone + 'static,
) -> SupportedConfigs {
SupportedConfigs(Box::new(i))
}
fn stream_to_erased(s: impl StreamTrait + Send + Sync + 'static) -> Stream {
Stream(Box::new(s))
}
impl<T> DeviceErased for T
where
T: DeviceTrait + Send + Sync + Clone + 'static,
T::SupportedInputConfigs: Clone + 'static,
T::SupportedOutputConfigs: Clone + 'static,
T::Stream: Send + Sync + 'static,
{
fn description(&self) -> Result<DeviceDescription, Error> {
<T as DeviceTrait>::description(self)
}
fn id(&self) -> Result<DeviceId, Error> {
<T as DeviceTrait>::id(self)
}
fn supports_input(&self) -> bool {
<T as DeviceTrait>::supports_input(self)
}
fn supports_output(&self) -> bool {
<T as DeviceTrait>::supports_output(self)
}
fn supported_input_configs(&self) -> Result<SupportedConfigs, Error> {
<T as DeviceTrait>::supported_input_configs(self).map(supported_configs_to_erased)
}
fn supported_output_configs(&self) -> Result<SupportedConfigs, Error> {
<T as DeviceTrait>::supported_output_configs(self).map(supported_configs_to_erased)
}
fn default_input_config(&self) -> Result<SupportedStreamConfig, Error> {
<T as DeviceTrait>::default_input_config(self)
}
fn default_output_config(&self) -> Result<SupportedStreamConfig, Error> {
<T as DeviceTrait>::default_output_config(self)
}
fn build_input_stream_raw(
&self,
config: StreamConfig,
sample_format: SampleFormat,
data_callback: InputCallback,
error_callback: ErrorCallback,
timeout: Option<Duration>,
) -> Result<Stream, Error> {
<T as DeviceTrait>::build_input_stream_raw(
self,
config,
sample_format,
data_callback,
error_callback,
timeout,
)
.map(stream_to_erased)
}
fn build_output_stream_raw(
&self,
config: StreamConfig,
sample_format: SampleFormat,
data_callback: OutputCallback,
error_callback: ErrorCallback,
timeout: Option<Duration>,
) -> Result<Stream, Error> {
<T as DeviceTrait>::build_output_stream_raw(
self,
config,
sample_format,
data_callback,
error_callback,
timeout,
)
.map(stream_to_erased)
}
fn clone(&self) -> Device {
device_to_erased(Clone::clone(self))
}
}
impl<T> StreamErased for T
where
T: StreamTrait + Send + Sync,
{
fn play(&self) -> Result<(), Error> {
<T as StreamTrait>::play(self)
}
fn pause(&self) -> Result<(), Error> {
<T as StreamTrait>::pause(self)
}
fn now(&self) -> StreamInstant {
<T as StreamTrait>::now(self)
}
fn buffer_size(&self) -> Result<FrameCount, Error> {
<T as StreamTrait>::buffer_size(self)
}
}
impl HostTrait for Host {
type Devices = Devices;
type Device = Device;
fn is_available() -> bool {
false
}
fn devices(&self) -> Result<Self::Devices, Error> {
self.0.devices()
}
fn default_input_device(&self) -> Option<Self::Device> {
self.0.default_input_device()
}
fn default_output_device(&self) -> Option<Self::Device> {
self.0.default_output_device()
}
}
impl DeviceTrait for Device {
type SupportedInputConfigs = SupportedConfigs;
type SupportedOutputConfigs = SupportedConfigs;
type Stream = Stream;
fn description(&self) -> Result<DeviceDescription, Error> {
self.0.description()
}
fn id(&self) -> Result<DeviceId, Error> {
self.0.id()
}
fn supports_input(&self) -> bool {
self.0.supports_input()
}
fn supports_output(&self) -> bool {
self.0.supports_output()
}
fn supported_input_configs(&self) -> Result<Self::SupportedInputConfigs, Error> {
self.0.supported_input_configs()
}
fn supported_output_configs(&self) -> Result<Self::SupportedOutputConfigs, Error> {
self.0.supported_output_configs()
}
fn default_input_config(&self) -> Result<SupportedStreamConfig, Error> {
self.0.default_input_config()
}
fn default_output_config(&self) -> Result<SupportedStreamConfig, Error> {
self.0.default_output_config()
}
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,
{
self.0.build_input_stream_raw(
config,
sample_format,
Box::new(data_callback),
Box::new(error_callback),
timeout,
)
}
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,
{
self.0.build_output_stream_raw(
config,
sample_format,
Box::new(data_callback),
Box::new(error_callback),
timeout,
)
}
}
impl StreamTrait for Stream {
fn play(&self) -> Result<(), Error> {
self.0.play()
}
fn pause(&self) -> Result<(), Error> {
self.0.pause()
}
fn now(&self) -> StreamInstant {
self.0.now()
}
fn buffer_size(&self) -> Result<FrameCount, Error> {
self.0.buffer_size()
}
}