use alloc::vec;
use alloc::vec::Vec;
use crate::extensions;
use crate::packet::{
MAX_FRAMES_PER_PACKET, PacketError, opus_packet_get_nb_frames,
opus_packet_get_samples_per_frame, opus_packet_parse_impl,
};
pub use crate::extensions::OpusExtensionData;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RepacketizerError {
BadArgument,
BufferTooSmall,
InternalError,
InvalidPacket,
}
impl RepacketizerError {
#[inline]
pub const fn code(self) -> i32 {
match self {
RepacketizerError::BadArgument => -1,
RepacketizerError::BufferTooSmall => -2,
RepacketizerError::InternalError => -3,
RepacketizerError::InvalidPacket => -4,
}
}
}
impl From<PacketError> for RepacketizerError {
#[inline]
fn from(value: PacketError) -> Self {
match value {
PacketError::BadArgument => RepacketizerError::InvalidPacket,
PacketError::InvalidPacket => RepacketizerError::InvalidPacket,
}
}
}
fn map_extension_error(err: extensions::ExtensionError) -> RepacketizerError {
match err {
extensions::ExtensionError::BadArgument => RepacketizerError::BadArgument,
extensions::ExtensionError::BufferTooSmall => RepacketizerError::BufferTooSmall,
extensions::ExtensionError::InvalidPacket => RepacketizerError::InvalidPacket,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
struct Frame {
start: usize,
len: u16,
padding_start: Option<usize>,
}
pub struct OpusRepacketizer {
toc: u8,
nb_frames: usize,
frames: [Frame; MAX_FRAMES_PER_PACKET],
framesize: usize,
padding_len: [usize; MAX_FRAMES_PER_PACKET],
padding_nb_frames: [u8; MAX_FRAMES_PER_PACKET],
buffer: Vec<u8>,
}
impl Default for OpusRepacketizer {
fn default() -> Self {
Self::new()
}
}
impl OpusRepacketizer {
#[inline]
pub fn new() -> Self {
OpusRepacketizer {
toc: 0,
nb_frames: 0,
frames: [Frame::default(); MAX_FRAMES_PER_PACKET],
framesize: 0,
padding_len: [0; MAX_FRAMES_PER_PACKET],
padding_nb_frames: [0; MAX_FRAMES_PER_PACKET],
buffer: Vec::new(),
}
}
#[inline]
pub const fn opus_repacketizer_get_size() -> usize {
core::mem::size_of::<OpusRepacketizer>()
}
#[inline]
pub fn opus_repacketizer_init(&mut self) -> &mut Self {
self.nb_frames = 0;
self.frames = [Frame::default(); MAX_FRAMES_PER_PACKET];
self.padding_len = [0; MAX_FRAMES_PER_PACKET];
self.padding_nb_frames = [0; MAX_FRAMES_PER_PACKET];
self.framesize = 0;
self.buffer.clear();
self
}
fn cat_impl(
&mut self,
data: &[u8],
len: usize,
self_delimited: bool,
) -> Result<(), RepacketizerError> {
if len < 1 || len > data.len() {
return Err(RepacketizerError::InvalidPacket);
}
if self.nb_frames == 0 {
self.toc = data[0];
self.framesize = opus_packet_get_samples_per_frame(data, 8000)? as usize;
} else if (self.toc & 0xFC) != (data[0] & 0xFC) {
return Err(RepacketizerError::InvalidPacket);
}
let curr_nb_frames = opus_packet_get_nb_frames(data, len)? as usize;
if (curr_nb_frames + self.nb_frames) * self.framesize > 960 {
return Err(RepacketizerError::InvalidPacket);
}
let parsed = opus_packet_parse_impl(data, len, self_delimited)?;
if parsed.frame_count == 0 {
return Err(RepacketizerError::InvalidPacket);
}
let base = self.buffer.len();
self.buffer.extend_from_slice(&data[..len]);
let mut cursor = base + parsed.payload_offset;
for (slot, size) in
(self.nb_frames..self.nb_frames + parsed.frame_count).zip(parsed.frame_sizes.iter())
{
self.frames[slot] = Frame {
start: cursor,
len: *size,
padding_start: None,
};
cursor = cursor
.checked_add(*size as usize)
.ok_or(RepacketizerError::InvalidPacket)?;
}
self.padding_len[self.nb_frames] = parsed.padding.len();
self.padding_nb_frames[self.nb_frames] = parsed.frame_count as u8;
if !parsed.padding.is_empty() {
let pad_start = base + (parsed.packet_offset - parsed.padding.len());
self.frames[self.nb_frames].padding_start = Some(pad_start);
}
for slot in self.nb_frames + 1..self.nb_frames + parsed.frame_count {
self.padding_len[slot] = 0;
self.padding_nb_frames[slot] = 0;
self.frames[slot].padding_start = None;
}
self.nb_frames += parsed.frame_count;
Ok(())
}
pub fn opus_repacketizer_cat(
&mut self,
data: &[u8],
len: usize,
) -> Result<(), RepacketizerError> {
self.cat_impl(data, len, false)
}
#[inline]
pub fn opus_repacketizer_get_nb_frames(&self) -> usize {
self.nb_frames
}
#[allow(clippy::too_many_arguments)]
fn opus_repacketizer_out_range_impl(
&self,
begin: usize,
end: usize,
data: &mut [u8],
maxlen: usize,
self_delimited: bool,
pad: bool,
extensions: &[OpusExtensionData<'_>],
) -> Result<usize, RepacketizerError> {
if begin >= end || end > self.nb_frames {
return Err(RepacketizerError::BadArgument);
}
let count = end - begin;
let frames = &self.frames[begin..end];
let first_len = frames[0].len as usize;
let last_len = frames[count - 1].len as usize;
let mut ones_begin = 0usize;
let mut ones_end = 0usize;
let mut ext_begin = 0usize;
let mut ext_len = 0usize;
let mut total_ext_count = extensions.len();
for i in begin..end {
let pad_len = self.padding_len[i];
let nb_pad_frames = usize::from(self.padding_nb_frames[i]);
if pad_len == 0 || nb_pad_frames == 0 {
continue;
}
let pad_start = self.frames[i]
.padding_start
.ok_or(RepacketizerError::InternalError)?;
let pad_end = pad_start
.checked_add(pad_len)
.filter(|end| *end <= self.buffer.len())
.ok_or(RepacketizerError::InternalError)?;
let padding = &self.buffer[pad_start..pad_end];
let count = extensions::opus_packet_extensions_count(padding, pad_len, nb_pad_frames)
.map_err(|_| RepacketizerError::InternalError)?;
total_ext_count = total_ext_count
.checked_add(count)
.ok_or(RepacketizerError::InternalError)?;
}
let mut all_extensions: Vec<OpusExtensionData<'_>> = Vec::with_capacity(total_ext_count);
if !extensions.is_empty() {
all_extensions.extend_from_slice(extensions);
}
for i in begin..end {
let pad_len = self.padding_len[i];
let nb_pad_frames = usize::from(self.padding_nb_frames[i]);
if pad_len == 0 || nb_pad_frames == 0 {
continue;
}
let pad_start = self.frames[i]
.padding_start
.ok_or(RepacketizerError::InternalError)?;
let pad_end = pad_start
.checked_add(pad_len)
.filter(|end| *end <= self.buffer.len())
.ok_or(RepacketizerError::InternalError)?;
let padding = &self.buffer[pad_start..pad_end];
let frame_count =
extensions::opus_packet_extensions_count(padding, pad_len, nb_pad_frames)
.map_err(|_| RepacketizerError::InternalError)?;
if frame_count == 0 {
continue;
}
let mut frame_exts = vec![OpusExtensionData::default(); frame_count];
extensions::opus_packet_extensions_parse(
padding,
pad_len,
nb_pad_frames,
&mut frame_exts,
)
.map_err(|_| RepacketizerError::InternalError)?;
for mut ext in frame_exts {
ext.frame += (i - begin) as i32;
all_extensions.push(ext);
}
}
let ext_count = all_extensions.len();
let mut ptr = 0usize;
let mut tot_size = if self_delimited {
1 + usize::from(last_len >= 252)
} else {
0
};
if count == 1 {
tot_size += first_len + 1;
if tot_size > maxlen {
return Err(RepacketizerError::BufferTooSmall);
}
data[ptr] = self.toc & 0xFC;
ptr += 1;
} else if count == 2 {
let second_len = frames[1].len as usize;
if second_len == first_len {
tot_size += 2 * first_len + 1;
if tot_size > maxlen {
return Err(RepacketizerError::BufferTooSmall);
}
data[ptr] = (self.toc & 0xFC) | 0x1;
ptr += 1;
} else {
tot_size += first_len + second_len + 2 + usize::from(first_len >= 252);
if tot_size > maxlen {
return Err(RepacketizerError::BufferTooSmall);
}
data[ptr] = (self.toc & 0xFC) | 0x2;
ptr += 1;
ptr += encode_size(first_len, &mut data[ptr..]);
}
}
if count > 2 || (pad && tot_size < maxlen) || ext_count > 0 {
let mut vbr = false;
let mut pad_amount = 0usize;
ptr = 0;
tot_size = if self_delimited {
1 + usize::from(last_len >= 252)
} else {
0
};
for frame in frames.iter().take(count).skip(1) {
if frame.len as usize != first_len {
vbr = true;
break;
}
}
if vbr {
tot_size += 2;
for frame in frames.iter().take(count - 1) {
let len = frame.len as usize;
tot_size += 1 + usize::from(len >= 252) + len;
}
tot_size += last_len;
if tot_size > maxlen {
return Err(RepacketizerError::BufferTooSmall);
}
data[ptr] = (self.toc & 0xFC) | 0x3;
ptr += 1;
data[ptr] = (count as u8) | 0x80;
ptr += 1;
} else {
tot_size += count * first_len + 2;
if tot_size > maxlen {
return Err(RepacketizerError::BufferTooSmall);
}
data[ptr] = (self.toc & 0xFC) | 0x3;
ptr += 1;
data[ptr] = count as u8;
ptr += 1;
}
if pad && tot_size < maxlen {
pad_amount = maxlen - tot_size;
}
if ext_count > 0 {
ext_len = extensions::opus_packet_extensions_generate(
None,
maxlen.saturating_sub(tot_size),
&all_extensions,
count,
false,
)
.map_err(map_extension_error)?;
if !pad {
pad_amount = ext_len + ext_len / 254 + 1;
}
}
if pad_amount != 0 {
let nb_255s = (pad_amount - 1) / 255;
let size_ok = tot_size
.checked_add(ext_len)
.and_then(|s| s.checked_add(nb_255s + 1))
.is_none_or(|needed| needed > maxlen);
if size_ok {
return Err(RepacketizerError::BufferTooSmall);
}
ext_begin = tot_size + pad_amount - ext_len;
ones_begin = tot_size + nb_255s + 1;
ones_end = tot_size + pad_amount - ext_len;
data[1] |= 0x40;
for _ in 0..nb_255s {
data[ptr] = 255;
ptr += 1;
}
data[ptr] = (pad_amount - 255 * nb_255s - 1) as u8;
ptr += 1;
tot_size += pad_amount;
}
if vbr {
for frame in frames.iter().take(count - 1) {
let len = frame.len as usize;
ptr += encode_size(len, &mut data[ptr..]);
}
}
}
if self_delimited {
ptr += encode_size(last_len, &mut data[ptr..]);
}
for frame in frames.iter() {
let len = frame.len as usize;
let src_start = frame.start;
let src_end = src_start + len;
if src_end > self.buffer.len() {
return Err(RepacketizerError::InternalError);
}
let dst_end = ptr + len;
if dst_end > data.len() {
return Err(RepacketizerError::BufferTooSmall);
}
data[ptr..dst_end].copy_from_slice(&self.buffer[src_start..src_end]);
ptr = dst_end;
}
if ext_len > 0 {
let generated = extensions::opus_packet_extensions_generate(
Some(&mut data[ext_begin..ext_begin + ext_len]),
ext_len,
&all_extensions,
count,
false,
)
.map_err(map_extension_error)?;
debug_assert_eq!(generated, ext_len);
}
for byte in data.iter_mut().take(ones_end).skip(ones_begin) {
*byte = 0x01;
}
if pad && ext_count == 0 {
for byte in data.iter_mut().take(maxlen).skip(ptr) {
*byte = 0;
}
}
Ok(tot_size)
}
#[inline]
pub fn opus_repacketizer_out_range(
&self,
begin: usize,
end: usize,
data: &mut [u8],
maxlen: usize,
) -> Result<usize, RepacketizerError> {
self.opus_repacketizer_out_range_impl(begin, end, data, maxlen, false, false, &[])
}
#[inline]
pub fn opus_repacketizer_out(
&self,
data: &mut [u8],
maxlen: usize,
) -> Result<usize, RepacketizerError> {
self.opus_repacketizer_out_range_impl(0, self.nb_frames, data, maxlen, false, false, &[])
}
}
fn encode_size(size: usize, data: &mut [u8]) -> usize {
if size < 252 {
data[0] = size as u8;
1
} else {
data[0] = 252 + (size & 0x3) as u8;
data[1] = ((size - usize::from(data[0])) >> 2) as u8;
2
}
}
pub fn opus_packet_pad(
data: &mut [u8],
len: usize,
new_len: usize,
) -> Result<(), RepacketizerError> {
opus_packet_pad_impl(data, len, new_len, true)
}
pub(crate) fn opus_packet_pad_with_extensions(
data: &mut [u8],
len: usize,
new_len: usize,
pad: bool,
extensions: &[OpusExtensionData<'_>],
) -> Result<usize, RepacketizerError> {
if len < 1 {
return Err(RepacketizerError::BadArgument);
}
if len == new_len {
return Ok(len);
}
if len > new_len || new_len > data.len() {
return Err(RepacketizerError::BadArgument);
}
let mut copy = Vec::with_capacity(len);
copy.extend_from_slice(&data[..len]);
let mut rp = OpusRepacketizer::new();
rp.opus_repacketizer_cat(©, len)?;
let written = rp.opus_repacketizer_out_range_impl(
0,
rp.nb_frames,
data,
new_len,
false,
pad,
extensions,
)?;
if written > 0 {
Ok(written)
} else {
Err(RepacketizerError::InternalError)
}
}
fn opus_packet_pad_impl(
data: &mut [u8],
len: usize,
new_len: usize,
pad: bool,
) -> Result<(), RepacketizerError> {
if len < 1 {
return Err(RepacketizerError::BadArgument);
}
if len == new_len {
return Ok(());
}
if len > new_len || new_len > data.len() {
return Err(RepacketizerError::BadArgument);
}
let mut copy = Vec::with_capacity(len);
copy.extend_from_slice(&data[..len]);
let mut rp = OpusRepacketizer::new();
rp.opus_repacketizer_cat(©, len)?;
let written =
rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, new_len, false, pad, &[])?;
if written > 0 {
Ok(())
} else {
Err(RepacketizerError::InternalError)
}
}
pub fn opus_packet_unpad(data: &mut [u8], len: usize) -> Result<usize, RepacketizerError> {
if len < 1 {
return Err(RepacketizerError::BadArgument);
}
let mut rp = OpusRepacketizer::new();
rp.opus_repacketizer_cat(data, len)?;
for slot in 0..rp.nb_frames {
rp.padding_len[slot] = 0;
rp.padding_nb_frames[slot] = 0;
rp.frames[slot].padding_start = None;
}
let written =
rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, len, false, false, &[])?;
debug_assert!(written > 0 && written <= len);
if written == 0 || written > len {
Err(RepacketizerError::InternalError)
} else {
Ok(written)
}
}
pub fn opus_multistream_packet_pad(
data: &mut [u8],
len: usize,
new_len: usize,
nb_streams: usize,
) -> Result<(), RepacketizerError> {
if len < 1 {
return Err(RepacketizerError::BadArgument);
}
if len == new_len {
return Ok(());
}
if len > new_len || new_len > data.len() {
return Err(RepacketizerError::BadArgument);
}
let mut offset = 0usize;
let mut remaining = len;
for _ in 0..nb_streams.saturating_sub(1) {
if remaining == 0 {
return Err(RepacketizerError::InvalidPacket);
}
let parsed = opus_packet_parse_impl(&data[offset..], remaining, true)?;
if parsed.packet_offset > remaining {
return Err(RepacketizerError::InvalidPacket);
}
offset += parsed.packet_offset;
remaining -= parsed.packet_offset;
}
opus_packet_pad(&mut data[offset..], remaining, remaining + (new_len - len))
}
pub fn opus_multistream_packet_unpad(
data: &mut [u8],
len: usize,
nb_streams: usize,
) -> Result<usize, RepacketizerError> {
if len < 1 {
return Err(RepacketizerError::BadArgument);
}
let mut offset = 0usize;
let mut remaining = len;
let mut dst_len = 0usize;
for stream in 0..nb_streams {
let self_delimited = stream + 1 != nb_streams;
if remaining == 0 {
return Err(RepacketizerError::InvalidPacket);
}
let packet_offset = {
let parsed = opus_packet_parse_impl(&data[offset..], remaining, self_delimited)?;
if parsed.packet_offset > remaining {
return Err(RepacketizerError::InvalidPacket);
}
parsed.packet_offset
};
let packet_end = offset + packet_offset;
let mut packet_copy = Vec::with_capacity(packet_offset);
packet_copy.extend_from_slice(&data[offset..packet_end]);
let mut rp = OpusRepacketizer::new();
rp.cat_impl(&packet_copy, packet_copy.len(), self_delimited)?;
for slot in 0..rp.nb_frames {
rp.padding_len[slot] = 0;
rp.padding_nb_frames[slot] = 0;
rp.frames[slot].padding_start = None;
}
let out_len = rp.opus_repacketizer_out_range_impl(
0,
rp.nb_frames,
&mut data[dst_len..],
len - dst_len,
self_delimited,
false,
&[],
)?;
dst_len += out_len;
offset += packet_offset;
remaining = remaining
.checked_sub(packet_offset)
.ok_or(RepacketizerError::InvalidPacket)?;
}
Ok(dst_len)
}