opus

package module
v1.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2026 License: BSD-2-Clause Imports: 9 Imported by: 0

README

Pure Go Opus Codec

Go Reference Test Race Fuzz License

日本語 | English

A pure-Go implementation of the Opus audio codec (RFC 6716 / RFC 8251) with no runtime CGO dependency. The decoder passes all 12 official RFC 8251 test vectors (RMSE < 0.001) and matches the libopus 1.6.1 reference frame-by-frame. The encoder implements the full CELT quality pipeline and produces standard Opus packets that libopus decodes correctly — see Status.

Note: the encoder is CELT-only and not bit-exact with libopus. It is suitable for encoding speech and music in pure Go; SILK and hybrid modes are not yet encoded.

Status

Area State
Decoder ✅ Passes all 12 official RFC 8251 vectors (RMSE < 0.001); matches libopus 1.6.1 reference. SILK, CELT, and hybrid (SILK+CELT) modes are reconstructed, including hybrid SILK→CELT redundancy.
Encoder ✅ Full CELT quality pipeline (Phase 1+2). Emits standard Opus packets that libopus 1.6.1 decodes correctly. SNR: ~48 dB (440 Hz), ~47 dB (1 kHz), ~43 dB (stereo) at 64 kbps. Not bit-exact with libopus. SILK/hybrid encode paths are not yet implemented.
CGO None at runtime. A libopus wrapper exists only for reference tests, behind the opusref build tag.
CI test, race, bench, and fuzz workflows run on amd64 and arm64.

See docs/CURRENT_IMPLEMENTATION.md for the authoritative, code-derived snapshot.

Installation

go get github.com/darui3018823/opus

Requires Go 1.24 or newer (see go.mod).

Usage

Decoding (int16)
package main

import (
	"log"

	"github.com/darui3018823/opus"
)

func main() {
	// 48 kHz, stereo.
	dec, err := opus.NewDecoder(48000, 2)
	if err != nil {
		log.Fatal(err)
	}

	// packet is one Opus packet (e.g. read from a file or the network).
	var packet []byte

	// Buffer for the decoded PCM. 120 ms at 48 kHz (the largest Opus frame)
	// is 5760 samples per channel; size generously for the frames you expect.
	pcm := make([]int16, 5760*2)

	n, err := dec.Decode(packet, pcm)
	if err != nil {
		log.Fatal(err)
	}
	// pcm[:n*2] now holds interleaved stereo samples (n samples per channel).
	_ = n
}
Decoding (float64)
// DecodeFloat returns a freshly allocated, interleaved []float64.
samples, err := dec.DecodeFloat(packet)
if err != nil {
	log.Fatal(err)
}
_ = samples
Encoding
enc, err := opus.NewEncoder(48000, 2, opus.ApplicationAudio)
if err != nil {
	log.Fatal(err)
}
enc.SetBitrate(64000)
enc.SetComplexity(10)
enc.SetVBR(true) // variable bitrate (default: CBR)

// 20 ms frame = 960 samples per channel at 48 kHz, interleaved stereo.
pcm := make([]int16, 960*2)
// ... fill pcm ...

packet, err := enc.Encode(pcm, 960)
if err != nil {
	log.Fatal(err)
}
_ = packet

// Float64 input is also supported:
//   packet, err := enc.EncodeFloat(make([]float64, 960*2), 960)

// Bandwidth is detected automatically from signal content; override if needed:
//   enc.SetBandwidth(opus.BandwidthWB)   // force wideband
//   enc.SetBandwidth(opus.BandwidthAuto) // restore auto

// 40 ms or 60 ms packets (multi-frame):
//   packet, err := enc.Encode(pcm1920, 1920) // 40 ms

