Skip to main content

opus_codec/
lib.rs

1//! Safe, ergonomic wrappers around libopus for encoding/decoding Opus audio.
2#![warn(missing_docs)]
3#![warn(clippy::all)]
4#![warn(clippy::pedantic)]
5#![warn(clippy::cargo)]
6#![allow(clippy::cast_possible_wrap)]
7#![allow(clippy::cast_possible_truncation)]
8
9// Borrowed state wrappers must not expose `&mut` access to their lifetime-erased
10// owning handle: doing so would let safe code move that handle out with
11// `mem::replace`. Generate explicit forwarding methods instead.
12macro_rules! delegate_ref_mut_methods {
13    ($(
14        $(#[$meta:meta])*
15        fn $name:ident($($arg:ident: $arg_ty:ty),* $(,)?) -> $ret:ty;
16    )*) => {$(
17        $(#[$meta])*
18        #[doc = "Calls the corresponding operation on this borrowed libopus state."]
19        ///
20        /// # Errors
21        /// Returns the same errors as the corresponding owning-handle method.
22        #[inline]
23        pub fn $name(&mut self, $($arg: $arg_ty),*) -> $ret {
24            self.inner.$name($($arg),*)
25        }
26    )*};
27}
28
29macro_rules! delegate_ref_unsafe_mut_methods {
30    ($(
31        $(#[$meta:meta])*
32        unsafe fn $name:ident($($arg:ident: $arg_ty:ty),* $(,)?) -> $ret:ty;
33    )*) => {$(
34        $(#[$meta])*
35        #[doc = "Calls the corresponding unsafe operation on this borrowed libopus state."]
36        ///
37        /// # Safety
38        /// The safety requirements of the corresponding owning-handle method apply.
39        ///
40        /// # Errors
41        /// Returns the same errors as the corresponding owning-handle method.
42        #[inline]
43        pub unsafe fn $name(&mut self, $($arg: $arg_ty),*) -> $ret {
44            unsafe { self.inner.$name($($arg),*) }
45        }
46    )*};
47}
48
49// Include the generated bindings
50#[allow(warnings)]
51#[allow(clippy::all)]
52mod bindings {
53    include!("bindings.rs");
54}
55
56mod alloc;
57pub mod constants;
58pub mod decoder;
59#[cfg(feature = "dred")]
60/// Deep Redundancy (DRED) decoder support.
61pub mod dred;
62pub mod encoder;
63pub mod error;
64pub mod multistream;
65pub mod packet;
66pub mod projection;
67mod raw;
68pub mod repacketizer;
69pub mod types;
70
71pub use alloc::AlignedBuffer;
72pub use constants::{MAX_FRAME_SAMPLES_48KHZ, MAX_PACKET_DURATION_MS, max_frame_samples_for};
73pub use decoder::Decoder;
74#[cfg(feature = "dred")]
75pub use dred::{DredDecoder, DredState};
76pub use encoder::Encoder;
77pub use error::{Error, Result};
78pub use multistream::{Mapping, MultistreamDecoder, MultistreamEncoder};
79pub use packet::{
80    packet_bandwidth, packet_channels, packet_frame_count, packet_has_lbrr, packet_parse,
81    packet_parse_into, packet_sample_count, packet_samples_per_frame, soft_clip,
82};
83pub use projection::{ProjectionDecoder, ProjectionEncoder};
84pub use repacketizer::Repacketizer;
85pub use types::{
86    Application, Bandwidth, Bitrate, Channels, Complexity, ExpertFrameDuration, FrameSize,
87    SampleRate, Signal,
88};
89
90#[doc(hidden)]
91pub use bindings::*;
92
93pub(crate) use raw::{RawHandle, checked_non_null};
94
95#[derive(Clone, Copy, Debug, PartialEq, Eq)]
96pub(crate) enum Ownership {
97    Owned,
98    Borrowed,
99}
100
101#[inline]
102pub(crate) fn opus_ptr_is_aligned(ptr: *const u8) -> bool {
103    // libopus aligns internal state to pointer-sized alignment (opus_private.h align()).
104    ptr.addr().is_multiple_of(std::mem::align_of::<usize>())
105}
106
107/// Returns the bundled libopus version string of this crate.
108#[must_use]
109pub fn version() -> &'static str {
110    "1.5.2"
111}
112
113/// Returns the runtime libopus version string from the linked C library.
114#[must_use]
115pub fn runtime_version() -> &'static str {
116    unsafe {
117        let ptr = crate::bindings::opus_get_version_string();
118        if ptr.is_null() {
119            return "";
120        }
121        std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("")
122    }
123}
124
125/// Returns a human-readable string for a libopus error code (via runtime library).
126#[must_use]
127pub fn strerror(code: i32) -> &'static str {
128    unsafe {
129        let ptr = crate::bindings::opus_strerror(code);
130        if ptr.is_null() {
131            return "";
132        }
133        std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("")
134    }
135}