ζ₯ζ¬θͺ | English
github.com/darui3018823/opus is a stateful, Pure Go Opus codec library with
no runtime CGO dependency. It provides single-stream, multistream, surround,
projection/Ambisonics, packet transformation, and Ogg Opus APIs.
The decoder's PCM is sample-exact against libopus 1.6.1's plain-C float
decoder on all 12 official RFC 8251 vectors, including packet loss
concealment. The encoder produces standards-compatible CELT, SILK-only, and
hybrid packets. Since v1.5.0 its automatic decisions follow libopus 1.6.1's
encoder (ModePolicyLibopus, the default), and its packets (2.5 to 120 ms)
are byte-identical to libopus's plain-C float build in the tested
configurations (automatic mode, mode transitions, 8β48 kHz input, CBR and
VBR, in-band FEC, and DTX). SetModePolicy(ModePolicyLegacy) restores the
decisions of earlier releases. The residual differences found by the libopus
parity audit (for example long noise concealment and rare encoder
float-rounding cases) are listed in the implementation snapshot.
The authoritative implementation snapshot is
docs/CURRENT_IMPLEMENTATION.md.
The compatibility target is standard Opus and core libopus behavior. DRED,
QEXT, OSCE/DNN processing, Opus Custom, and the libopus C ABI are outside that
claim, as is bit-exact encoder output beyond ModePolicyLibopus's tested
configurations; see
docs/LIBOPUS_SCOPE.md.
go get github.com/darui3018823/opusThe module currently declares Go 1.24.11 in go.mod.
package main
import (
"fmt"
"log"
"github.com/darui3018823/opus"
)
func main() {
const channels = 2
encoder, err := opus.NewEncoder(
opus.SampleRate48kHz,
channels,
opus.ApplicationAudio,
)
if err != nil {
log.Fatal(err)
}
// frameSize is samples per channel; PCM is interleaved.
pcm := make([]int16, opus.FrameSize20ms*channels)
packet, err := encoder.Encode(pcm, opus.FrameSize20ms)
if err != nil {
log.Fatal(err)
}
decoder, err := opus.NewDecoder(opus.SampleRate48kHz, channels)
if err != nil {
log.Fatal(err)
}
decoded := make([]int16, opus.MaxFrameSize*channels)
samplesPerChannel, err := decoder.Decode(packet, decoded)
if err != nil {
log.Fatal(err)
}
decoded = decoded[:samplesPerChannel*channels]
fmt.Println(samplesPerChannel, len(decoded)) // 960 1920
}Executable examples are included in the root package documentation and Ogg Opus package documentation.
| Area | Support |
|---|---|
| Sample rates | 8, 12, 16, 24, and 48 kHz |
| Single-stream channels | Mono and stereo |
| PCM APIs | Interleaved int16, signed 24-bit-in-int32, float32, and float64 |
| Encoder packet durations | CELT 2.5/5/10 ms; exact 20 ms multiples through 120 ms |
| Decoder packet durations | Valid Opus packets up to 120 ms |
| Coding modes | CELT encode/decode; voice-oriented SILK-only and hybrid encode; SILK/hybrid decode |
| Loss handling | Explicit-duration CELT/SILK/hybrid PLC and SILK LBRR in-band FEC in int16, signed 24-bit-in-int32, float32, and float64 |
| Multistream/surround | RFC self-delimited framing; families 0, 1 (through 7.1), and 255; matching PLC/FEC PCM variants |
| Projection/Ambisonics | RFC 8486 families 2 and 3; predefined first- through fifth-order family-3 matrices |
| Packet tools | Validated inspection, repacketizing, padding, soft clipping, LBRR detection, extensions |
| Ogg Opus | CRC/lacing, headers/tags (mapping families 0-3 and 255), timing trims, chained reading, per-link seek, validated single-link writing |
| Runtime dependencies | Pure Go; CGO/libopus is optional and test-only under opusref |
MaxFrameSize is 5760 samples per channel at 48 kHz (120 ms).
MaxFrameBytes is the 1275-byte compressed-frame limit. MaxPacketSize is a
conservative bound for an unpadded single-stream packet; explicit padding may
exceed it.
DecodePLC, DecodePLC24, DecodePLCFloat32, and DecodePLCFloat conceal an
explicit missing duration. The duration may be any positive 2.5 ms multiple
(multistream and projection decoders conceal at most 120 ms per call, as in
libopus). Before the first successfully decoded packet, and after
Reset, PLC returns zero concealment.
For in-band FEC, prefer DecodeFECWithDuration for int16 or the explicit-
duration DecodeFEC24, DecodeFECFloat32, and DecodeFECFloat variants. They
recover LBRR from the first Opus frame in the carrier and use PLC for an
unrecoverable prefix or when FEC is unavailable. The original DecodeFEC
remains a compatibility wrapper that infers the missing duration from the
carrier and retains its legacy CELT-only error behavior. MultistreamDecoder
provides the same PCM variants and duration contract; SurroundDecoder
inherits them. A returned FEC error does not commit partial decoder state.
Encoder, decoder, multistream, surround, projection, repacketizer, and Ogg
reader/writer values are stateful and are not safe for concurrent use. Use one
instance per logical stream, process packets in order, and serialize every
operation on an instance, including getters, controls, child stream access,
seeking, and Reset. Distinct instances may run concurrently. Do not copy an
instance after first use.
Codec methods borrow per-call PCM, packet, and destination slices only until
the call returns. Constructors copy mappings and matrices. Returned packet,
PCM, mapping, and matrix slices are caller-owned copies. Ogg readers and writers
borrow their io.Reader/io.Writer for the instance lifetime and do not close
it.
Where a codec type exposes Reset, it clears codec history and last-packet
observations while retaining configuration such as bitrate, application,
output gain, and phase-inversion controls. Reuse an instance after Reset only
for a new stream with the same configuration, or apply new controls explicitly.
CI downloads the unmodified RFC 8251 vector archive and runs all 12 decoder
vectors. Vector data is not committed, so local vector tests skip when
testdata/opus_newvectors/ is absent.
go test -count=1 ./...
go test -count=1 -run TestOfficialVectors .Optional opusref tests require a C toolchain and libopus. They compare decoder
output, interoperability, final ranges, FEC/PLC, multistream, projection, and
selected encoder quality behavior against libopus 1.6.1. They are reference
checks, not runtime dependencies.
go test -count=1 -tags opusref ./...The current CELT constrained-VBR and TF-allocation corrections are guarded by a 140-cell opt-in corpus scoreboard; the measured one-second byte totals stayed unchanged while the targeted music/mixed worst cases improved. Surround channel-role masking improved the weighted SNR of the deterministic 5.1 and 7.1 fixtures without changing elementary packet lengths. SILK scratch reuse is guarded by packet/final-range digests and reduced allocations in the recorded Windows amd64 benchmarks. v1.7.0 roughly halves encode and decode time against v1.6.0 and removes about 97% of the bytes allocated, without changing decoded PCM, final ranges or encoded bytes. v1.7.1 fixes four encoder differences from plain-C libopus found on real audio, so encoded bytes change on the frames they affect; decoding is unchanged. These are regression fixtures and local measurements, not universal quality or performance guarantees; see the real-corpus scoreboard and the performance baseline for conditions and values.
Public decoder and packet/container parsing paths are designed to reject malformed input with errors instead of panicking. Stateful decoder sequences, PLC/FEC interleaving, encoder controls and extreme PCM (including floating-point edge cases), packet extensions, multistream framing, repacketizing, and Ogg Reader/Writer round trips have dedicated fuzz targets. CI runs the target set nightly on Linux amd64 and arm64.
This is a bounded API guarantee, not a claim that fuzzing proves correctness. Callers must still enforce application-level packet, stream, CPU, and memory budgets; fuzz coverage does not guarantee audio quality, timing availability, or protection against every denial-of-service pattern. Report suspected security issues through SECURITY.md, not a public issue.
Example local runs:
go test -run='^$' -fuzz='^FuzzDecoderSequence$' -fuzztime=60s .
go test -run='^$' -fuzz='^FuzzOggOpusReaderWriter$' -fuzztime=60s ./oggopusModePolicyLibopus(the default) reproduces libopus for single-stream packets of every duration and for the multistream, surround (mapping families 0, 1 and 255), and projection / Ambisonics (families 2 and 3) encoders.ModePolicyLegacy, the Go encoder's earlier decisions, differs from libopus: below about 40 kbit/s it codes speech at 8 kHz and tonal music down to 4 kHz audio bandwidth.- Byte identity is measured against libopus built without SIMD kernels; a libopus linked with SIMD kernels sums floats in a different order, so its CELT output differs.
- DRED and QEXT packet extensions are transported opaquely; their codecs/DSP are not implemented.
- Projection family 3 uses predefined libopus 1.6.1 matrices; arbitrary custom encoder matrix generation is not provided.
- The Ogg Opus reader supports chained logical streams but not multiplexed physical-stream demultiplexing. Each Writer emits one logical stream.
- Not every libopus single-stream or multistream CTL has a public equivalent.
go generate ./...
git diff --exit-code
go fmt ./...
go vet ./...
go test -count=1 ./...
go test -race -count=1 ./...
go test -run='^$' -bench '^BenchmarkPerf/' -benchmem .Normal CI runs native tests on Linux, macOS, and Windows for both amd64 and
arm64. The Windows arm64 runner is currently a GitHub public-preview image.
Generated-file drift, vet, and official vectors are separate Ubuntu jobs, and
the opusref workflow stays on Ubuntu with libopus. See the workflow files for
the exact current matrix.
- Go API reference
- Ogg Opus API reference
- Current implementation snapshot
- CTL and helper parity
- Performance baseline and benchmark method
- Historical architecture and design background
- Mode/rate policy differences
- Real-corpus scoreboard
- Developer guide
- Release checklist
- Possible v2 API changes
- Security policy
- Contributing guide
BSD 2-Clause License. See LICENSE.