Supported Configurations

  • Sample rates: 8 kHz, 12 kHz, 16 kHz, 24 kHz, 48 kHz. Non-48 kHz input to the encoder is resampled to 48 kHz internally; the decoder resamples its output to the requested rate.
  • Channels: mono and stereo.
  • Decoder frame sizes: all Opus durations (2.5/5/10/20/40/60 ms), selected per packet by the TOC byte.
  • Encoder frame sizes: 20 ms, 40 ms, 60 ms (multi-frame, RFC 6716 §3.2).
  • Encoder bandwidth: automatic (signal-content-driven FFT detection) or manual (SetBandwidth/SetMaxBandwidth). Ranges: NB/WB/SWB/FB.
  • Application types (drive bandwidth and transient-detection behaviour):
    • opus.ApplicationVOIP — narrower bandwidth tiers, eager short-block switching
    • opus.ApplicationAudio — music/general defaults
    • opus.ApplicationRestrictedLowDelay

Public API

Encoder
func NewEncoder(sampleRate, channels int, application Application) (*Encoder, error)

func (e *Encoder) Encode(pcm []int16, frameSize int) ([]byte, error)
func (e *Encoder) EncodeFloat(pcm []float64, frameSize int) ([]byte, error)

func (e *Encoder) SetBitrate(bitrate int) error       // 6000–510000 bps
func (e *Encoder) SetComplexity(complexity int) error  // 0–10
func (e *Encoder) SetVBR(vbr bool)
func (e *Encoder) SetVBRConstraint(constrained bool)   // true = CVBR
func (e *Encoder) SetApplication(application Application)
func (e *Encoder) SetBandwidth(bw Bandwidth)           // Auto/NB/WB/SWB/FB
func (e *Encoder) SetMaxBandwidth(bw Bandwidth)
func (e *Encoder) Bandwidth() Bandwidth
func (e *Encoder) SetDTX(dtx bool)
func (e *Encoder) SetPacketPadding(n int)
func (e *Encoder) Reset() error
Decoder
func NewDecoder(sampleRate, channels int) (*Decoder, error)

func (d *Decoder) Decode(data []byte, pcm []int16) (int, error)
func (d *Decoder) DecodeFloat(data []byte) ([]float64, error)
func (d *Decoder) DecodeFEC(data []byte, pcm []int16) (int, error) // currently a CELT PLC fallback
func (d *Decoder) Reset() error
func (d *Decoder) GetLastPacketDuration() int

There is intentionally no EncodeFloat32, DecodeFloat32, or DecodePLC(pcm, frameSize) API. Use the float64 variants above.

Architecture

github.com/darui3018823/opus/
├── opus.go / constants.go / errors.go  # Public API (Encoder/Decoder)
├── internal/
│   ├── opus_framing.go                  # TOC byte parsing/generation (RFC 6716 §3)
│   ├── dsp/                             # FFT, MDCT/IMDCT, windows, math
│   ├── entcode/                         # Range encoder/decoder
│   ├── resampler/                       # Opus-rate sample rate conversion
│   ├── celt/                            # CELT decoder parity + simplified encoder
│   ├── silk/                            # SILK decoder/encoder, tables, helpers
│   └── cgoref/                          # libopus reference wrapper (build tag: opusref)
└── docs/                                # Design and status documentation

Decoding flow: Opus packet → TOC parsed → CELT or SILK/hybrid path → range decoder + reconstruction → optional resample/channel adjust → PCM.

Encoding flow: PCM → optional resample to 48 kHz → CELT encoder (MDCT, band processing, PVQ) → range coder → TOC prepended → Opus packet.

Building & Testing

go build ./...
go vet ./...
go test ./...                 # library packages + official vectors (when present)
go test -race ./...
go test -bench=. -benchmem -run='^$' ./...

Official RFC 8251 test vectors are not committed (testdata/ is git-ignored). Tests that need them call t.Skip when they are absent. To run them locally, download and extract the vectors so they land in testdata/opus_newvectors/:

curl -fSL -o /tmp/v.tar.gz https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz
mkdir -p testdata && tar -xzf /tmp/v.tar.gz -C testdata/
go test -run TestOfficialVectors ./...
libopus reference comparison (optional)

The TestCGORef test decodes every vector with both this codec and libopus and compares them frame-by-frame. It requires a C toolchain plus libopus and is gated behind the opusref build tag (so normal builds stay CGO-free):

go test -tags opusref -run TestCGORef .

