From 4eb96b0cdc73c0bdbd309c12e32fbab7c1f3e7e0 Mon Sep 17 00:00:00 2001 From: GengTeng Date: Tue, 22 Mar 2022 11:35:30 +0800 Subject: [PATCH 1/3] Update build.rs --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index da1f778..8c45f0f 100644 --- a/build.rs +++ b/build.rs @@ -14,7 +14,7 @@ fn find_package(name: &str) -> Vec { target_arch = "arm64".to_owned(); } let mut target = if target_os == "macos" { - "x64-osx".to_owned() + format!("{}-osx", target_arch) } else if target_os == "windows" { "x64-windows-static".to_owned() } else { From ebccd917c42493b77bc450510d0a5fb031b63ef1 Mon Sep 17 00:00:00 2001 From: gengteng Date: Tue, 22 Mar 2022 15:28:50 +0800 Subject: [PATCH 2/3] use vcpkg --- Cargo.toml | 1 + build.rs | 37 +++++++------------------------------ 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 48b6c88..a105c7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,4 @@ documentation = "https://docs.rs/magnum-opus" [build-dependencies] target_build_utils = "0.3" bindgen = "0.59" +vcpkg = "0.2" diff --git a/build.rs b/build.rs index 8c45f0f..23c6b4c 100644 --- a/build.rs +++ b/build.rs @@ -4,42 +4,19 @@ use std::{ }; fn find_package(name: &str) -> Vec { - let vcpkg_root = std::env::var("VCPKG_ROOT").unwrap(); - let mut path: PathBuf = vcpkg_root.into(); - let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); - let mut target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - if target_arch == "x86_64" { - target_arch = "x64".to_owned(); - } else if target_arch == "aarch64" { - target_arch = "arm64".to_owned(); - } - let mut target = if target_os == "macos" { - format!("{}-osx", target_arch) - } else if target_os == "windows" { - "x64-windows-static".to_owned() - } else { - format!("{}-{}", target_arch, target_os) - }; - if target_arch == "x86" { - target = target.replace("x64", "x86"); - } - println!("cargo:info={}", target); - path.push("installed"); - path.push(target); - println!( - "{}", - format!("cargo:rustc-link-lib=static={}", name.trim_start_matches("lib")) - ); + let lib = vcpkg::find_package(name).expect("Failed to find package"); + println!("cargo:info={}", lib.vcpkg_triplet); //TODO + let lib_name = name.trim_start_matches("lib").to_string(); + println!("{}", format!("cargo:rustc-link-lib=static={}", lib_name)); println!( "{}", format!( "cargo:rustc-link-search={}", - path.join("lib").to_str().unwrap() + lib.link_paths.get(0).unwrap().display() ) ); - let include = path.join("include"); - println!("{}", format!("cargo:include={}", include.to_str().unwrap())); - vec![include] + println!("{}", format!("cargo:include={}", lib.include_paths.get(0).unwrap().display())); + lib.include_paths } fn generate_bindings(ffi_header: &Path, include_paths: &[PathBuf], ffi_rs: &Path) { From 522c33adf2082a7a59f71e68a62bd9bc2cd34863 Mon Sep 17 00:00:00 2001 From: gengteng Date: Tue, 22 Mar 2022 15:28:50 +0800 Subject: [PATCH 3/3] use vcpkg; cargo fmt --- Cargo.toml | 1 + build.rs | 60 +- src/lib.rs | 1334 ++++++++++++++++++++++------------------- tests/fec.rs | 2 +- tests/opus-padding.rs | 5 +- tests/tests.rs | 234 +++++--- 6 files changed, 881 insertions(+), 755 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 48b6c88..a105c7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,4 @@ documentation = "https://docs.rs/magnum-opus" [build-dependencies] target_build_utils = "0.3" bindgen = "0.59" +vcpkg = "0.2" diff --git a/build.rs b/build.rs index 8c45f0f..072e15c 100644 --- a/build.rs +++ b/build.rs @@ -4,42 +4,32 @@ use std::{ }; fn find_package(name: &str) -> Vec { - let vcpkg_root = std::env::var("VCPKG_ROOT").unwrap(); - let mut path: PathBuf = vcpkg_root.into(); - let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); - let mut target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - if target_arch == "x86_64" { - target_arch = "x64".to_owned(); - } else if target_arch == "aarch64" { - target_arch = "arm64".to_owned(); - } - let mut target = if target_os == "macos" { - format!("{}-osx", target_arch) - } else if target_os == "windows" { - "x64-windows-static".to_owned() - } else { - format!("{}-{}", target_arch, target_os) - }; - if target_arch == "x86" { - target = target.replace("x64", "x86"); + let library = vcpkg::find_package(name).expect("Failed to find package"); + println!("cargo:info={}", library.vcpkg_triplet); //TODO + let lib_name = name.trim_start_matches("lib").to_string(); + println!("{}", format!("cargo:rustc-link-lib=static={}", lib_name)); + + match (library.link_paths.as_slice(), library.include_paths.as_slice()) { + ([link_search, ..], [include, ..]) => { + println!( + "{}", + format!("cargo:rustc-link-search={}", link_search.display()) + ); + println!("{}", format!("cargo:include={}", include.display())); + } + _ => { + panic!( + "{}", + if library.link_paths.is_empty() { + "link path not found" + } else { + "include path not found" + } + ) + } } - println!("cargo:info={}", target); - path.push("installed"); - path.push(target); - println!( - "{}", - format!("cargo:rustc-link-lib=static={}", name.trim_start_matches("lib")) - ); - println!( - "{}", - format!( - "cargo:rustc-link-search={}", - path.join("lib").to_str().unwrap() - ) - ); - let include = path.join("include"); - println!("{}", format!("cargo:include={}", include.to_str().unwrap())); - vec![include] + + library.include_paths } fn generate_bindings(ffi_header: &Path, include_paths: &[PathBuf], ffi_rs: &Path) { diff --git a/src/lib.rs b/src/lib.rs index 9a2fbf0..9baae6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ mod opus_ffi; use opus_ffi as ffi; - use std::ffi::CStr; use std::marker::PhantomData; @@ -29,7 +28,7 @@ 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 + // 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 @@ -57,115 +56,117 @@ 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, + /// 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, + /// 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, + /// 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)), - } - } + 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, + /// 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() - } + 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, + /// 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. @@ -174,8 +175,10 @@ pub enum Bitrate { /// 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() + // verison string should always be ASCII + unsafe { CStr::from_ptr(ffi::opus_get_version_string()) } + .to_str() + .unwrap() } macro_rules! ffi { @@ -211,205 +214,220 @@ macro_rules! enc_ctl { /// An Opus encoder with associated state. #[derive(Debug)] pub struct Encoder { - ptr: *mut ffi::OpusEncoder, - channels: Channels, + 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 + /// 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) } - } + fn drop(&mut self) { + unsafe { ffi::opus_encoder_destroy(self.ptr) } + } } // "A single codec state may only be accessed from a single thread at @@ -436,136 +454,151 @@ macro_rules! dec_ctl { /// An Opus decoder with associated state. #[derive(Debug)] pub struct Decoder { - ptr: *mut ffi::OpusDecoder, - channels: Channels, + 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) - } + /// 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) } - } + fn drop(&mut self) { + unsafe { ffi::opus_decoder_destroy(self.ptr) } + } } // See `unsafe impl Send for Encoder`. @@ -576,106 +609,121 @@ unsafe impl Send for Decoder {} /// 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) - } + use super::ffi; + use super::*; + 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) + } } // ============================================================================ @@ -684,24 +732,30 @@ pub mod packet { /// Soft-clipping to bring a float signal within the [-1,1] range. #[derive(Debug)] pub struct SoftClip { - channels: Channels, - memory: [f32; 2], + 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()) }; - } + /// 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(), + ) + }; + } } // ============================================================================ @@ -710,40 +764,48 @@ impl SoftClip { /// A repacketizer used to merge together or split apart multiple Opus packets. #[derive(Debug)] pub struct Repacketizer { - ptr: *mut ffi::OpusRepacketizer, + 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 } - } + /// 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) } - } + fn drop(&mut self) { + unsafe { ffi::opus_repacketizer_destroy(self.ptr) } + } } // See `unsafe impl Send for Encoder`. @@ -758,51 +820,67 @@ unsafe impl Send for Repacketizer {} /// An in-progress repacketization. #[derive(Debug)] pub struct RepacketizerState<'rp, 'buf> { - rp: &'rp mut Repacketizer, - phantom: PhantomData<&'buf [u8]>, + 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) - } + /// 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) + } } // ============================================================================ @@ -817,53 +895,65 @@ pub type Result = std::result::Result; /// An error generated by the Opus library. #[derive(Debug)] pub struct Error { - function: &'static str, - code: ErrorCode, + 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 } + 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()) - } + 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 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 + 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()) + check_len(slice.len()) } diff --git a/tests/fec.rs b/tests/fec.rs index 5f660cf..f59c4a7 100644 --- a/tests/fec.rs +++ b/tests/fec.rs @@ -10,4 +10,4 @@ fn blah() { let mut output = vec![0i16; 5760]; let size = magnum_opus.decode(&[], &mut output[..], true).unwrap(); assert_eq!(size, 5760); -} \ No newline at end of file +} diff --git a/tests/opus-padding.rs b/tests/opus-padding.rs index 65dd0a8..007a437 100644 --- a/tests/opus-padding.rs +++ b/tests/opus-padding.rs @@ -25,5 +25,8 @@ fn test_overflow() { drop(input); drop(output); - assert_eq!(result.unwrap_err().code(), magnum_opus::ErrorCode::InvalidPacket); + assert_eq!( + result.unwrap_err().code(), + magnum_opus::ErrorCode::InvalidPacket + ); } diff --git a/tests/tests.rs b/tests/tests.rs index 4b5783a..245fb40 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,24 +1,32 @@ extern crate magnum_opus; fn check_ascii(s: &str) -> &str { - for &b in s.as_bytes() { - assert!(b < 0x80, "Non-ASCII character in string"); - assert!(b > 0x00, "NUL in string") - } - std::str::from_utf8(s.as_bytes()).unwrap() + for &b in s.as_bytes() { + assert!(b < 0x80, "Non-ASCII character in string"); + assert!(b > 0x00, "NUL in string") + } + std::str::from_utf8(s.as_bytes()).unwrap() } #[test] fn strings_ascii() { - use magnum_opus::ErrorCode::*; - - println!("\nVersion: {}", check_ascii(magnum_opus::version())); - - let codes = [BadArg, BufferTooSmall, InternalError, InvalidPacket, - Unimplemented, InvalidState, AllocFail, Unknown]; - for &code in codes.iter() { - println!("{:?}: {}", code, check_ascii(code.description())); - } + use magnum_opus::ErrorCode::*; + + println!("\nVersion: {}", check_ascii(magnum_opus::version())); + + let codes = [ + BadArg, + BufferTooSmall, + InternalError, + InvalidPacket, + Unimplemented, + InvalidState, + AllocFail, + Unknown, + ]; + for &code in codes.iter() { + println!("{:?}: {}", code, check_ascii(code.description())); + } } // 48000Hz * 1 channel * 20 ms / 1000 @@ -26,102 +34,136 @@ const MONO_20MS: usize = 48000 * 1 * 20 / 1000; #[test] fn encode_mono() { - let mut encoder = magnum_opus::Encoder::new(48000, magnum_opus::Channels::Mono, magnum_opus::Application::Audio).unwrap(); - - let mut output = [0; 256]; - let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap(); - assert_eq!(&output[..len], &[248, 255, 254]); - - let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap(); - assert_eq!(&output[..len], &[248, 255, 254]); - - let len = encoder.encode(&[1_i16; MONO_20MS], &mut output).unwrap(); - assert!(len > 190 && len < 220); - - let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap(); - assert!(len > 170 && len < 190); - - let myvec = encoder.encode_vec(&[1_i16; MONO_20MS], output.len()).unwrap(); - assert!(myvec.len() > 120 && myvec.len() < 140); + let mut encoder = magnum_opus::Encoder::new( + 48000, + magnum_opus::Channels::Mono, + magnum_opus::Application::Audio, + ) + .unwrap(); + + let mut output = [0; 256]; + let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap(); + assert_eq!(&output[..len], &[248, 255, 254]); + + let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap(); + assert_eq!(&output[..len], &[248, 255, 254]); + + let len = encoder.encode(&[1_i16; MONO_20MS], &mut output).unwrap(); + assert!(len > 190 && len < 220); + + let len = encoder.encode(&[0_i16; MONO_20MS], &mut output).unwrap(); + assert!(len > 170 && len < 190); + + let myvec = encoder + .encode_vec(&[1_i16; MONO_20MS], output.len()) + .unwrap(); + assert!(myvec.len() > 120 && myvec.len() < 140); } #[test] fn encode_stereo() { - let mut encoder = magnum_opus::Encoder::new(48000, magnum_opus::Channels::Stereo, magnum_opus::Application::Audio).unwrap(); - - let mut output = [0; 512]; - let len = encoder.encode(&[0_i16; 2 * MONO_20MS], &mut output).unwrap(); - assert_eq!(&output[..len], &[252, 255, 254]); - - let len = encoder.encode(&[0_i16; 4 * MONO_20MS], &mut output).unwrap(); - assert_eq!(&output[..len], &[253, 255, 254, 255, 254]); - - let len = encoder.encode(&[17_i16; 2 * MONO_20MS], &mut output).unwrap(); - assert!(len > 240); - - let len = encoder.encode(&[0_i16; 2 * MONO_20MS], &mut output).unwrap(); - assert!(len > 240); - - // Very small buffer should still succeed - let len = encoder.encode(&[95_i16; 2 * MONO_20MS], &mut [0; 20]).unwrap(); - assert!(len <= 20); - - let myvec = encoder.encode_vec(&[95_i16; 2 * MONO_20MS], 20).unwrap(); - assert!(myvec.len() <= 20); + let mut encoder = magnum_opus::Encoder::new( + 48000, + magnum_opus::Channels::Stereo, + magnum_opus::Application::Audio, + ) + .unwrap(); + + let mut output = [0; 512]; + let len = encoder + .encode(&[0_i16; 2 * MONO_20MS], &mut output) + .unwrap(); + assert_eq!(&output[..len], &[252, 255, 254]); + + let len = encoder + .encode(&[0_i16; 4 * MONO_20MS], &mut output) + .unwrap(); + assert_eq!(&output[..len], &[253, 255, 254, 255, 254]); + + let len = encoder + .encode(&[17_i16; 2 * MONO_20MS], &mut output) + .unwrap(); + assert!(len > 240); + + let len = encoder + .encode(&[0_i16; 2 * MONO_20MS], &mut output) + .unwrap(); + assert!(len > 240); + + // Very small buffer should still succeed + let len = encoder + .encode(&[95_i16; 2 * MONO_20MS], &mut [0; 20]) + .unwrap(); + assert!(len <= 20); + + let myvec = encoder.encode_vec(&[95_i16; 2 * MONO_20MS], 20).unwrap(); + assert!(myvec.len() <= 20); } #[test] fn encode_bad_rate() { - match magnum_opus::Encoder::new(48001, magnum_opus::Channels::Mono, magnum_opus::Application::Audio) { - Ok(_) => panic!("Encoder::new did not return BadArg"), - Err(err) => assert_eq!(err.code(), magnum_opus::ErrorCode::BadArg), - } + match magnum_opus::Encoder::new( + 48001, + magnum_opus::Channels::Mono, + magnum_opus::Application::Audio, + ) { + Ok(_) => panic!("Encoder::new did not return BadArg"), + Err(err) => assert_eq!(err.code(), magnum_opus::ErrorCode::BadArg), + } } #[test] fn encode_bad_buffer() { - let mut encoder = magnum_opus::Encoder::new(48000, magnum_opus::Channels::Stereo, magnum_opus::Application::Audio).unwrap(); - match encoder.encode(&[1_i16; 2 * MONO_20MS], &mut [0; 0]) { - Ok(_) => panic!("encode with 0-length buffer did not return BadArg"), - Err(err) => assert_eq!(err.code(), magnum_opus::ErrorCode::BadArg), - } + let mut encoder = magnum_opus::Encoder::new( + 48000, + magnum_opus::Channels::Stereo, + magnum_opus::Application::Audio, + ) + .unwrap(); + match encoder.encode(&[1_i16; 2 * MONO_20MS], &mut [0; 0]) { + Ok(_) => panic!("encode with 0-length buffer did not return BadArg"), + Err(err) => assert_eq!(err.code(), magnum_opus::ErrorCode::BadArg), + } } #[test] fn repacketizer() { - let mut rp = magnum_opus::Repacketizer::new().unwrap(); - let mut out = [0; 256]; - - for _ in 0..2 { - let packet1 = [249, 255, 254, 255, 254]; - let packet2 = [248, 255, 254]; - - let mut state = rp.begin(); - state.cat(&packet1).unwrap(); - state.cat(&packet2).unwrap(); - let len = state.out(&mut out).unwrap(); - assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]); - } - for _ in 0..2 { - let packet = [248, 255, 254]; - let state = rp.begin().cat_move(&packet).unwrap(); - let packet = [249, 255, 254, 255, 254]; - let state = state.cat_move(&packet).unwrap(); - let len = {state}.out(&mut out).unwrap(); - assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]); - } - for _ in 0..2 { - let len = rp.combine(&[ - &[249, 255, 254, 255, 254], - &[248, 255, 254], - ], &mut out).unwrap(); - assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]); - } - for _ in 0..2 { - let len = rp.begin() - .cat_move(&[248, 255, 254]).unwrap() - .cat_move(&[248, 71, 71]).unwrap() - .out(&mut out).unwrap(); - assert_eq!(&out[..len], &[249, 255, 254, 71, 71]); - } + let mut rp = magnum_opus::Repacketizer::new().unwrap(); + let mut out = [0; 256]; + + for _ in 0..2 { + let packet1 = [249, 255, 254, 255, 254]; + let packet2 = [248, 255, 254]; + + let mut state = rp.begin(); + state.cat(&packet1).unwrap(); + state.cat(&packet2).unwrap(); + let len = state.out(&mut out).unwrap(); + assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]); + } + for _ in 0..2 { + let packet = [248, 255, 254]; + let state = rp.begin().cat_move(&packet).unwrap(); + let packet = [249, 255, 254, 255, 254]; + let state = state.cat_move(&packet).unwrap(); + let len = { state }.out(&mut out).unwrap(); + assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]); + } + for _ in 0..2 { + let len = rp + .combine(&[&[249, 255, 254, 255, 254], &[248, 255, 254]], &mut out) + .unwrap(); + assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]); + } + for _ in 0..2 { + let len = rp + .begin() + .cat_move(&[248, 255, 254]) + .unwrap() + .cat_move(&[248, 71, 71]) + .unwrap() + .out(&mut out) + .unwrap(); + assert_eq!(&out[..len], &[249, 255, 254, 71, 71]); + } }