use alloc::vec::Vec;
use core::fmt;
use core::time::Duration;
pub const MAX_FRAME_LEN: usize = 1275;
const MAX_PACKET_DURATION_TENTH_MS: u32 = 1200;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Mode {
SilkOnly,
Hybrid,
CeltOnly,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Bandwidth {
NarrowBand,
MediumBand,
WideBand,
SuperWideBand,
FullBand,
}
impl Bandwidth {
#[must_use]
pub const fn sample_rate_hz(self) -> u32 {
match self {
Bandwidth::NarrowBand => 8_000,
Bandwidth::MediumBand => 12_000,
Bandwidth::WideBand => 16_000,
Bandwidth::SuperWideBand => 24_000,
Bandwidth::FullBand => 48_000,
}
}
#[must_use]
pub const fn audio_bandwidth_hz(self) -> u32 {
match self {
Bandwidth::NarrowBand => 4_000,
Bandwidth::MediumBand => 6_000,
Bandwidth::WideBand => 8_000,
Bandwidth::SuperWideBand => 12_000,
Bandwidth::FullBand => 20_000,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum FrameSize {
Ms2_5,
Ms5,
Ms10,
Ms20,
Ms40,
Ms60,
}
impl FrameSize {
#[must_use]
pub const fn tenth_ms(self) -> u32 {
match self {
FrameSize::Ms2_5 => 25,
FrameSize::Ms5 => 50,
FrameSize::Ms10 => 100,
FrameSize::Ms20 => 200,
FrameSize::Ms40 => 400,
FrameSize::Ms60 => 600,
}
}
#[must_use]
pub const fn duration(self) -> Duration {
Duration::from_micros(self.tenth_ms() as u64 * 100)
}
#[must_use]
pub const fn samples_per_channel_48k(self) -> usize {
(self.tenth_ms() / 5) as usize * 24
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Toc(u8);
impl Toc {
#[must_use]
pub const fn new(byte: u8) -> Self {
Toc(byte)
}
#[must_use]
pub fn from_parts(config: u8, stereo: bool, frame_count_code: u8) -> Self {
assert!(config < 32, "config must be 0..32");
assert!(frame_count_code < 4, "frame count code must be 0..4");
Toc((config << 3) | (u8::from(stereo) << 2) | frame_count_code)
}
#[must_use]
pub const fn byte(self) -> u8 {
self.0
}
#[must_use]
pub const fn config(self) -> u8 {
self.0 >> 3
}
#[must_use]
pub const fn stereo(self) -> bool {
(self.0 >> 2) & 1 == 1
}
#[must_use]
pub const fn channels(self) -> u8 {
1 + ((self.0 >> 2) & 1)
}
#[must_use]
pub const fn frame_count_code(self) -> u8 {
self.0 & 0x3
}
#[must_use]
pub const fn mode(self) -> Mode {
match self.config() {
0..=11 => Mode::SilkOnly,
12..=15 => Mode::Hybrid,
_ => Mode::CeltOnly,
}
}
#[must_use]
pub const fn bandwidth(self) -> Bandwidth {
match self.config() {
0..=3 => Bandwidth::NarrowBand,
4..=7 => Bandwidth::MediumBand,
8..=11 => Bandwidth::WideBand,
12..=13 => Bandwidth::SuperWideBand,
14..=15 => Bandwidth::FullBand,
16..=19 => Bandwidth::NarrowBand,
20..=23 => Bandwidth::WideBand,
24..=27 => Bandwidth::SuperWideBand,
_ => Bandwidth::FullBand,
}
}
#[must_use]
pub const fn frame_size(self) -> FrameSize {
let config = self.config();
if config < 12 {
match config & 0x3 {
0 => FrameSize::Ms10,
1 => FrameSize::Ms20,
2 => FrameSize::Ms40,
_ => FrameSize::Ms60,
}
} else if config < 16 {
if config & 0x1 == 0 {
FrameSize::Ms10
} else {
FrameSize::Ms20
}
} else {
match config & 0x3 {
0 => FrameSize::Ms2_5,
1 => FrameSize::Ms5,
2 => FrameSize::Ms10,
_ => FrameSize::Ms20,
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum PacketError {
Empty,
FrameTooLarge,
Code1UnevenPayload,
InvalidFrameLength,
InvalidFrameCount,
InvalidPadding,
CbrPayloadNotDivisible,
}
impl fmt::Display for PacketError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
PacketError::Empty => "packet is empty [R1]",
PacketError::FrameTooLarge => "frame length exceeds 1275 bytes [R2]",
PacketError::Code1UnevenPayload => "code 1 packet payload length is odd [R3]",
PacketError::InvalidFrameLength => "truncated or overrunning frame length [R4/R7]",
PacketError::InvalidFrameCount => "frame count is zero or exceeds 120 ms [R5]",
PacketError::InvalidPadding => "padding overruns the packet [R6/R7]",
PacketError::CbrPayloadNotDivisible => "CBR payload is not a multiple of the frame count [R6]",
};
f.write_str(msg)
}
}
#[cfg(feature = "std")]
impl std::error::Error for PacketError {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Packet<'a> {
toc: Toc,
frames: Vec<&'a [u8]>,
padding: usize,
}
impl<'a> Packet<'a> {
pub fn parse(data: &'a [u8]) -> Result<Self, PacketError> {
let (&toc_byte, mut rest) = data.split_first().ok_or(PacketError::Empty)?;
let toc = Toc::new(toc_byte);
let mut frames = Vec::new();
let mut padding = 0usize;
match toc.frame_count_code() {
0 => {
check_frame_len(rest.len())?;
frames.push(rest);
},
1 => {
if rest.len() % 2 != 0 {
return Err(PacketError::Code1UnevenPayload);
}
let half = rest.len() / 2;
check_frame_len(half)?;
let (a, b) = rest.split_at(half);
frames.push(a);
frames.push(b);
},
2 => {
let n1 = read_frame_len(&mut rest)?;
let frame1 = take(&mut rest, n1)?;
check_frame_len(rest.len())?;
frames.push(frame1);
frames.push(rest);
},
_ => {
let (&count_byte, body) = rest.split_first().ok_or(PacketError::InvalidFrameLength)?;
rest = body;
let vbr = count_byte >> 7 == 1;
let has_padding = (count_byte >> 6) & 1 == 1;
let frame_count = usize::from(count_byte & 0x3F);
if frame_count == 0 || frame_count as u32 * toc.frame_size().tenth_ms() > MAX_PACKET_DURATION_TENTH_MS {
return Err(PacketError::InvalidFrameCount);
}
if has_padding {
loop {
let (&b, body) = rest.split_first().ok_or(PacketError::InvalidPadding)?;
rest = body;
if b == 255 {
padding += 254;
} else {
padding += usize::from(b);
break;
}
}
if padding > rest.len() {
return Err(PacketError::InvalidPadding);
}
rest = &rest[..rest.len() - padding];
}
if vbr {
let mut lengths = Vec::with_capacity(frame_count - 1);
for _ in 0..frame_count - 1 {
lengths.push(read_frame_len(&mut rest)?);
}
for n in lengths {
frames.push(take(&mut rest, n)?);
}
check_frame_len(rest.len())?;
frames.push(rest);
} else {
if rest.len() % frame_count != 0 {
return Err(PacketError::CbrPayloadNotDivisible);
}
let size = rest.len() / frame_count;
check_frame_len(size)?;
for _ in 0..frame_count {
frames.push(take(&mut rest, size)?);
}
}
},
}
Ok(Packet { toc, frames, padding })
}
pub fn parse_self_delimited(data: &'a [u8]) -> Result<(Self, usize), PacketError> {
let (&toc_byte, mut rest) = data.split_first().ok_or(PacketError::Empty)?;
let toc = Toc::new(toc_byte);
let mut frames = Vec::new();
let mut padding = 0usize;
match toc.frame_count_code() {
0 => {
let n = read_frame_len(&mut rest)?;
frames.push(take(&mut rest, n)?);
},
1 => {
let n = read_frame_len(&mut rest)?;
frames.push(take(&mut rest, n)?);
frames.push(take(&mut rest, n)?);
},
2 => {
let n1 = read_frame_len(&mut rest)?;
let n2 = read_frame_len(&mut rest)?;
frames.push(take(&mut rest, n1)?);
frames.push(take(&mut rest, n2)?);
},
_ => {
let (&count_byte, body) = rest.split_first().ok_or(PacketError::InvalidFrameLength)?;
rest = body;
let vbr = count_byte >> 7 == 1;
let has_padding = (count_byte >> 6) & 1 == 1;
let frame_count = usize::from(count_byte & 0x3F);
if frame_count == 0 || frame_count as u32 * toc.frame_size().tenth_ms() > MAX_PACKET_DURATION_TENTH_MS {
return Err(PacketError::InvalidFrameCount);
}
if has_padding {
loop {
let (&b, body) = rest.split_first().ok_or(PacketError::InvalidPadding)?;
rest = body;
if b == 255 {
padding += 254;
} else {
padding += usize::from(b);
break;
}
}
}
if vbr {
let mut lengths = Vec::with_capacity(frame_count);
for _ in 0..frame_count {
lengths.push(read_frame_len(&mut rest)?);
}
for n in lengths {
frames.push(take(&mut rest, n)?);
}
} else {
let size = read_frame_len(&mut rest)?;
for _ in 0..frame_count {
frames.push(take(&mut rest, size)?);
}
}
if padding > rest.len() {
return Err(PacketError::InvalidPadding);
}
rest = &rest[padding..];
},
}
let consumed = data.len() - rest.len();
Ok((Packet { toc, frames, padding }, consumed))
}
#[must_use]
pub const fn toc(&self) -> Toc {
self.toc
}
#[must_use]
pub fn frames(&self) -> &[&'a [u8]] {
&self.frames
}
#[must_use]
pub const fn padding(&self) -> usize {
self.padding
}
#[must_use]
pub fn duration(&self) -> Duration {
Duration::from_micros(self.frames.len() as u64 * u64::from(self.toc.frame_size().tenth_ms()) * 100)
}
}
fn check_frame_len(len: usize) -> Result<(), PacketError> {
if len > MAX_FRAME_LEN {
Err(PacketError::FrameTooLarge)
} else {
Ok(())
}
}
fn read_frame_len(rest: &mut &[u8]) -> Result<usize, PacketError> {
let (&b0, body) = rest.split_first().ok_or(PacketError::InvalidFrameLength)?;
*rest = body;
let len = match b0 {
0..=251 => usize::from(b0),
_ => {
let (&b1, body) = rest.split_first().ok_or(PacketError::InvalidFrameLength)?;
*rest = body;
usize::from(b1) * 4 + usize::from(b0)
},
};
debug_assert!(len <= MAX_FRAME_LEN);
Ok(len)
}
fn take<'a>(rest: &mut &'a [u8], n: usize) -> Result<&'a [u8], PacketError> {
if n > rest.len() {
return Err(PacketError::InvalidFrameLength);
}
let (head, tail) = rest.split_at(n);
*rest = tail;
Ok(head)
}