use audiopus_sys as ffi;
use opus1::internals::eval::demo::DemoDecoder;
use std::ffi::CStr;
use std::os::raw::c_int;
unsafe extern "C" {
fn opus_decode24(
st: *mut ffi::OpusDecoder,
data: *const u8,
len: i32,
pcm: *mut i32,
frame_size: c_int,
decode_fec: c_int,
) -> c_int;
}
const OPUS_SET_FORCE_MODE_REQUEST: c_int = 11002;
pub const MODE_SILK_ONLY: c_int = 1000;
pub const MODE_HYBRID: c_int = 1001;
pub const MODE_CELT_ONLY: c_int = 1002;
const OPUS_GET_FINAL_RANGE_REQUEST: c_int = 4031;
const OPUS_GET_LAST_PACKET_DURATION_REQUEST: c_int = 4039;
const OPUS_SET_IGNORE_EXTENSIONS_REQUEST: c_int = 4058;
pub fn version() -> String {
unsafe { CStr::from_ptr(ffi::opus_get_version_string()) }.to_string_lossy().into_owned()
}
pub struct CEncoder {
state: *mut ffi::OpusEncoder,
channels: usize,
}
unsafe impl Send for CEncoder {}
impl CEncoder {
pub fn new(rate: u32, channels: usize, application: c_int) -> Result<Self, String> {
let mut error: c_int = 0;
let state = unsafe { ffi::opus_encoder_create(rate as i32, channels as c_int, application, &mut error) };
if state.is_null() || error != ffi::OPUS_OK {
return Err(format!("opus_encoder_create failed with {error}"));
}
Ok(Self { state, channels })
}
pub fn ctl(&mut self, request: c_int, value: c_int) -> Result<(), String> {
let ret = unsafe { ffi::opus_encoder_ctl(self.state, request, value) };
if ret == ffi::OPUS_OK { Ok(()) } else { Err(format!("opus_encoder_ctl({request}, {value}) failed with {ret}")) }
}
pub fn get(&self, request: c_int) -> Result<i32, String> {
let mut value: i32 = 0;
let ret = unsafe { ffi::opus_encoder_ctl(self.state, request, &mut value as *mut i32) };
if ret == ffi::OPUS_OK { Ok(value) } else { Err(format!("opus_encoder_ctl({request}) failed with {ret}")) }
}
pub fn channels(&self) -> usize {
self.channels
}
pub fn set_force_mode(&mut self, mode: c_int) -> Result<(), String> {
self.ctl(OPUS_SET_FORCE_MODE_REQUEST, mode)
}
pub fn final_range(&self) -> u32 {
self.get(OPUS_GET_FINAL_RANGE_REQUEST).unwrap_or(0) as u32
}
pub fn encode(&mut self, pcm: &[f32], frame: usize, out: &mut [u8]) -> Result<usize, String> {
assert!(pcm.len() >= frame * self.channels);
let ret = unsafe {
ffi::opus_encode_float(self.state, pcm.as_ptr(), frame as c_int, out.as_mut_ptr(), out.len() as i32)
};
if ret < 0 { Err(format!("opus_encode_float failed with {ret}")) } else { Ok(ret as usize) }
}
}
impl Drop for CEncoder {
fn drop(&mut self) {
unsafe { ffi::opus_encoder_destroy(self.state) }
}
}
pub struct CDecoder {
state: *mut ffi::OpusDecoder,
channels: usize,
}
unsafe impl Send for CDecoder {}
impl CDecoder {
pub fn new(rate: u32, channels: usize) -> Result<Self, String> {
let mut error: c_int = 0;
let state = unsafe { ffi::opus_decoder_create(rate as i32, channels as c_int, &mut error) };
if state.is_null() || error != ffi::OPUS_OK {
return Err(format!("opus_decoder_create failed with {error}"));
}
let ret = unsafe { ffi::opus_decoder_ctl(state, OPUS_SET_IGNORE_EXTENSIONS_REQUEST, 1 as c_int) };
if ret != ffi::OPUS_OK {
unsafe { ffi::opus_decoder_destroy(state) };
return Err(format!("OPUS_SET_IGNORE_EXTENSIONS failed with {ret}"));
}
Ok(Self { state, channels })
}
fn get(&self, request: c_int) -> i32 {
let mut value: i32 = 0;
unsafe { ffi::opus_decoder_ctl(self.state, request, &mut value as *mut i32) };
value
}
}
impl DemoDecoder for CDecoder {
fn channels(&self) -> usize {
self.channels
}
fn decode24(&mut self, data: &[u8], frame_size: usize, decode_fec: bool, out: &mut [i32]) -> Result<usize, &'static str> {
if out.len() < frame_size * self.channels {
return Err("output buffer too small");
}
let ptr = if data.is_empty() { std::ptr::null() } else { data.as_ptr() };
let ret = unsafe {
opus_decode24(self.state, ptr, data.len() as i32, out.as_mut_ptr(), frame_size as c_int, decode_fec as c_int)
};
if ret < 0 { Err("libopus decode error") } else { Ok(ret as usize) }
}
fn last_packet_duration(&self) -> usize {
self.get(OPUS_GET_LAST_PACKET_DURATION_REQUEST).max(0) as usize
}
fn final_range(&self) -> u32 {
self.get(OPUS_GET_FINAL_RANGE_REQUEST) as u32
}
}
impl Drop for CDecoder {
fn drop(&mut self) {
unsafe { ffi::opus_decoder_destroy(self.state) }
}
}