use crate::bindings::{
OpusDRED, OpusDREDDecoder, opus_decoder_dred_decode, opus_decoder_dred_decode_float,
opus_dred_alloc, opus_dred_decoder_create, opus_dred_decoder_ctl, opus_dred_decoder_destroy,
opus_dred_decoder_get_size, opus_dred_decoder_init, opus_dred_free, opus_dred_get_size,
opus_dred_parse, opus_dred_process,
};
use crate::constants::max_frame_samples_for;
use crate::decoder::Decoder;
use crate::error::{Error, Result};
use crate::types::SampleRate;
use crate::{AlignedBuffer, Ownership, RawHandle};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
pub struct DredDecoder {
raw: RawHandle<OpusDREDDecoder>,
}
unsafe impl Send for DredDecoder {}
unsafe impl Sync for DredDecoder {}
pub struct DredDecoderRef<'a> {
inner: DredDecoder,
_marker: PhantomData<&'a mut OpusDREDDecoder>,
}
unsafe impl Send for DredDecoderRef<'_> {}
unsafe impl Sync for DredDecoderRef<'_> {}
impl DredDecoder {
fn from_raw(ptr: NonNull<OpusDREDDecoder>, ownership: Ownership) -> Self {
Self {
raw: RawHandle::new(ptr, ownership, opus_dred_decoder_destroy),
}
}
pub fn new() -> Result<Self> {
let mut err = 0;
let ptr = unsafe { opus_dred_decoder_create(std::ptr::addr_of_mut!(err)) };
if err != 0 {
return Err(Error::from_code(err));
}
let ptr = NonNull::new(ptr).ok_or(Error::AllocFail)?;
Ok(Self::from_raw(ptr, Ownership::Owned))
}
pub unsafe fn init_in_place(ptr: *mut OpusDREDDecoder) -> Result<()> {
if ptr.is_null() {
return Err(Error::BadArg);
}
if !crate::opus_ptr_is_aligned(ptr.cast()) {
return Err(Error::BadArg);
}
let r = unsafe { opus_dred_decoder_init(ptr) };
if r != 0 {
return Err(Error::from_code(r));
}
Ok(())
}
pub fn as_mut_ptr(&mut self) -> *mut OpusDREDDecoder {
self.raw.as_ptr()
}
pub fn size() -> Result<usize> {
let raw = unsafe { opus_dred_decoder_get_size() };
usize::try_from(raw).map_err(|_| Error::InternalError)
}
pub unsafe fn control<T>(&mut self, request: i32, arg: T) -> Result<()>
where
T: Copy,
{
let r = unsafe { opus_dred_decoder_ctl(self.raw.as_ptr(), request, arg) };
if r != 0 {
return Err(Error::from_code(r));
}
Ok(())
}
pub fn parse(
&mut self,
state: &mut DredState,
data: &[u8],
max_dred_samples: usize,
sampling_rate: SampleRate,
dred_end: &mut i32,
defer_processing: bool,
) -> Result<usize> {
let len = i32::try_from(data.len()).map_err(|_| Error::BadArg)?;
let max_samples = i32::try_from(max_dred_samples).map_err(|_| Error::BadArg)?;
let result = unsafe {
opus_dred_parse(
self.raw.as_ptr(),
state.raw.as_ptr(),
data.as_ptr(),
len,
max_samples,
sampling_rate.as_i32(),
dred_end,
i32::from(defer_processing),
)
};
if result < 0 {
return Err(Error::from_code(result));
}
usize::try_from(result).map_err(|_| Error::InternalError)
}
pub fn process(&mut self, src: &DredState, dst: &mut DredState) -> Result<()> {
let r = unsafe { opus_dred_process(self.raw.as_ptr(), src.raw.as_ptr(), dst.raw.as_ptr()) };
if r != 0 {
return Err(Error::from_code(r));
}
Ok(())
}
pub fn decode_into_i16(
&mut self,
decoder: &mut Decoder,
state: &DredState,
dred_offset: i32,
pcm: &mut [i16],
) -> Result<usize> {
let channel_count = decoder.channels().as_usize();
let frame_size = validate_pcm_frame_len(pcm, channel_count, decoder.sample_rate())?;
let result = unsafe {
opus_decoder_dred_decode(
decoder.as_mut_ptr(),
state.raw.as_ptr(),
dred_offset,
pcm.as_mut_ptr(),
frame_size,
)
};
if result < 0 {
return Err(Error::from_code(result));
}
usize::try_from(result).map_err(|_| Error::InternalError)
}
pub fn decode_into_f32(
&mut self,
decoder: &mut Decoder,
state: &DredState,
dred_offset: i32,
pcm: &mut [f32],
) -> Result<usize> {
let channel_count = decoder.channels().as_usize();
let frame_size = validate_pcm_frame_len(pcm, channel_count, decoder.sample_rate())?;
let result = unsafe {
opus_decoder_dred_decode_float(
decoder.as_mut_ptr(),
state.raw.as_ptr(),
dred_offset,
pcm.as_mut_ptr(),
frame_size,
)
};
if result < 0 {
return Err(Error::from_code(result));
}
usize::try_from(result).map_err(|_| Error::InternalError)
}
}
impl<'a> DredDecoderRef<'a> {
#[must_use]
pub unsafe fn from_raw(ptr: *mut OpusDREDDecoder) -> Self {
debug_assert!(!ptr.is_null(), "from_raw called with null ptr");
debug_assert!(crate::opus_ptr_is_aligned(ptr.cast()));
let decoder =
DredDecoder::from_raw(unsafe { NonNull::new_unchecked(ptr) }, Ownership::Borrowed);
Self {
inner: decoder,
_marker: PhantomData,
}
}
pub fn init_in(buf: &'a mut AlignedBuffer) -> Result<Self> {
let required = DredDecoder::size()?;
if buf.capacity_bytes() < required {
return Err(Error::BadArg);
}
let ptr = buf.as_mut_ptr::<OpusDREDDecoder>();
unsafe { DredDecoder::init_in_place(ptr)? };
Ok(unsafe { Self::from_raw(ptr) })
}
}
impl Deref for DredDecoderRef<'_> {
type Target = DredDecoder;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for DredDecoderRef<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
fn validate_pcm_frame_len<T>(
pcm: &[T],
channel_count: usize,
sample_rate: SampleRate,
) -> Result<i32> {
if channel_count == 0 {
return Err(Error::InvalidState);
}
if pcm.is_empty() {
return Err(Error::BadArg);
}
if !pcm.len().is_multiple_of(channel_count) {
return Err(Error::BadArg);
}
let frame_size_per_ch = pcm.len() / channel_count;
if frame_size_per_ch == 0 || frame_size_per_ch > max_frame_samples_for(sample_rate) {
return Err(Error::BadArg);
}
i32::try_from(frame_size_per_ch).map_err(|_| Error::BadArg)
}
pub struct DredState {
raw: NonNull<OpusDRED>,
}
unsafe impl Send for DredState {}
unsafe impl Sync for DredState {}
impl DredState {
pub fn new() -> Result<Self> {
let mut err = 0;
let ptr = unsafe { opus_dred_alloc(std::ptr::addr_of_mut!(err)) };
if err != 0 {
return Err(Error::from_code(err));
}
let ptr = NonNull::new(ptr).ok_or(Error::AllocFail)?;
Ok(Self { raw: ptr })
}
pub fn size() -> Result<usize> {
let raw = unsafe { opus_dred_get_size() };
if raw == 0 {
return Err(Error::Unimplemented);
}
if raw < 0 {
return Err(Error::InternalError);
}
usize::try_from(raw).map_err(|_| Error::InternalError)
}
pub fn as_mut_ptr(&mut self) -> *mut OpusDRED {
self.raw.as_ptr()
}
}
impl Drop for DredState {
fn drop(&mut self) {
unsafe { opus_dred_free(self.raw.as_ptr()) };
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validate_pcm_frame_len_checks_arguments() {
let pcm = vec![0i16; 4];
assert!(validate_pcm_frame_len(&pcm, 2, SampleRate::Hz48000).is_ok());
let err = validate_pcm_frame_len(&pcm, 0, SampleRate::Hz48000).unwrap_err();
assert_eq!(err, Error::InvalidState);
let err = validate_pcm_frame_len(&pcm[..3], 2, SampleRate::Hz48000).unwrap_err();
assert_eq!(err, Error::BadArg);
let err = validate_pcm_frame_len(&[] as &[i16], 2, SampleRate::Hz48000).unwrap_err();
assert_eq!(err, Error::BadArg);
}
}