nihility_listener/
input.rs1use crate::error::*;
2use cpal::SampleRate;
3use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
4use serde::{Deserialize, Serialize};
5use tokio::sync::broadcast;
6use tracing::{debug, error, info};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AudioInputConfig {
11 pub sample_channel_size: usize,
12 pub use_device: usize,
13 pub sample_rate: u32,
14 pub channels: u16,
15}
16
17pub struct AudioInput {
19 stream: cpal::Stream,
20 sample_sender: broadcast::Sender<f32>,
21}
22
23impl AudioInput {
24 pub fn init(config: AudioInputConfig) -> Result<Self> {
26 let host = cpal::default_host();
27 for (device_index, device) in host.input_devices()?.enumerate() {
28 if device_index == config.use_device {
29 debug!("using input device {}", device.name()?);
30 for supported_input_config_range in device.supported_input_configs()? {
31 if supported_input_config_range.channels().eq(&config.channels)
32 && supported_input_config_range
33 .sample_format()
34 .eq(&cpal::SampleFormat::F32)
35 && let Some(supported_input_config) = supported_input_config_range
36 .try_with_sample_rate(SampleRate(config.sample_rate))
37 .map(|x| x.config())
38 {
39 info!("input stream config: {:?}", supported_input_config);
40 let (sample_sender, _) = broadcast::channel(config.sample_channel_size);
41 let cloned_sample_sender = sample_sender.clone();
42 let input_stream = device.build_input_stream(
43 &supported_input_config,
44 move |data: &[f32], _| {
45 for &sample in data {
46 if let Err(e) = cloned_sample_sender.send(sample) {
47 error!("failed to send sample: {}", e);
48 return;
49 }
50 }
51 },
52 |e| {
53 error!("Audio input stream error: {}", e);
54 },
55 None,
56 )?;
57 return Ok(Self {
58 stream: input_stream,
59 sample_sender,
60 });
61 }
62 }
63 }
64 }
65 Err(NihilityListenerError::Init(
66 "could not build audio input".to_string(),
67 ))
68 }
69
70 pub fn get_sample_receiver(&self) -> broadcast::Receiver<f32> {
71 self.sample_sender.subscribe()
72 }
73
74 pub async fn run(&self) -> Result<()> {
76 self.stream.play()?;
77 Ok(())
78 }
79}
80
81impl Default for AudioInputConfig {
82 fn default() -> Self {
83 Self {
84 sample_channel_size: 16000 * 3,
85 use_device: 0,
86 sample_rate: 16000,
87 channels: 1,
88 }
89 }
90}