scope/input/
cpal.rs

1use std::sync::mpsc;
2use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
3
4use super::{stream_to_matrix, Matrix};
5
6pub struct DefaultAudioDeviceWithCPAL {
7	rx: mpsc::Receiver<Matrix<f64>>,
8	#[allow(unused)]
9	stream: cpal::Stream,
10}
11
12#[derive(Debug, thiserror::Error)]
13pub enum AudioDeviceErrors {
14	#[error("{0}")]
15	Device(#[from] cpal::DevicesError),
16
17	#[error("device not found")]
18	NotFound,
19
20	#[error("{0}")]
21	BuildStream(#[from] cpal::BuildStreamError),
22
23	#[error("{0}")]
24	PlayStream(#[from] cpal::PlayStreamError),
25
26	#[error("{0}")]
27	SupportedStreamsError(#[from] cpal::SupportedStreamConfigsError),
28}
29
30impl DefaultAudioDeviceWithCPAL {
31	pub fn instantiate(device: Option<&str>, opts: &crate::cfg::SourceOptions, timeout_secs: u64) -> Result<Box<impl super::DataSource<f64>>, AudioDeviceErrors> {
32		let host = cpal::default_host();
33		let device = match device {
34			Some(name) => host
35				.input_devices()?
36				.find(|x| x.name().as_deref().unwrap_or("") == name)
37				.ok_or(AudioDeviceErrors::NotFound)?,
38			None => host
39				.default_input_device()
40				.ok_or(AudioDeviceErrors::NotFound)?,
41		};
42
43		let max_channels = device
44			.supported_input_configs()?
45			.map(|x| x.channels())
46			.max()
47			.unwrap_or(opts.channels as u16);
48
49		let actual_channels = std::cmp::min(opts.channels as u16, max_channels);
50
51		let cfg = cpal::StreamConfig {
52			channels: actual_channels,
53			buffer_size: cpal::BufferSize::Fixed(opts.buffer),
54			sample_rate: cpal::SampleRate(opts.sample_rate),
55		};
56		let (tx, rx) = mpsc::channel();
57		let stream = device.build_input_stream(
58			&cfg,
59			move |data:&[f32], _info| {
60				tx.send(
61					stream_to_matrix(data.iter().cloned(), actual_channels as usize, 1.)
62				)
63					.unwrap_or(())
64			},
65			|e| eprintln!("error in input stream: {e}"),
66			Some(std::time::Duration::from_secs(timeout_secs)),
67		)?;
68		stream.play()?;
69
70		Ok(Box::new(DefaultAudioDeviceWithCPAL { stream, rx }))
71	}
72}
73
74impl super::DataSource<f64> for DefaultAudioDeviceWithCPAL {
75	fn recv(&mut self) -> Option<super::Matrix<f64>> {
76		match self.rx.recv() {
77			Ok(x) => Some(x),
78			Err(e) => {
79				println!("error receiving from source? {e}");
80				None
81			},
82		}
83	}
84}