mod raw;
use {crate::GenericSample, crate::error::OperationError, std::ptr::null};
#[derive(Debug, Clone, Copy)]
pub enum OpusApplication {
Audio,
Voip,
RestrictedLowdelay,
}
impl OpusApplication {
fn to_opus_int(self) -> i32 {
match self {
Self::Audio => raw::OPUS_APPLICATION_AUDIO as i32,
Self::Voip => raw::OPUS_APPLICATION_VOIP as i32,
Self::RestrictedLowdelay => raw::OPUS_APPLICATION_RESTRICTED_LOWDELAY as i32,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum OpusBandwidth {
Narrowband,
Mediumband,
Wideband,
Superwideband,
Fullband,
Custom(i32),
}
impl OpusBandwidth {
fn to_opus_int(self) -> i32 {
match self {
Self::Narrowband => raw::OPUS_BANDWIDTH_NARROWBAND as i32,
Self::Mediumband => raw::OPUS_BANDWIDTH_MEDIUMBAND as i32,
Self::Wideband => raw::OPUS_BANDWIDTH_WIDEBAND as i32,
Self::Superwideband => raw::OPUS_BANDWIDTH_SUPERWIDEBAND as i32,
Self::Fullband => raw::OPUS_BANDWIDTH_FULLBAND as i32,
Self::Custom(value) => value,
}
}
}
pub struct OpusEncoder {
encoder: *mut raw::OpusEncoder,
channels: usize,
}
impl OpusEncoder {
pub(self) fn new(
sample_rate: usize,
channels: usize,
application: OpusApplication,
) -> Result<Self, OperationError> {
let mut error = 0;
let encoder = unsafe {
raw::opus_encoder_create(
sample_rate as _,
channels as _,
application.to_opus_int(),
&mut error,
)
};
if error != raw::OPUS_OK as i32 {
return Err(OperationError::Opus(format!(
"Failed to create Opus encoder: {}",
error
)));
}
if encoder.is_null() {
return Err(OperationError::Opus("Opus encoder is null".to_owned()));
}
Ok(Self { encoder, channels })
}
pub fn set_bitrate(&mut self, bitrate: usize) -> Result<(), OperationError> {
let result = unsafe {
raw::opus_encoder_ctl(self.encoder, raw::OPUS_SET_BITRATE_REQUEST as _, bitrate)
};
if result != raw::OPUS_OK as i32 {
return Err(OperationError::Opus(format!(
"Failed to set bitrate: {}",
result
)));
}
Ok(())
}
pub fn set_complexity(&mut self, complexity: i32) -> Result<(), OperationError> {
let result = unsafe {
raw::opus_encoder_ctl(
self.encoder,
raw::OPUS_SET_COMPLEXITY_REQUEST as _,
complexity,
)
};
if result != raw::OPUS_OK as i32 {
return Err(OperationError::Opus(format!(
"Failed to set complexity: {}",
result
)));
}
Ok(())
}
pub fn set_bandwidth(&mut self, bandwidth: OpusBandwidth) -> Result<(), OperationError> {
let result = unsafe {
raw::opus_encoder_ctl(
self.encoder,
raw::OPUS_SET_BANDWIDTH_REQUEST as _,
bandwidth.to_opus_int(),
)
};
if result != raw::OPUS_OK as i32 {
return Err(OperationError::Opus(format!(
"Failed to set bandwidth: {}",
result
)));
}
Ok(())
}
pub fn encode<S>(
&self,
pcm: &[S],
frame_size: usize,
max_data_bytes: usize,
) -> Result<Vec<u8>, OperationError>
where
S: GenericSample,
{
let samples_per_channel = pcm.len() / self.channels;
if samples_per_channel < frame_size {
return Err(OperationError::Opus(format!(
"Input data too short for encoding: need {} samples per channel, got {}",
frame_size, samples_per_channel
)));
}
let mut encoded = vec![0u8; max_data_bytes + 1];
let encoded_len = unsafe {
if S::is_i16() {
raw::opus_encode(
self.encoder,
pcm.as_ptr() as _,
frame_size as _,
encoded.as_mut_ptr(),
max_data_bytes as _,
)
} else {
raw::opus_encode_float(
self.encoder,
pcm.as_ptr() as _,
frame_size as _,
encoded.as_mut_ptr(),
max_data_bytes as _,
)
}
};
if encoded_len < 0 {
return Err(OperationError::Opus(format!(
"Failed to encode: {}",
encoded_len
)));
}
encoded.truncate(encoded_len as usize + 1);
Ok(encoded)
}
pub fn channels(&self) -> usize {
self.channels
}
}
impl Drop for OpusEncoder {
fn drop(&mut self) {
if !self.encoder.is_null() {
unsafe {
raw::opus_encoder_destroy(self.encoder);
}
}
}
}
pub struct OpusDecoder {
decoder: *mut raw::OpusDecoder,
channels: usize,
}
impl OpusDecoder {
pub(self) fn new(sample_rate: usize, channels: usize) -> Result<Self, OperationError> {
let mut error = 0;
let decoder =
unsafe { raw::opus_decoder_create(sample_rate as _, channels as _, &mut error) };
if error != raw::OPUS_OK as i32 {
return Err(OperationError::Opus(format!(
"Failed to create Opus decoder: {}",
error
)));
}
if decoder.is_null() {
return Err(OperationError::Opus("Opus decoder is null".to_owned()));
}
Ok(Self { decoder, channels })
}
pub fn decode<S>(
&self,
data: Option<&[u8]>,
frame_size: usize,
) -> Result<Vec<S>, OperationError>
where
S: GenericSample,
{
let mut decoded = vec![S::zero(); frame_size * self.channels];
let decoded_samples = unsafe {
if let Some(data) = data {
raw::opus_decode(
self.decoder,
data.as_ptr(),
data.len() as _,
decoded.as_mut_ptr() as _,
frame_size as _, 0, )
} else {
raw::opus_decode(
self.decoder,
null(),
0,
decoded.as_mut_ptr() as _,
frame_size as _, 0,
)
}
};
if decoded_samples < 0 {
return Err(OperationError::Opus(format!(
"Failed to decode: {}",
decoded_samples
)));
}
decoded.truncate(decoded_samples as usize * self.channels);
Ok(decoded)
}
}
impl Drop for OpusDecoder {
fn drop(&mut self) {
if !self.decoder.is_null() {
unsafe {
raw::opus_decoder_destroy(self.decoder);
}
}
}
}
pub struct OpusCodec;
impl OpusCodec {
pub const MAX_PACKET_SIZE: usize = 1500;
pub fn new_encoder(
sample_rate: usize,
channels: usize,
application: OpusApplication,
) -> Result<OpusEncoder, OperationError> {
OpusEncoder::new(sample_rate, channels, application)
}
pub fn new_decoder(sample_rate: usize, channels: usize) -> Result<OpusDecoder, OperationError> {
OpusDecoder::new(sample_rate, channels)
}
pub fn calculate_frame_size(sample_rate: usize, duration_ms: u64) -> usize {
(sample_rate * duration_ms as usize) / 1000
}
pub fn get_max_bandwidth_for_sample_rate(sample_rate: usize) -> OpusBandwidth {
match sample_rate {
8000 => OpusBandwidth::Narrowband,
12000 => OpusBandwidth::Mediumband,
16000 => OpusBandwidth::Wideband,
24000 => OpusBandwidth::Superwideband,
_ => OpusBandwidth::Fullband, }
}
pub fn version() -> String {
unsafe {
let version_ptr = raw::opus_get_version_string();
let c_str = std::ffi::CStr::from_ptr(version_ptr);
c_str.to_string_lossy().to_string()
}
}
}