From 2d7ef8336d8976703402ddb8ef5ccec20a7f99ec Mon Sep 17 00:00:00 2001 From: Tad Hardesty Date: Wed, 24 Feb 2016 00:50:13 -0600 Subject: [PATCH] Initial commit --- .gitignore | 2 ++ Cargo.toml | 8 +++++ src/lib.rs | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9d37c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..605c963 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +authors = ["Tad Hardesty "] +name = "opus" +version = "0.1.0" + +[dependencies] +opus-sys = "0.1.2" +libc = "0.1" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..47d2d87 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,102 @@ +extern crate opus_sys as ffi; +extern crate libc; + +use libc::{c_int}; + +// Generic CTLs +const OPUS_RESET_STATE: c_int = 4028; // void +const OPUS_GET_FINAL_RANGE: c_int = 4031; // *uint +const OPUS_GET_BANDWIDTH: c_int = 4009; // *int +const OPUS_GET_SAMPLE_RATE: c_int = 4029; // *int + +pub enum CodingMode { + Voip = 2048, + Audio = 2049, + LowDelay = 2051, +} + +pub enum Channels { + Mono = 1, + Stereo = 2, +} + +pub struct Error(&'static str, c_int); + +fn check(what: &'static str, code: c_int) -> Result<()> { + if code < 0 { + Err(Error(what, code)) + } else { + Ok(()) + } +} + +pub type Result = std::result::Result; + +pub struct Encoder { + ptr: *mut ffi::OpusEncoder, +} + +impl Encoder { + pub fn new(sample_rate: u32, channels: Channels, mode: CodingMode) -> 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("opus_encoder_create", error)) + } else { + Ok(Encoder { ptr: ptr }) + } + } + + pub fn encode(&mut self, input: &[i16], output: &mut [u8]) -> Result { + let len = unsafe { ffi::opus_encode(self.ptr, + input.as_ptr(), input.len() as c_int, + output.as_mut_ptr(), output.len() as c_int) }; + try!(check("opus_encode", len)); + Ok(len as usize) + } + + pub fn encode_float(&mut self, input: &[f32], output: &mut [u8]) -> Result { + let len = unsafe { ffi::opus_encode_float(self.ptr, + input.as_ptr(), input.len() as c_int, + output.as_mut_ptr(), output.len() as c_int) }; + try!(check("opus_encode_float", len)); + Ok(len as usize) + } + + pub fn reset_state(&mut self) -> Result<()> { + check("opus_encoder_ctl(OPUS_RESET_STATE)", unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_RESET_STATE) }) + } + + pub fn get_final_range(&mut self) -> Result { + let mut value = 0; + let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_FINAL_RANGE, &mut value) }; + try!(check("opus_encoder_ctl(OPUS_GET_FINAL_RANGE)", result)); + Ok(value) + } + + pub fn get_bandwidth(&mut self) -> Result { + let mut value = 0; + let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_BANDWIDTH, &mut value) }; + try!(check("opus_encoder_ctl(OPUS_GET_BANDWIDTH)", result)); + Ok(value) + } + + pub fn get_sample_rate(&mut self) -> Result { + let mut value = 0; + let result = unsafe { ffi::opus_encoder_ctl(self.ptr, OPUS_GET_SAMPLE_RATE, &mut value) }; + try!(check("opus_encoder_ctl(OPUS_GET_SAMPLE_RATE)", result)); + Ok(value) + } + + // TODO: Many more CTLs +} + +impl Drop for Encoder { + fn drop(&mut self) { + unsafe { ffi::opus_encoder_destroy(self.ptr) } + } +}