On Windows, run CGO builds from PowerShell with a working MinGW/MSYS2 toolchain.

Fuzzing
go test -run='^$' -fuzz='^FuzzDecode$' -fuzztime=60s .

FuzzDecode and FuzzDecodeFloat assert that the decoder never panics on arbitrary input. The fuzz CI workflow runs them nightly and on demand.

Continuous Integration

Four GitHub Actions workflows, each running on a matrix of amd64 (ubuntu-latest) and arm64 (ubuntu-24.04-arm):

  • test.ymlgo vet, go test ./..., and the official RFC 8251 vectors.
  • race.ymlgo test -race ./....
  • bench.ymlgo test -bench=. -benchmem, uploading results as artifacts.
  • fuzz.yml — nightly + manual go test -fuzz per target.

Documentation

Limitations

  • The encoder is CELT-only. SILK (speech-optimised) and hybrid (SILK+CELT) modes are not yet encoded; all output is CELT regardless of the application setting.
  • The encoder is not bit-exact with libopus, but produces standards-conformant packets that any compliant decoder (including libopus) can decode.
  • DecodeFEC is currently a PLC fallback, not packet FEC extraction.
  • No multistream, surround, or Ogg Opus container API.

Contributing

See CONTRIBUTING.md for guidelines on how to contribute, report bugs, and submit pull requests.

Please note that this project is released with a Contributor Code of Conduct. By participating you agree to abide by its terms.

License

BSD 2-Clause License — see LICENSE.

Acknowledgments

  • libopus — reference implementation by the Xiph.Org Foundation.
  • RFC 6716 / RFC 8251 — the Opus specification and its updates.

Support

For issues and questions, please use the GitHub issue tracker.

Documentation

Overview

Package opus provides a Pure Go implementation of the Opus audio codec. This implementation is based on the official libopus reference implementation and aims for complete compatibility without using CGO.

Index

Constants

View Source
const (
	Version      = "0.1.0"
	VersionMajor = 0
	VersionMinor = 1
	VersionPatch = 0
)

Opus version constants

View Source
const (
	SampleRate8kHz  = 8000
	SampleRate12kHz = 12000
	SampleRate16kHz = 16000
	SampleRate24kHz = 24000
	SampleRate48kHz = 48000
)

Sample rates supported by Opus

View Source
const (
	FrameSize2_5ms = 120  // 2.5ms at 48kHz
	FrameSize5ms   = 240  // 5ms at 48kHz
	FrameSize10ms  = 480  // 10ms at 48kHz
	FrameSize20ms  = 960  // 20ms at 48kHz (most common)
	FrameSize40ms  = 1920 // 40ms at 48kHz
	FrameSize60ms  = 2880 // 60ms at 48kHz
)

Frame sizes in samples (at 48kHz)

View Source
const (
	ApplicationVOIP               = 2048 // Voice over IP
	ApplicationAudio              = 2049 // General audio
	ApplicationRestrictedLowDelay = 2051 // Lowest latency
)

Application types

View Source
const (
	BandwidthAuto          = -1000 // automatic selection (default)
	BandwidthNarrowband    = 1101  // 4kHz
	BandwidthMediumband    = 1102  // 6kHz
	BandwidthWideband      = 1103  // 8kHz
	BandwidthSuperWideband = 1104  // 12kHz
	BandwidthFullband      = 1105  // 20kHz
)

Bandwidth types

View Source
const (
	ChannelsMono   = 1
	ChannelsStereo = 2
)

Channel modes

View Source
const (
	ModeSILKOnly = 1000
	ModeHybrid   = 1001
	ModeCELTOnly = 1002
)

Opus modes (internal)

View Source
const (
	BitrateAuto   = -1000
	BitrateMax    = -1
	BitrateMin    = 500    // 500 bps
	BitrateMaxVal = 512000 // 512 kbps
)

Bitrate constants

