use audio_codec::{CodecType, create_decoder, create_encoder};
pub struct TranscodingPipeline {
input_codec: CodecType,
output_codec: CodecType,
decoder: Box<dyn audio_codec::Decoder>,
encoder: Box<dyn audio_codec::Encoder>,
resampler_input: Option<LinearResampler>,
resampler_output: Option<LinearResampler>,
}
impl TranscodingPipeline {
pub fn new(input_codec: CodecType, output_codec: CodecType) -> Self {
let decoder = create_decoder(input_codec);
let encoder = create_encoder(output_codec);
let input_sample_rate = decoder.sample_rate();
let output_sample_rate = encoder.sample_rate();
let resampler_input = if input_sample_rate != 8000 {
Some(LinearResampler::new(input_sample_rate, 8000))
} else {
None
};
let resampler_output = if output_sample_rate != 8000 {
Some(LinearResampler::new(8000, output_sample_rate))
} else {
None
};
Self {
input_codec,
output_codec,
decoder,
encoder,
resampler_input,
resampler_output,
}
}
pub fn decode_to_pcm(&mut self, payload: &[u8]) -> Vec<i16> {
let mut pcm = self.decoder.decode(payload);
if let Some(ref mut resampler) = self.resampler_input {
pcm = resampler.resample(&pcm);
}
pcm
}
pub fn encode_from_pcm(&mut self, pcm: &[i16]) -> Vec<u8> {
let mut pcm = pcm.to_vec();
if let Some(ref mut resampler) = self.resampler_output {
pcm = resampler.resample(&pcm);
}
self.encoder.encode(&pcm)
}
pub fn input_codec(&self) -> CodecType {
self.input_codec
}
pub fn output_codec(&self) -> CodecType {
self.output_codec
}
}
pub struct LinearResampler {
src_rate: u32,
dst_rate: u32,
ratio: f32,
}
impl LinearResampler {
pub fn new(src_rate: u32, dst_rate: u32) -> Self {
Self {
src_rate,
dst_rate,
ratio: src_rate as f32 / dst_rate as f32,
}
}
pub fn resample(&mut self, samples: &[i16]) -> Vec<i16> {
if self.src_rate == self.dst_rate {
return samples.to_vec();
}
let new_len = (samples.len() as f32 / self.ratio) as usize;
let mut result = Vec::with_capacity(new_len);
for i in 0..new_len {
let src_idx = i as f32 * self.ratio;
let src_idx_floor = src_idx.floor() as usize;
let src_idx_ceil = (src_idx.ceil() as usize).min(samples.len().saturating_sub(1));
let frac = src_idx - src_idx.floor();
let sample = if src_idx_floor == src_idx_ceil {
samples[src_idx_floor]
} else {
let s0 = samples[src_idx_floor] as f32;
let s1 = samples[src_idx_ceil] as f32;
(s0 + frac * (s1 - s0)) as i16
};
result.push(sample);
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_transcoding_pipeline_pcmu_to_pcmu() {
let mut pipeline = TranscodingPipeline::new(CodecType::PCMU, CodecType::PCMU);
let pcm: Vec<i16> = (0..160).map(|i| (i as i16 * 100) % 32767).collect();
let encoded = pipeline.encode_from_pcm(&pcm);
assert!(!encoded.is_empty());
let decoded = pipeline.decode_to_pcm(&encoded);
assert_eq!(decoded.len(), 160);
}
#[test]
fn test_linear_resampler_16khz_to_8khz() {
let mut resampler = LinearResampler::new(16000, 8000);
let samples: Vec<i16> = (0..320).map(|i| (i as i16 * 100) % 32767).collect();
let resampled = resampler.resample(&samples);
assert_eq!(resampled.len(), 160);
}
#[test]
fn test_linear_resampler_8khz_to_16khz() {
let mut resampler = LinearResampler::new(8000, 16000);
let samples: Vec<i16> = (0..160).map(|i| (i as i16 * 100) % 32767).collect();
let resampled = resampler.resample(&samples);
assert_eq!(resampled.len(), 320);
}
#[test]
fn test_linear_resampler_noop() {
let mut resampler = LinearResampler::new(8000, 8000);
let samples: Vec<i16> = (0..160).map(|i| (i as i16 * 100) % 32767).collect();
let resampled = resampler.resample(&samples);
assert_eq!(resampled.len(), 160);
assert_eq!(resampled, samples);
}
#[test]
fn test_transcoding_pipeline_with_resampling() {
let mut pipeline = TranscodingPipeline::new(CodecType::G722, CodecType::PCMU);
let pcm_16k: Vec<i16> = (0..320).map(|i| (i as i16 * 100) % 32767).collect();
let encoded = pipeline.encode_from_pcm(&pcm_16k);
assert!(!encoded.is_empty());
}
}