poppy 0.0.1

[WIP] An opus implementation in pure rust
Documentation

use std::num::NonZeroU16;
use std::fmt::{self, Display};
use ::common::types::{
    Bandwidth,
    FrameSize,
    Channels,
};
use ::common::util::div_rem;


#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Mode {
    Silk,
    Celt,
    Hybrid,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PacketLength<'a> {
    Single,
    DoubleEq,
    Double(NonZeroU16),
    VariableCbr(NonZeroU16),
    VariableVbr(&'a [u8]),
}

#[derive(Debug)]
pub struct Packet<'a> {
    //header: header::PacketHeader,
    mode: Mode,
    bandwidth: Bandwidth,
    frame_size: FrameSize,
    channels: Channels,
    length: PacketLength<'a>,
    data: &'a [u8],
}

impl<'a> Display for Packet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Packet {{\n\tmode: {:?},\n\tbandwidth: {:?},\n\tframe size: {:?},\n\tchannels: {:?},\n\ttype: {:?},\n\tpackage length: {}\n}}", 
            self.mode, self.bandwidth, self.frame_size, self.channels, self.length, self.data.len())
    }
}

#[derive(Debug)]
pub enum PacketErrorKind {
    InvalidLength,
    InvalidFormat,
    Dtx,
}

impl<'a> Packet<'a> {
    pub fn read(data: &'a [u8]) -> Result<Self, PacketErrorKind> {
        let (&toc, mut data) = data.split_first().ok_or(PacketErrorKind::InvalidLength)?;
        let channels = match toc & 4 {
            0 => Channels::Mono,
            4 => Channels::Stereo,
            _ => unreachable!(),
        };

        let length = match toc & 3 {
            0 => {
                if data.len() <= 1275 {
                    PacketLength::Single
                } else {
                    return Err(PacketErrorKind::InvalidLength);
                }
            },
            1 => {
                let len = data.len();
                if len & 1 == 0 && len <= 2550 {
                    PacketLength::DoubleEq
                } else {
                    return Err(PacketErrorKind::InvalidLength);
                }
            },
            2 => {
                let res = length(data)?;
                if res.0.get() as usize > res.1.len() {
                    return Err(PacketErrorKind::InvalidLength);
                }
                data = res.1;
                PacketLength::Double(res.0)
            },
            3 => {
                let (&config, split_data) = data.split_first().ok_or(PacketErrorKind::InvalidLength)?;
                data = split_data;
                if config & 64 == 64 {
                    let (padding_len, striped_data) = padding_length(data).ok_or(PacketErrorKind::InvalidLength)?;
                    let striped_data_len = striped_data.len();
                    if padding_len > striped_data_len {
                        return Err(PacketErrorKind::InvalidLength);
                    }
                    data = &striped_data[..striped_data_len-padding_len];
                }
                let frame_count = config & 63;
                if frame_count == 0 { return Err(PacketErrorKind::InvalidFormat) }
                
                fn length_internal(data: &[u8]) -> Result<(usize, bool), PacketErrorKind> {
                    let frame_size_one = usize::from(*data.get(0).ok_or(PacketErrorKind::InvalidLength)?);
                    if frame_size_one == 0 {
                        Err(PacketErrorKind::Dtx)
                    } else if frame_size_one <= 251 {
                        Ok((frame_size_one, false))
                    } else {
                        let frame_size_two = usize::from(*data.get(1).ok_or(PacketErrorKind::InvalidLength)?);
                        Ok((frame_size_two * 4 + frame_size_one, true))
                    }
                }

                if config & 128 == 128 {
                    let mut sum = 0;
                    let mut cursor = 0;
                    for _ in 0..frame_count-1 {
                        let (val, double) = length_internal(&data[cursor..])?;
                        if double { cursor += 2 } else { cursor += 1 }
                        sum += val as usize;
                    }
                    let (lengths, split_data) = data.split_at(cursor);
                    data = split_data;
                    if data.len() < sum { return Err(PacketErrorKind::InvalidLength) }
                    PacketLength::VariableVbr(lengths)
                } else {
                    let (res, rem) = div_rem(data.len(), frame_count as usize);
                    if rem != 0 || res > 1275{ return Err(PacketErrorKind::InvalidLength) }
                    PacketLength::VariableCbr(unsafe { NonZeroU16::new_unchecked(res as u16) })
                }

            },
            _ => unreachable!(),
        };

        let config = toc >> 3;
        let (mode, bandwidth, frame_size) = match config {
            x if x & 0x10 == 0x10 => (
                Mode::Celt,
                celt_bandwidth(config),
                celt_frame_size(config),
            ),
            x if x & 0xC == 0xC => (
                Mode::Hybrid,
                hybrid_bandwidth(config),
                hybrid_frame_size(config),
            ),
            _ => (
                Mode::Silk,
                silk_bandwidth(config),
                silk_frame_size(config),
            )
        };

        Ok(Self {
            mode,
            bandwidth,
            frame_size,
            channels,
            length,
            data,
        })
    }

