Skip to main content

nihility_listener/
input.rs

1use 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/// 音频数据输入配置
9#[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
17/// 音频数据输入
18pub struct AudioInput {
19    stream: cpal::Stream,
20    sample_sender: broadcast::Sender<f32>,
21}
22
23impl AudioInput {
24    /// 初始化音频输入实例,传入音频采用发送实例
25    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    /// 开始接收音频输入
75    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}