View Source
const (
	SetBitrateRequest             = 4002
	GetBitrateRequest             = 4003
	SetForceChannelsRequest       = 4022
	GetForceChannelsRequest       = 4023
	SetMaxBandwidthRequest        = 4004
	GetMaxBandwidthRequest        = 4005
	SetBandwidthRequest           = 4008
	GetBandwidthRequest           = 4009
	SetComplexityRequest          = 4010
	GetComplexityRequest          = 4011
	SetInbandFECRequest           = 4012
	GetInbandFECRequest           = 4013
	SetPacketLossPercRequest      = 4014
	GetPacketLossPercRequest      = 4015
	SetDTXRequest                 = 4016
	GetDTXRequest                 = 4017
	SetVBRRequest                 = 4006
	GetVBRRequest                 = 4007
	SetVBRConstraintRequest       = 4020
	GetVBRConstraintRequest       = 4021
	SetSignalRequest              = 4024
	GetSignalRequest              = 4025
	SetApplicationRequest         = 4000
	GetApplicationRequest         = 4001
	GetLookaheadRequest           = 4027
	SetExpertFrameDurationRequest = 4040
	GetExpertFrameDurationRequest = 4041
	SetPredictionDisabledRequest  = 4042
	GetPredictionDisabledRequest  = 4043
	ResetStateRequest             = 4028
)

Encoder/Decoder control codes (CTL)

View Source
const (
	ComplexityMin     = 0
	ComplexityMax     = 10
	ComplexityDefault = 9
)

Complexity (0-10)

View Source
const (
	PacketLossPercMin = 0
	PacketLossPercMax = 100
)

Packet loss percentage (0-100)

View Source
const (
	MaxPacketSize = 1500 // bytes
	MaxFrameSize  = 2880 // samples at 48kHz for 60ms
)

Maximum packet size

Variables

View Source
var (
	// ErrBadArg indicates that one or more arguments are invalid
	ErrBadArg = errors.New("opus: bad argument")

	// ErrBufferTooSmall indicates that the provided buffer is too small
	ErrBufferTooSmall = errors.New("opus: buffer too small")

	// ErrInternalError indicates an internal error occurred
	ErrInternalError = errors.New("opus: internal error")

	// ErrInvalidPacket indicates the packet is invalid or corrupted
	ErrInvalidPacket = errors.New("opus: invalid packet")

	// ErrUnimplemented indicates a feature is not yet implemented
	ErrUnimplemented = errors.New("opus: unimplemented")

	// ErrInvalidState indicates the encoder/decoder is in an invalid state
	ErrInvalidState = errors.New("opus: invalid state")

	// ErrAllocFail indicates memory allocation failed
	ErrAllocFail = errors.New("opus: allocation failed")

	// ErrUnsupportedSampleRate indicates the sample rate is not supported
	ErrUnsupportedSampleRate = errors.New("opus: unsupported sample rate")

	// ErrUnsupportedChannels indicates the channel count is not supported
	ErrUnsupportedChannels = errors.New("opus: unsupported number of channels")

	// ErrUnsupportedFrameSize indicates the frame size is not supported
	ErrUnsupportedFrameSize = errors.New("opus: unsupported frame size")

	// ErrUnsupportedBandwidth indicates the bandwidth is not supported
	ErrUnsupportedBandwidth = errors.New("opus: unsupported bandwidth")
)

Common Opus errors

Functions

This section is empty.

Types

type Application

type Application = int

Application specifies the encoding mode (use constants from package)

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

Decoder represents an Opus decoder instance

func NewDecoder

func NewDecoder(sampleRate, channels int) (*Decoder, error)

NewDecoder creates a new Opus decoder

sampleRate must be one of: 8000, 12000, 16000, 24000, 48000 Hz channels must be 1 (mono) or 2 (stereo)

func (*Decoder) Decode

func (d *Decoder) Decode(data []byte, pcm []int16) (int, error)

Decode decodes an Opus packet to PCM samples

data is the compressed Opus packet pcm is the output buffer for 16-bit PCM samples Returns the number of samples per channel decoded (clamped to buffer size)

func (*Decoder) DecodeFEC

func (d *Decoder) DecodeFEC(data []byte, pcm []int16) (int, error)

DecodeFEC decodes forward error correction data This is used for packet loss concealment

func (*Decoder) DecodeFloat

