rustpbx 0.4.8

A SIP PBX implementation in Rust
Documentation
use audio_codec::CodecType;

pub struct TranscodingPipeline {
    _input_codec: CodecType,
    _output_codec: CodecType,
}

const BIAS: i16 = 0x84;
const CLIP: i16 = 32635;

static PCMU_ENCODE_TABLE: [i16; 256] = {
    let mut table = [0i16; 256];
    let mut i: i16 = 0;
    while i < 256 {
        let val = (i as i16) - 128;
        let sign = if val < 0 { 0x00 } else { 0x80 };
        let mut magnitude = if val < 0 { -val } else { val };
        let mut chord = 7;
        let step: i16;
        if magnitude > 32766 {
            magnitude = 32766;
        }
        magnitude += BIAS;
        if magnitude > CLIP {
            magnitude = CLIP;
        }
        let mut mag = magnitude as i16;
        while mag > 15 {
            mag >>= 1;
            chord -= 1;
            if chord < 0 {
                chord = 0;
                break;
            }
        }
        step = ((chord as i16) << 4) | (mag - 15) as i16;
        table[i as usize] = (sign | step as u8 as i16) ^ 0xFF;
        i += 1;
    }
    table
};

static PCMU_DECODE_TABLE: [i16; 256] = {
    let mut table = [0i16; 256];
    let mut i: i16 = 0;
    while i < 256 {
        let val = (i as u8) ^ 0xFF;
        let sign = if (val & 0x80) != 0 { 1i16 } else { -1i16 };
        let chord = ((val & 0x70) >> 4) as i16;
        let step = (val & 0x0F) as i16;
        let mut magnitude = ((step << 1) + 33) << chord;
        magnitude -= 33;
        table[i as usize] = sign * magnitude as i16;
        i += 1;
    }
    table
};

impl TranscodingPipeline {
    pub fn new(input_codec: CodecType, output_codec: CodecType) -> Self {
        Self {
            _input_codec: input_codec,
            _output_codec: output_codec,
        }
    }

    pub fn encode_from_pcm(&self, pcm: &[i16]) -> Vec<u8> {
        let mut encoded = Vec::with_capacity(pcm.len());
        for &sample in pcm {
            let s = sample.clamp(-32768, 32767);
            let idx = ((s >> 8) + 128) as usize;
            encoded.push(PCMU_ENCODE_TABLE[idx] as u8);
        }
        encoded
    }

    pub fn decode_to_pcm(&self, encoded: &[u8]) -> Vec<i16> {
        let mut pcm = Vec::with_capacity(encoded.len());
        for &byte in encoded {
            pcm.push(PCMU_DECODE_TABLE[byte as usize]);
        }
        pcm
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_pcmu_roundtrip() {
        let 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_eq!(encoded.len(), 160);
        let decoded = pipeline.decode_to_pcm(&encoded);
        assert_eq!(decoded.len(), 160);
    }
}