use crate::bindings::{
OpusRepacketizer, opus_repacketizer_cat, opus_repacketizer_create, opus_repacketizer_destroy,
opus_repacketizer_get_nb_frames, opus_repacketizer_get_size, opus_repacketizer_init,
opus_repacketizer_out, opus_repacketizer_out_range,
};
use crate::error::{Error, Result};
use crate::{AlignedBuffer, Ownership, RawHandle};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
pub struct Repacketizer {
rp: RawHandle<OpusRepacketizer>,
packets: Vec<Vec<u8>>,
}
unsafe impl Send for Repacketizer {}
unsafe impl Sync for Repacketizer {}
pub struct RepacketizerRef<'a> {
inner: Repacketizer,
_marker: PhantomData<&'a mut OpusRepacketizer>,
}
unsafe impl Send for RepacketizerRef<'_> {}
unsafe impl Sync for RepacketizerRef<'_> {}
impl Repacketizer {
fn from_raw(ptr: NonNull<OpusRepacketizer>, ownership: Ownership) -> Self {
Self {
rp: RawHandle::new(ptr, ownership, opus_repacketizer_destroy),
packets: Vec::new(),
}
}
pub fn new() -> Result<Self> {
let rp = unsafe { opus_repacketizer_create() };
let rp = NonNull::new(rp).ok_or(Error::AllocFail)?;
Ok(Self::from_raw(rp, Ownership::Owned))
}
pub fn reset(&mut self) {
unsafe { opus_repacketizer_init(self.rp.as_ptr()) };
self.packets.clear();
}
pub fn push(&mut self, packet: &[u8]) -> Result<()> {
if packet.is_empty() {
return Err(Error::BadArg);
}
let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
self.packets.push(packet.to_vec());
let idx = self.packets.len() - 1;
let r =
unsafe { opus_repacketizer_cat(self.rp.as_ptr(), self.packets[idx].as_ptr(), len_i32) };
if r != 0 {
self.packets.pop();
return Err(Error::from_code(r));
}
Ok(())
}
#[must_use]
pub fn frame_count(&self) -> i32 {
unsafe { opus_repacketizer_get_nb_frames(self.rp.as_ptr()) }
}
#[must_use]
pub fn len(&self) -> usize {
let frames = self.frame_count();
debug_assert!(
frames >= 0,
"repacketizer frame count should be non-negative"
);
usize::try_from(frames).unwrap_or(0)
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn emit_range(&mut self, begin: i32, end: i32, out: &mut [u8]) -> Result<usize> {
if out.is_empty() {
return Err(Error::BadArg);
}
if begin < 0 || end <= begin {
return Err(Error::BadArg);
}
let out_len_i32 = i32::try_from(out.len()).map_err(|_| Error::BadArg)?;
let n = unsafe {
opus_repacketizer_out_range(self.rp.as_ptr(), begin, end, out.as_mut_ptr(), out_len_i32)
};
if n < 0 {
return Err(Error::from_code(n));
}
usize::try_from(n).map_err(|_| Error::InternalError)
}
pub fn emit(&mut self, out: &mut [u8]) -> Result<usize> {
if out.is_empty() {
return Err(Error::BadArg);
}
let out_len_i32 = i32::try_from(out.len()).map_err(|_| Error::BadArg)?;
let n = unsafe { opus_repacketizer_out(self.rp.as_ptr(), out.as_mut_ptr(), out_len_i32) };
if n < 0 {
return Err(Error::from_code(n));
}
usize::try_from(n).map_err(|_| Error::InternalError)
}
pub fn size() -> Result<usize> {
let raw = unsafe { opus_repacketizer_get_size() };
if raw <= 0 {
return Err(Error::InternalError);
}
usize::try_from(raw).map_err(|_| Error::InternalError)
}
pub unsafe fn init_in_place(ptr: *mut OpusRepacketizer) -> Result<()> {
if ptr.is_null() {
return Err(Error::BadArg);
}
if !crate::opus_ptr_is_aligned(ptr.cast()) {
return Err(Error::BadArg);
}
unsafe { opus_repacketizer_init(ptr) };
Ok(())
}
}
impl<'a> RepacketizerRef<'a> {
#[must_use]
pub unsafe fn from_raw(ptr: *mut OpusRepacketizer) -> Self {
debug_assert!(!ptr.is_null(), "from_raw called with null ptr");
debug_assert!(crate::opus_ptr_is_aligned(ptr.cast()));
let repacketizer =
Repacketizer::from_raw(unsafe { NonNull::new_unchecked(ptr) }, Ownership::Borrowed);
Self {
inner: repacketizer,
_marker: PhantomData,
}
}
pub fn init_in(buf: &'a mut AlignedBuffer) -> Result<Self> {
let required = Repacketizer::size()?;
if buf.capacity_bytes() < required {
return Err(Error::BadArg);
}
let ptr = buf.as_mut_ptr::<OpusRepacketizer>();
unsafe { Repacketizer::init_in_place(ptr)? };
Ok(unsafe { Self::from_raw(ptr) })
}
}
impl Deref for RepacketizerRef<'_> {
type Target = Repacketizer;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for RepacketizerRef<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}