func (d *Decoder) DecodeFloat(data []byte) ([]float64, error)

DecodeFloat decodes an Opus packet to floating-point PCM samples

data is the compressed Opus packet Returns float64 samples in range [-1.0, 1.0]

func (*Decoder) GetLastPacketDuration

func (d *Decoder) GetLastPacketDuration() int

GetLastPacketDuration returns the duration of the last decoded packet in samples

func (*Decoder) Reset

func (d *Decoder) Reset() error

Reset resets the decoder state

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Encoder represents an Opus encoder instance

func NewEncoder

func NewEncoder(sampleRate, channels int, application Application) (*Encoder, error)

NewEncoder creates a new Opus encoder

sampleRate must be one of: 8000, 12000, 16000, 24000, 48000 Hz channels must be 1 (mono) or 2 (stereo) application specifies the encoding mode

func (*Encoder) Application added in v1.1.1

func (e *Encoder) Application() Application

Application returns the current application mode.

func (*Encoder) Bandwidth added in v1.1.0

func (e *Encoder) Bandwidth() int

Bandwidth reports the coded bandwidth the encoder would currently use, as a public Bandwidth* constant.

func (*Encoder) Bitrate added in v1.1.1

func (e *Encoder) Bitrate() int

Bitrate returns the current target bitrate in bits per second.

func (*Encoder) Complexity added in v1.1.1

func (e *Encoder) Complexity() int

Complexity returns the current complexity setting (0–10).

func (*Encoder) DTX added in v1.1.0

func (e *Encoder) DTX() bool

DTX reports whether discontinuous transmission is enabled.

func (*Encoder) Encode

func (e *Encoder) Encode(pcm []int16, frameSize int) ([]byte, error)

Encode encodes PCM audio samples

