use cpal::traits::{EventLoopTrait, HostTrait};
use std::marker::PhantomData;
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
pub use self::buffer::Buffer;
pub use self::device::{Device, Devices};
pub use self::receiver::Receiver;
pub use self::requester::Requester;
pub use self::stream::Stream;
pub use cpal;
#[doc(inline)]
pub use cpal::{
BackendSpecificError, BuildStreamError, DefaultFormatError, DeviceNameError, DevicesError,
PauseStreamError, PlayStreamError, StreamError, SupportedFormatsError,
};
#[doc(inline)]
pub use cpal::{Format, HostId, HostUnavailable, SupportedInputFormats, SupportedOutputFormats};
pub use sample;
pub mod buffer;
pub mod device;
pub mod receiver;
pub mod requester;
pub mod stream;
pub struct Host {
host: Arc<cpal::Host>,
event_loop: Arc<cpal::EventLoop>,
process_fn_tx: Mutex<Option<mpsc::Sender<stream::ProcessFnMsg>>>,
}
impl Host {
pub fn from_id(id: HostId) -> Result<Self, HostUnavailable> {
let host = cpal::host_from_id(id)?;
Ok(Self::from_cpal_host(host))
}
pub fn new() -> Self {
let host = cpal::default_host();
Self::from_cpal_host(host)
}
fn from_cpal_host(host: cpal::Host) -> Self {
let host = Arc::new(host);
let event_loop = Arc::new(host.event_loop());
let process_fn_tx = Mutex::new(None);
Host {
host,
event_loop,
process_fn_tx,
}
}
pub fn devices(&self) -> Result<Devices, DevicesError> {
let devices = self.host.devices()?;
Ok(Devices { devices })
}
pub fn input_devices(&self) -> Result<stream::input::Devices, DevicesError> {
let devices = self.host.input_devices()?;
Ok(stream::input::Devices { devices })
}
pub fn output_devices(&self) -> Result<stream::output::Devices, DevicesError> {
let devices = self.host.output_devices()?;
Ok(stream::output::Devices { devices })
}
pub fn default_input_device(&self) -> Option<Device> {
self.host
.default_input_device()
.map(|device| Device { device })
}
pub fn default_output_device(&self) -> Option<Device> {
self.host
.default_output_device()
.map(|device| Device { device })
}
pub fn new_input_stream<M, S>(&self, model: M) -> stream::input::BuilderInit<M, S> {
stream::input::Builder {
capture: Default::default(),
builder: self.new_stream(model),
}
}
pub fn new_output_stream<M, S>(&self, model: M) -> stream::output::BuilderInit<M, S> {
stream::output::Builder {
render: Default::default(),
builder: self.new_stream(model),
}
}
fn new_stream<M, S>(&self, model: M) -> stream::Builder<M, S> {
let process_fn_tx = if self.process_fn_tx.lock().unwrap().is_none() {
let event_loop = self.event_loop.clone();
let (tx, rx) = mpsc::channel();
let mut loop_context = stream::LoopContext::new(rx);
thread::Builder::new()
.name("cpal::EventLoop::run thread".into())
.spawn(move || event_loop.run(move |id, data| loop_context.process(id, data)))
.expect("failed to spawn cpal::EventLoop::run thread");
*self.process_fn_tx.lock().unwrap() = Some(tx.clone());
tx
} else {
self.process_fn_tx.lock().unwrap().as_ref().unwrap().clone()
};
stream::Builder {
host: self.host.clone(),
event_loop: self.event_loop.clone(),
process_fn_tx: process_fn_tx,
model,
sample_rate: None,
channels: None,
frames_per_buffer: None,
device: None,
sample_format: PhantomData,
}
}
}
impl Default for Host {
fn default() -> Self {
Self::new()
}
}