use crate::frames::{decode_length, OpusPacket, MAX_FRAMES_PER_PACKET, MAX_FRAME_BYTES};
use crate::toc::{FrameCountCode, OpusTocByte};
use crate::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SelfDelimitedParse<'a> {
pub packet: OpusPacket<'a>,
pub consumed: usize,
}
pub fn parse_self_delimited(buffer: &[u8]) -> Result<SelfDelimitedParse<'_>, Error> {
if buffer.is_empty() {
return Err(Error::EmptyPacket);
}
let toc = OpusTocByte::from_byte(buffer[0]);
let mut cursor = 1usize;
let (frames, padding) = match toc.frame_count_code {
FrameCountCode::One => parse_sd_code0(buffer, &mut cursor)?,
FrameCountCode::TwoEqual => parse_sd_code1(buffer, &mut cursor)?,
FrameCountCode::TwoUnequal => parse_sd_code2(buffer, &mut cursor)?,
FrameCountCode::Arbitrary => parse_sd_code3(buffer, &mut cursor)?,
};
let packet = OpusPacket::new_self_delim(toc, frames, padding);
Ok(SelfDelimitedParse {
packet,
consumed: cursor,
})
}
fn parse_sd_code0<'a>(
buffer: &'a [u8],
cursor: &mut usize,
) -> Result<(Vec<&'a [u8]>, usize), Error> {
let n1 = read_length_advance(buffer, cursor)?;
let frame = take_frame_advance(buffer, cursor, n1)?;
Ok((vec![frame], 0))
}
fn parse_sd_code1<'a>(
buffer: &'a [u8],
cursor: &mut usize,
) -> Result<(Vec<&'a [u8]>, usize), Error> {
let n1 = read_length_advance(buffer, cursor)?;
let frame1 = take_frame_advance(buffer, cursor, n1)?;
let frame2 = take_frame_advance(buffer, cursor, n1)?;
Ok((vec![frame1, frame2], 0))
}
fn parse_sd_code2<'a>(
buffer: &'a [u8],
cursor: &mut usize,
) -> Result<(Vec<&'a [u8]>, usize), Error> {
let n1 = read_length_advance(buffer, cursor)?;
let n2 = read_length_advance(buffer, cursor)?;
let frame1 = take_frame_advance(buffer, cursor, n1)?;
let frame2 = take_frame_advance(buffer, cursor, n2)?;
Ok((vec![frame1, frame2], 0))
}
fn parse_sd_code3<'a>(
buffer: &'a [u8],
cursor: &mut usize,
) -> Result<(Vec<&'a [u8]>, usize), Error> {
let fc = *buffer.get(*cursor).ok_or(Error::MalformedPacket)?;
*cursor += 1;
let v_bit = fc & 0x01 != 0;
let p_bit = fc & 0x02 != 0;
let m = fc >> 2;
if m == 0 || m > MAX_FRAMES_PER_PACKET {
return Err(Error::MalformedPacket);
}
let m = m as usize;
let mut padding_bytes: usize = 0;
if p_bit {
loop {
let byte = *buffer.get(*cursor).ok_or(Error::MalformedPacket)? as usize;
*cursor += 1;
if byte == 255 {
padding_bytes += 254;
} else {
padding_bytes += byte;
break;
}
}
}
let mut frames: Vec<&[u8]> = Vec::with_capacity(m);
if v_bit {
let mut sizes: Vec<usize> = Vec::with_capacity(m);
for _ in 0..m.saturating_sub(1) {
sizes.push(read_length_advance(buffer, cursor)?);
}
let last_size = read_length_advance(buffer, cursor)?;
sizes.push(last_size);
for n in sizes {
frames.push(take_frame_advance(buffer, cursor, n)?);
}
} else {
let per = read_length_advance(buffer, cursor)?;
for _ in 0..m {
frames.push(take_frame_advance(buffer, cursor, per)?);
}
}
if buffer.len() - *cursor < padding_bytes {
return Err(Error::MalformedPacket);
}
*cursor += padding_bytes;
Ok((frames, padding_bytes))
}
fn read_length_advance(buffer: &[u8], cursor: &mut usize) -> Result<usize, Error> {
let tail = buffer.get(*cursor..).ok_or(Error::MalformedPacket)?;
let (length, consumed) = decode_length(tail)?;
*cursor += consumed;
Ok(length)
}
fn take_frame_advance<'a>(
buffer: &'a [u8],
cursor: &mut usize,
n: usize,
) -> Result<&'a [u8], Error> {
if n > MAX_FRAME_BYTES {
return Err(Error::MalformedPacket);
}
let end = cursor.checked_add(n).ok_or(Error::MalformedPacket)?;
if end > buffer.len() {
return Err(Error::MalformedPacket);
}
let slice = &buffer[*cursor..end];
*cursor = end;
Ok(slice)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::toc::FrameCountCode;
fn toc_byte(config: u8, stereo: bool, code: u8) -> u8 {
(config << 3) | ((stereo as u8) << 2) | (code & 0x03)
}
#[test]
fn code0_short_length_one_frame() {
let bytes = [toc_byte(0, false, 0), 3, 0xAA, 0xBB, 0xCC, 0xFF];
let r = parse_self_delimited(&bytes).unwrap();
assert_eq!(r.consumed, 1 + 1 + 3);
assert_eq!(r.packet.frame_count(), 1);
assert_eq!(r.packet.frames()[0], &[0xAA, 0xBB, 0xCC]);
assert_eq!(r.packet.toc.frame_count_code, FrameCountCode::One);
assert_eq!(bytes.len() - r.consumed, 1);
}
#[test]
fn code0_two_byte_length() {
let mut bytes = vec![toc_byte(0, false, 0), 252, 0];
bytes.extend(std::iter::repeat(0x7Fu8).take(252));
let r = parse_self_delimited(&bytes).unwrap();
assert_eq!(r.consumed, 1 + 2 + 252);
assert_eq!(r.packet.frames()[0].len(), 252);
}
#[test]
fn code0_zero_length_dtx() {
let bytes = [toc_byte(0, false, 0), 0];
let r = parse_self_delimited(&bytes).unwrap();
assert_eq!(r.consumed, 2);
assert_eq!(r.packet.frames()[0].len(), 0);
}
#[test]
fn code1_two_equal_frames() {
let bytes = [
toc_byte(0, false, 1),
2,
0xAA,
0xBB,
0xCC,
0xDD,
0x11,
];
let r = parse_self_delimited(&bytes).unwrap();
assert_eq!(r.consumed, 1 + 1 + 4);
assert_eq!(r.packet.frame_count(), 2);
assert_eq!(r.packet.frames()[0], &[0xAA, 0xBB]);
assert_eq!(r.packet.frames()[1], &[0xCC, 0xDD]);
}
#[test]
fn code2_two_lengths_then_frames() {
let bytes = [toc_byte(0, false, 2), 3, 2, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE];
let r = parse_self_delimited(&bytes).unwrap();
assert_eq!(r.consumed, 1 + 1 + 1 + 3 + 2);
assert_eq!(r.packet.frame_count(), 2);
assert_eq!(r.packet.frames()[0], &[0xAA, 0xBB, 0xCC]);
assert_eq!(r.packet.frames()[1], &[0xDD, 0xEE]);
}
#[test]
fn code3_cbr_three_frames_no_padding() {
let fc = 3u8 << 2;
let bytes = [
toc_byte(0, false, 3),
fc,
2,
0x10,
0x11,
0x20,
0x21,
0x30,
0x31,
];
let r = parse_self_delimited(&bytes).unwrap();
assert_eq!(r.consumed, 1 + 1 + 1 + 6);
assert_eq!(r.packet.frame_count(), 3);
assert_eq!(r.packet.frames()[0], &[0x10, 0x11]);
assert_eq!(r.packet.frames()[1], &[0x20, 0x21]);
assert_eq!(r.packet.frames()[2], &[0x30, 0x31]);
assert_eq!(r.packet.padding, 0);
}
#[test]
fn code3_cbr_with_padding() {
let fc = (2u8 << 2) | 0b10;
let bytes = [
toc_byte(0, false, 3),
fc,
2, 3, 0xAA,
0xBB,
0xCC,
0xDD,
0xEE,
0xFF,
0x55,
0x66, ];
let r = parse_self_delimited(&bytes).unwrap();
assert_eq!(r.consumed, 12);
assert_eq!(r.packet.frame_count(), 2);
assert_eq!(r.packet.padding, 2);
}
#[test]
fn code3_vbr_three_frames() {
let fc = (3u8 << 2) | 0b01;
let bytes = [
toc_byte(0, false, 3),
fc,
2, 3, 1, 0xAA,
0xBB,
0xCC,
0xDD,
0xEE,
0xFF,
];
let r = parse_self_delimited(&bytes).unwrap();
assert_eq!(r.consumed, 1 + 1 + 1 + 1 + 1 + 2 + 3 + 1);
assert_eq!(r.packet.frame_count(), 3);
assert_eq!(r.packet.frames()[0], &[0xAA, 0xBB]);
assert_eq!(r.packet.frames()[1], &[0xCC, 0xDD, 0xEE]);
assert_eq!(r.packet.frames()[2], &[0xFF]);
}
#[test]
fn two_streams_chained_back_to_back() {
let bytes = [
toc_byte(0, false, 0),
2,
0xA0,
0xA1,
toc_byte(0, false, 1),
1,
0xB0,
0xB1,
];
let a = parse_self_delimited(&bytes).unwrap();
assert_eq!(a.consumed, 4);
assert_eq!(a.packet.frames()[0], &[0xA0, 0xA1]);
let rest = &bytes[a.consumed..];
let b = parse_self_delimited(rest).unwrap();
assert_eq!(b.consumed, 4);
assert_eq!(b.packet.frame_count(), 2);
assert_eq!(b.packet.frames()[0], &[0xB0]);
assert_eq!(b.packet.frames()[1], &[0xB1]);
}
#[test]
fn empty_buffer_rejected() {
assert_eq!(parse_self_delimited(&[]), Err(Error::EmptyPacket));
}
#[test]
fn code0_truncated_after_length() {
let bytes = [toc_byte(0, false, 0), 4, 0xAA, 0xBB];
assert_eq!(parse_self_delimited(&bytes), Err(Error::MalformedPacket));
}
#[test]
fn code0_length_field_truncated_two_byte_form() {
let bytes = [toc_byte(0, false, 0), 252];
assert_eq!(parse_self_delimited(&bytes), Err(Error::MalformedPacket));
}
#[test]
fn code3_zero_frame_count_rejected() {
let fc = 0u8;
let bytes = [toc_byte(0, false, 3), fc, 1, 0xAA];
assert_eq!(parse_self_delimited(&bytes), Err(Error::MalformedPacket));
}
#[test]
fn code3_frame_count_above_48_rejected() {
let fc = 49u8 << 2;
let bytes = [toc_byte(0, false, 3), fc, 1, 0xAA];
assert_eq!(parse_self_delimited(&bytes), Err(Error::MalformedPacket));
}
#[test]
fn frame_size_above_1275_rejected() {
let mut bytes = vec![
toc_byte(0, false, 0),
255,
0, ];
bytes[1] = 255;
bytes[2] = 255;
bytes.extend(std::iter::repeat(0u8).take(10));
assert_eq!(parse_self_delimited(&bytes), Err(Error::MalformedPacket));
}
#[test]
fn code3_cbr_missing_padding_bytes() {
let fc = (1u8 << 2) | 0b10;
let bytes = [
toc_byte(0, false, 3),
fc,
4, 1, 0xAA, ];
assert_eq!(parse_self_delimited(&bytes), Err(Error::MalformedPacket));
}
#[test]
fn code3_padding_chain_runs_off_end() {
let fc = (1u8 << 2) | 0b10;
let bytes = [toc_byte(0, false, 3), fc];
assert_eq!(parse_self_delimited(&bytes), Err(Error::MalformedPacket));
}
}