Skip to main content

audio_cpp/
audio.rs

1//! 音频辅助:WAV 读取等便捷封装。
2//!
3//! # 关于非 WAV 音频格式(mp3 / flac / ogg / m4a …)
4//!
5//! 引擎只接受 **f32 采样**(采样率 + 声道数 + 交错采样数组),不解析容器格式;
6//! [`load_wav`] 是 C 侧内置的 RIFF/WAVE 读取器,仅支持 WAV。要喂给引擎其他
7//! 格式的音频,本 crate **不内置解码库**(避免替用户锁定生态 / 增加依赖),
8//! 而是留出 [`WavAudio`] + `Request::asr` / `vad` / `diar` 等的 `Buffer` 路径——
9//! 用户用任意 Rust 解码库(如 [symphonia]、[rodio]、[hound]、[claxon])解码出
10//! f32 采样后,直接构造 [`WavAudio`] 交给请求即可。
11//!
12//! 完整的可运行示例见 `load_any_audio`(在 `audio-cpp/examples/` 下),
13//! 它用 symphonia 解码 mp3/flac/ogg/m4a 后经 `AudioInput::Buffer` 跑通 VAD 链路。
14//!
15//! [symphonia]: https://crates.io/crates/symphonia
16//! [rodio]: https://crates.io/crates/rodio
17//! [hound]: https://crates.io/crates/hound
18//! [claxon]: https://crates.io/crates/claxon
19
20use std::ffi::c_char;
21use std::os::raw::c_int;
22use std::ptr;
23
24use audio_cpp_sys::*;
25
26use crate::error::Error;
27use crate::ffi;
28
29/// 从 WAV 文件读取的音频数据。
30#[derive(Debug, Clone)]
31pub struct WavAudio {
32    /// 采样率(Hz)。
33    pub sample_rate: i32,
34    /// 声道数。
35    pub channels: i32,
36    /// 采样数据(交错存放,值域 -1..1)。
37    pub samples: Vec<f32>,
38}
39
40/// 将 RIFF/WAVE 文件读取为 `float` 采样。
41///
42/// 底层调用 `audiocpp_audio_load_wav`;返回的缓冲由本函数负责用
43/// `audiocpp_audio_free` 释放(拷贝进 Rust `Vec` 之后)。
44///
45/// # Errors
46///
47/// 路径含 NUL / 非 UTF-8,或文件无法解析为 WAV 时返回对应 [`Error`] 变体。
48pub fn load_wav(path: &str) -> Result<WavAudio, Error> {
49    let path_c = ffi::cstring(path)?;
50    let mut sample_rate: c_int = 0;
51    let mut channels: c_int = 0;
52    let mut count: usize = 0;
53    let mut samples: *mut f32 = ptr::null_mut();
54    let rc = unsafe {
55        audiocpp_audio_load_wav(
56            path_c.as_ptr() as *const c_char,
57            &mut sample_rate,
58            &mut channels,
59            &mut count,
60            &mut samples,
61        )
62    };
63    if rc != 0 {
64        return Err(Error::Ffi(ffi::last_error()));
65    }
66    if samples.is_null() {
67        return Err(Error::Ffi("WAV 读取返回空缓冲".to_string()));
68    }
69    let n = count;
70    // 纵深防御:C 侧谎报超大 count 会导致 from_raw_parts 越界读。
71    // WAV 容器上限 4GiB,f32 采样数不可能超过 u32::MAX。
72    if n > u32::MAX as usize {
73        unsafe { audiocpp_audio_free(samples) };
74        return Err(Error::Ffi(format!("WAV 采样数异常过大: {n}")));
75    }
76    let data = unsafe { std::slice::from_raw_parts(samples, n) }.to_vec();
77    unsafe { audiocpp_audio_free(samples) };
78    Ok(WavAudio {
79        sample_rate,
80        channels,
81        samples: data,
82    })
83}