use super::GenericCtl;
use crate::{
error::try_map_opus_error, ffi, Application, Bandwidth, Bitrate, Channels, ErrorCode, Result,
SampleRate, Signal, TryFrom,
};
#[derive(Debug)]
pub struct Encoder {
pointer: *mut ffi::OpusEncoder,
channels: Channels,
}
unsafe impl Send for Encoder {}
impl GenericCtl for Encoder {
fn final_range(&self) -> Result<u32> {
self.encoder_ctl_request(ffi::OPUS_GET_FINAL_RANGE_REQUEST)
.map(|v| v as u32)
}
fn phase_inversion_disabled(&self) -> Result<bool> {
self.encoder_ctl_request(ffi::OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST)
.map(|b| b == 1)
}
fn set_phase_inversion_disabled(&mut self, disabled: bool) -> Result<()> {
let disable_phase_inversion = if disabled { 1 } else { 0 };
self.set_encoder_ctl_request(
ffi::OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST,
disable_phase_inversion,
)
.map(|_| ())
}
fn sample_rate(&self) -> Result<SampleRate> {
self.encoder_ctl_request(ffi::OPUS_GET_SAMPLE_RATE_REQUEST)
.and_then(SampleRate::try_from)
}
fn reset_state(&mut self) -> Result<()> {
self.encoder_ctl_request(ffi::OPUS_RESET_STATE).map(|_| ())
}
}
impl Encoder {
pub fn new(sample_rate: SampleRate, channels: Channels, mode: Application) -> Result<Encoder> {
let mut opus_code = 0;
let pointer = unsafe {
ffi::opus_encoder_create(
sample_rate as i32,
channels as i32,
mode as i32,
&mut opus_code,
)
};
if opus_code == ffi::OPUS_OK || !pointer.is_null() {
return Ok(Encoder { pointer, channels });
}
Err(ErrorCode::from(opus_code))?
}
pub fn encoder_ctl_request(&self, request: i32) -> Result<i32> {
let mut value = 0;
let ffi_result = unsafe { ffi::opus_encoder_ctl(self.pointer, request, &mut value) };
try_map_opus_error(ffi_result)?;
Ok(value)
}
pub fn set_encoder_ctl_request(&mut self, request: i32, value: i32) -> Result<()> {
try_map_opus_error(unsafe { ffi::opus_encoder_ctl(self.pointer, request, value) })?;
Ok(())
}
pub fn encode(&self, input: &[i16], output: &mut [u8]) -> Result<usize> {
try_map_opus_error(unsafe {
ffi::opus_encode(
self.pointer,
input.as_ptr(),
input.len() as i32 / self.channels as i32,
output.as_mut_ptr(),
output.len() as i32,
)
})
.map(|n| n as usize)
}
pub fn encode_float(&self, input: &[f32], output: &mut [u8]) -> Result<usize> {
try_map_opus_error(unsafe {
ffi::opus_encode_float(
self.pointer,
input.as_ptr(),
input.len() as i32 / self.channels as i32,
output.as_mut_ptr(),
output.len() as i32,
)
})
.map(|n| n as usize)
}
pub fn complexity(&self) -> Result<u8> {
self.encoder_ctl_request(ffi::OPUS_GET_COMPLEXITY_REQUEST)
.map(|v| v as u8)
}
pub fn set_complexity(&mut self, complexity: u8) -> Result<()> {
self.set_encoder_ctl_request(ffi::OPUS_SET_COMPLEXITY_REQUEST, i32::from(complexity))
}
pub fn application(&self) -> Result<Application> {
self.encoder_ctl_request(ffi::OPUS_GET_APPLICATION_REQUEST)
.and_then(Application::try_from)
}
pub fn set_application(&mut self, application: Application) -> Result<()> {
self.set_encoder_ctl_request(ffi::OPUS_SET_APPLICATION_REQUEST, application as i32)
.map(|_| ())
}
pub fn set_bitrate(&mut self, bitrate: Bitrate) -> Result<()> {
self.set_encoder_ctl_request(ffi::OPUS_SET_BITRATE_REQUEST, bitrate.into())?;
Ok(())
}
pub fn bitrate(&self) -> Result<Bitrate> {
self.encoder_ctl_request(ffi::OPUS_GET_BITRATE_REQUEST)
.and_then(Bitrate::try_from)
}
pub fn enable_vbr_constraint(&mut self) -> Result<()> {
self.set_vbr_constraint(true)
}
pub fn disable_vbr_constraint(&mut self) -> Result<()> {
self.set_vbr_constraint(false)
}
pub fn set_vbr_constraint(&mut self, enable: bool) -> Result<()> {
let if_vbr_shall_be_enabled = if enable { 1 } else { 0 };
self.set_encoder_ctl_request(
ffi::OPUS_SET_VBR_CONSTRAINT_REQUEST,
if_vbr_shall_be_enabled,
)
.map(|_| ())
}
pub fn vbr_constraint(&self) -> Result<bool> {
self.encoder_ctl_request(ffi::OPUS_GET_VBR_CONSTRAINT_REQUEST)
.map(|b| b == 1)
}
pub fn enable_vbr(&mut self) -> Result<()> {
self.set_vbr(true)
}
pub fn disable_vbr(&mut self) -> Result<()> {
self.set_vbr(false)
}
pub fn set_vbr(&mut self, enable: bool) -> Result<()> {
let if_vbr_shall_be_enabled = if enable { 1 } else { 0 };
self.set_encoder_ctl_request(ffi::OPUS_SET_VBR_REQUEST, if_vbr_shall_be_enabled)
.map(|_| ())
}
pub fn vbr(&self) -> Result<bool> {
self.encoder_ctl_request(ffi::OPUS_GET_VBR_REQUEST)
.map(|b| b == 1)
}
pub fn set_inband_fec(&mut self, enable: bool) -> Result<()> {
let if_inband_fec_shall_be_enabled = if enable { 1 } else { 0 };
self.set_encoder_ctl_request(
ffi::OPUS_SET_INBAND_FEC_REQUEST,
if_inband_fec_shall_be_enabled,
)
.map(|_| ())
}
pub fn enable_inband_fec(&mut self) -> Result<()> {
self.set_inband_fec(true)
}
pub fn disable_inband_fec(&mut self) -> Result<()> {
self.set_inband_fec(false)
}
pub fn inband_fec(&self) -> Result<bool> {
self.encoder_ctl_request(ffi::OPUS_GET_INBAND_FEC_REQUEST)
.map(|n| n == 1)
}
pub fn packet_loss_perc(&self) -> Result<u8> {
self.encoder_ctl_request(ffi::OPUS_GET_PACKET_LOSS_PERC_REQUEST)
.map(|n| n as u8)
}
pub fn set_packet_loss_perc(&mut self, percentage: u8) -> Result<()> {
self.set_encoder_ctl_request(
ffi::OPUS_SET_PACKET_LOSS_PERC_REQUEST,
i32::from(percentage),
)
.map(|_| ())
}
pub fn lookahead(&self) -> Result<u32> {
self.encoder_ctl_request(ffi::OPUS_GET_LOOKAHEAD_REQUEST)
.map(|n| n as u32)
}
pub fn set_force_channels(&mut self, channels: Channels) -> Result<()> {
self.set_encoder_ctl_request(ffi::OPUS_SET_FORCE_CHANNELS_REQUEST, channels as i32)
.map(|_| ())
}
pub fn force_channels(&self) -> Result<Channels> {
self.encoder_ctl_request(ffi::OPUS_GET_FORCE_CHANNELS_REQUEST)
.and_then(Channels::try_from)
}
pub fn max_bandwidth(&self) -> Result<Bandwidth> {
self.encoder_ctl_request(ffi::OPUS_GET_MAX_BANDWIDTH_REQUEST)
.and_then(Bandwidth::try_from)
}
pub fn set_max_bandwidth(&mut self, bandwidth: Bandwidth) -> Result<()> {
self.set_encoder_ctl_request(ffi::OPUS_SET_MAX_BANDWIDTH_REQUEST, bandwidth as i32)
}
pub fn prediction_disabled(&self) -> Result<bool> {
self.encoder_ctl_request(ffi::OPUS_GET_PREDICTION_DISABLED_REQUEST)
.map(|n| n == 1)
}
pub fn set_prediction_disabled(&mut self, precition_disabled: bool) -> Result<()> {
let precition_disabled = if precition_disabled { 1 } else { 0 };
self.set_encoder_ctl_request(
ffi::OPUS_SET_PREDICTION_DISABLED_REQUEST,
precition_disabled,
)
.map(|_| ())
}
pub fn signal(&self) -> Result<Signal> {
self.encoder_ctl_request(ffi::OPUS_GET_SIGNAL_REQUEST)
.and_then(Signal::try_from)
}
pub fn set_signal(&mut self, signal: Signal) -> Result<()> {
self.set_encoder_ctl_request(ffi::OPUS_SET_SIGNAL_REQUEST, signal as i32)
.map(|_| ())
}
pub fn bandwidth(&self) -> Result<Bandwidth> {
self.encoder_ctl_request(ffi::OPUS_GET_BANDWIDTH_REQUEST)
.and_then(Bandwidth::try_from)
}
pub fn set_bandwidth(&mut self, bandwidth: Bandwidth) -> Result<()> {
self.set_encoder_ctl_request(ffi::OPUS_SET_BANDWIDTH_REQUEST, bandwidth as i32)
}
}
impl Drop for Encoder {
fn drop(&mut self) {
unsafe { ffi::opus_encoder_destroy(self.pointer) }
}
}
#[cfg(test)]
mod tests {
use super::Encoder;
use crate::{Application, Bandwidth, Bitrate, Channels, Error, ErrorCode, SampleRate, Signal};
use matches::assert_matches;
#[test]
fn set_get_inband_fec() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
assert_matches!(encoder.inband_fec(), Ok(false));
encoder
.set_inband_fec(true)
.expect("Could not set inband FEC to true.");
assert_matches!(encoder.inband_fec(), Ok(true));
encoder
.set_inband_fec(false)
.expect("Could not set inband FEC to false.");
assert_matches!(encoder.inband_fec(), Ok(false));
encoder
.enable_inband_fec()
.expect("Could not set inband FEC to true.");
assert_matches!(encoder.inband_fec(), Ok(true));
encoder
.disable_inband_fec()
.expect("Could not set inband FEC to false.");
assert_matches!(encoder.inband_fec(), Ok(false));
}
#[test]
fn set_get_vbr_constraint() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
assert_matches!(encoder.vbr_constraint(), Ok(true));
encoder
.set_vbr_constraint(false)
.expect("Could not disable VBR constraint.");
assert_matches!(encoder.vbr_constraint(), Ok(false));
encoder
.set_vbr_constraint(true)
.expect("Could not enable VBR constraint.");
assert_matches!(encoder.vbr_constraint(), Ok(true));
encoder
.enable_vbr_constraint()
.expect("Could not enable VBR constraint.");
assert_matches!(encoder.vbr_constraint(), Ok(true));
encoder
.disable_vbr_constraint()
.expect("Could not disable VBR constraint.");
assert_matches!(encoder.vbr_constraint(), Ok(false));
}
#[test]
fn set_get_vbr() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
assert_matches!(encoder.vbr(), Ok(true));
encoder.set_vbr(false).expect("Could not disable VBR.");
assert_matches!(encoder.vbr(), Ok(false));
encoder.set_vbr(true).expect("Could not enable VBR.");
assert_matches!(encoder.vbr(), Ok(true));
encoder.enable_vbr().expect("Could not enable VBR.");
assert_matches!(encoder.vbr(), Ok(true));
encoder.disable_vbr().expect("Could not disable VBR.");
assert_matches!(encoder.vbr(), Ok(false));
}
#[test]
fn set_get_packet_loss_perc() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
assert_matches!(encoder.packet_loss_perc(), Ok(0));
encoder
.set_packet_loss_perc(10)
.expect("Could not set packet loss perc to 10%.");
assert_matches!(encoder.packet_loss_perc(), Ok(10));
encoder
.set_packet_loss_perc(100)
.expect("Could not set packet loss perc to 100%.");
assert_matches!(encoder.packet_loss_perc(), Ok(100));
assert_matches!(
encoder.set_packet_loss_perc(101),
Err(Error::Opus(ErrorCode::BadArgument))
);
assert_matches!(encoder.packet_loss_perc(), Ok(100));
}
#[test]
fn set_get_force_channels() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
assert_matches!(encoder.force_channels(), Ok(Channels::Auto));
encoder
.set_force_channels(Channels::Mono)
.expect("Could not set force channels to mono.");
assert_matches!(encoder.force_channels(), Ok(Channels::Mono));
encoder
.set_force_channels(Channels::Stereo)
.expect("Could not set force channels to stereo.");
assert_matches!(encoder.force_channels(), Ok(Channels::Stereo));
encoder
.set_force_channels(Channels::Auto)
.expect("Could not set force channels to mono.");
assert_matches!(encoder.force_channels(), Ok(Channels::Auto));
}
#[test]
fn set_get_prediction_disabled() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
assert_matches!(encoder.prediction_disabled(), Ok(false));
encoder
.set_prediction_disabled(true)
.expect("Could not set prediction disabled to true.");
assert_matches!(encoder.prediction_disabled(), Ok(true));
encoder
.set_prediction_disabled(false)
.expect("Could not set prediction disabled to false.");
assert_matches!(encoder.prediction_disabled(), Ok(false));
}
#[test]
fn set_get_signal() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
assert_matches!(encoder.signal(), Ok(Signal::Auto));
encoder
.set_signal(Signal::Music)
.expect("Could not set signal to music.");
assert_matches!(encoder.signal(), Ok(Signal::Music));
encoder
.set_signal(Signal::Voice)
.expect("Could not set signal to voice.");
assert_matches!(encoder.signal(), Ok(Signal::Voice));
encoder
.set_signal(Signal::Auto)
.expect("Could not set signal back to.");
assert_matches!(encoder.signal(), Ok(Signal::Auto));
}
#[test]
fn encoder_construction() {
assert_matches!(
Encoder::new(SampleRate::Hz48000, Channels::Auto, Application::Audio),
Err(Error::Opus(ErrorCode::BadArgument))
);
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio)
.expect("Could not create stereo audio encoder");
Encoder::new(SampleRate::Hz48000, Channels::Mono, Application::Audio)
.expect("Could not create mono audio encoder");
}
#[test]
fn encoding() {
let stereo_encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
const STEREO_20MS: usize = 48000 * 2 * 20 / 1000;
let input = [0_i16; STEREO_20MS];
let mut output = [0; 256];
let len = stereo_encoder.encode(&input, &mut output).unwrap();
assert_eq!(&output[..len], &[252, 255, 254]);
let mono_encoder =
Encoder::new(SampleRate::Hz48000, Channels::Mono, Application::Audio).unwrap();
const MONO_20MS: usize = 48000 * 1 * 20 / 1000;
let input = [0_i16; MONO_20MS];
let mut output = [0; 256];
let len = mono_encoder.encode(&input, &mut output).unwrap();
assert_eq!(&output[..len], &[248, 255, 254]);
}
#[test]
fn set_max_bandwidth() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
assert_matches!(encoder.max_bandwidth(), Ok(Bandwidth::Fullband));
let bandwidth_to_set = Bandwidth::Narrowband;
encoder.set_max_bandwidth(bandwidth_to_set).unwrap();
let bandwidth_got = encoder.max_bandwidth().unwrap();
assert_eq!(bandwidth_to_set, bandwidth_got);
}
#[test]
fn get_set_complexity() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio).unwrap();
encoder
.set_complexity(10)
.expect("Could not set complexity to 10.");
assert_matches!(encoder.complexity(), Ok(10));
encoder
.set_complexity(0)
.expect("Could not set complexity to 0.");
assert_matches!(encoder.complexity(), Ok(0));
assert_matches!(
encoder.set_complexity(11),
Err(Error::Opus(ErrorCode::BadArgument))
);
}
#[test]
fn set_get_application() {
let application_to_set = Application::Audio;
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Stereo, application_to_set).unwrap();
let current_application = encoder.application().unwrap();
assert_eq!(current_application, application_to_set);
let application_to_set = Application::Voip;
encoder.set_application(application_to_set).unwrap();
let current_application = encoder.application().unwrap();
assert_eq!(current_application, application_to_set);
let application_to_set = Application::LowDelay;
encoder.set_application(application_to_set).unwrap();
let current_application = encoder.application().unwrap();
assert_eq!(current_application, application_to_set);
let application_to_set = Application::Audio;
encoder.set_application(application_to_set).unwrap();
let current_application = encoder.application().unwrap();
assert_eq!(current_application, application_to_set);
}
#[test]
fn set_get_bitrate() {
let mut encoder =
Encoder::new(SampleRate::Hz48000, Channels::Mono, Application::Audio).unwrap();
let bitrate = 512000;
encoder
.set_bitrate(Bitrate::BitsPerSecond(bitrate))
.expect("Could not set bitrate to 512000.");
assert_matches!(encoder.bitrate(), _bitrate);
}
}