gopus

May 5, 2026 ยท View on GitHub

Pure Go Opus codec for Go applications.

Go Reference Go Report Card License

gopus implements Opus (RFC 6716) and Ogg Opus (RFC 7845) in pure Go. It is built for real-time use: no cgo, no C toolchain, and caller-owned buffers on the main encode/decode hot path.

Status

gopus is usable today, but it is still pre-v1.

  • Recommended starting surface: Encoder, Decoder, MultistreamEncoder, MultistreamDecoder, Reader, Writer, and container/ogg.
  • The main API target is the zero-allocation caller-owned path:
    • func (d *Decoder) Decode(data []byte, pcm []float32) (int, error)
    • func (e *Encoder) Encode(pcm []float32, data []byte) (int, error)
  • The default build intentionally does not support every optional libopus build-time extension. It supports SetDNNBlob(...); QEXT and DRED are tag-gated, and OSCE BWE remains quarantine-only. See Optional Extensions for the supported, tag-gated, and unsupported matrix.
  • Low-level packages such as celt, silk, hybrid, rangecoding, and plc are implementation detail, not a stable public contract yet.
  • Validation and parity work is pinned against libopus 1.6.1.
  • No tagged release has been published yet. If you adopt gopus before v0.1.0, pin the exact version you validate.

Trust And Verification

Installation

go get github.com/thesyncim/gopus

Requirements:

  • Go 1.25+
  • No cgo or external C toolchain for normal builds

Performance Snapshot

Official RFC 8251 test-vector decode benchmarks use pinned libopus 1.6.1 as the baseline, with the same preloaded packets, reset cadence, and 48 kHz stereo output. Current checked-in results were measured on Apple M4 Max with Go 1.26.0 and Go PGO profile default.pgo; the full report uses median-of-3 runs at 200ms, 1s, and 5s minimum run times. The table below highlights the 5s row. Ratios above 1.00x mean gopus is slower than libopus.

Pathgopus ns/samplelibopus ns/samplegopus/libopusgopus allocs/op
Float32 decode19.7819.361.02x0
Int16 decode20.0719.521.03x0

See the full Markdown report in Official Test Vector Decode Performance. Reproduce it with BENCH_TESTVECTORS_COMPARE_CASES=aggregate BENCH_TESTVECTORS_COMPARE_PATHS=all BENCH_TESTVECTORS_COMPARE_TIMES=200,1000,5000 BENCH_TESTVECTORS_COMPARE_COUNT=3 make bench-testvectors-compare.

Quick Start

Use caller-owned buffers in real-time paths.

package main

import (
	"log"

	"github.com/thesyncim/gopus"
)

func main() {
	const sampleRate = 48000
	const channels = 2

	enc, err := gopus.NewEncoder(gopus.EncoderConfig{
		SampleRate:  sampleRate,
		Channels:    channels,
		Application: gopus.ApplicationAudio,
	})
	if err != nil {
		log.Fatal(err)
	}

	decCfg := gopus.DefaultDecoderConfig(sampleRate, channels)
	dec, err := gopus.NewDecoder(decCfg)
	if err != nil {
		log.Fatal(err)
	}

	pcmIn := make([]float32, 960*channels)
	packetBuf := make([]byte, 4000)
	pcmOut := make([]float32, decCfg.MaxPacketSamples*channels)

	nPacket, err := enc.Encode(pcmIn, packetBuf)
	if err != nil {
		log.Fatal(err)
	}
	if nPacket == 0 {
		return
	}

	nSamples, err := dec.Decode(packetBuf[:nPacket], pcmOut)
	if err != nil {
		log.Fatal(err)
	}

	decoded := pcmOut[:nSamples*channels]
	_ = decoded
}

Packet loss concealment uses dec.Decode(nil, pcmOut). If you prefer convenience over zero-allocation behavior, allocating helpers such as EncodeFloat32 and EncodeInt16Slice are also available.

Support Matrix

AreaStatusNotes
Mono/stereo encode/decodeSupportedEncoder / Decoder with caller-owned buffers
Multistream encode/decodeSupportedDefault mappings for 1-8 channels; explicit mappings up to 255 channels
Ogg Opus containerSupportedcontainer/ogg reader/writer
Streaming facadeSupportedReader / Writer
Allocating convenience helpersSupportedSimpler to use, but not zero-allocation
Low-level codec packagesExperimentalMay change before v1
Optional libopus build-time extensionsMixedDefault builds support SetDNNBlob(...) only. QEXT requires -tags gopus_qext; DRED control/standalone surfaces require -tags gopus_dred; OSCE BWE remains unsupported outside quarantine builds. See Optional Extensions

Environment and codec expectations:

TopicCurrent expectation
Go versionsGo 1.25+ is required; scheduled safety automation also exercises Go 1.26
CI platformsLinux, macOS, and Windows
Optimized architecturesamd64 and arm64 have tuned assembly kernels; other architectures use pure Go fallbacks
Sample rates8000, 12000, 16000, 24000, 48000 Hz
Frame durations2.5 ms to 120 ms, depending on mode
ChannelsEncoder / Decoder: 1-2; default multistream: 1-8; explicit multistream: up to 255 channels

Encoder, Decoder, MultistreamEncoder, and MultistreamDecoder are not safe for concurrent use. Use one instance per goroutine.

Verification

If you want to evaluate or contribute to the codec, these are the main entry points:

  • go test ./...
  • make test-quality
  • make bench-guard
  • make bench-testvectors
  • make bench-testvectors-compare
  • make verify-production

make ensure-libopus bootstraps the pinned libopus 1.6.1 reference used by parity and quality checks. make ensure-testvectors fetches the official RFC 8251 vectors; benchmark targets that need them run it automatically. Some verification paths also expect ffmpeg and opusdec to be available.

Docs and Project Hygiene

License

BSD 3-Clause. See LICENSE.