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}