use std::time::Duration;
use unsafe_libopus::{OPUS_OK, OpusDecoder, opus_decode_float, opus_decoder_create, opus_decoder_destroy};
use crate::opus;
use crate::{Error, Format};
const MAX_FRAME_MS: usize = 120;
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct Config {
pub format: Format,
pub sample_rate: Option<u32>,
pub channels: Option<u32>,
pub latency_max: Option<Duration>,
}
impl Config {
pub fn new() -> Self {
Self::default()
}
}
pub struct Decoder {
inner: *mut OpusDecoder,
sample_rate: u32,
channel_count: u32,
max_frame_size: usize,
}
unsafe impl Send for Decoder {}
impl Decoder {
pub fn new(catalog: &hang::catalog::AudioConfig) -> Result<Self, Error> {
let (sample_rate, channel_count) = if let Some(desc) = &catalog.description {
let mut buf = desc.as_ref();
match moq_mux::codec::opus::Config::parse(&mut buf) {
Ok(head) => (head.sample_rate, head.channel_count),
Err(_) => (catalog.sample_rate, catalog.channel_count),
}
} else {
(catalog.sample_rate, catalog.channel_count)
};
opus::validate_rate(sample_rate)?;
let channels = opus::validate_channels(channel_count)?;
let mut err = 0i32;
let inner = unsafe { opus_decoder_create(sample_rate as i32, channels, &mut err) };
if err != OPUS_OK || inner.is_null() {
return Err(opus::error(err, "opus_decoder_create"));
}
let max_frame_size = (sample_rate as usize * MAX_FRAME_MS) / 1000;
Ok(Self {
inner,
sample_rate,
channel_count,
max_frame_size,
})
}
pub fn sample_rate(&self) -> u32 {
self.sample_rate
}
pub fn channel_count(&self) -> u32 {
self.channel_count
}
pub fn decode(&mut self, packet: &[u8]) -> Result<Vec<f32>, Error> {
let mut out = vec![0.0f32; self.max_frame_size * self.channel_count as usize];
let samples = unsafe {
opus_decode_float(
&mut *self.inner,
packet.as_ptr(),
packet.len() as i32,
out.as_mut_ptr(),
self.max_frame_size as i32,
0,
)
};
if samples < 0 {
return Err(opus::error(samples, "opus_decode_float"));
}
out.truncate(samples as usize * self.channel_count as usize);
Ok(out)
}
}
impl Drop for Decoder {
fn drop(&mut self) {
unsafe { opus_decoder_destroy(self.inner) };
}
}