use std::sync::{Arc, Mutex};
use audio_cpp::{load_wav, Backend, Registry, RunMode, TaskKind};
fn main() -> Result<(), audio_cpp::Error> {
let args: Vec<String> = std::env::args().collect();
if args.len() < 3 {
eprintln!("用法: vad_streaming <silero_vad_16k.safetensors> <input.wav>");
std::process::exit(1);
}
let registry = Registry::new()?;
let model = registry.load(&args[1], None, None)?;
let wav = load_wav(&args[2])?;
println!("音频: {}Hz {}ch {}采样", wav.sample_rate, wav.channels, wav.samples.len());
let session = model.create_task_session(
TaskKind::Vad,
RunMode::Streaming,
Backend::Cpu,
0,
4,
None,
)?;
println!("会话: family={} task={} mode={}", session.family(), session.task_kind(), session.run_mode());
println!("流式策略: {:?}", session.streaming_policy()?);
use audio_cpp::StreamEvent;
let events = Arc::new(Mutex::new(Vec::<String>::new()));
let collector = Arc::clone(&events);
let mut session = session;
session.set_event_callback(Some(move |event: StreamEvent| {
for act in &event.voice_activity {
collector.lock().unwrap().push(format!(
"{} @{} (p={:.3})",
act.kind, act.sample, act.probability
));
}
}));
let policy = session.streaming_policy()?;
let chunk = if policy.preferred_audio_chunk_samples > 0 {
policy.preferred_audio_chunk_samples
} else {
512
};
session.start(None)?;
let mut pos = 0usize;
let mut start_sample = 0i64;
while pos < wav.samples.len() {
let end = (pos + chunk).min(wav.samples.len());
let block = &wav.samples[pos..end];
if block.len() == chunk {
session.process_audio(block, wav.sample_rate, wav.channels, start_sample)?;
} else {
let mut padded = vec![0f32; chunk];
padded[..block.len()].copy_from_slice(block);
session.process_audio(&padded, wav.sample_rate, wav.channels, start_sample)?;
}
pos = end;
start_sample += block.len() as i64;
}
let result = session.finish()?;
session.reset();
let events = events.lock().unwrap();
println!("=== 流式事件 ===");
for e in events.iter() {
println!(" {e}");
}
println!("=== 最终语音片段 ===");
for seg in &result.speech_segments {
println!(
" {}..{} 置信度={}",
seg.span.start_sample, seg.span.end_sample, seg.confidence
);
}
Ok(())
}