use crate::error::*;
use cpal::SampleRate;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast;
use tracing::{debug, error, info};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AudioInputConfig {
pub sample_channel_size: usize,
pub use_device: usize,
pub sample_rate: u32,
pub channels: u16,
}
pub struct AudioInput {
stream: cpal::Stream,
sample_sender: broadcast::Sender<f32>,
}
impl AudioInput {
pub fn init(config: AudioInputConfig) -> Result<Self> {
let host = cpal::default_host();
for (device_index, device) in host.input_devices()?.enumerate() {
if device_index == config.use_device {
debug!("using input device {}", device.name()?);
for supported_input_config_range in device.supported_input_configs()? {
if supported_input_config_range.channels().eq(&config.channels)
&& supported_input_config_range
.sample_format()
.eq(&cpal::SampleFormat::F32)
&& let Some(supported_input_config) = supported_input_config_range
.try_with_sample_rate(SampleRate(config.sample_rate))
.map(|x| x.config())
{
info!("input stream config: {:?}", supported_input_config);
let (sample_sender, _) = broadcast::channel(config.sample_channel_size);
let cloned_sample_sender = sample_sender.clone();
let input_stream = device.build_input_stream(
&supported_input_config,
move |data: &[f32], _| {
for &sample in data {
if let Err(e) = cloned_sample_sender.send(sample) {
error!("failed to send sample: {}", e);
return;
}
}
},
|e| {
error!("Audio input stream error: {}", e);
},
None,
)?;
return Ok(Self {
stream: input_stream,
sample_sender,
});
}
}
}
}
Err(NihilityAsrError::Init(
"could not build audio input".to_string(),
))
}
pub fn get_sample_receiver(&self) -> broadcast::Receiver<f32> {
self.sample_sender.subscribe()
}
pub fn play(&self) -> Result<()> {
self.stream.play()?;
Ok(())
}
pub fn pause(&self) -> Result<()> {
self.stream.pause()?;
Ok(())
}
}
impl Default for AudioInputConfig {
fn default() -> Self {
Self {
sample_channel_size: 16000 * 3,
use_device: 0,
sample_rate: 16000,
channels: 1,
}
}
}