1#![no_std]
21#![warn(missing_docs)]
22#![allow(clippy::style)]
23#![allow(clippy::missing_transmute_annotations)]
24#![allow(clippy::needless_lifetimes)]
25
26use core::{slice, str};
27
28pub use opusic_sys as sys;
29
30macro_rules! map_sys_error {
31 ($result:expr => $ok:expr) => {{
32 let result = $result;
33 if result < 0 {
34 Err(result.into())
35 } else {
36 Ok($ok)
37 }
38 }};
39}
40
41mod mem;
42mod encoder;
43pub use encoder::*;
44mod decoder;
45pub use decoder::*;
46#[cfg(feature = "dred")]
47pub mod dred;
48pub mod repacketizer;
49pub mod multistream;
50pub mod utils;
51
52pub const fn frame_bytes_size(sample_rate: SampleRate, channels: Channels, duration_ms: usize) -> usize {
54 ((sample_rate as usize) * (channels as usize) * duration_ms) / 1000
55}
56
57const _FRAME_SIZE_TEST: () = {
58 assert!(frame_bytes_size(SampleRate::Hz48000, Channels::Mono, 10) == 480);
59 assert!(frame_bytes_size(SampleRate::Hz48000, Channels::Stereo, 10) == 960);
60};
61
62#[repr(i32)]
63#[derive(Debug, Clone, Copy, Eq, PartialEq)]
64pub enum ErrorCode {
66 Ok = sys::OPUS_OK,
68 BadArg = sys::OPUS_BAD_ARG,
70 AllocFail = sys::OPUS_ALLOC_FAIL,
72 InvalidState = sys::OPUS_INVALID_STATE,
74 InvalidPacket = sys::OPUS_INVALID_PACKET,
76 BufferTooSmall = sys::OPUS_BUFFER_TOO_SMALL,
78 Internal = sys::OPUS_INTERNAL_ERROR,
80 Unimplemented = sys::OPUS_UNIMPLEMENTED,
82 Unknown = -200,
84}
85
86impl ErrorCode {
87 #[cold]
88 #[inline(never)]
89 const fn unknown() -> Self {
90 Self::Unknown
91 }
92
93 #[cold]
94 #[inline(never)]
95 const fn invalid_packet() -> Self {
96 Self::InvalidPacket
97 }
98
99 #[cold]
100 #[inline(never)]
101 const fn bad_arg() -> Self {
102 Self::BadArg
103 }
104
105 #[cold]
106 #[inline(never)]
107 const fn alloc_fail() -> Self {
108 Self::AllocFail
109 }
110
111 #[inline]
112 pub const fn message(&self) -> &'static str {
114 match self {
115 Self::Ok => "No error",
116 Self::BadArg => "One or more invalid/out of range arguments",
117 Self::AllocFail => "Memory allocation has failed",
118 Self::InvalidState => "An encoder or decoder structure is invalid or already freed",
119 Self::InvalidPacket => "The compressed data passed is corrupted",
120 Self::BufferTooSmall => "Not enough bytes allocated in the buffer",
121 Self::Internal => "An internal error was detected",
122 Self::Unimplemented => "Invalid/unsupported request number",
123 Self::Unknown => "Unknown error",
124 }
125 }
126}
127
128impl From<i32> for ErrorCode {
129 #[inline]
130 fn from(value: i32) -> Self {
131 match value {
132 sys::OPUS_OK => Self::Ok,
133 sys::OPUS_UNIMPLEMENTED => Self::Unimplemented,
134 sys::OPUS_INVALID_STATE => Self::InvalidState,
135 sys::OPUS_INVALID_PACKET => Self::InvalidPacket,
136 sys::OPUS_INTERNAL_ERROR => Self::Internal,
137 sys::OPUS_BUFFER_TOO_SMALL => Self::BufferTooSmall,
138 sys::OPUS_BAD_ARG => Self::BadArg,
139 sys::OPUS_ALLOC_FAIL => Self::AllocFail,
140 _ => Self::unknown(),
141 }
142 }
143}
144
145#[derive(Debug, Clone, Copy, Eq, PartialEq)]
147pub enum Bitrate {
148 Value(u32),
150 Auto,
152 Max,
155}
156
157impl From<i32> for Bitrate {
158 #[inline(always)]
159 fn from(value: i32) -> Self {
160 match value {
161 sys::OPUS_AUTO => Self::Auto,
162 sys::OPUS_BITRATE_MAX => Self::Max,
165 value => Self::Value(value as _)
166 }
167 }
168}
169
170impl From<Bitrate> for i32 {
171 #[inline(always)]
172 fn from(value: Bitrate) -> Self {
173 match value {
174 Bitrate::Max => sys::OPUS_BITRATE_MAX,
175 Bitrate::Auto => sys::OPUS_AUTO,
176 Bitrate::Value(value) => value as _,
177 }
178 }
179}
180
181#[repr(i32)]
182#[derive(Debug, Clone, Copy, Eq, PartialEq)]
183pub enum Application {
185 Voip = sys::OPUS_APPLICATION_VOIP,
187 Audio = sys::OPUS_APPLICATION_AUDIO,
189 LowDelay = sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY,
193}
194
195impl Application {
196 #[inline(always)]
197 const fn from_sys(value: i32) -> Option<Self> {
198 match value {
199 sys::OPUS_APPLICATION_AUDIO => Some(Self::Audio),
200 sys::OPUS_APPLICATION_VOIP => Some(Self::Voip),
201 sys::OPUS_APPLICATION_RESTRICTED_LOWDELAY => Some(Self::LowDelay),
202 _ => None,
203 }
204 }
205}
206
207#[repr(i32)]
208#[derive(Debug, Clone, Copy, Eq, PartialEq)]
209pub enum SampleRate {
211 Hz8000 = 8000,
213 Hz12000 = 12000,
215 Hz16000 = 16000,
217 Hz24000 = 24000,
219 Hz48000 = 48000,
221}
222
223#[repr(i32)]
224#[derive(Debug, Clone, Copy, Eq, PartialEq)]
225pub enum Bandwidth {
227 Auto = sys::OPUS_AUTO,
229 Narrow = sys::OPUS_BANDWIDTH_NARROWBAND,
231 Medium = sys::OPUS_BANDWIDTH_MEDIUMBAND,
233 Wide = sys::OPUS_BANDWIDTH_WIDEBAND,
235 Superwide = sys::OPUS_BANDWIDTH_SUPERWIDEBAND,
237 Full = sys::OPUS_BANDWIDTH_FULLBAND,
239}
240
241impl From<i32> for Bandwidth {
242 #[inline(always)]
243 fn from(value: i32) -> Self {
244 match value {
245 sys::OPUS_BANDWIDTH_FULLBAND => Self::Full,
246 sys::OPUS_BANDWIDTH_SUPERWIDEBAND => Self::Superwide,
247 sys::OPUS_BANDWIDTH_WIDEBAND => Self::Wide,
248 sys::OPUS_BANDWIDTH_MEDIUMBAND => Self::Medium,
249 sys::OPUS_BANDWIDTH_NARROWBAND => Self::Narrow,
250 _ => Self::Auto
251 }
252 }
253}
254
255#[repr(u8)]
256#[derive(Debug, Clone, Copy, Eq, PartialEq)]
257pub enum Channels {
259 Mono = 1,
261 Stereo = 2,
263}
264
265#[repr(i32)]
266#[derive(Debug, Clone, Copy, Eq, PartialEq)]
267pub enum Signal {
269 Auto = sys::OPUS_AUTO,
271 Voice = sys::OPUS_SIGNAL_VOICE,
273 Music = sys::OPUS_SIGNAL_MUSIC,
275}
276
277impl From<i32> for Signal {
278 #[inline(always)]
279 fn from(value: i32) -> Self {
280 match value {
281 sys::OPUS_SIGNAL_MUSIC => Self::Music,
282 sys::OPUS_SIGNAL_VOICE => Self::Voice,
283 _ => Self::Auto
284 }
285 }
286}
287
288#[repr(i32)]
289#[derive(Debug, Clone, Copy, Eq, PartialEq)]
290pub enum InbandFec {
292 Off = 0,
294 Mode1 = 1,
299 Mode2 = 2,
301}
302
303#[repr(i32)]
304#[derive(Debug, Clone, Copy, Eq, PartialEq)]
305pub enum FrameDuration {
307 SizeArg = sys::OPUS_FRAMESIZE_ARG,
309 Size2_5 = sys::OPUS_FRAMESIZE_2_5_MS,
311 Size5 = sys::OPUS_FRAMESIZE_5_MS,
313 Size10 = sys::OPUS_FRAMESIZE_10_MS,
315 Size20 = sys::OPUS_FRAMESIZE_20_MS,
317 Size40 = sys::OPUS_FRAMESIZE_40_MS,
319 Size60 = sys::OPUS_FRAMESIZE_60_MS,
321 Size80 = sys::OPUS_FRAMESIZE_80_MS,
323 Size100 = sys::OPUS_FRAMESIZE_100_MS,
325 Size120 = sys::OPUS_FRAMESIZE_120_MS,
327}
328
329pub fn version() -> &'static str {
331 unsafe {
333 let ptr = sys::opus_get_version_string();
334 let mut len = 0usize;
335
336 while *ptr.add(len) != 0 {
337 len = len.saturating_add(1);
338 }
339
340 let slice = slice::from_raw_parts(ptr as _, len);
341 core::str::from_utf8_unchecked(slice)
342 }
343}