opus-rs
A pure-Rust implementation of the Opus audio codec (RFC 6716), ported from the reference C implementation (libopus 1.6).
Production-ready
Features
- Pure Rust — no C dependencies
- High Performance: Competitive with C libopus on x64/aarch64
#![no_std]+ noalloc: fully heap-free — runs on bare metal, RTOS, and WebAssembly with no global allocator
Quick Start
use ;
// Encode
let mut encoder = new.unwrap;
encoder.bitrate_bps = 16000;
encoder.use_cbr = true;
let input = vec!; // 20ms frame at 16kHz
let mut output = vec!;
let bytes = encoder.encode.unwrap;
// Decode
let mut decoder = new.unwrap;
let mut pcm = vec!;
let samples = decoder.decode.unwrap;
WAV Roundtrip
# Rust encoder/decoder
#![no_std] + no-alloc Support
opus-rs is fully heap-free: it builds as #![no_std] with no alloc crate and therefore needs no global allocator. All working buffers are inline, fixed-size arrays (sized to the Opus worst case); growable state uses an internal FixedVec<T, N> (a tiny Vec-like type over [MaybeUninit<T>; N]).
Disable the default std feature and enable libm (a pure-Rust math backend for sin/cos/sqrt/…, which core does not provide):
[]
= "0.1"
= false
= ["libm"]
The public API (OpusEncoder/OpusDecoder with encode/decode writing into caller-provided buffers) is identical to the std build.
Feature flags
| Feature | Default | Description |
|---|---|---|
std |
yes | Enables OS-backed runtime x86 SIMD detection (CPUID). Without it the crate is #![no_std]. |
libm |
no | Required for #![no_std] builds — provides float math via a pure-Rust port of musl libm. Not needed when std is on. |
Runtime dependency footprint:
stdbuild → 0 deps;no_stdbuild → 1 dep (libm, pure Rust).
Notes for no_std users
- Large structs: because every working buffer is inline,
OpusEncoder/OpusDecoderare large (~250 KB / ~175 KB each). On a constrained target, place them in astatic(wrap init in your ownOnce-like guard) or a dedicated buffer rather than on the stack. Test threads use a 16 MB stack (see.cargo/config.toml). - x86 SIMD: without
std, AVX/AVX2 dispatch falls back to compile-time detection. Build withRUSTFLAGS="-C target-feature=+avx2"to enable it. aarch64 NEON is unconditional. - Packets are capped at the RFC 6716 maximum of 1276 bytes (the heap-free range-coder buffer is sized accordingly); standalone
RangeCoder/CELT use supports up to 2048 bytes. - Verified targets:
thumbv7em-none-eabi(Cortex-M),wasm32-unknown-unknown, and any Linux no_std target. Check withscripts/check_no_std.sh.
Performance
Criterion benchmark (cargo bench --bench opus_vs_c_bench) with 20 samples, 100 ms warm-up, 500 ms measurement, real speech input (fixtures/answer_16k.wav), mono encode-only. All numbers below are wall-clock time for the full frame set.
vs C Opus (libopus 1.6.1) on x86-64 (AVX2/FMA)
Measured on AMD Ryzen 7 5700X, compiled with --release (opt-level=3 + ThinLTO).
| Config | Pure Rust | C Opus | Ratio |
|---|---|---|---|
| 8 kHz / 20 ms VoIP | 39.9 ms | 40.6 ms | 0.98× (Rust 2% faster) |
| 16 kHz / 20 ms VoIP | 66.8 ms | 67.1 ms | 1.00× (Rust 0.5% faster) |
| 16 kHz / 10 ms VoIP | 73.2 ms | 72.5 ms | 1.01× (within noise) |
| 48 kHz / 20 ms Audio | 25.1 ms | 28.4 ms | 0.88× (Rust 12% faster) |
| 48 kHz / 10 ms Audio | 29.7 ms | 31.2 ms | 0.95× (Rust 5% faster) |
vs C Opus (libopus 1.6.1) on Apple Silicon
Measured on Apple Silicon M-series (aarch64), compiled with --release (opt-level=3 + ThinLTO), latest run on 2026-04-23.
| Config | Pure Rust | C Opus | Ratio |
|---|---|---|---|
| 8 kHz / 20 ms VoIP | 31.47 ms | 31.20 ms | 1.01× (C 0.9% faster) |
| 16 kHz / 20 ms VoIP | 51.19 ms | 52.81 ms | 0.97× (Rust 3.1% faster) |
| 16 kHz / 10 ms VoIP | 55.69 ms | 55.49 ms | 1.00× (within noise) |
| 48 kHz / 20 ms Audio | 13.97 ms | 19.39 ms | 0.72× (Rust 28% faster) |
| 48 kHz / 10 ms Audio | 16.19 ms | 20.28 ms | 0.80× (Rust 20% faster) |
Release Notes
0.1.27
#![no_std]with noalloc: the crate is now fully heap-free — no global allocator is required. AllVec/Boxworking buffers were replaced with an internalFixedVec<T, N>(inline[MaybeUninit<T>; N]);std::sync::LazyLockwas replaced with a heap-freeOnceCell; no_std float math (sin/cos/sqrt/…) is routed through an optionallibmfeature (pure-Rust musl port).- Verified on
thumbv7em-none-eabi(Cortex-M),wasm32-unknown-unknown, and Linux no_std.scripts/check_no_std.shreproduces. - Feature flags:
std(default) → 0 runtime deps;default-features = false, features = ["libm"]→ 1 dep (libm). - Encoder/decoder structs are inline and large (~250 KB / ~175 KB); place them in a
staticor dedicated buffer on constrained targets.
- Verified on
- Performance: unchanged vs 0.1.26 (measured within ±0.5% on
opus_real; no per-frame allocation overhead). - Conformance: RFC 6716 1276-byte packet cap enforced on the Opus path; the standalone
RangeCoder/CELT buffer supports up to 2048 bytes. wav_testexample now tags output files by build (_std/_nostd) for A/B listening across build modes.
License
See COPYING for the original Opus license (BSD-3-Clause).
Links
- RustPBX: https://github.com/restsend/rustpbx
- RustRTC: https://github.com/restsend/rustrtc
- SIP Stack: https://github.com/restsend/rsipstack
- Rust Voice Agent: https://github.com/restsend/active-call