#![no_std]
#![warn(missing_docs)]
#![allow(clippy::style)]
#![allow(clippy::missing_transmute_annotations)]
#![allow(clippy::needless_lifetimes)]
use core::{slice, str};
pub use opusic_sys as sys;
macro_rules! map_sys_error {
($result:expr => $ok:expr) => {{
let result = $result;
if result < 0 {
Err(result.into())
} else {
Ok($ok)
}
}};
}
mod mem;
mod encoder;
pub use encoder::*;
mod decoder;
pub use decoder::*;
#[cfg(feature = "dred")]
pub mod dred;
pub mod repacketizer;
pub mod multistream;
pub mod utils;
pub const fn frame_bytes_size(sample_rate: SampleRate, channels: Channels, duration_ms: usize) -> usize {
((sample_rate as usize) * (channels as usize) * duration_ms) / 1000
}
const _FRAME_SIZE_TEST: () = {
assert!(frame_bytes_size(SampleRate::Hz48000, Channels::Mono, 10) == 480);
assert!(frame_bytes_size(SampleRate::Hz48000, Channels::Stereo, 10) == 960);
};
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ErrorCode {
Ok = sys::OPUS_OK,
BadArg = sys::OPUS_BAD_ARG,
AllocFail = sys::OPUS_ALLOC_FAIL,
InvalidState = sys::OPUS_INVALID_STATE,
InvalidPacket = sys::OPUS_INVALID_PACKET,
BufferTooSmall = sys::OPUS_BUFFER_TOO_SMALL,
Internal = sys::OPUS_INTERNAL_ERROR,
Unimplemented = sys::OPUS_UNIMPLEMENTED,
Unknown = -200,
}
impl ErrorCode {
#[cold]
#[inline(never)]
const fn unknown() -> Self {
Self::Unknown
}
#[cold]
#[inline(never)]
const fn invalid_packet() -> Self {
Self::InvalidPacket
}
#[cold]
#[inline(never)]
const fn bad_arg() -> Self {
Self::BadArg
}
#[cold]
#[inline(never)]
const fn alloc_fail() -> Self {
Self::AllocFail
}
#[inline]
pub const fn message(&self) -> &'static str {
match self {
Self::Ok => "No error",
Self::BadArg => "One or more invalid/out of range arguments",
Self::AllocFail => "Memory allocation has failed",
Self::InvalidState => "An encoder or decoder structure is invalid or already freed",
Self::InvalidPacket => "The compressed data passed is corrupted",
Self::BufferTooSmall => "Not enough bytes allocated in the buffer",
Self::Internal => "An internal error was detected",
Self::Unimplemented => "Invalid/unsupported request number",
Self::Unknown => "Unknown error",
}
}
}
impl From<i32> for ErrorCode {
#[inline]
fn from(value: i32) -> Self {
match value {
sys::OPUS_OK => Self::Ok,
sys::OPUS_UNIMPLEMENTED => Self::Unimplemented,
sys::OPUS_INVALID_STATE => Self::InvalidState,
sys::OPUS_INVALID_PACKET => Self::InvalidPacket,
sys::OPUS_INTERNAL_ERROR => Self::Internal,
sys::OPUS_BUFFER_TOO_SMALL => Self::BufferTooSmall,
sys::OPUS_BAD_ARG => Self::BadArg,
sys::OPUS_ALLOC_FAIL => Self::AllocFail,
_ => Self::unknown(),
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Bitrate {
Value(u32),
Auto,
Max,
}
impl From<i32> for Bitrate {
#[inline(always)]
fn from(value: i32) -> Self {
match value {
sys::OPUS_AUTO => Self::Auto,
sys::OPUS_BITRATE_MAX => Self::Max,
value => Self::Value(value as _)
}
}
}
impl From<Bitrate> for i32 {
#[inline(always)]
fn from(value: Bitrate) -> Self {
match value {
Bitrate::Max => sys::OPUS_BITRATE_MAX,
Bitrate::Auto => sys::OPUS_AUTO,
Bitrate::Value(value) => value as _,
}
}
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Application {
Voip = sys::OPUS_APPLICATION_VOIP,
Audio = sys::OPUS_APPLICATION_AUDIO,
LowDelay = sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY,
}
impl Application {
#[inline(always)]
const fn from_sys(value: i32) -> Option<Self> {
match value {
sys::OPUS_APPLICATION_AUDIO => Some(Self::Audio),
sys::OPUS_APPLICATION_VOIP => Some(Self::Voip),
sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY => Some(Self::LowDelay),
_ => None,
}
}
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum SampleRate {
Hz8000 = 8000,
Hz12000 = 12000,
Hz16000 = 16000,
Hz24000 = 24000,
Hz48000 = 48000,
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Bandwidth {
Auto = sys::OPUS_AUTO,
Narrow = sys::OPUS_BANDWIDTH_NARROWBAND,
Medium = sys::OPUS_BANDWIDTH_MEDIUMBAND,
Wide = sys::OPUS_BANDWIDTH_WIDEBAND,
Superwide = sys::OPUS_BANDWIDTH_SUPERWIDEBAND,
Full = sys::OPUS_BANDWIDTH_FULLBAND,
}
impl From<i32> for Bandwidth {
#[inline(always)]
fn from(value: i32) -> Self {
match value {
sys::OPUS_BANDWIDTH_FULLBAND => Self::Full,
sys::OPUS_BANDWIDTH_SUPERWIDEBAND => Self::Superwide,
sys::OPUS_BANDWIDTH_WIDEBAND => Self::Wide,
sys::OPUS_BANDWIDTH_MEDIUMBAND => Self::Medium,
sys::OPUS_BANDWIDTH_NARROWBAND => Self::Narrow,
_ => Self::Auto
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Channels {
Mono = 1,
Stereo = 2,
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Signal {
Auto = sys::OPUS_AUTO,
Voice = sys::OPUS_SIGNAL_VOICE,
Music = sys::OPUS_SIGNAL_MUSIC,
}
impl From<i32> for Signal {
#[inline(always)]
fn from(value: i32) -> Self {
match value {
sys::OPUS_SIGNAL_MUSIC => Self::Music,
sys::OPUS_SIGNAL_VOICE => Self::Voice,
_ => Self::Auto
}
}
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum InbandFec {
Off = 0,
Mode1 = 1,
Mode2 = 2,
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum FrameDuration {
SizeArg = sys::OPUS_FRAMESIZE_ARG,
Size2_5 = sys::OPUS_FRAMESIZE_2_5_MS,
Size5 = sys::OPUS_FRAMESIZE_5_MS,
Size10 = sys::OPUS_FRAMESIZE_10_MS,
Size20 = sys::OPUS_FRAMESIZE_20_MS,
Size40 = sys::OPUS_FRAMESIZE_40_MS,
Size60 = sys::OPUS_FRAMESIZE_60_MS,
Size80 = sys::OPUS_FRAMESIZE_80_MS,
Size100 = sys::OPUS_FRAMESIZE_100_MS,
Size120 = sys::OPUS_FRAMESIZE_120_MS,
}
pub fn version() -> &'static str {
unsafe {
let ptr = sys::opus_get_version_string();
let mut len = 0usize;
while *ptr.add(len) != 0 {
len = len.saturating_add(1);
}
let slice = slice::from_raw_parts(ptr as _, len);
core::str::from_utf8_unchecked(slice)
}
}