use crate::packet::frame_count;
use crate::{Error, Result};
pub(crate) fn samples_per_frame(toc: u8, fs: i32) -> i32 {
if toc & 0x80 != 0 {
let a = ((toc >> 3) & 0x3) as i32;
(fs << a) / 400
} else if toc & 0x60 == 0x60 {
if toc & 0x08 != 0 { fs / 50 } else { fs / 100 }
} else {
let a = ((toc >> 3) & 0x3) as i32;
if a == 3 {
fs * 60 / 1000
} else {
(fs << a) / 100
}
}
}
fn parse_size(data: &[u8]) -> (i32, i32) {
if data.is_empty() {
(-1, -1)
} else if data[0] < 252 {
(1, data[0] as i32)
} else if data.len() < 2 {
(-1, -1)
} else {
(2, data[1] as i32 * 4 + data[0] as i32)
}
}
fn encode_size(size: i32, out: &mut Vec<u8>) {
if size < 252 {
out.push(size as u8);
} else {
let b0 = 252 + (size & 0x3);
out.push(b0 as u8);
out.push(((size - b0) >> 2) as u8);
}
}
pub(crate) const MAX_FRAMES: usize = 48;
const _: () = assert!(5760 / 120 == MAX_FRAMES);
#[derive(Clone, Copy)]
pub(crate) struct FrameList<T: Copy> {
items: [T; MAX_FRAMES],
len: usize,
}
impl<T: Copy + Default> FrameList<T> {
fn new() -> Self {
Self {
items: [T::default(); MAX_FRAMES],
len: 0,
}
}
fn push(&mut self, item: T) {
self.items[self.len] = item;
self.len += 1;
}
fn clear(&mut self) {
self.len = 0;
}
}
impl<T: Copy> std::ops::Deref for FrameList<T> {
type Target = [T];
fn deref(&self) -> &[T] {
&self.items[..self.len]
}
}
pub(crate) fn parse_packet(
data: &[u8],
self_delimited: bool,
) -> Result<(u8, FrameList<&[u8]>, usize)> {
if data.is_empty() {
return Err(Error::InvalidPacket("invalid packet"));
}
let framesize = samples_per_frame(data[0], 48000);
let toc = data[0];
let mut pos = 1usize; let mut len = data.len() as i32 - 1;
let mut cbr = false;
let mut last_size = len;
let mut sizes = FrameList::<i32>::new();
let count: usize = match toc & 0x3 {
0 => 1,
1 => {
cbr = true;
if !self_delimited {
if len & 1 != 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
last_size = len / 2;
sizes.push(last_size);
}
2
}
2 => {
let (bytes, sz) = parse_size(&data[pos..]);
if bytes < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
len -= bytes;
if sz < 0 || sz > len {
return Err(Error::InvalidPacket("invalid packet"));
}
pos += bytes as usize;
sizes.push(sz);
last_size = len - sz;
2
}
_ => {
if len < 1 {
return Err(Error::InvalidPacket("invalid packet"));
}
let ch = data[pos];
pos += 1;
len -= 1;
let count = (ch & 0x3f) as usize;
if count == 0 || framesize * count as i32 > 5760 {
return Err(Error::InvalidPacket("invalid packet"));
}
if ch & 0x40 != 0 {
loop {
if len <= 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
let p = data[pos];
pos += 1;
len -= 1;
let tmp = if p == 255 { 254 } else { p as i32 };
len -= tmp;
if p != 255 {
break;
}
}
}
if len < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
cbr = ch & 0x80 == 0;
if !cbr {
last_size = len;
for _ in 0..count - 1 {
let (bytes, sz) = parse_size(&data[pos..]);
if bytes < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
len -= bytes;
if sz < 0 || sz > len {
return Err(Error::InvalidPacket("invalid packet"));
}
pos += bytes as usize;
sizes.push(sz);
last_size -= bytes + sz;
}
if last_size < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
} else if !self_delimited {
last_size = len / count as i32;
if last_size * count as i32 != len {
return Err(Error::InvalidPacket("invalid packet"));
}
for _ in 0..count - 1 {
sizes.push(last_size);
}
}
count
}
};
if self_delimited {
let (bytes, sz) = parse_size(&data[pos..]);
if bytes < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
len -= bytes;
if sz < 0 || sz > len {
return Err(Error::InvalidPacket("invalid packet"));
}
pos += bytes as usize;
if cbr {
if sz * count as i32 > len {
return Err(Error::InvalidPacket("invalid packet"));
}
sizes.clear();
for _ in 0..count - 1 {
sizes.push(sz);
}
sizes.push(sz);
} else {
if bytes + sz > last_size {
return Err(Error::InvalidPacket("invalid packet"));
}
sizes.push(sz);
}
} else {
if last_size > 1275 {
return Err(Error::InvalidPacket("invalid packet"));
}
sizes.push(last_size);
}
let mut frames = FrameList::new();
let mut off = pos;
for &s in sizes.iter() {
if off + s as usize > data.len() {
return Err(Error::InvalidPacket("invalid packet"));
}
frames.push(&data[off..off + s as usize]);
off += s as usize;
}
let packet_offset = off; Ok((toc, frames, packet_offset))
}
pub(crate) fn take_self_delimited_into(data: &[u8], out: &mut Vec<u8>) -> Result<usize> {
let (toc, frames, consumed) = parse_packet(data, true)?;
out.clear();
emit_packet(toc, frames.iter().copied(), None, false, out)?;
Ok(consumed)
}
#[derive(Default)]
pub struct Repacketizer {
toc: u8,
framesize: i32,
frames: Vec<Vec<u8>>,
spare: Vec<Vec<u8>>,
}
impl std::fmt::Debug for Repacketizer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Repacketizer")
.field("nb_frames", &self.frames.len())
.field("toc", &format_args!("{:#04x}", self.toc))
.field("framesize", &self.framesize)
.field("bytes", &self.frames.iter().map(Vec::len).sum::<usize>())
.finish()
}
}
impl Repacketizer {
pub fn new() -> Self {
Repacketizer::default()
}
pub fn clear(&mut self) {
self.spare.append(&mut self.frames);
self.toc = 0;
self.framesize = 0;
}
pub fn nb_frames(&self) -> usize {
self.frames.len()
}
pub fn cat(&mut self, data: &[u8]) -> Result<()> {
self.cat_impl(data, false)
}
fn cat_impl(&mut self, data: &[u8], self_delimited: bool) -> Result<()> {
if data.is_empty() {
return Err(Error::InvalidPacket("cat: the packet is empty"));
}
if self.frames.is_empty() {
self.toc = data[0];
self.framesize = samples_per_frame(data[0], 8000);
} else if self.toc & 0xfc != data[0] & 0xfc {
return Err(Error::InvalidPacket("toc mismatch"));
}
let curr = frame_count(data)?;
if (curr + self.frames.len()) as i32 * self.framesize > 960 {
return Err(Error::InvalidPacket("packet exceeds 120 ms"));
}
let (_toc, frames, _off) = parse_packet(data, self_delimited)?;
for &f in frames.iter() {
let mut frame = self.spare.pop().unwrap_or_default();
frame.clear();
frame.extend_from_slice(f);
self.frames.push(frame);
}
Ok(())
}
pub fn out_range(&self, begin: usize, end: usize) -> Result<Vec<u8>> {
self.out_range_impl(begin, end, None)
}
pub fn out(&self) -> Result<Vec<u8>> {
self.out_range_impl(0, self.frames.len(), None)
}
pub fn out_into(&self, out: &mut Vec<u8>) -> Result<()> {
self.out_range_full(0, self.frames.len(), None, false, out)
}
pub fn out_range_into(&self, begin: usize, end: usize, out: &mut Vec<u8>) -> Result<()> {
self.out_range_full(begin, end, None, false, out)
}
pub fn out_self_delimited_into(&self, out: &mut Vec<u8>) -> Result<()> {
self.out_range_full(0, self.frames.len(), None, true, out)
}
pub(crate) fn out_range_impl(
&self,
begin: usize,
end: usize,
pad_to: Option<usize>,
) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.out_range_full(begin, end, pad_to, false, &mut out)?;
Ok(out)
}
pub fn out_self_delimited(&self) -> Result<Vec<u8>> {
let mut out = Vec::new();
self.out_range_full(0, self.frames.len(), None, true, &mut out)?;
Ok(out)
}
fn out_range_full(
&self,
begin: usize,
end: usize,
pad_to: Option<usize>,
self_delimited: bool,
out: &mut Vec<u8>,
) -> Result<()> {
if begin >= end || end > self.frames.len() {
return Err(Error::InvalidArgument(
"frame range must satisfy begin < end <= nb_frames",
));
}
emit_packet(
self.toc,
self.frames[begin..end].iter().map(Vec::as_slice),
pad_to,
self_delimited,
out,
)
}
}
fn emit_packet<'f>(
toc: u8,
frames: impl ExactSizeIterator<Item = &'f [u8]> + Clone,
pad_to: Option<usize>,
self_delimited: bool,
out: &mut Vec<u8>,
) -> Result<()> {
let count = frames.len();
if count == 0 {
return Err(Error::InvalidArgument("a packet needs at least one frame"));
}
let lens = || frames.clone().map(<[u8]>::len);
let first_len = lens().next().unwrap_or(0);
let last_len = lens().last().unwrap_or(0);
let vbr = lens().any(|l| l != first_len);
let start = out.len();
if count == 1 {
out.push(toc & 0xfc); } else if count == 2 && !vbr {
out.push((toc & 0xfc) | 0x1); } else if count == 2 {
out.push((toc & 0xfc) | 0x2); encode_size(first_len as i32, out);
}
if count > 2 || pad_to.is_some() {
out.truncate(start);
out.push((toc & 0xfc) | 0x3);
out.push(if vbr {
(count as u8) | 0x80
} else {
count as u8
});
let mut tot = 2usize;
if vbr {
for l in lens().take(count - 1) {
tot += 1 + usize::from(l >= 252) + l;
}
tot += last_len;
} else {
tot += count * first_len;
}
let pad_amount = pad_to.map(|n| n.saturating_sub(tot)).unwrap_or(0);
if pad_amount != 0 {
out[start + 1] |= 0x40; let nb_255s = (pad_amount - 1) / 255;
out.extend(std::iter::repeat_n(255u8, nb_255s));
out.push((pad_amount - 255 * nb_255s - 1) as u8);
}
if vbr {
for l in lens().take(count - 1) {
encode_size(l as i32, out);
}
}
if self_delimited {
encode_size(last_len as i32, out);
}
for f in frames.clone() {
out.extend_from_slice(f);
}
if let Some(n) = pad_to {
while out.len() - start < n {
out.push(0);
}
}
return Ok(());
}
if self_delimited {
encode_size(last_len as i32, out);
}
for f in frames.clone() {
out.extend_from_slice(f);
}
Ok(())
}
pub fn pad_packet(packet: &mut Vec<u8>, new_len: usize) -> Result<()> {
if packet.is_empty() {
return Err(Error::InvalidArgument("pad_packet: the packet is empty"));
}
if packet.len() == new_len {
return Ok(());
}
if packet.len() > new_len {
return Err(Error::InvalidArgument(
"pad_packet: new_len is smaller than the packet",
));
}
let mut rp = Repacketizer::new();
rp.cat(packet)?;
let padded = rp.out_range_impl(0, rp.nb_frames(), Some(new_len))?;
*packet = padded;
Ok(())
}
pub fn unpad_packet(packet: &[u8]) -> Result<Vec<u8>> {
if packet.is_empty() {
return Err(Error::InvalidArgument("unpad_packet: the packet is empty"));
}
let mut rp = Repacketizer::new();
rp.cat(packet)?;
rp.out_range_impl(0, rp.nb_frames(), None)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn split_merge_roundtrip() {
let toc = 12u8 << 3;
let mut pkt = vec![toc | 0x3, 3 | 0x80]; let f0 = vec![0xAAu8; 3];
let f1 = vec![0xBBu8; 5];
let f2 = vec![0xCCu8; 4];
encode_size(3, &mut pkt);
encode_size(5, &mut pkt);
pkt.extend_from_slice(&f0);
pkt.extend_from_slice(&f1);
pkt.extend_from_slice(&f2);
let mut rp = Repacketizer::new();
rp.cat(&pkt).unwrap();
assert_eq!(rp.nb_frames(), 3);
assert_eq!(rp.out().unwrap(), pkt);
let s0 = rp.out_range(0, 1).unwrap();
assert_eq!(s0[0] & 0x3, 0);
assert_eq!(&s0[1..], &f0[..]);
let s1 = rp.out_range(1, 2).unwrap();
assert_eq!(&s1[1..], &f1[..]);
}
#[test]
fn take_self_delimited_matches_the_repacketizer() {
let toc = 12u8 << 3; let cases: &[&[usize]] = &[&[3], &[4, 4], &[3, 5], &[4, 4, 4], &[3, 5, 4], &[300, 2]];
for lens in cases {
let mut rp = Repacketizer::new();
for (i, &l) in lens.iter().enumerate() {
let mut pkt = vec![toc];
pkt.extend(std::iter::repeat_n(i as u8 + 1, l));
rp.cat(&pkt).unwrap();
}
let mut sd = rp.out_self_delimited().unwrap();
let trailer = [0xEEu8; 7]; sd.extend_from_slice(&trailer);
let mut out = vec![0xFF; 3];
let consumed = take_self_delimited_into(&sd, &mut out).unwrap();
assert_eq!(consumed, sd.len() - trailer.len(), "lens {lens:?}");
assert_eq!(out, rp.out().unwrap(), "lens {lens:?}");
}
}
#[test]
fn pad_unpad_identity() {
let toc = 8u8 << 3; let mut pkt = vec![toc];
pkt.extend_from_slice(&[1, 2, 3, 4, 5]);
let orig = pkt.clone();
pad_packet(&mut pkt, orig.len() + 10).unwrap();
assert_eq!(pkt.len(), orig.len() + 10);
let back = unpad_packet(&pkt).unwrap();
let (_t, f, _) = parse_packet(&back, false).unwrap();
assert_eq!(f[0], &orig[1..]);
}
#[test]
fn cbr_merge_code1() {
let toc = 8u8 << 3;
let p = vec![toc, 9, 9, 9]; let mut rp = Repacketizer::new();
rp.cat(&p).unwrap();
rp.cat(&p).unwrap();
let out = rp.out().unwrap();
assert_eq!(out[0] & 0x3, 1); assert_eq!(rp.nb_frames(), 2);
}
}
#[cfg(test)]
mod sd_tests {
use super::*;
#[test]
fn self_delimited_roundtrip() {
let toc = 12u8 << 3;
let mut rp = Repacketizer::new();
let mut p = vec![toc | 0x3, 3 | 0x80];
encode_size(3, &mut p);
encode_size(5, &mut p);
p.extend_from_slice(&[1u8; 3]);
p.extend_from_slice(&[2u8; 5]);
p.extend_from_slice(&[3u8; 4]);
rp.cat(&p).unwrap();
let sd = rp.out_self_delimited().unwrap();
let mut stream = sd.clone();
stream.extend_from_slice(&[0xEE; 7]);
let (t, frames, off) = parse_packet(&stream, true).unwrap();
assert_eq!(t, toc | 0x3);
assert_eq!(frames.len(), 3);
assert_eq!(frames[0], &[1, 1, 1]);
assert_eq!(frames[2], &[3, 3, 3, 3]);
assert_eq!(off, sd.len()); }
}