// Copyright 2016 Tad Hardesty // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! High-level bindings for libopus. //! //! Only brief descriptions are included here. For detailed information, consult //! the [libopus documentation](https://opus-codec.org/docs/opus_api-1.1.2/). #![warn(missing_docs)] mod opus_ffi; use opus_ffi as ffi; use std::ffi::CStr; use std::marker::PhantomData; use std::os::raw::c_int; // ============================================================================ // Constants // Generic CTLs const OPUS_RESET_STATE: c_int = 4028; // void const OPUS_GET_FINAL_RANGE: c_int = 4031; // out *u32 const OPUS_GET_BANDWIDTH: c_int = 4009; // out *i32 const OPUS_GET_SAMPLE_RATE: c_int = 4029; // out *i32 // Encoder CTLs const OPUS_SET_BITRATE: c_int = 4002; // in i32 const OPUS_GET_BITRATE: c_int = 4003; // out *i32 const OPUS_SET_VBR: c_int = 4006; // in i32 const OPUS_GET_VBR: c_int = 4007; // out *i32 const OPUS_SET_VBR_CONSTRAINT: c_int = 4020; // in i32 const OPUS_GET_VBR_CONSTRAINT: c_int = 4021; // out *i32 const OPUS_SET_INBAND_FEC: c_int = 4012; // in i32 const OPUS_GET_INBAND_FEC: c_int = 4013; // out *i32 const OPUS_SET_PACKET_LOSS_PERC: c_int = 4014; // in i32 const OPUS_GET_PACKET_LOSS_PERC: c_int = 4015; // out *i32 const OPUS_SET_DTX_REQUEST: c_int = 4016; const OPUS_GET_DTX_REQUEST: c_int = 4017; const OPUS_GET_LOOKAHEAD: c_int = 4027; // out *i32 const OPUS_GET_IN_DTX_REQUEST: c_int = 4049; // Decoder CTLs const OPUS_SET_GAIN: c_int = 4034; // in i32 const OPUS_GET_GAIN: c_int = 4045; // out *i32 const OPUS_GET_LAST_PACKET_DURATION: c_int = 4039; // out *i32 const OPUS_GET_PITCH: c_int = 4033; // out *i32 // Bitrate const OPUS_AUTO: c_int = -1000; const OPUS_BITRATE_MAX: c_int = -1; /// The possible applications for the codec. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum Application { /// Best for most VoIP/videoconference applications where listening quality /// and intelligibility matter most. Voip = 2048, /// Best for broadcast/high-fidelity application where the decoded audio /// should be as close as possible to the input. Audio = 2049, /// Only use when lowest-achievable latency is what matters most. LowDelay = 2051, } /// The available channel setings. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum Channels { /// One channel. Mono = 1, /// Two channels, left and right. Stereo = 2, } /// The available bandwidth level settings. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum Bandwidth { /// Auto/default setting. Auto = -1000, /// 4kHz bandpass. Narrowband = 1101, /// 6kHz bandpass. Mediumband = 1102, /// 8kHz bandpass. Wideband = 1103, /// 12kHz bandpass. Superwideband = 1104, /// 20kHz bandpass. Fullband = 1105, } impl Bandwidth { fn from_int(value: i32) -> Option { Some(match value { -1000 => Bandwidth::Auto, 1101 => Bandwidth::Narrowband, 1102 => Bandwidth::Mediumband, 1103 => Bandwidth::Wideband, 1104 => Bandwidth::Superwideband, 1105 => Bandwidth::Fullband, _ => return None, }) } fn decode(value: i32, what: &'static str) -> Result { match Bandwidth::from_int(value) { Some(bandwidth) => Ok(bandwidth), None => Err(Error::bad_arg(what)), } } } /// Possible error codes. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum ErrorCode { /// One or more invalid/out of range arguments. BadArg = -1, /// Not enough bytes allocated in the buffer. BufferTooSmall = -2, /// An internal error was detected. InternalError = -3, /// The compressed data passed is corrupted. InvalidPacket = -4, /// Invalid/unsupported request number. Unimplemented = -5, /// An encoder or decoder structure is invalid or already freed. InvalidState = -6, /// Memory allocation has failed. AllocFail = -7, /// An unknown failure. Unknown = -8, } impl ErrorCode { fn from_int(value: c_int) -> ErrorCode { use ErrorCode::*; match value { ffi::OPUS_BAD_ARG => BadArg, ffi::OPUS_BUFFER_TOO_SMALL => BufferTooSmall, ffi::OPUS_INTERNAL_ERROR => InternalError, ffi::OPUS_INVALID_PACKET => InvalidPacket, ffi::OPUS_UNIMPLEMENTED => Unimplemented, ffi::OPUS_INVALID_STATE => InvalidState, ffi::OPUS_ALLOC_FAIL => AllocFail, _ => Unknown, } } /// Get a human-readable error string for this error code. pub fn description(self) -> &'static str { // should always be ASCII and non-null for any input unsafe { CStr::from_ptr(ffi::opus_strerror(self as c_int)) }.to_str().unwrap() } } /// Possible bitrates. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Bitrate { /// Explicit bitrate choice (in bits/second). Bits(i32), /// Maximum bitrate allowed (up to maximum number of bytes for the packet). Max, /// Default bitrate decided by the encoder (not recommended). Auto, } /// Get the libopus version string. /// /// Applications may look for the substring "-fixed" in the version string to /// determine whether they have a fixed-point or floating-point build at /// runtime. pub fn version() -> &'static str { // verison string should always be ASCII unsafe { CStr::from_ptr(ffi::opus_get_version_string()) }.to_str().unwrap() } macro_rules! ffi { ($f:ident $(, $rest:expr)*) => { match unsafe { ffi::$f($($rest),*) } { code if code < 0 => return Err(Error::from_code(stringify!($f), code)), code => code, } } } macro_rules! ctl { ($f:ident, $this:ident, $ctl:ident, $($rest:expr),*) => { match unsafe { ffi::$f($this.ptr, $ctl, $($rest),*) } { code if code < 0 => return Err(Error::from_code( concat!(stringify!($f), "(", stringify!($ctl), ")"), code, )), _ => (), } } } // ============================================================================ // Encoder macro_rules! enc_ctl { ($this:ident, $ctl:ident $(, $rest:expr)*) => { ctl!(opus_encoder_ctl, $this, $ctl, $($rest),*) } } /// An Opus encoder with associated state. #[derive(Debug)] pub struct Encoder { ptr: *mut ffi::OpusEncoder, channels: Channels, } impl Encoder { /// Create and initialize an encoder. pub fn new(sample_rate: u32, channels: Channels, mode: Application) -> Result { let mut error = 0; let ptr = unsafe { ffi::opus_encoder_create( sample_rate as i32, channels as c_int, mode as c_int, &mut error) }; if error != ffi::OPUS_OK || ptr.is_null() { Err(Error::from_code("opus_encoder_create", error)) } else { Ok(Encoder { ptr: ptr, channels: channels }) } } /// Encode an Opus frame. pub fn encode(&mut self, input: &[i16], output: &mut [u8]) -> Result { let len = ffi!(opus_encode, self.ptr, input.as_ptr(), len(input) / self.channels as c_int, output.as_mut_ptr(), len(output)); Ok(len as usize) } /// Encode an Opus frame from floating point input. pub fn encode_float(&mut self, input: &[f32], output: &mut [u8]) -> Result { let len = ffi!(opus_encode_float, self.ptr, input.as_ptr(), len(input) / self.channels as c_int, output.as_mut_ptr(), len(output)); Ok(len as usize) } /// Encode an Opus frame to a new buffer. pub fn encode_vec(&mut self, input: &[i16], max_size: usize) -> Result> { let mut output: Vec = vec![0; max_size]; let result = self.encode(input, output.as_mut_slice())?; output.truncate(result); Ok(output) } /// Encode an Opus frame from floating point input to a new buffer. pub fn encode_vec_float(&mut self, input: &[f32], max_size: usize) -> Result> { let mut output: Vec = vec![0; max_size]; let result = self.encode_float(input, output.as_mut_slice())?; output.truncate(result); Ok(output) } // ------------ // Generic CTLs /// Reset the codec state to be equivalent to a freshly initialized state. pub fn reset_state(&mut self) -> Result<()> { enc_ctl!(self, OPUS_RESET_STATE); Ok(()) } /// Get the final range of the codec's entropy coder. pub fn get_final_range(&mut self) -> Result { let mut value: u32 = 0; enc_ctl!(self, OPUS_GET_FINAL_RANGE, &mut value); Ok(value) } /// Get the encoder's configured bandpass. pub fn get_bandwidth(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_BANDWIDTH, &mut value); Bandwidth::decode(value, "opus_encoder_ctl(OPUS_GET_BANDWIDTH)") } /// Get the samping rate the encoder was intialized with. pub fn get_sample_rate(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_SAMPLE_RATE, &mut value); Ok(value as u32) } // ------------ // Encoder CTLs /// Set the encoder's bitrate. pub fn set_bitrate(&mut self, value: Bitrate) -> Result<()> { let value: i32 = match value { Bitrate::Auto => OPUS_AUTO, Bitrate::Max => OPUS_BITRATE_MAX, Bitrate::Bits(b) => b, }; enc_ctl!(self, OPUS_SET_BITRATE, value); Ok(()) } /// Get the encoder's bitrate. pub fn get_bitrate(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_BITRATE, &mut value); Ok(match value { OPUS_AUTO => Bitrate::Auto, OPUS_BITRATE_MAX => Bitrate::Max, _ => Bitrate::Bits(value), }) } /// Enable or disable variable bitrate. pub fn set_vbr(&mut self, vbr: bool) -> Result<()> { let value: i32 = if vbr { 1 } else { 0 }; enc_ctl!(self, OPUS_SET_VBR, value); Ok(()) } /// Determine if variable bitrate is enabled. pub fn get_vbr(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_VBR, &mut value); Ok(value != 0) } /// Enable or disable constrained VBR. pub fn set_vbr_constraint(&mut self, vbr: bool) -> Result<()> { let value: i32 = if vbr { 1 } else { 0 }; enc_ctl!(self, OPUS_SET_VBR_CONSTRAINT, value); Ok(()) } /// Determine if constrained VBR is enabled. pub fn get_vbr_constraint(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_VBR_CONSTRAINT, &mut value); Ok(value != 0) } /// Configures the encoder's use of inband forward error correction (FEC). pub fn set_inband_fec(&mut self, value: bool) -> Result<()> { let value: i32 = if value { 1 } else { 0 }; enc_ctl!(self, OPUS_SET_INBAND_FEC, value); Ok(()) } /// Gets encoder's configured use of inband forward error correction. pub fn get_inband_fec(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_INBAND_FEC, &mut value); Ok(value != 0) } /// Sets the encoder's expected packet loss percentage. pub fn set_packet_loss_perc(&mut self, value: i32) -> Result<()> { enc_ctl!(self, OPUS_SET_PACKET_LOSS_PERC, value); Ok(()) } /// Gets the encoder's expected packet loss percentage. pub fn get_packet_loss_perc(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_PACKET_LOSS_PERC, &mut value); Ok(value) } /// Configures the encoder's use of discontinuous transmission (DTX). pub fn set_dtx(&mut self, value: bool) -> Result<()> { let value: i32 = if value { 1 } else { 0 }; enc_ctl!(self, OPUS_SET_DTX_REQUEST, value); Ok(()) } /// Gets encoder's configured use of discontinuous transmission. pub fn get_dtx(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_DTX_REQUEST, &mut value); Ok(value != 0) } /// Gets the total samples of delay added by the entire codec. pub fn get_lookahead(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_LOOKAHEAD, &mut value); Ok(value) } /// Gets the DTX state of the encoder. /// Returns whether the last encoded frame was either a comfort noise update during DTX or not encoded because of DTX. pub fn get_in_dtx(&mut self) -> Result { let mut value: i32 = 0; enc_ctl!(self, OPUS_GET_IN_DTX_REQUEST, &mut value); Ok(value != 0) } // TODO: Encoder-specific CTLs } impl Drop for Encoder { fn drop(&mut self) { unsafe { ffi::opus_encoder_destroy(self.ptr) } } } // "A single codec state may only be accessed from a single thread at // a time and any required locking must be performed by the caller. Separate // streams must be decoded with separate decoder states and can be decoded // in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK // defined." // // In other words, opus states may be moved between threads at will. A special // compilation mode intended for embedded platforms forbids multithreaded use // of the library as a whole rather than on a per-state basis, but the opus-sys // crate does not use this mode. unsafe impl Send for Encoder {} // ============================================================================ // Decoder macro_rules! dec_ctl { ($this:ident, $ctl:ident $(, $rest:expr)*) => { ctl!(opus_decoder_ctl, $this, $ctl, $($rest),*) } } /// An Opus decoder with associated state. #[derive(Debug)] pub struct Decoder { ptr: *mut ffi::OpusDecoder, channels: Channels, } impl Decoder { /// Create and initialize a decoder. pub fn new(sample_rate: u32, channels: Channels) -> Result { let mut error = 0; let ptr = unsafe { ffi::opus_decoder_create( sample_rate as i32, channels as c_int, &mut error) }; if error != ffi::OPUS_OK || ptr.is_null() { Err(Error::from_code("opus_decoder_create", error)) } else { Ok(Decoder { ptr: ptr, channels: channels }) } } /// Decode an Opus packet. pub fn decode(&mut self, input: &[u8], output: &mut [i16], fec: bool) -> Result { let ptr = match input.len() { 0 => std::ptr::null(), _ => input.as_ptr(), }; let len = ffi!(opus_decode, self.ptr, ptr, len(input), output.as_mut_ptr(), len(output) / self.channels as c_int, fec as c_int); Ok(len as usize) } /// Decode an Opus packet with floating point output. pub fn decode_float(&mut self, input: &[u8], output: &mut [f32], fec: bool) -> Result { let ptr = match input.len() { 0 => std::ptr::null(), _ => input.as_ptr(), }; let len = ffi!(opus_decode_float, self.ptr, ptr, len(input), output.as_mut_ptr(), len(output) / self.channels as c_int, fec as c_int); Ok(len as usize) } /// Get the number of samples of an Opus packet. pub fn get_nb_samples(&self, packet: &[u8]) -> Result { let len = ffi!(opus_decoder_get_nb_samples, self.ptr, packet.as_ptr(), packet.len() as i32); Ok(len as usize) } // ------------ // Generic CTLs /// Reset the codec state to be equivalent to a freshly initialized state. pub fn reset_state(&mut self) -> Result<()> { dec_ctl!(self, OPUS_RESET_STATE); Ok(()) } /// Get the final range of the codec's entropy coder. pub fn get_final_range(&mut self) -> Result { let mut value: u32 = 0; dec_ctl!(self, OPUS_GET_FINAL_RANGE, &mut value); Ok(value) } /// Get the decoder's last bandpass. pub fn get_bandwidth(&mut self) -> Result { let mut value: i32 = 0; dec_ctl!(self, OPUS_GET_BANDWIDTH, &mut value); Bandwidth::decode(value, "opus_decoder_ctl(OPUS_GET_BANDWIDTH)") } /// Get the samping rate the decoder was intialized with. pub fn get_sample_rate(&mut self) -> Result { let mut value: i32 = 0; dec_ctl!(self, OPUS_GET_SAMPLE_RATE, &mut value); Ok(value as u32) } // ------------ // Decoder CTLs /// Configures decoder gain adjustment. /// /// Scales the decoded output by a factor specified in Q8 dB units. This has /// a maximum range of -32768 to 32768 inclusive, and returns `BadArg` /// otherwise. The default is zero indicating no adjustment. This setting /// survives decoder reset. /// /// `gain = pow(10, x / (20.0 * 256))` pub fn set_gain(&mut self, gain: i32) -> Result<()> { dec_ctl!(self, OPUS_SET_GAIN, gain); Ok(()) } /// Gets the decoder's configured gain adjustment. pub fn get_gain(&mut self) -> Result { let mut value: i32 = 0; dec_ctl!(self, OPUS_GET_GAIN, &mut value); Ok(value) } /// Gets the duration (in samples) of the last packet successfully decoded /// or concealed. pub fn get_last_packet_duration(&mut self) -> Result { let mut value: i32 = 0; dec_ctl!(self, OPUS_GET_LAST_PACKET_DURATION, &mut value); Ok(value as u32) } /// Gets the pitch of the last decoded frame, if available. /// /// This can be used for any post-processing algorithm requiring the use of /// pitch, e.g. time stretching/shortening. If the last frame was not /// voiced, or if the pitch was not coded in the frame, then zero is /// returned. pub fn get_pitch(&mut self) -> Result { let mut value: i32 = 0; dec_ctl!(self, OPUS_GET_PITCH, &mut value); Ok(value) } } impl Drop for Decoder { fn drop(&mut self) { unsafe { ffi::opus_decoder_destroy(self.ptr) } } } // See `unsafe impl Send for Encoder`. unsafe impl Send for Decoder {} // ============================================================================ // Packet Analysis /// Analyze raw Opus packets. pub mod packet { use super::*; use super::ffi; use std::{ptr, slice}; /// Get the bandwidth of an Opus packet. pub fn get_bandwidth(packet: &[u8]) -> Result { if packet.len() < 1 { return Err(Error::bad_arg("opus_packet_get_bandwidth")); } let bandwidth = ffi!(opus_packet_get_bandwidth, packet.as_ptr()); Bandwidth::decode(bandwidth, "opus_packet_get_bandwidth") } /// Get the number of channels from an Opus packet. pub fn get_nb_channels(packet: &[u8]) -> Result { if packet.len() < 1 { return Err(Error::bad_arg("opus_packet_get_nb_channels")); } let channels = ffi!(opus_packet_get_nb_channels, packet.as_ptr()); match channels { 1 => Ok(Channels::Mono), 2 => Ok(Channels::Stereo), _ => Err(Error::bad_arg("opus_packet_get_nb_channels")), } } /// Get the number of frames in an Opus packet. pub fn get_nb_frames(packet: &[u8]) -> Result { let frames = ffi!(opus_packet_get_nb_frames, packet.as_ptr(), len(packet)); Ok(frames as usize) } /// Get the number of samples of an Opus packet. pub fn get_nb_samples(packet: &[u8], sample_rate: u32) -> Result { let frames = ffi!(opus_packet_get_nb_samples, packet.as_ptr(), len(packet), sample_rate as c_int); Ok(frames as usize) } /// Get the number of samples per frame from an Opus packet. pub fn get_samples_per_frame(packet: &[u8], sample_rate: u32) -> Result { if packet.len() < 1 { return Err(Error::bad_arg("opus_packet_get_samples_per_frame")) } let samples = ffi!(opus_packet_get_samples_per_frame, packet.as_ptr(), sample_rate as c_int); Ok(samples as usize) } /// Parse an Opus packet into one or more frames. pub fn parse(packet: &[u8]) -> Result { let mut toc: u8 = 0; let mut frames = [ptr::null(); 48]; let mut sizes = [0i16; 48]; let mut payload_offset: i32 = 0; let num_frames = ffi!(opus_packet_parse, packet.as_ptr(), len(packet), &mut toc, frames.as_mut_ptr(), sizes.as_mut_ptr(), &mut payload_offset); let mut frames_vec = Vec::with_capacity(num_frames as usize); for i in 0..num_frames as usize { frames_vec.push(unsafe { slice::from_raw_parts(frames[i], sizes[i] as usize) }); } Ok(Packet { toc: toc, frames: frames_vec, payload_offset: payload_offset as usize, }) } /// A parsed Opus packet, retuned from `parse`. #[derive(Debug)] pub struct Packet<'a> { /// The TOC byte of the packet. pub toc: u8, /// The frames contained in the packet. pub frames: Vec<&'a [u8]>, /// The offset into the packet at which the payload is located. pub payload_offset: usize, } /// Pad a given Opus packet to a larger size. /// /// The packet will be extended from the first `prev_len` bytes of the /// buffer into the rest of the available space. pub fn pad(packet: &mut [u8], prev_len: usize) -> Result { let result = ffi!(opus_packet_pad, packet.as_mut_ptr(), check_len(prev_len), len(packet)); Ok(result as usize) } /// Remove all padding from a given Opus packet and rewrite the TOC sequence /// to minimize space usage. pub fn unpad(packet: &mut [u8]) -> Result { let result = ffi!(opus_packet_unpad, packet.as_mut_ptr(), len(packet)); Ok(result as usize) } } // ============================================================================ // Float Soft Clipping /// Soft-clipping to bring a float signal within the [-1,1] range. #[derive(Debug)] pub struct SoftClip { channels: Channels, memory: [f32; 2], } impl SoftClip { /// Initialize a new soft-clipping state. pub fn new(channels: Channels) -> SoftClip { SoftClip { channels: channels, memory: [0.0; 2] } } /// Apply soft-clipping to a float signal. pub fn apply(&mut self, signal: &mut [f32]) { unsafe { ffi::opus_pcm_soft_clip( signal.as_mut_ptr(), len(signal) / self.channels as c_int, self.channels as c_int, self.memory.as_mut_ptr()) }; } } // ============================================================================ // Repacketizer /// A repacketizer used to merge together or split apart multiple Opus packets. #[derive(Debug)] pub struct Repacketizer { ptr: *mut ffi::OpusRepacketizer, } impl Repacketizer { /// Create and initialize a repacketizer. pub fn new() -> Result { let ptr = unsafe { ffi::opus_repacketizer_create() }; if ptr.is_null() { Err(Error::from_code("opus_repacketizer_create", ffi::OPUS_ALLOC_FAIL)) } else { Ok(Repacketizer { ptr: ptr }) } } /// Shortcut to combine several smaller packets into one larger one. pub fn combine(&mut self, input: &[&[u8]], output: &mut [u8]) -> Result { let mut state = self.begin(); for &packet in input { state.cat(packet)?; } state.out(output) } /// Begin using the repacketizer. pub fn begin<'rp, 'buf>(&'rp mut self) -> RepacketizerState<'rp, 'buf> { unsafe { ffi::opus_repacketizer_init(self.ptr); } RepacketizerState { rp: self, phantom: PhantomData } } } impl Drop for Repacketizer { fn drop(&mut self) { unsafe { ffi::opus_repacketizer_destroy(self.ptr) } } } // See `unsafe impl Send for Encoder`. unsafe impl Send for Repacketizer {} // To understand why these lifetime bounds are needed, imagine that the // repacketizer keeps an internal Vec<&'buf [u8]>, which is added to by cat() // and accessed by get_nb_frames(), out(), and out_range(). To prove that these // lifetime bounds are correct, a dummy implementation with the same signatures // but a real Vec<&'buf [u8]> rather than unsafe blocks may be substituted. /// An in-progress repacketization. #[derive(Debug)] pub struct RepacketizerState<'rp, 'buf> { rp: &'rp mut Repacketizer, phantom: PhantomData<&'buf [u8]>, } impl<'rp, 'buf> RepacketizerState<'rp, 'buf> { /// Add a packet to the current repacketizer state. pub fn cat(&mut self, packet: &'buf [u8]) -> Result<()> { ffi!(opus_repacketizer_cat, self.rp.ptr, packet.as_ptr(), len(packet)); Ok(()) } /// Add a packet to the current repacketizer state, moving it. #[inline] pub fn cat_move<'b2>(self, packet: &'b2 [u8]) -> Result> where 'buf: 'b2 { let mut shorter = self; shorter.cat(packet)?; Ok(shorter) } /// Get the total number of frames contained in packet data submitted so /// far via `cat`. pub fn get_nb_frames(&mut self) -> usize { unsafe { ffi::opus_repacketizer_get_nb_frames(self.rp.ptr) as usize } } /// Construct a new packet from data previously submitted via `cat`. /// /// All previously submitted frames are used. pub fn out(&mut self, buffer: &mut [u8]) -> Result { let result = ffi!(opus_repacketizer_out, self.rp.ptr, buffer.as_mut_ptr(), len(buffer)); Ok(result as usize) } /// Construct a new packet from data previously submitted via `cat`, with /// a manually specified subrange. /// /// The `end` index should not exceed the value of `get_nb_frames()`. pub fn out_range(&mut self, begin: usize, end: usize, buffer: &mut [u8]) -> Result { let result = ffi!(opus_repacketizer_out_range, self.rp.ptr, check_len(begin), check_len(end), buffer.as_mut_ptr(), len(buffer)); Ok(result as usize) } } // ============================================================================ // TODO: Multistream API // ============================================================================ // Error Handling /// Opus error Result alias. pub type Result = std::result::Result; /// An error generated by the Opus library. #[derive(Debug)] pub struct Error { function: &'static str, code: ErrorCode, } impl Error { fn bad_arg(what: &'static str) -> Error { Error { function: what, code: ErrorCode::BadArg } } fn from_code(what: &'static str, code: c_int) -> Error { Error { function: what, code: ErrorCode::from_int(code) } } /// Get the name of the Opus function from which the error originated. #[inline] pub fn function(&self) -> &'static str { self.function } /// Get a textual description of the error provided by Opus. #[inline] pub fn description(&self) -> &'static str { self.code.description() } /// Get the Opus error code of the error. #[inline] pub fn code(&self) -> ErrorCode { self.code } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}: {}", self.function, self.description()) } } impl std::error::Error for Error { fn description(&self) -> &str { self.code.description() } } fn check_len(val: usize) -> c_int { let len = val as c_int; if len as usize != val { panic!("length out of range: {}", val); } len } #[inline] fn len(slice: &[T]) -> c_int { check_len(slice.len()) }