#![allow(clippy::unwrap_used, clippy::expect_used)]
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::ptr;
use audio_cpp_sys::*;
unsafe fn take_string(ptr: *mut c_char) -> String {
if ptr.is_null() {
return String::new();
}
let s = unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned();
unsafe { audiocpp_free_string(ptr) };
s
}
unsafe fn last_error(default: &str) -> String {
let p = unsafe { audiocpp_last_error() };
if p.is_null() {
default.to_string()
} else {
unsafe { CStr::from_ptr(p) }.to_string_lossy().into_owned()
}
}
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 3 {
eprintln!(
"用法: vad_offline <silero_vad_16k.safetensors> <input.wav>\n\
例如: cargo run -p audio-cpp-sys --example vad_offline -- \
./silero_vad_16k.safetensors ./speech.wav"
);
std::process::exit(1);
}
let model_path = &args[1];
let wav_path = &args[2];
let registry = unsafe { audiocpp_registry_default() };
assert!(!registry.is_null(), "创建默认注册表失败: {}", unsafe {
last_error("未知错误")
});
let model_path_c = CString::new(model_path.as_str()).expect("模型路径含 NUL");
let model = unsafe {
audiocpp_registry_load(registry, model_path_c.as_ptr(), ptr::null(), ptr::null())
};
if model.is_null() {
let msg = unsafe { last_error("未知错误") };
unsafe { audiocpp_registry_free(registry) };
panic!("加载模型失败: {msg}");
}
println!("模型加载成功: {model_path}");
let task = CString::new("vad").unwrap();
let mode = CString::new("offline").unwrap();
let backend = CString::new("cpu").unwrap();
let session = unsafe {
audiocpp_model_create_task_session(
model,
task.as_ptr(),
mode.as_ptr(),
backend.as_ptr(),
0, 4, ptr::null(),
)
};
if session.is_null() {
let msg = unsafe { last_error("未知错误") };
unsafe {
audiocpp_model_free(model);
audiocpp_registry_free(registry);
}
panic!("创建 VAD 会话失败: {msg}");
}
println!("会话已创建(family={})", unsafe {
let p = audiocpp_session_family(session);
CStr::from_ptr(p).to_string_lossy().into_owned()
});
let request_json = format!(
r#"{{"audio_path":"{}","options":{{"vad_threshold":0.5}}}}"#,
wav_path.replace('\\', "\\\\").replace('"', "\\\"")
);
let request_c = CString::new(request_json).expect("请求含 NUL");
let mut result_json = ptr::null_mut();
let rc = unsafe { audiocpp_session_run_offline(session, request_c.as_ptr(), &mut result_json) };
if rc != 0 {
let msg = unsafe { last_error("未知错误") };
unsafe {
audiocpp_session_free(session);
audiocpp_model_free(model);
audiocpp_registry_free(registry);
}
panic!("离线运行失败: {msg}");
}
let result = unsafe { take_string(result_json) };
println!("=== VAD 结果 ===\n{result}");
unsafe {
audiocpp_session_free(session);
audiocpp_model_free(model);
audiocpp_registry_free(registry);
}
println!("\nvad_offline 完成");
}