use numpy::PyArray2;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use super::numpy_io::{interleaved_f32_to_numpy, interleaved_i16_to_numpy};
#[pyclass(module = "ruopus", name = "OpusDecoder")]
pub struct OpusDecoder {
inner: crate::decoder::OpusDecoder,
channels: usize,
sample_rate: u32,
}
#[pymethods]
impl OpusDecoder {
#[new]
#[pyo3(signature = (channels, *, sample_rate = 48_000))]
fn new(channels: usize, sample_rate: u32) -> PyResult<Self> {
if channels != 1 && channels != 2 {
return Err(PyValueError::new_err("channels must be 1 or 2"));
}
if !matches!(sample_rate, 48_000 | 24_000 | 16_000 | 12_000 | 8_000) {
return Err(PyValueError::new_err(
"sample_rate must be one of 48000, 24000, 16000, 12000, 8000",
));
}
Ok(Self {
inner: crate::decoder::OpusDecoder::with_rate(sample_rate, channels),
channels,
sample_rate,
})
}
#[getter]
fn channels(&self) -> usize {
self.channels
}
#[getter]
fn sample_rate(&self) -> u32 {
self.sample_rate
}
#[getter]
fn final_range(&self) -> u32 {
self.inner.final_range()
}
#[pyo3(signature = (data) -> "numpy.typing.NDArray[numpy.float32]")]
fn decode_packet<'py>(&mut self, py: Python<'py>, data: &[u8]) -> PyResult<Bound<'py, PyArray2<f32>>> {
let owned = data.to_vec();
let pcm = py.detach(|| self.inner.decode_packet(&owned))?;
interleaved_f32_to_numpy(py, pcm, self.channels)
}
#[pyo3(signature = (data) -> "numpy.typing.NDArray[numpy.int16]")]
fn decode_packet_i16<'py>(&mut self, py: Python<'py>, data: &[u8]) -> PyResult<Bound<'py, PyArray2<i16>>> {
let owned = data.to_vec();
let pcm = py.detach(|| self.inner.decode_packet_i16(&owned))?;
interleaved_i16_to_numpy(py, pcm, self.channels)
}
#[pyo3(signature = (frame_size) -> "numpy.typing.NDArray[numpy.float32]")]
fn decode_lost<'py>(&mut self, py: Python<'py>, frame_size: usize) -> PyResult<Bound<'py, PyArray2<f32>>> {
let pcm = py.detach(|| self.inner.decode_lost(frame_size));
interleaved_f32_to_numpy(py, pcm, self.channels)
}
#[pyo3(signature = (data, frame_size) -> "numpy.typing.NDArray[numpy.float32]")]
fn decode_fec<'py>(
&mut self,
py: Python<'py>,
data: &[u8],
frame_size: usize,
) -> PyResult<Bound<'py, PyArray2<f32>>> {
let owned = data.to_vec();
let pcm = py.detach(|| self.inner.decode_fec(&owned, frame_size))?;
interleaved_f32_to_numpy(py, pcm, self.channels)
}
fn __repr__(&self) -> String {
format!(
"OpusDecoder(channels={}, sample_rate={})",
self.channels, self.sample_rate
)
}
}