1#![no_std]
20#![warn(missing_docs)]
21#![allow(clippy::style)]
22#![allow(clippy::missing_transmute_annotations)]
23#![allow(clippy::needless_lifetimes)]
24
25use core::{slice, str};
26
27pub use opusic_sys as sys;
28
29macro_rules! map_sys_error {
30 ($result:expr => $ok:expr) => {{
31 let result = $result;
32 if result < 0 {
33 Err(result.into())
34 } else {
35 Ok($ok)
36 }
37 }};
38}
39
40mod mem;
41mod encoder;
42pub use encoder::*;
43mod decoder;
44pub use decoder::*;
45#[cfg(feature = "dred")]
46pub mod dred;
47pub mod repacketizer;
48pub mod multistream;
49pub mod utils;
50
51pub const fn frame_bytes_size(sample_rate: SampleRate, channels: Channels, duration_ms: usize) -> usize {
53 ((sample_rate as usize) * (channels as usize) * duration_ms) / 1000
54}
55
56const _FRAME_SIZE_TEST: () = {
57 assert!(frame_bytes_size(SampleRate::Hz48000, Channels::Mono, 10) == 480);
58 assert!(frame_bytes_size(SampleRate::Hz48000, Channels::Stereo, 10) == 960);
59};
60
61#[repr(i32)]
62#[derive(Debug, Clone, Copy, Eq, PartialEq)]
63pub enum ErrorCode {
65 Ok = sys::OPUS_OK,
67 BadArg = sys::OPUS_BAD_ARG,
69 AllocFail = sys::OPUS_ALLOC_FAIL,
71 InvalidState = sys::OPUS_INVALID_STATE,
73 InvalidPacket = sys::OPUS_INVALID_PACKET,
75 BufferTooSmall = sys::OPUS_BUFFER_TOO_SMALL,
77 Internal = sys::OPUS_INTERNAL_ERROR,
79 Unimplemented = sys::OPUS_UNIMPLEMENTED,
81 Unknown = -200,
83}
84
85impl ErrorCode {
86 #[cold]
87 #[inline(never)]
88 const fn unknown() -> Self {
89 Self::Unknown
90 }
91
92 #[cold]
93 #[inline(never)]
94 const fn invalid_packet() -> Self {
95 Self::InvalidPacket
96 }
97
98 #[cold]
99 #[inline(never)]
100 const fn bad_arg() -> Self {
101 Self::BadArg
102 }
103
104 #[cold]
105 #[inline(never)]
106 const fn alloc_fail() -> Self {
107 Self::AllocFail
108 }
109
110 #[inline]
111 pub const fn message(&self) -> &'static str {
113 match self {
114 Self::Ok => "No error",
115 Self::BadArg => "One or more invalid/out of range arguments",
116 Self::AllocFail => "Memory allocation has failed",
117 Self::InvalidState => "An encoder or decoder structure is invalid or already freed",
118 Self::InvalidPacket => "The compressed data passed is corrupted",
119 Self::BufferTooSmall => "Not enough bytes allocated in the buffer",
120 Self::Internal => "An internal error was detected",
121 Self::Unimplemented => "Invalid/unsupported request number",
122 Self::Unknown => "Unknown error",
123 }
124 }
125}
126
127impl From<i32> for ErrorCode {
128 #[inline]
129 fn from(value: i32) -> Self {
130 match value {
131 sys::OPUS_OK => Self::Ok,
132 sys::OPUS_UNIMPLEMENTED => Self::Unimplemented,
133 sys::OPUS_INVALID_STATE => Self::InvalidState,
134 sys::OPUS_INVALID_PACKET => Self::InvalidPacket,
135 sys::OPUS_INTERNAL_ERROR => Self::Internal,
136 sys::OPUS_BUFFER_TOO_SMALL => Self::BufferTooSmall,
137 sys::OPUS_BAD_ARG => Self::BadArg,
138 sys::OPUS_ALLOC_FAIL => Self::AllocFail,
139 _ => Self::unknown(),
140 }
141 }
142}
143
144#[derive(Debug, Clone, Copy, Eq, PartialEq)]
146pub enum Bitrate {
147 Value(u32),
149 Auto,
151 Max,
154}
155
156impl From<i32> for Bitrate {
157 #[inline(always)]
158 fn from(value: i32) -> Self {
159 match value {
160 sys::OPUS_AUTO => Self::Auto,
161 sys::OPUS_BITRATE_MAX => Self::Max,
164 value => Self::Value(value as _)
165 }
166 }
167}
168
169impl From<Bitrate> for i32 {
170 #[inline(always)]
171 fn from(value: Bitrate) -> Self {
172 match value {
173 Bitrate::Max => sys::OPUS_BITRATE_MAX,
174 Bitrate::Auto => sys::OPUS_AUTO,
175 Bitrate::Value(value) => value as _,
176 }
177 }
178}
179
180#[repr(i32)]
181#[derive(Debug, Clone, Copy, Eq, PartialEq)]
182pub enum Application {
184 Voip = sys::OPUS_APPLICATION_VOIP,
186 Audio = sys::OPUS_APPLICATION_AUDIO,
188 LowDelay = sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY,
192}
193
194impl Application {
195 #[inline(always)]
196 const fn from_sys(value: i32) -> Option<Self> {
197 match value {
198 sys::OPUS_APPLICATION_AUDIO => Some(Self::Audio),
199 sys::OPUS_APPLICATION_VOIP => Some(Self::Voip),
200 sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY => Some(Self::LowDelay),
201 _ => None,
202 }
203 }
204}
205
206#[repr(i32)]
207#[derive(Debug, Clone, Copy, Eq, PartialEq)]
208pub enum SampleRate {
210 Hz8000 = 8000,
212 Hz12000 = 12000,
214 Hz16000 = 16000,
216 Hz24000 = 24000,
218 Hz48000 = 48000,
220}
221
222#[repr(i32)]
223#[derive(Debug, Clone, Copy, Eq, PartialEq)]
224pub enum Bandwidth {
226 Auto = sys::OPUS_AUTO,
228 Narrow = sys::OPUS_BANDWIDTH_NARROWBAND,
230 Medium = sys::OPUS_BANDWIDTH_MEDIUMBAND,
232 Wide = sys::OPUS_BANDWIDTH_WIDEBAND,
234 Superwide = sys::OPUS_BANDWIDTH_SUPERWIDEBAND,
236 Full = sys::OPUS_BANDWIDTH_FULLBAND,
238}
239
240impl From<i32> for Bandwidth {
241 #[inline(always)]
242 fn from(value: i32) -> Self {
243 match value {
244 sys::OPUS_BANDWIDTH_FULLBAND => Self::Full,
245 sys::OPUS_BANDWIDTH_SUPERWIDEBAND => Self::Superwide,
246 sys::OPUS_BANDWIDTH_WIDEBAND => Self::Wide,
247 sys::OPUS_BANDWIDTH_MEDIUMBAND => Self::Medium,
248 sys::OPUS_BANDWIDTH_NARROWBAND => Self::Narrow,
249 _ => Self::Auto
250 }
251 }
252}
253
254#[repr(u8)]
255#[derive(Debug, Clone, Copy, Eq, PartialEq)]
256pub enum Channels {
258 Mono = 1,
260 Stereo = 2,
262}
263
264#[repr(i32)]
265#[derive(Debug, Clone, Copy, Eq, PartialEq)]
266pub enum Signal {
268 Auto = sys::OPUS_AUTO,
270 Voice = sys::OPUS_SIGNAL_VOICE,
272 Music = sys::OPUS_SIGNAL_MUSIC,
274}
275
276impl From<i32> for Signal {
277 #[inline(always)]
278 fn from(value: i32) -> Self {
279 match value {
280 sys::OPUS_SIGNAL_MUSIC => Self::Music,
281 sys::OPUS_SIGNAL_VOICE => Self::Voice,
282 _ => Self::Auto
283 }
284 }
285}
286
287#[repr(i32)]
288#[derive(Debug, Clone, Copy, Eq, PartialEq)]
289pub enum InbandFec {
291 Off = 0,
293 Mode1 = 1,
298 Mode2 = 2,
300}
301
302#[repr(i32)]
303#[derive(Debug, Clone, Copy, Eq, PartialEq)]
304pub enum FrameDuration {
306 SizeArg = sys::OPUS_FRAMESIZE_ARG,
308 Size2_5 = sys::OPUS_FRAMESIZE_2_5_MS,
310 Size5 = sys::OPUS_FRAMESIZE_5_MS,
312 Size10 = sys::OPUS_FRAMESIZE_10_MS,
314 Size20 = sys::OPUS_FRAMESIZE_20_MS,
316 Size40 = sys::OPUS_FRAMESIZE_40_MS,
318 Size60 = sys::OPUS_FRAMESIZE_60_MS,
320 Size80 = sys::OPUS_FRAMESIZE_80_MS,
322 Size100 = sys::OPUS_FRAMESIZE_100_MS,
324 Size120 = sys::OPUS_FRAMESIZE_120_MS,
326}
327
328pub fn version() -> &'static str {
330 unsafe {
332 let ptr = sys::opus_get_version_string();
333 let mut len = 0usize;
334
335 while *ptr.add(len) != 0 {
336 len = len.saturating_add(1);
337 }
338
339 let slice = slice::from_raw_parts(ptr as _, len);
340 core::str::from_utf8_unchecked(slice)
341 }
342}