    pub fn frames(&self) -> Frames {
        Frames {
            length: self.length,
            second: false,
            data: self.data,
        }
    }

    pub fn mode(&self) -> Mode {
        self.mode
    }

    pub fn bandwidth(&self) -> Bandwidth {
        self.bandwidth
    }

    pub fn channels(&self) -> Channels {
        self.channels
    }

    pub fn frame_size(&self) -> FrameSize {
        self.frame_size
    }
}

fn length(data: &[u8]) -> Result<(NonZeroU16, &[u8]), PacketErrorKind> {
    let frame_size_one = u16::from(*data.get(0).ok_or(PacketErrorKind::InvalidLength)?);
    if frame_size_one == 0 {
        Err(PacketErrorKind::Dtx)
    } else if frame_size_one <= 251 {
        Ok((unsafe { NonZeroU16::new_unchecked(frame_size_one) }, &data[1..]))
    } else {
        let frame_size_two = u16::from(*data.get(1).ok_or(PacketErrorKind::InvalidLength)?);
        Ok((unsafe { NonZeroU16::new_unchecked(frame_size_two * 4 + frame_size_one) }, &data[2..]))
    }
}

fn padding_length(data: &[u8]) -> Option<(usize, &[u8])> {
    let mut len = 0;
    for (i, &val) in data.iter().enumerate() {
        len += val as usize;
        if val != 255 {
            return Some((len, &data[i+1..]));
        }
    }
    None
}

fn length_unchecked(data: &[u8]) -> (usize, &[u8]) {
    let frame_size_one = unsafe { *data.get_unchecked(0) as usize };
    if frame_size_one <= 251 {
        (frame_size_one, &data[1..])
    } else {
        let frame_size_two = unsafe { *data.get_unchecked(1) as usize};
        (frame_size_two * 4 + frame_size_one, &data[2..])
    }
}

pub struct Frames<'a> {
    length: PacketLength<'a>,
    data: &'a [u8],
    second: bool,
}

impl<'a> Iterator for Frames<'a> {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<Self::Item> {
        if self.data.is_empty() { 
            None 
        } else {
            match self.length {
                PacketLength::Single => {
                    let ret = self.data;
                    self.data = &[0; 0];
                    Some(ret)
                }
                PacketLength::DoubleEq |
                PacketLength::Double(_) |
                PacketLength::VariableVbr(_)
                if self.second => { 
                    let ret = self.data;
                    self.data = &[0; 0];
                    Some(ret)
                },
                PacketLength::DoubleEq => {
                    let (ret, data) = self.data.split_at(self.data.len()/2);
                    self.data = data;
                    self.second = true;
                    Some(ret)
                },
                PacketLength::Double(len) => {
                    let (ret, data) = self.data.split_at(len.get() as usize);
                    self.data = data;
                    self.second = true;
                    Some(ret)
                },
                PacketLength::VariableCbr(frame_length) => {
                    let (res, split_data) = self.data.split_at(frame_length.get() as usize);
                    self.data = split_data;
                    Some(res)
                },
                PacketLength::VariableVbr(ref mut lengths) => {
                    let (len, split_lengths) = length_unchecked(lengths);
                    let (ret, data) = self.data.split_at(len);
                    self.data = data;
                    if split_lengths.is_empty() { self.second = true }
                    *lengths = split_lengths;
                    Some(ret)
                }
            }
        }
    }
}



fn celt_frame_size(val: u8) -> FrameSize {
    match val & 3 {
        0 => FrameSize::Ms2_5,
        1 => FrameSize::Ms5,
        2 => FrameSize::Ms10,
        3 => FrameSize::Ms20,
        _ => unreachable!(),
    }
}

fn celt_bandwidth(val: u8) -> Bandwidth {
    match val & 0xC {
        0 => Bandwidth::Narrow,
        4 => Bandwidth::Wide,
        8 => Bandwidth::SuperWide,
        12 => Bandwidth::Full,
        _ => unreachable!(),
    }
}

fn hybrid_frame_size(val: u8) -> FrameSize {
    match val & 1 {
        0 => FrameSize::Ms10,
        1 => FrameSize::Ms20,
        _ => unreachable!(),
    }
}

fn hybrid_bandwidth(val: u8) -> Bandwidth {
    match val & 2 {
        0 => Bandwidth::SuperWide,
        2 => Bandwidth::Full,
        _ => unreachable!(),
    }
}

fn silk_frame_size(val: u8) -> FrameSize {
    match val & 3 {
        0 => FrameSize::Ms10,
        1 => FrameSize::Ms20,
        2 => FrameSize::Ms40,
        3 => FrameSize::Ms60,
        _ => unreachable!(),
    }
}

fn silk_bandwidth(val: u8) -> Bandwidth {
    match val & 0xC {
        0 => Bandwidth::Narrow,
        4 => Bandwidth::Medium,
        8 => Bandwidth::Wide,
        _ => unreachable!(),
    }
}