use cpal::traits::DeviceTrait;
use cpal::{Device, Error, ErrorKind, SampleFormat, Stream, StreamConfig};
use std::marker::PhantomData;
pub mod utils;
pub use utils::{default_device, find_device, list_device_names, list_devices};
pub use crate::output::OutputType as InputType;
pub use crate::output::{device_name, list_hosts, SampleRate, SampleType};
pub struct InputClass<S: SampleType> {
channels: u16,
device: Device,
in_type: InputType,
buffer_size: Option<i32>,
sample_rate: SampleRate,
stream: Option<Stream>,
stream_config: StreamConfig,
callback: Option<Callback<S>>,
sample_type: PhantomData<S>,
output_routing: Option<Vec<Device>>,
}
type Callback<S> = Box<dyn FnMut(&[S]) + Send + 'static>;
impl<S: SampleType> InputClass<S> {
pub fn new(
device: Option<Device>,
in_type: InputType,
sample_rate: SampleRate,
buffer_size: Option<i32>,
callback: impl FnMut(&[S]) + Send + 'static,
) -> Self {
let device =
device.unwrap_or_else(|| default_device().expect("no default input device available"));
let buffer_size_form = match buffer_size {
Some(frames) => cpal::BufferSize::Fixed(frames as u32),
None => cpal::BufferSize::Default,
};
let channels = device
.default_input_config()
.map(|config| config.channels())
.unwrap_or(1);
let stream_config = StreamConfig {
channels,
sample_rate: sample_rate as u32,
buffer_size: buffer_size_form,
};
InputClass {
channels,
device,
in_type,
buffer_size,
sample_rate,
stream: None,
stream_config,
callback: Some(Box::new(callback)),
sample_type: PhantomData,
output_routing: None,
}
}
pub fn with_routing(mut self, devices: Vec<Device>) -> Self {
self.output_routing = Some(devices);
self
}
pub fn set_routing(&mut self, devices: Option<Vec<Device>>) {
self.output_routing = devices;
}
pub fn output_routing(&self) -> Option<&[Device]> {
self.output_routing.as_deref()
}
pub fn channels(&self) -> u16 {
self.channels
}
pub fn device(&self) -> Device {
self.device.clone()
}
pub fn name(&self) -> String {
device_name(&self.device)
}
pub fn buffer_size(&self) -> Option<i32> {
self.buffer_size
}
pub fn sample_rate(&self) -> i32 {
self.sample_rate as i32
}
pub fn sample_format(&self) -> SampleFormat {
S::format()
}
pub fn in_type(&self) -> InputType {
self.in_type
}
pub fn build_stream(&mut self) -> Result<&Stream, Error> {
let mut callback = self.callback.take().ok_or_else(|| {
Error::with_message(
ErrorKind::UnsupportedOperation,
"stream already built for this input",
)
})?;
let stream = self.device.build_input_stream(
self.stream_config,
move |data: &[S], _: &cpal::InputCallbackInfo| callback(data),
Self::err_fn,
None,
)?;
self.stream = Some(stream);
Ok(self.stream.as_ref().unwrap())
}
pub fn set_callback(&mut self, callback: impl FnMut(&[S]) + Send + 'static) {
self.callback = Some(Box::new(callback));
}
pub fn close(&mut self) {
self.stream.take();
}
pub fn stream(&self) -> Option<&Stream> {
self.stream.as_ref()
}
fn err_fn(err: cpal::Error) {
eprintln!("audio input stream error: {}", err);
}
}