use crate::devices::types::AudioDeviceError; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use cpal::{default_host, Device, SampleFormat, Stream}; use dasp::interpolate::sinc::Sinc; use dasp::ring_buffer; use dasp::signal::{self, Signal}; use dasp::Frame; use std::sync::{mpsc::channel, Arc}; use tauri::async_runtime::Mutex; pub struct InputDeviceManager { device: Device, stream: Arc>>, } fn resample( signal: impl Signal, source_hz: f64, target_hz: f64, ) -> impl Signal { let ring_buffer = ring_buffer::Fixed::from([i16::EQUILIBRIUM; 10]); let sinc = Sinc::new(ring_buffer); signal.from_hz_to_hz(sinc, source_hz, target_hz) } impl InputDeviceManager { pub fn new() -> Result { let host = default_host(); let device = host .default_input_device() .ok_or(AudioDeviceError::NoDevicesFound)?; let manager = InputDeviceManager { device, stream: Arc::new(Mutex::new(None)), }; Ok(manager) } pub async fn start_listening(&self) -> impl Signal { let config = self .device .supported_input_configs() .expect("failed to get supported input configs") .find(|c| c.sample_format() == SampleFormat::I16) .expect("failed to find PCM s16 config") .with_max_sample_rate(); let channels = config.channels() as usize; let (tx, rx) = channel::>(); let stream = self .device .build_input_stream( &config.config(), move |data: &[i16], _: &cpal::InputCallbackInfo| { let mono = data .chunks(channels) .map(|frame| (frame.iter().sum::() / channels as i16).to_le()); let _ = tx.send(mono.collect()); }, |err| eprintln!("encountered error streaming input: {}", err), None, ) .expect("failed to create input stream"); stream.play().expect("failed to start input stream"); let samples = rx.into_iter().flat_map(|x| x.into_iter()); let signal = signal::from_iter(samples); let signal = resample(signal, config.sample_rate().0 as f64, 16000.0); let mut s = self.stream.lock().await; *s = Some(stream); signal } pub async fn stop_listening(&self) { let mut s = self.stream.lock().await; *s = None; } }