pcm contains interleaved 16-bit PCM samples (left, right, left, right, ...) frameSize is the number of samples per channel (at the encoder's sample rate) Returns compressed Opus packet

func (*Encoder) EncodeFloat

func (e *Encoder) EncodeFloat(pcm []float64, frameSize int) ([]byte, error)

EncodeFloat encodes floating-point PCM samples

pcm contains interleaved float64 samples in range [-1.0, 1.0] frameSize is the number of samples per channel (at the encoder's sample rate)

func (*Encoder) Reset

func (e *Encoder) Reset() error

Reset resets the encoder state

func (*Encoder) SetApplication

func (e *Encoder) SetApplication(application Application)

SetApplication changes the application mode. This re-derives the CELT content hint (voice for VOIP, music otherwise), which influences bandwidth selection and transient sensitivity; it does not affect already-emitted packets.

func (*Encoder) SetBandwidth added in v1.1.0

func (e *Encoder) SetBandwidth(bw int) error

SetBandwidth forces a specific coded bandwidth, overriding the automatic selection (it is still clamped to the input sample rate's Nyquist limit). Pass BandwidthAuto to return to automatic selection (the default). bw must be BandwidthAuto or one of the public Bandwidth* constants. CELT has no medium-band mode, so BandwidthMediumband is rounded up to BandwidthWideband.

func (*Encoder) SetBitrate

func (e *Encoder) SetBitrate(bitrate int) error

SetBitrate sets the target bitrate in bits per second

func (*Encoder) SetComplexity

func (e *Encoder) SetComplexity(complexity int) error

SetComplexity sets the computational complexity (0-10) Higher values use more CPU but may provide better quality

func (*Encoder) SetDTX added in v1.1.0

func (e *Encoder) SetDTX(enabled bool)

SetDTX enables or disables discontinuous transmission. When enabled, frames the encoder detects as silent are emitted as minimal packets (a few bytes) instead of being padded to the target size. This reduces bitrate during silence. The decoder reconstructs such frames as digital silence. DTX is off by default. The reduction is effective in any rate mode; in CBR it overrides the fixed-size padding for silent frames only.

func (*Encoder) SetMaxBandwidth added in v1.1.0

func (e *Encoder) SetMaxBandwidth(bw int) error

SetMaxBandwidth caps the automatically selected coded bandwidth. bw must be one of the public Bandwidth* constants (Narrowband..Fullband). The encoder never exceeds this cap, nor the input sample rate's Nyquist limit. The default is BandwidthFullband (no extra cap). Has no effect when an explicit bandwidth is forced via SetBandwidth.

func (*Encoder) SetPacketPadding added in v1.1.0

func (e *Encoder) SetPacketPadding(n int)

SetPacketPadding sets the number of code-3 padding-data bytes appended to each emitted packet (RFC 6716 §3.2.5). When n > 0, every packet is encoded as a code-3 packet with the padding flag set and n zero bytes appended at the end; the padding does not affect the decoded audio (the decoder strips it). This is useful for keeping a constant on-the-wire packet size or for obscuring the true payload length. n <= 0 disables padding (the default), restoring the compact code-0/1/2/3 selection.

func (*Encoder) SetSignalType added in v1.1.1

func (e *Encoder) SetSignalType(s SignalType)

SetSignalType overrides the content hint used by encoder heuristics. SignalAuto (the default) re-derives the hint from the current Application setting (VOIP → voice, otherwise music). Calling this with SignalVoice or SignalMusic pins the hint regardless of the Application value; a subsequent SetApplication call will overwrite it again.

func (*Encoder) SetVBR

func (e *Encoder) SetVBR(vbr bool)

SetVBR enables or disables variable bitrate mode. When enabled, this sets constrained VBR (CVBR), which is the libopus default: the encoder produces variable-size packets but keeps the average bitrate close to the target. Use SetVBRConstraint(false) for unconstrained VBR.

func (*Encoder) SetVBRConstraint added in v1.1.0

func (e *Encoder) SetVBRConstraint(constrained bool)

SetVBRConstraint controls the VBR constraint. When true (default), CVBR is used; when false, unconstrained VBR is used. Has no effect if VBR is disabled.

func (*Encoder) SignalType added in v1.1.1

func (e *Encoder) SignalType() SignalType

SignalType reports the current content hint.

func (*Encoder) VBR added in v1.1.1

func (e *Encoder) VBR() bool

VBR reports whether variable bitrate is enabled.

type SignalType added in v1.1.1

type SignalType = celt.SignalType

SignalType is a content hint that lets the encoder tune heuristics for the dominant signal type without changing the bitstream format.

const (
	// SignalAuto lets the encoder derive a hint from the Application setting
	// (VOIP → voice, Audio/RestrictedLowDelay → music). This is the default.
	SignalAuto SignalType = celt.SignalUnknown
	// SignalVoice marks speech-leaning content. The encoder uses narrower
	// bandwidth tiers (matching ApplicationVOIP) and switches to short blocks
	// more eagerly on plosive onsets.
	SignalVoice SignalType = celt.SignalVoice
	// SignalMusic marks music or general audio content, applying wider
	// bandwidth tiers and standard transient sensitivity.
	SignalMusic SignalType = celt.SignalMusic
)

Directories

Path Synopsis
toccheck command
celt
Package celt implements the CELT (Constrained Energy Lapped Transform) codec.
Package celt implements the CELT (Constrained Energy Lapped Transform) codec.
cgoref
Package cgoref is the libopus CGO reference wrapper.
Package cgoref is the libopus CGO reference wrapper.
dsp
Package dsp provides digital signal processing utilities for the Opus codec.
Package dsp provides digital signal processing utilities for the Opus codec.
entcode
Package entcode provides entropy coding (range coding) for Opus, bit-exact with the range coder in libopus 1.3.1 (celt/entcode.c, celt/entenc.c, celt/entdec.c).
Package entcode provides entropy coding (range coding) for Opus, bit-exact with the range coder in libopus 1.3.1 (celt/entcode.c, celt/entenc.c, celt/entdec.c).
resampler
Package resampler provides high-quality sample rate conversion for Opus.
Package resampler provides high-quality sample rate conversion for Opus.
silk
Package silk implements the SILK speech codec for Opus.
Package silk implements the SILK speech codec for Opus.
testing
Package testing provides verification and comparison tools for Opus library development.
Package testing provides verification and comparison tools for Opus library development.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL