#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_possible_wrap)]
use crate::bindings::{
OPUS_BANDWIDTH_FULLBAND, OPUS_BANDWIDTH_MEDIUMBAND, OPUS_BANDWIDTH_NARROWBAND,
OPUS_BANDWIDTH_SUPERWIDEBAND, OPUS_BANDWIDTH_WIDEBAND, opus_multistream_packet_pad,
opus_multistream_packet_unpad, opus_packet_get_bandwidth, opus_packet_get_nb_channels,
opus_packet_get_nb_frames, opus_packet_get_nb_samples, opus_packet_get_samples_per_frame,
opus_packet_has_lbrr, opus_packet_pad, opus_packet_parse, opus_packet_unpad,
opus_pcm_soft_clip,
};
use crate::error::{Error, Result};
use crate::types::{Bandwidth, Channels, SampleRate};
pub fn packet_bandwidth(packet: &[u8]) -> Result<Bandwidth> {
if packet.is_empty() {
return Err(Error::BadArg);
}
let bw = unsafe { opus_packet_get_bandwidth(packet.as_ptr()) };
match bw {
x if x == OPUS_BANDWIDTH_NARROWBAND as i32 => Ok(Bandwidth::Narrowband),
x if x == OPUS_BANDWIDTH_MEDIUMBAND as i32 => Ok(Bandwidth::Mediumband),
x if x == OPUS_BANDWIDTH_WIDEBAND as i32 => Ok(Bandwidth::Wideband),
x if x == OPUS_BANDWIDTH_SUPERWIDEBAND as i32 => Ok(Bandwidth::SuperWideband),
x if x == OPUS_BANDWIDTH_FULLBAND as i32 => Ok(Bandwidth::Fullband),
_ => Err(Error::InvalidPacket),
}
}
pub fn packet_channels(packet: &[u8]) -> Result<Channels> {
if packet.is_empty() {
return Err(Error::BadArg);
}
let ch = unsafe { opus_packet_get_nb_channels(packet.as_ptr()) };
match ch {
1 => Ok(Channels::Mono),
2 => Ok(Channels::Stereo),
_ => Err(Error::InvalidPacket),
}
}
pub fn packet_frame_count(packet: &[u8]) -> Result<usize> {
if packet.is_empty() {
return Err(Error::BadArg);
}
let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
let n = unsafe { opus_packet_get_nb_frames(packet.as_ptr(), len_i32) };
if n < 0 {
return Err(Error::from_code(n));
}
usize::try_from(n).map_err(|_| Error::InternalError)
}
pub fn packet_sample_count(packet: &[u8], sample_rate: SampleRate) -> Result<usize> {
if packet.is_empty() {
return Err(Error::BadArg);
}
let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
let n = unsafe { opus_packet_get_nb_samples(packet.as_ptr(), len_i32, sample_rate.as_i32()) };
if n < 0 {
return Err(Error::from_code(n));
}
usize::try_from(n).map_err(|_| Error::InternalError)
}
pub fn packet_samples_per_frame(packet: &[u8], sample_rate: SampleRate) -> Result<usize> {
if packet.is_empty() {
return Err(Error::BadArg);
}
let n = unsafe { opus_packet_get_samples_per_frame(packet.as_ptr(), sample_rate.as_i32()) };
if n <= 0 {
return Err(Error::InvalidPacket);
}
usize::try_from(n).map_err(|_| Error::InternalError)
}
pub fn packet_has_lbrr(packet: &[u8]) -> Result<bool> {
if packet.is_empty() {
return Err(Error::BadArg);
}
let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
let v = unsafe { opus_packet_has_lbrr(packet.as_ptr(), len_i32) };
if v < 0 {
return Err(Error::from_code(v));
}
Ok(v != 0)
}
pub fn soft_clip(
pcm: &mut [f32],
frame_size_per_ch: usize,
channels: i32,
softclip_mem: &mut [f32],
) -> Result<()> {
if frame_size_per_ch == 0 {
return Err(Error::BadArg);
}
let channels_usize = usize::try_from(channels).map_err(|_| Error::BadArg)?;
if channels_usize == 0 {
return Err(Error::BadArg);
}
if softclip_mem.len() < channels_usize {
return Err(Error::BadArg);
}
let needed_samples = frame_size_per_ch
.checked_mul(channels_usize)
.ok_or(Error::BadArg)?;
if pcm.len() < needed_samples {
return Err(Error::BadArg);
}
let frame_i32 = i32::try_from(frame_size_per_ch).map_err(|_| Error::BadArg)?;
unsafe {
opus_pcm_soft_clip(
pcm.as_mut_ptr(),
frame_i32,
channels,
softclip_mem.as_mut_ptr(),
);
}
Ok(())
}
pub fn packet_parse(packet: &[u8]) -> Result<(u8, usize, Vec<&[u8]>)> {
if packet.is_empty() {
return Err(Error::BadArg);
}
let mut out_toc: u8 = 0;
let mut payload_offset: i32 = 0;
let mut frames_ptrs: [*const u8; 48] = [std::ptr::null(); 48];
let mut sizes: [i16; 48] = [0; 48];
let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
let n = unsafe {
opus_packet_parse(
packet.as_ptr(),
len_i32,
&raw mut out_toc,
frames_ptrs.as_mut_ptr().cast::<*const u8>(),
sizes.as_mut_ptr(),
&raw mut payload_offset,
)
};
if n < 0 {
return Err(Error::from_code(n));
}
let count = usize::try_from(n).map_err(|_| Error::InternalError)?;
let mut frames = Vec::with_capacity(count);
for i in 0..count {
let size = usize::try_from(sizes[i]).map_err(|_| Error::InternalError)?;
let ptr = frames_ptrs[i];
if ptr.is_null() {
return Err(Error::InvalidPacket);
}
let ptr_addr = ptr as usize;
let base_addr = packet.as_ptr() as usize;
if ptr_addr < base_addr {
return Err(Error::InvalidPacket);
}
let start = ptr_addr - base_addr;
let end = start + size;
if end > packet.len() {
return Err(Error::InvalidPacket);
}
frames.push(&packet[start..end]);
}
Ok((
out_toc,
usize::try_from(payload_offset).map_err(|_| Error::InternalError)?,
frames,
))
}
pub fn packet_pad(packet: &mut [u8], len: usize, new_len: usize) -> Result<()> {
if new_len < len || new_len > packet.len() {
return Err(Error::BadArg);
}
let len_i32 = i32::try_from(len).map_err(|_| Error::BadArg)?;
let new_len_i32 = i32::try_from(new_len).map_err(|_| Error::BadArg)?;
let r = unsafe { opus_packet_pad(packet.as_mut_ptr(), len_i32, new_len_i32) };
if r != 0 {
return Err(Error::from_code(r));
}
Ok(())
}
pub fn packet_unpad(packet: &mut [u8], len: usize) -> Result<usize> {
if len > packet.len() {
return Err(Error::BadArg);
}
let len_i32 = i32::try_from(len).map_err(|_| Error::BadArg)?;
let n = unsafe { opus_packet_unpad(packet.as_mut_ptr(), len_i32) };
if n < 0 {
return Err(Error::from_code(n));
}
usize::try_from(n).map_err(|_| Error::InternalError)
}
pub fn multistream_packet_pad(
packet: &mut [u8],
len: usize,
new_len: usize,
nb_streams: i32,
) -> Result<()> {
if new_len < len || new_len > packet.len() {
return Err(Error::BadArg);
}
let len_i32 = i32::try_from(len).map_err(|_| Error::BadArg)?;
let new_len_i32 = i32::try_from(new_len).map_err(|_| Error::BadArg)?;
let r = unsafe {
opus_multistream_packet_pad(packet.as_mut_ptr(), len_i32, new_len_i32, nb_streams)
};
if r != 0 {
return Err(Error::from_code(r));
}
Ok(())
}
pub fn multistream_packet_unpad(packet: &mut [u8], len: usize, nb_streams: i32) -> Result<usize> {
if len > packet.len() {
return Err(Error::BadArg);
}
let len_i32 = i32::try_from(len).map_err(|_| Error::BadArg)?;
let n = unsafe { opus_multistream_packet_unpad(packet.as_mut_ptr(), len_i32, nb_streams) };
if n < 0 {
return Err(Error::from_code(n));
}
usize::try_from(n).map_err(|_| Error::InternalError)
}