use crate::Result;
use crate::services::vad::audio_loader::DirectAudioLoader;
use crate::services::vad::detector::AudioInfo;
use std::path::Path;
pub struct VadAudioProcessor {}
#[derive(Debug, Clone)]
pub struct ProcessedAudioData {
pub samples: Vec<i16>,
pub info: AudioInfo,
}
impl VadAudioProcessor {
pub fn new() -> Result<Self> {
Ok(Self {})
}
pub async fn load_and_prepare_audio_direct(
&self,
audio_path: &Path,
) -> Result<ProcessedAudioData> {
let audio_path_buf = audio_path.to_path_buf();
let load_result =
tokio::task::spawn_blocking(move || -> Result<Option<(Vec<i16>, AudioInfo)>> {
let loader = DirectAudioLoader::new()?;
const DEFAULT_MAX_AUDIO_BYTES: u64 = 2_147_483_648;
match loader.load_audio_samples(&audio_path_buf, DEFAULT_MAX_AUDIO_BYTES) {
Ok((samples, info)) => Ok(Some((samples, info))),
Err(e) => {
if let Ok(metadata) = std::fs::metadata(&audio_path_buf) {
if metadata.len() == 0 {
return Ok(None);
}
}
Err(e)
}
}
})
.await
.map_err(|e| crate::error::SubXError::audio_processing(e.to_string()))??;
let (samples, info) = match load_result {
Some(v) => v,
None => {
return Ok(ProcessedAudioData {
samples: vec![],
info: AudioInfo {
sample_rate: 16000, channels: 1,
duration_seconds: 0.0,
total_samples: 0,
},
});
}
};
let mono_samples = if info.channels == 1 {
samples
} else {
self.extract_first_channel(&samples, info.channels as usize)
};
let mono_info = AudioInfo {
sample_rate: info.sample_rate,
channels: 1,
duration_seconds: info.duration_seconds,
total_samples: mono_samples.len(),
};
Ok(ProcessedAudioData {
samples: mono_samples,
info: mono_info,
})
}
fn extract_first_channel(&self, samples: &[i16], channels: usize) -> Vec<i16> {
samples.iter().step_by(channels).copied().collect()
}
}