gopus

package module
v0.0.0-...-e7301bc Latest Latest
Warning

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

Go to latest
Published: Feb 13, 2026 License: BSD-3-Clause Imports: 12 Imported by: 0

README

gopus

Pure Go Opus codec for production systems.

Go Reference Go Report Card License

gopus implements Opus (RFC 6716) and Ogg Opus (RFC 7845) in pure Go.

No cgo. No C toolchain. Caller-owned buffers in the encode/decode hot path.

Why gopus

  • Pure Go codec stack (encode + decode), interoperable with libopus.
  • Full Opus modes: SILK, CELT, Hybrid.
  • Architecture-tuned assembly kernels on amd64/arm64 with pure Go fallbacks on other targets.
  • Core hot path is zero-allocation with caller-provided buffers.
  • Ogg Opus container reader/writer (container/ogg).
  • Multistream support (default mappings for 1-8 channels, explicit mappings up to 255 channels).
  • Compliance and parity coverage against libopus 1.6.1 fixtures.

Status Snapshot (2026-02-10)

  • Decoder: complete and stable across SILK/CELT/Hybrid, stereo, and sample rates.
  • Encoder: complete feature surface (FEC/LBRR, DTX, controls, multistream, ambisonics).
  • Allocations: zero allocs/op in encoder and decoder core hot paths.
  • TestSILKParamTraceAgainstLibopus: PASS with exact SILK-WB trace parity on canonical 50-frame fixture.
  • TestEncoderComplianceSummary: PASS (19 passed, 0 failed).
  • Remaining quality gap: strict production threshold (Q >= 0, about 48 dB SNR) is not yet met in all profiles.

Installation

go get github.com/thesyncim/gopus

Requirements:

  • Go 1.25+

Quick Start (Zero-Allocation Path)

Use Encode / Decode with caller-owned buffers for real-time paths.

package main

import (
	"log"

	"github.com/thesyncim/gopus"
)

func main() {
	enc, err := gopus.NewEncoder(48000, 2, gopus.ApplicationAudio)
	if err != nil {
		log.Fatal(err)
	}
	_ = enc.SetBitrate(128000)
	_ = enc.SetComplexity(10)
	_ = enc.SetFrameSize(960) // 20 ms at 48 kHz

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

	// Input/output buffers are caller-owned.
	pcmIn := make([]float32, enc.FrameSize()*enc.Channels())
	packetBuf := make([]byte, 4000)
	pcmOut := make([]float32, decCfg.MaxPacketSamples*decCfg.Channels)

	nPacket, err := enc.Encode(pcmIn, packetBuf)
	if err != nil {
		log.Fatal(err)
	}
	if nPacket == 0 {
		// DTX can suppress silent frames.
		return
	}

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

Packet loss concealment (PLC):

nSamples, err := dec.Decode(nil, pcmOut) // nil packet => PLC
_ = nSamples
_ = err

Convenience API (Allocating)

Convenience helpers allocate output buffers:

  • (*Encoder).EncodeFloat32
  • (*Encoder).EncodeInt16Slice
  • (*MultistreamEncoder).EncodeFloat32
  • (*MultistreamEncoder).EncodeInt16Slice

Use them for simplicity, not for the tightest real-time loop.

API Surface

Type Purpose
Encoder Mono/stereo Opus encoding
Decoder Mono/stereo Opus decoding
MultistreamEncoder Multichannel Opus encoding
MultistreamDecoder Multichannel Opus decoding
Reader Streaming decode (io.Reader)
Writer Streaming encode (io.Writer)
container/ogg.Reader Ogg Opus packet reader
container/ogg.Writer Ogg Opus packet writer

Application hints:

  • ApplicationVoIP
  • ApplicationAudio
  • ApplicationLowDelay

Ogg Opus Example

package main

import (
	"io"
	"log"
	"os"

	"github.com/thesyncim/gopus"
	"github.com/thesyncim/gopus/container/ogg"
)

func main() {
	const sampleRate = 48000
	const channels = 2
	const frameSize = 960 // 20 ms at 48 kHz

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

	outFile, err := os.Create("out.opus")
	if err != nil {
		log.Fatal(err)
	}
	defer outFile.Close()

	ow, err := ogg.NewWriter(outFile, sampleRate, channels)
	if err != nil {
		log.Fatal(err)
	}

	pcm := make([]float32, frameSize*channels)
	packetBuf := make([]byte, 4000)
	pcmOut := make([]float32, 5760*channels)

	nPacket, err := enc.Encode(pcm, packetBuf)
	if err != nil {
		log.Fatal(err)
	}
	if nPacket > 0 {
		if err := ow.WritePacket(packetBuf[:nPacket], frameSize); err != nil {
			log.Fatal(err)
		}
	}
	if err := ow.Close(); err != nil {
		log.Fatal(err)
	}

	inFile, err := os.Open("out.opus")
	if err != nil {
		log.Fatal(err)
	}
	defer inFile.Close()

	or, err := ogg.NewReader(inFile)
	if err != nil {
		log.Fatal(err)
	}

	for {
		packet, _, err := or.ReadPacket()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		if _, err := dec.Decode(packet, pcmOut); err != nil {
			log.Fatal(err)
		}
	}
}

Supported Configurations

Sample rates:

  • 8000, 12000, 16000, 24000, 48000 Hz

Frame sizes (samples/channel at 48 kHz):

  • 120 (2.5 ms, CELT-only)
  • 240 (5 ms, CELT-only)
  • 480 (10 ms)
  • 960 (20 ms, default)
  • 1920 (40 ms, SILK/hybrid)
  • 2880 (60 ms, SILK/hybrid)

Channels:

  • Core Encoder / Decoder: 1 or 2 channels
  • Default multistream constructors: 1-8 channels
  • Explicit multistream constructors: up to 255 channels

Performance and Allocations

Core guidance:

  • Reuse Encoder / Decoder instances.
  • Reuse input/output buffers.
  • Use Encode and Decode in hot paths.

Benchmarks:

go test -run='^$' -bench='^Benchmark(DecoderDecode|EncoderEncode)_' -benchmem ./...
go test -bench=. -benchmem ./...
go test -run '^TestHotPathAllocs' -count=1 .
make bench-guard

PGO:

make pgo-generate
make build

Assembly Optimizations

gopus includes native assembly kernels for amd64 and arm64 in CELT and SILK hot paths. Other architectures use pure Go fallbacks with matching behavior.

Implemented assembly surfaces:

  • CELT:
    • celt/haar1_amd64.s, celt/haar1_arm64.s (haar1Stride1Asm)
    • celt/xcorr_amd64.s, celt/xcorr_arm64.s (celtInnerProd, dualInnerProd, celtPitchXcorr)
  • SILK:
    • silk/inner_prod_amd64.s, silk/inner_prod_arm64.s (innerProductF32Asm, energyF32Asm)
    • silk/nsq_pred_amd64.s, silk/nsq_pred_arm64.s (shortTermPrediction16, shortTermPrediction10)
    • silk/nsq_warp_amd64.s, silk/nsq_warp_arm64.s (warpedARFeedback24, warpedARFeedback16)

For build-tag details and maintenance guidance, see ASSEMBLY.md.

Parity and Compliance Workflow

# Full suite
go test ./... -count=1

# SILK trace parity vs libopus
go test ./testvectors -run TestSILKParamTraceAgainstLibopus -count=1 -v

# Encoder compliance summary
go test ./testvectors -run TestEncoderComplianceSummary -count=1 -v

# Project shortcuts
make test-fast
make test-race
make test-race-parity
make test-fuzz-smoke
make test-parity
make bench-guard
make verify-production
make verify-production-exhaustive
make release-evidence
make ensure-libopus
make test-exhaustive
make test-provenance
make fixtures-gen
make fixtures-gen-amd64
make docker-build
make docker-test
make docker-test-exhaustive

Docker targets use persistent caches:

  • build layers in .docker-cache/ (buildx local cache)
  • Go modules in gopus-gomod volume
  • Go build cache in gopus-gobuild-* volumes
  • pinned libopus artifacts in gopus-libopus-* volumes

Examples

go build ./examples/...

go run ./examples/roundtrip
go run ./examples/ogg-file
go run ./examples/ffmpeg-interop
go run ./examples/decode-play
go run ./examples/encode-play
go run ./examples/bench-decode
go run ./examples/bench-encode

See examples/README.md for details.

Project Layout

  • encoder/: encoder core
  • silk/: SILK implementation
  • celt/: CELT implementation
  • hybrid/: SILK/CELT bridge
  • testvectors/: parity/compliance fixtures and tests
  • container/ogg/: Ogg Opus reader/writer
  • ASSEMBLY.md: architecture-specific assembly coverage and fallbacks
  • tmp_check/opus-1.6.1/: libopus 1.6.1 reference tooling

Thread Safety

Encoder, Decoder, MultistreamEncoder, and MultistreamDecoder are not safe for concurrent use.

Use one instance per goroutine.

Contributing

  1. Open an issue describing the change.
  2. Add or update focused tests.
  3. Verify parity/compliance commands for affected areas.
  4. Submit a PR with a clear problem statement and tradeoffs.

See CI_GUARDRAILS.md for merge-blocking CI checks and branch-protection requirements.

License

BSD 3-Clause. See LICENSE.

References

Documentation

Overview

Package gopus implements the Opus audio codec in pure Go.

Opus is a lossy audio codec designed for interactive speech and music transmission. It supports bitrates from 6 to 510 kbit/s, sampling rates from 8 to 48 kHz, and frame sizes from 2.5 to 60 ms.

This implementation follows RFC 6716 and is compatible with the reference libopus implementation. It requires no cgo dependencies.

Quick Start

Encoding:

enc, err := gopus.NewEncoder(48000, 2, gopus.ApplicationAudio)
if err != nil {
    log.Fatal(err)
}

pcm := make([]float32, 960*2) // 20ms stereo at 48kHz
// ... fill pcm with audio samples ...

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

Decoding:

cfg := gopus.DefaultDecoderConfig(48000, 2)
dec, err := gopus.NewDecoder(cfg)
if err != nil {
    log.Fatal(err)
}

pcmOut := make([]float32, cfg.MaxPacketSamples*cfg.Channels)
n, err := dec.Decode(packet, pcmOut)
if err != nil {
    log.Fatal(err)
}

Opus Modes

Opus operates in three modes:

  • SILK: speech-optimized, 8-24 kHz bandwidth
  • CELT: audio-optimized, full 48 kHz bandwidth
  • Hybrid: SILK for low frequencies + CELT for high frequencies

The encoder automatically selects the appropriate mode based on the Application hint provided to NewEncoder:

  • ApplicationVoIP: Prefers SILK for speech
  • ApplicationAudio: Prefers CELT/Hybrid for music
  • ApplicationLowDelay: Uses CELT for minimum latency

Sample Formats

Both int16 and float32 PCM formats are supported. float32 is the internal format and avoids conversion overhead. int16 is provided for compatibility with common audio APIs.

For float32, samples should be normalized to [-1.0, 1.0]. For int16, the full range [-32768, 32767] is used.

Stereo audio uses interleaved samples: L0, R0, L1, R1, ...

Thread Safety

Encoder and Decoder instances are NOT safe for concurrent use. Each goroutine should create its own instance.

Buffer Sizing

For caller-provided buffers:

  • Decode output: max 5760 * channels samples (120ms at 48kHz, default cap)
  • Encode output: 4000 bytes is sufficient for any Opus packet

Packet Loss Concealment

When a packet is lost, pass nil to Decode to trigger packet loss concealment (PLC). The decoder will generate audio to conceal the gap:

if packetLost {
    n, err = dec.Decode(nil, pcmOut) // PLC
} else {
    n, err = dec.Decode(packet, pcmOut)
}

Packet Structure

Each Opus packet starts with a TOC (Table of Contents) byte:

  • Bits 7-3: Configuration (0-31)
  • Bit 2: Stereo flag
  • Bits 1-0: Frame count code (0-3)

Use ParseTOC to extract these fields, and ParsePacket to determine the frame boundaries within a packet.

Configuration

The encoder supports various configuration options:

enc.SetBitrate(64000)     // Target bitrate (6000-510000 bps)
enc.SetComplexity(10)     // Quality vs CPU (0-10)
enc.SetFEC(true)          // Forward error correction
enc.SetDTX(true)          // Discontinuous transmission
enc.SetFrameSize(480)     // Frame size (120-2880 samples)

Multistream (Surround Sound)

For surround sound applications (5.1, 7.1, etc.), use MultistreamEncoder and MultistreamDecoder. These support 1-8 channels with standard Vorbis-style channel mapping per RFC 7845.

Multistream encoding example (5.1 surround):

enc, err := gopus.NewMultistreamEncoderDefault(48000, 6, gopus.ApplicationAudio)
if err != nil {
    log.Fatal(err)
}

pcm := make([]float32, 960*6) // 20ms of 6-channel audio at 48kHz
// ... fill pcm with interleaved samples: FL, C, FR, RL, RR, LFE ...

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

Multistream decoding example:

dec, err := gopus.NewMultistreamDecoderDefault(48000, 6)
if err != nil {
    log.Fatal(err)
}

pcmOut := make([]float32, 960*6)
_, err = dec.Decode(packet, pcmOut)
if err != nil {
    log.Fatal(err)
}

Supported channel configurations:

  • 1: mono (1 stream, 0 coupled)
  • 2: stereo (1 stream, 1 coupled)
  • 3: 3.0 (2 streams, 1 coupled)
  • 4: quad (2 streams, 2 coupled)
  • 5: 5.0 (3 streams, 2 coupled)
  • 6: 5.1 surround (4 streams, 2 coupled)
  • 7: 6.1 surround (5 streams, 2 coupled)
  • 8: 7.1 surround (5 streams, 3 coupled)

For custom channel mappings, use NewMultistreamEncoder and NewMultistreamDecoder with explicit stream and mapping parameters.

Example (RoundTrip)
package main

import (
	"fmt"
	"math"

	"github.com/thesyncim/gopus"
)

func main() {
	// Complete encode-decode round trip
	enc, _ := gopus.NewEncoder(48000, 1, gopus.ApplicationVoIP)
	cfg := gopus.DefaultDecoderConfig(48000, 1)
	dec, _ := gopus.NewDecoder(cfg)
	pcmOut := make([]float32, cfg.MaxPacketSamples*cfg.Channels)

	// 20ms of mono audio at 48kHz
	input := make([]float32, 960)
	for i := range input {
		input[i] = float32(math.Sin(float64(i) * 0.02))
	}

	// Encode
	packet, _ := enc.EncodeFloat32(input)

	// Decode
	n, _ := dec.Decode(packet, pcmOut)

	fmt.Printf("Round trip: %d samples -> %d bytes -> %d samples\n",
		len(input), len(packet), n)
}

Index

Examples

Constants

View Source
const (
	// SignalAuto lets the encoder detect the signal type automatically.
	SignalAuto = types.SignalAuto
	// SignalVoice hints that the input is speech, biasing toward SILK mode.
	SignalVoice = types.SignalVoice
	// SignalMusic hints that the input is music, biasing toward CELT mode.
	SignalMusic = types.SignalMusic
)
View Source
const (
	// BitrateModeVBR enables unconstrained variable bitrate mode.
	BitrateModeVBR = encoder.ModeVBR
	// BitrateModeCVBR enables constrained variable bitrate mode.
	BitrateModeCVBR = encoder.ModeCVBR
	// BitrateModeCBR enables constant bitrate mode.
	BitrateModeCBR = encoder.ModeCBR
)
View Source
const (
	ModeSILK   = types.ModeSILK   // SILK-only mode (configs 0-11)
	ModeHybrid = types.ModeHybrid // Hybrid SILK+CELT (configs 12-15)
	ModeCELT   = types.ModeCELT   // CELT-only mode (configs 16-31)
)

Re-export mode constants for convenience.

View Source
const (
	BandwidthNarrowband    = types.BandwidthNarrowband    // 4kHz audio, 8kHz sample rate
	BandwidthMediumband    = types.BandwidthMediumband    // 6kHz audio, 12kHz sample rate
	BandwidthWideband      = types.BandwidthWideband      // 8kHz audio, 16kHz sample rate
	BandwidthSuperwideband = types.BandwidthSuperwideband // 12kHz audio, 24kHz sample rate
	BandwidthFullband      = types.BandwidthFullband      // 20kHz audio, 48kHz sample rate
)

Re-export bandwidth constants for convenience.

Variables

View Source
var (
	// ErrInvalidSampleRate indicates an unsupported sample rate.
	// Valid sample rates are: 8000, 12000, 16000, 24000, 48000.
	ErrInvalidSampleRate = errors.New("gopus: invalid sample rate (must be 8000, 12000, 16000, 24000, or 48000)")

	// ErrInvalidChannels indicates an unsupported channel count.
	// Valid channel counts are 1 (mono) or 2 (stereo).
	ErrInvalidChannels = errors.New("gopus: invalid channels (must be 1 or 2)")

	// ErrInvalidMaxPacketSamples indicates an invalid max packet sample cap.
	ErrInvalidMaxPacketSamples = errors.New("gopus: invalid max packet samples (must be > 0)")

	// ErrInvalidMaxPacketBytes indicates an invalid max packet size cap.
	ErrInvalidMaxPacketBytes = errors.New("gopus: invalid max packet bytes (must be > 0)")

	// ErrPacketTooLarge indicates the packet exceeds configured limits.
	ErrPacketTooLarge = errors.New("gopus: packet exceeds configured limits")

	// ErrBufferTooSmall indicates the output buffer is too small for the decoded frame.
	// The buffer must be at least frameSize * channels samples.
	ErrBufferTooSmall = errors.New("gopus: output buffer too small")

	// ErrInvalidFrameSize indicates the input frame size doesn't match expected.
	// The PCM input length must be frameSize * channels.
	ErrInvalidFrameSize = errors.New("gopus: invalid frame size")

	// ErrInvalidBitrate indicates the bitrate is out of valid range.
	// Valid bitrates are 6000 to 510000 bits per second.
	ErrInvalidBitrate = errors.New("gopus: invalid bitrate (must be 6000-510000)")

	// ErrInvalidBitrateMode indicates an invalid bitrate mode.
	// Valid modes are BitrateModeVBR, BitrateModeCVBR, and BitrateModeCBR.
	ErrInvalidBitrateMode = errors.New("gopus: invalid bitrate mode")

	// ErrInvalidComplexity indicates the complexity is out of valid range.
	// Valid complexity values are 0 to 10.
	ErrInvalidComplexity = errors.New("gopus: invalid complexity (must be 0-10)")

	// ErrInvalidApplication indicates an invalid application hint.
	// Valid values are ApplicationVoIP, ApplicationAudio, or ApplicationLowDelay.
	ErrInvalidApplication = errors.New("gopus: invalid application")

	// ErrInvalidPacketLoss indicates an invalid packet loss percentage.
	// Valid range is 0 to 100.
	ErrInvalidPacketLoss = errors.New("gopus: invalid packet loss percentage (must be 0-100)")

	// ErrInvalidStreams indicates an invalid stream count for multistream encoding/decoding.
	// Valid stream counts are 1 to 255.
	ErrInvalidStreams = errors.New("gopus: invalid stream count (must be 1-255)")

	// ErrInvalidCoupledStreams indicates an invalid coupled streams count.
	// Coupled streams must be between 0 and total streams.
	ErrInvalidCoupledStreams = errors.New("gopus: invalid coupled streams (must be 0 to streams)")

	// ErrInvalidMapping indicates an invalid channel mapping table.
	// The mapping table length must equal the channel count.
	ErrInvalidMapping = errors.New("gopus: invalid mapping table")

	// ErrInvalidBandwidth indicates an invalid bandwidth for the current mode.
	// For SILK-only mode, only NB, MB, and WB are valid (not SWB or FB).
	ErrInvalidBandwidth = errors.New("gopus: invalid bandwidth for mode")

	// ErrInvalidSignal indicates an invalid signal type hint.
	// Valid values are SignalAuto, SignalVoice, or SignalMusic.
	ErrInvalidSignal = errors.New("gopus: invalid signal type (must be SignalAuto, SignalVoice, or SignalMusic)")

	// ErrInvalidLSBDepth indicates an invalid LSB depth.
	// Valid range is 8 to 24 bits.
	ErrInvalidLSBDepth = errors.New("gopus: invalid LSB depth (must be 8-24)")

	// ErrInvalidForceChannels indicates an invalid force channels value.
	// Valid values are -1 (auto), 1 (mono), or 2 (stereo).
	ErrInvalidForceChannels = errors.New("gopus: invalid force channels (must be -1, 1, or 2)")

	// ErrNoFECData indicates no FEC (LBRR) data is available for recovery.
	// This occurs when FEC decode is requested but the previous packet
	// was CELT-only mode or didn't contain LBRR data.
	ErrNoFECData = errors.New("gopus: no FEC data available for recovery")

	// ErrInvalidArgument indicates one or more function arguments are invalid.
	ErrInvalidArgument = errors.New("gopus: invalid argument")

	// ErrInvalidGain indicates an invalid decoder gain value.
	// Valid range is -32768 to 32767 (Q8 dB).
	ErrInvalidGain = errors.New("gopus: invalid gain (must be -32768 to 32767)")
)

Public error types for encoding and decoding operations.

View Source
var (
	ErrPacketTooShort    = errors.New("opus: packet too short")
	ErrInvalidFrameCount = errors.New("opus: invalid frame count (M > 48)")
	ErrInvalidPacket     = errors.New("opus: invalid packet structure")
)

Errors returned by packet parsing functions.

Functions

func ConfigFromParams

func ConfigFromParams(mode Mode, bandwidth Bandwidth, frameSize int) int

ConfigFromParams returns the config index for given mode, bandwidth, and frame size. Returns -1 if the combination is invalid.

func GenerateTOC

func GenerateTOC(config uint8, stereo bool, frameCode uint8) byte

GenerateTOC creates a TOC byte from encoding parameters. config: Configuration index 0-31 (from configTable) stereo: True for stereo, false for mono frameCode: Frame count code 0-3

0: 1 frame
1: 2 equal-sized frames
2: 2 different-sized frames
3: arbitrary number of frames

func MultistreamPacketPad

func MultistreamPacketPad(data []byte, length, newLen, numStreams int) error

MultistreamPacketPad pads the final stream packet inside a multistream packet.

func MultistreamPacketUnpad

func MultistreamPacketUnpad(data []byte, length, numStreams int) (int, error)

MultistreamPacketUnpad removes padding from all streams in a multistream packet. It returns the new packet length.

func PacketPad

func PacketPad(data []byte, length, newLen int) error

PacketPad pads a packet in-place to newLen bytes.

data must have capacity for at least newLen bytes. length is the current packet length in data.

func PacketUnpad

func PacketUnpad(data []byte, length int) (int, error)

PacketUnpad removes packet padding in-place and returns the new packet length.

func ValidConfig

func ValidConfig(config uint8) bool

ValidConfig returns true if the configuration index is valid.

Types

type Application

type Application int

Application hints the encoder for optimization.

const (
	// ApplicationVoIP optimizes for speech transmission with low latency.
	// Prefers SILK mode for speech frequencies.
	ApplicationVoIP Application = iota

	// ApplicationAudio optimizes for music and high-quality audio.
	// Prefers CELT/Hybrid mode for full-bandwidth audio.
	ApplicationAudio

	// ApplicationLowDelay minimizes algorithmic delay.
	// Uses CELT mode exclusively with small frame sizes.
	ApplicationLowDelay
)

type Bandwidth

type Bandwidth = types.Bandwidth

Bandwidth is an alias for types.Bandwidth representing the audio bandwidth.

type BitrateMode

type BitrateMode = encoder.BitrateMode

BitrateMode controls how the encoder sizes packets.

type Decoder

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

Decoder decodes Opus packets into PCM audio samples.

A Decoder instance maintains internal state and is NOT safe for concurrent use. Each goroutine should create its own Decoder instance.

The decoder supports all Opus modes (SILK, Hybrid, CELT) and automatically detects the mode from the TOC byte in each packet.

func NewDecoder

func NewDecoder(cfg DecoderConfig) (*Decoder, error)

NewDecoder creates a new Opus decoder.

Example
package main

import (
	"fmt"
	"log"

	"github.com/thesyncim/gopus"
)

func main() {
	// Create a decoder for 48kHz stereo audio
	dec, err := gopus.NewDecoder(gopus.DefaultDecoderConfig(48000, 2))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Decoder: %dHz, %d channels\n", dec.SampleRate(), dec.Channels())
}
Output:

Decoder: 48000Hz, 2 channels

func (*Decoder) Bandwidth

func (d *Decoder) Bandwidth() Bandwidth

Bandwidth returns the bandwidth of the last successfully decoded packet.

func (*Decoder) Channels

func (d *Decoder) Channels() int

Channels returns the number of audio channels (1 or 2).

func (*Decoder) DebugPrevMode

func (d *Decoder) DebugPrevMode() Mode

DebugPrevMode returns the previous decode mode (SILK/Hybrid/CELT). This is intended for testing/debugging parity with libopus.

func (*Decoder) DebugPrevPacketStereo

func (d *Decoder) DebugPrevPacketStereo() bool

DebugPrevPacketStereo returns the last packet's stereo flag. This is intended for testing/debugging parity with libopus.

func (*Decoder) DebugPrevRedundancy

func (d *Decoder) DebugPrevRedundancy() bool

DebugPrevRedundancy reports whether the previous frame used CELT redundancy. This is intended for testing/debugging parity with libopus.

func (*Decoder) Decode

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

Decode decodes an Opus packet into float32 PCM samples.

data: Opus packet data, or nil for Packet Loss Concealment (PLC). pcm: Output buffer for decoded samples. Must be large enough to hold frameSize * frameCount * channels samples, where frameSize and frameCount are determined from the packet TOC and frame code.

Returns the number of samples per channel decoded, or an error.

When data is nil, the decoder performs packet loss concealment using the last successfully decoded frame parameters.

Buffer sizing: For 60ms frames at 48kHz stereo, pcm must have at least 2880 * 2 = 5760 elements. For multi-frame packets (code 1/2/3), the buffer must be large enough for all frames combined.

Multi-frame packets (RFC 6716 Section 3.2):

  • Code 0: 1 frame (most common)
  • Code 1: 2 equal-sized frames
  • Code 2: 2 different-sized frames
  • Code 3: Arbitrary number of frames (1-48)
Example
package main

import (
	"fmt"
	"log"
	"math"

	"github.com/thesyncim/gopus"
)

func main() {
	// Create encoder and decoder
	enc, _ := gopus.NewEncoder(48000, 2, gopus.ApplicationAudio)
	cfg := gopus.DefaultDecoderConfig(48000, 2)
	dec, _ := gopus.NewDecoder(cfg)
	pcmOut := make([]float32, cfg.MaxPacketSamples*cfg.Channels)

	// Generate and encode a test signal
	pcm := make([]float32, 960*2)
	for i := range pcm {
		pcm[i] = float32(math.Sin(float64(i) * 0.01))
	}

	packet, _ := enc.EncodeFloat32(pcm)

	// Decode the packet
	n, err := dec.Decode(packet, pcmOut)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Decoded %d bytes to %d samples\n", len(packet), n)
}
Example (PacketLoss)
package main

import (
	"fmt"
	"log"

	"github.com/thesyncim/gopus"
)

func main() {
	cfg := gopus.DefaultDecoderConfig(48000, 2)
	dec, _ := gopus.NewDecoder(cfg)
	pcmOut := make([]float32, cfg.MaxPacketSamples*cfg.Channels)

	// First, decode a real packet to initialize state
	enc, _ := gopus.NewEncoder(48000, 2, gopus.ApplicationAudio)
	pcm := make([]float32, 960*2)
	packet, _ := enc.EncodeFloat32(pcm)
	_, _ = dec.Decode(packet, pcmOut)

	// Simulate packet loss by passing nil
	// Decoder uses PLC to generate concealment audio
	n, err := dec.Decode(nil, pcmOut)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("PLC generated %d samples\n", n)
}

func (*Decoder) DecodeInt16

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

DecodeInt16 decodes an Opus packet into int16 PCM samples.

data: Opus packet data, or nil for PLC. pcm: Output buffer for decoded samples. Must be large enough to hold all frames in multi-frame packets (frameSize * frameCount * channels samples).

Returns the number of samples per channel decoded, or an error.

The samples are converted from float32 with proper clamping to [-32768, 32767].

func (*Decoder) DecodeWithFEC

func (d *Decoder) DecodeWithFEC(data []byte, pcm []float32, fec bool) (int, error)

DecodeWithFEC decodes an Opus packet, optionally recovering a lost frame using FEC.

If fec is true and the previous packet contained LBRR redundancy data, the decoder will use that data to recover the lost frame instead of using PLC extrapolation. This produces better audio quality during packet loss.

If fec is true but no LBRR data is available, the decoder falls back to standard PLC. If fec is false, this behaves identically to Decode().

Parameters:

  • data: Opus packet data, or nil to trigger FEC/PLC for a lost packet
  • pcm: Output buffer for decoded samples
  • fec: If true and data is nil, attempt FEC recovery before falling back to PLC

Returns the number of samples per channel decoded, or an error.

Usage pattern for handling packet loss:

// When packet N is lost:
// 1. First decode packet N+1's FEC data to recover N
samples, _ := decoder.DecodeWithFEC(packetN1, pcmN, true)
// 2. Then decode packet N+1 normally
samples, _ := decoder.Decode(packetN1, pcmN1)

Note: FEC recovery uses LBRR (Low Bitrate Redundancy) data that is encoded at the encoder side when the encoder has FEC enabled. LBRR data is only available in SILK and Hybrid modes, not in CELT-only mode.

func (*Decoder) FinalRange

func (d *Decoder) FinalRange() uint32

FinalRange returns the final range coder state after decoding. This matches libopus OPUS_GET_FINAL_RANGE and is used for bitstream verification. Must be called after Decode() to get a meaningful value.

Per libopus, the final range is XORed with any redundancy frame's range. If the packet length was <= 1, FinalRange returns 0.

func (*Decoder) Gain

func (d *Decoder) Gain() int

Gain returns the current decoder output gain in Q8 dB units.

func (*Decoder) GetCELTDecoder

func (d *Decoder) GetCELTDecoder() *celt.Decoder

GetCELTDecoder returns the internal CELT decoder for debugging purposes. This allows access to internal state like preemph_state and overlap_buffer.

func (*Decoder) GetSILKDecoder

func (d *Decoder) GetSILKDecoder() *silk.Decoder

GetSILKDecoder returns the internal SILK decoder for debugging purposes. This allows access to internal state like resampler state and sMid buffer.

func (*Decoder) InDTX

func (d *Decoder) InDTX() bool

InDTX reports whether the most recently decoded packet was a DTX packet.

func (*Decoder) LastPacketDuration

func (d *Decoder) LastPacketDuration() int

LastPacketDuration returns the duration (in samples per channel at 48kHz scale) of the last decoded packet.

func (*Decoder) Pitch

func (d *Decoder) Pitch() int

Pitch returns the most recent CELT postfilter pitch period.

This mirrors OPUS_GET_PITCH behavior for decoded CELT/hybrid content. Returns 0 when no pitch information is available.

func (*Decoder) Reset

func (d *Decoder) Reset()

Reset clears the decoder state for a new stream. Call this when starting to decode a new audio stream.

func (*Decoder) SampleRate

func (d *Decoder) SampleRate() int

SampleRate returns the sample rate in Hz.

func (*Decoder) SetGain

func (d *Decoder) SetGain(gainQ8 int) error

SetGain sets output gain in Q8 dB units (libopus OPUS_SET_GAIN semantics).

Valid range is [-32768, 32767], where 256 = +1 dB and -256 = -1 dB.

type DecoderConfig

type DecoderConfig struct {
	// SampleRate must be one of: 8000, 12000, 16000, 24000, 48000.
	SampleRate int
	// Channels must be 1 (mono) or 2 (stereo).
	Channels int
	// MaxPacketSamples caps the maximum decoded samples per channel per packet.
	// If zero, defaultMaxPacketSamples is used.
	MaxPacketSamples int
	// MaxPacketBytes caps the maximum Opus packet size in bytes.
	// If zero, defaultMaxPacketBytes is used.
	MaxPacketBytes int
}

DecoderConfig configures a Decoder instance.

func DefaultDecoderConfig

func DefaultDecoderConfig(sampleRate, channels int) DecoderConfig

DefaultDecoderConfig returns a config with default caps for the given stream format.

type Encoder

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

Encoder encodes PCM audio samples into Opus packets.

An Encoder instance maintains internal state and is NOT safe for concurrent use. Each goroutine should create its own Encoder instance.

The encoder supports three modes:

  • SILK: optimized for speech at lower bitrates
  • CELT: optimized for music and high-quality audio
  • Hybrid: combines SILK and CELT for wideband speech

The mode is automatically selected based on the Application hint and bandwidth settings.

Zero-allocation design: All scratch buffers are pre-allocated at construction time. The Encode and EncodeInt16 methods perform zero heap allocations in the hot path when called with properly sized caller-provided buffers.

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. channels must be 1 (mono) or 2 (stereo). application hints the encoder for optimization.

Returns an error if the parameters are invalid.

Example
package main

import (
	"fmt"
	"log"

	"github.com/thesyncim/gopus"
)

func main() {
	// Create an encoder for 48kHz stereo audio
	enc, err := gopus.NewEncoder(48000, 2, gopus.ApplicationAudio)
	if err != nil {
		log.Fatal(err)
	}

	// Configure encoder settings
	enc.SetBitrate(64000) // 64 kbps
	enc.SetComplexity(10) // Maximum quality

	fmt.Printf("Encoder: %dHz, %d channels\n", enc.SampleRate(), enc.Channels())
}
Output:

Encoder: 48000Hz, 2 channels

func (*Encoder) Application

func (e *Encoder) Application() Application

Application returns the current encoder application hint.

func (*Encoder) Bandwidth

func (e *Encoder) Bandwidth() Bandwidth

Bandwidth returns the currently configured target bandwidth.

func (*Encoder) Bitrate

func (e *Encoder) Bitrate() int

Bitrate returns the current target bitrate in bits per second.

func (*Encoder) BitrateMode

func (e *Encoder) BitrateMode() BitrateMode

BitrateMode returns the active encoder bitrate control mode.

func (*Encoder) Channels

func (e *Encoder) Channels() int

Channels returns the number of audio channels (1 or 2).

func (*Encoder) Complexity

func (e *Encoder) Complexity() int

Complexity returns the current complexity setting.

func (*Encoder) DTXEnabled

func (e *Encoder) DTXEnabled() bool

DTXEnabled returns whether DTX is enabled.

func (*Encoder) Encode

func (e *Encoder) Encode(pcm []float32, data []byte) (int, error)

Encode encodes float32 PCM samples into an Opus packet.

pcm: Input samples (interleaved if stereo). Length must be frameSize * channels. data: Output buffer for the encoded packet. Recommended size is 4000 bytes.

Returns the number of bytes written to data, or an error. Returns 0 bytes written if DTX suppresses the frame (silence detected).

Buffer sizing: 4000 bytes is sufficient for any Opus packet.

func (*Encoder) EncodeFloat32

func (e *Encoder) EncodeFloat32(pcm []float32) ([]byte, error)

EncodeFloat32 encodes float32 PCM samples and returns a new byte slice.

This is a convenience method that allocates the output buffer. For performance-critical code, use Encode with a pre-allocated buffer.

pcm: Input samples (interleaved if stereo).

Returns the encoded packet or an error.

Example
package main

import (
	"fmt"
	"log"

	"github.com/thesyncim/gopus"
)

func main() {
	enc, err := gopus.NewEncoder(48000, 2, gopus.ApplicationAudio)
	if err != nil {
		log.Fatal(err)
	}

	// Generate 20ms of stereo silence (960 samples per channel)
	pcm := make([]float32, 960*2)

	// Encode the frame
	packet, err := enc.EncodeFloat32(pcm)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Encoded %d samples to %d bytes\n", len(pcm)/2, len(packet))
	// Output will vary based on encoder state
}

func (*Encoder) EncodeInt16

func (e *Encoder) EncodeInt16(pcm []int16, data []byte) (int, error)

EncodeInt16 encodes int16 PCM samples into an Opus packet.

pcm: Input samples (interleaved if stereo). Length must be frameSize * channels. data: Output buffer for the encoded packet.

Returns the number of bytes written to data, or an error.

The samples are converted from int16 by dividing by 32768.

func (*Encoder) EncodeInt16Slice

func (e *Encoder) EncodeInt16Slice(pcm []int16) ([]byte, error)

EncodeInt16Slice encodes int16 PCM samples and returns a new byte slice.

This is a convenience method that allocates the output buffer. For performance-critical code, use EncodeInt16 with a pre-allocated buffer.

pcm: Input samples (interleaved if stereo).

Returns the encoded packet or an error.

func (*Encoder) FECEnabled

func (e *Encoder) FECEnabled() bool

FECEnabled returns whether FEC is enabled.

func (*Encoder) FinalRange

func (e *Encoder) FinalRange() uint32

FinalRange returns the final range coder state after encoding. This matches libopus OPUS_GET_FINAL_RANGE and is used for bitstream verification. Must be called after Encode() to get a meaningful value.

func (*Encoder) ForceChannels

func (e *Encoder) ForceChannels() int

ForceChannels returns the forced channel count (-1 = auto).

func (*Encoder) FrameSize

func (e *Encoder) FrameSize() int

FrameSize returns the current frame size in samples at 48kHz.

func (*Encoder) LSBDepth

func (e *Encoder) LSBDepth() int

LSBDepth returns the current input bit depth setting.

func (*Encoder) Lookahead

func (e *Encoder) Lookahead() int

Lookahead returns the encoder's algorithmic delay in samples.

Matches libopus OPUS_GET_LOOKAHEAD behavior:

  • Base lookahead is Fs/400 (2.5ms)
  • Delay compensation Fs/250 is included for VoIP/Audio
  • Delay compensation is omitted for LowDelay

func (*Encoder) MaxBandwidth

func (e *Encoder) MaxBandwidth() Bandwidth

MaxBandwidth returns the current maximum bandwidth limit.

func (*Encoder) PacketLoss

func (e *Encoder) PacketLoss() int

PacketLoss returns the configured expected packet loss percentage.

func (*Encoder) PhaseInversionDisabled

func (e *Encoder) PhaseInversionDisabled() bool

PhaseInversionDisabled returns whether stereo phase inversion is disabled.

func (*Encoder) PredictionDisabled

func (e *Encoder) PredictionDisabled() bool

PredictionDisabled returns whether inter-frame prediction is disabled.

func (*Encoder) Reset

func (e *Encoder) Reset()

Reset clears the encoder state for a new stream. Call this when starting to encode a new audio stream.

func (*Encoder) SampleRate

func (e *Encoder) SampleRate() int

SampleRate returns the sample rate in Hz.

func (*Encoder) SetApplication

func (e *Encoder) SetApplication(application Application) error

SetApplication updates the encoder application hint.

Valid values are ApplicationVoIP, ApplicationAudio, and ApplicationLowDelay.

func (*Encoder) SetBandwidth

func (e *Encoder) SetBandwidth(bandwidth Bandwidth) error

SetBandwidth sets the target audio bandwidth.

func (*Encoder) SetBitrate

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

SetBitrate sets the target bitrate in bits per second.

Valid range is 6000 to 510000 (6 kbps to 510 kbps). Returns ErrInvalidBitrate if out of range.

Example
package main

import (
	"fmt"
	"log"

	"github.com/thesyncim/gopus"
)

func main() {
	enc, _ := gopus.NewEncoder(48000, 2, gopus.ApplicationAudio)

	// Set bitrate to 128 kbps
	err := enc.SetBitrate(128000)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Bitrate set to %d bps\n", enc.Bitrate())
}
Output:

Bitrate set to 128000 bps

func (*Encoder) SetBitrateMode

func (e *Encoder) SetBitrateMode(mode BitrateMode) error

SetBitrateMode sets the encoder bitrate control mode.

func (*Encoder) SetComplexity

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

SetComplexity sets the encoder's computational complexity.

complexity must be 0-10, where:

  • 0-1: Minimal processing, fastest encoding
  • 2-4: Basic analysis, good for real-time with limited CPU
  • 5-7: Moderate analysis, balanced quality/speed
  • 8-10: Thorough analysis, highest quality

Returns ErrInvalidComplexity if out of range.

Example
package main

import (
	"fmt"
	"log"

	"github.com/thesyncim/gopus"
)

func main() {
	enc, _ := gopus.NewEncoder(48000, 2, gopus.ApplicationAudio)

	// Set complexity to maximum quality
	err := enc.SetComplexity(10)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Complexity: %d\n", enc.Complexity())
}
Output:

Complexity: 10

func (*Encoder) SetDTX

func (e *Encoder) SetDTX(enabled bool)

SetDTX enables or disables Discontinuous Transmission.

When enabled, the encoder reduces bitrate during silence by:

  • Suppressing packets entirely during silence
  • Sending periodic comfort noise frames

DTX is useful for VoIP applications to reduce bandwidth.

Example
package main

import (
	"fmt"

	"github.com/thesyncim/gopus"
)

func main() {
	enc, _ := gopus.NewEncoder(48000, 1, gopus.ApplicationVoIP)

	// Enable DTX for bandwidth savings during silence
	enc.SetDTX(true)

	fmt.Printf("DTX enabled: %v\n", enc.DTXEnabled())
}
Output:

DTX enabled: true

func (*Encoder) SetFEC

func (e *Encoder) SetFEC(enabled bool)

SetFEC enables or disables in-band Forward Error Correction.

When enabled, the encoder includes redundant information for loss recovery. FEC is most effective when the receiver can request retransmission of lost packets.

Example
package main

import (
	"fmt"

	"github.com/thesyncim/gopus"
)

func main() {
	enc, _ := gopus.NewEncoder(48000, 2, gopus.ApplicationVoIP)

	// Enable FEC for packet loss recovery
	enc.SetFEC(true)

	fmt.Printf("FEC enabled: %v\n", enc.FECEnabled())
}
Output:

FEC enabled: true

func (*Encoder) SetForceChannels

func (e *Encoder) SetForceChannels(channels int) error

SetForceChannels forces the encoder to use a specific channel count.

channels must be one of:

  • -1: automatic (use input channels)
  • 1: force mono output
  • 2: force stereo output

Note: Forcing stereo on mono input will duplicate the channel. Forcing mono on stereo input will downmix to mono.

Returns ErrInvalidForceChannels if the value is not valid.

func (*Encoder) SetFrameSize

func (e *Encoder) SetFrameSize(samples int) error

SetFrameSize sets the frame size in samples at 48kHz.

Valid sizes depend on the encoding mode:

  • SILK: 480, 960, 1920, 2880 (10, 20, 40, 60 ms)
  • CELT: 120, 240, 480, 960 (2.5, 5, 10, 20 ms)
  • Hybrid: 480, 960 (10, 20 ms)

Default is 960 (20ms).

func (*Encoder) SetLSBDepth

func (e *Encoder) SetLSBDepth(depth int) error

SetLSBDepth sets the bit depth of the input signal.

depth must be 8-24. This affects DTX silence detection: lower bit depths have a higher noise floor, so the encoder adjusts its silence threshold accordingly.

Default is 24 (full precision). Returns ErrInvalidLSBDepth if out of range.

func (*Encoder) SetMaxBandwidth

func (e *Encoder) SetMaxBandwidth(bandwidth Bandwidth) error

SetMaxBandwidth sets the maximum audio bandwidth.

The encoder will not use a bandwidth higher than this limit. This is useful for limiting bandwidth without changing the sample rate.

Valid values are:

  • BandwidthNarrowband (4kHz)
  • BandwidthMediumband (6kHz)
  • BandwidthWideband (8kHz)
  • BandwidthSuperwideband (12kHz)
  • BandwidthFullband (20kHz)

func (*Encoder) SetPacketLoss

func (e *Encoder) SetPacketLoss(lossPercent int) error

SetPacketLoss sets the expected packet loss percentage.

lossPercent must be in the range [0, 100].

func (*Encoder) SetPhaseInversionDisabled

func (e *Encoder) SetPhaseInversionDisabled(disabled bool)

SetPhaseInversionDisabled disables stereo phase inversion.

Phase inversion is a technique used to improve stereo decorrelation. Some audio processing pipelines may have issues with phase-inverted audio. Disabling it (true) ensures no phase inversion is applied.

Default is false (phase inversion enabled).

func (*Encoder) SetPredictionDisabled

func (e *Encoder) SetPredictionDisabled(disabled bool)

SetPredictionDisabled disables inter-frame prediction.

When disabled (true), each frame can be decoded independently, which improves error resilience at the cost of compression efficiency. This is useful for applications with high packet loss.

Default is false (prediction enabled).

func (*Encoder) SetSignal

func (e *Encoder) SetSignal(signal Signal) error

SetSignal sets the signal type hint for mode selection.

signal must be one of:

  • SignalAuto: automatically detect signal type
  • SignalVoice: optimize for speech (biases toward SILK)
  • SignalMusic: optimize for music (biases toward CELT)

Returns ErrInvalidSignal if the value is not valid.

func (*Encoder) SetVBR

func (e *Encoder) SetVBR(enabled bool)

SetVBR enables or disables VBR mode.

Disabling VBR switches to CBR. Enabling VBR restores VBR while preserving the current VBR constraint state.

func (*Encoder) SetVBRConstraint

func (e *Encoder) SetVBRConstraint(constrained bool)

SetVBRConstraint enables or disables VBR constraint.

This setting is remembered even while VBR is disabled.

func (*Encoder) Signal

func (e *Encoder) Signal() Signal

Signal returns the current signal type hint.

func (*Encoder) VBR

func (e *Encoder) VBR() bool

VBR returns whether VBR mode is enabled.

func (*Encoder) VBRConstraint

func (e *Encoder) VBRConstraint() bool

VBRConstraint returns whether VBR constraint is enabled.

type Mode

type Mode = types.Mode

Mode is an alias for types.Mode representing the Opus coding mode.

type MultistreamDecoder

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

MultistreamDecoder decodes Opus multistream packets into multi-channel PCM audio.

A MultistreamDecoder instance maintains internal state and is NOT safe for concurrent use. Each goroutine should create its own MultistreamDecoder instance.

Multistream decoding is used for surround sound configurations (5.1, 7.1, etc.) where multiple coupled (stereo) and uncoupled (mono) streams are combined.

Reference: RFC 6716 Appendix B, RFC 7845 Section 5.1.1

func NewMultistreamDecoder

func NewMultistreamDecoder(sampleRate, channels, streams, coupledStreams int, mapping []byte) (*MultistreamDecoder, error)

NewMultistreamDecoder creates a new multistream decoder with explicit configuration.

Parameters:

  • sampleRate: output sample rate (8000, 12000, 16000, 24000, or 48000 Hz)
  • channels: total output channels (1-255)
  • streams: total elementary streams (N, 1-255)
  • coupledStreams: number of coupled stereo streams (M, 0 to streams)
  • mapping: channel mapping table (length must equal channels)

The mapping table determines how decoded audio is routed to output channels:

  • Values 0 to 2*M-1: from coupled streams (even=left, odd=right of stereo pair)
  • Values 2*M to N+M-1: from uncoupled (mono) streams
  • Value 255: silent channel (output zeros)

func NewMultistreamDecoderDefault

func NewMultistreamDecoderDefault(sampleRate, channels int) (*MultistreamDecoder, error)

NewMultistreamDecoderDefault creates a multistream decoder with default Vorbis-style mapping for standard channel configurations (1-8 channels).

This is a convenience function that calls the internal DefaultMapping() to get the appropriate streams, coupledStreams, and mapping for the given channel count.

Supported channel counts:

  • 1: mono (1 stream, 0 coupled)
  • 2: stereo (1 stream, 1 coupled)
  • 3: 3.0 (2 streams, 1 coupled)
  • 4: quad (2 streams, 2 coupled)
  • 5: 5.0 (3 streams, 2 coupled)
  • 6: 5.1 surround (4 streams, 2 coupled)
  • 7: 6.1 surround (5 streams, 2 coupled)
  • 8: 7.1 surround (5 streams, 3 coupled)

func (*MultistreamDecoder) Channels

func (d *MultistreamDecoder) Channels() int

Channels returns the number of audio channels.

func (*MultistreamDecoder) CoupledStreams

func (d *MultistreamDecoder) CoupledStreams() int

CoupledStreams returns the number of coupled (stereo) streams.

func (*MultistreamDecoder) Decode

func (d *MultistreamDecoder) Decode(data []byte, pcm []float32) (int, error)

Decode decodes an Opus multistream packet into float32 PCM samples.

data: Opus multistream packet data, or nil for Packet Loss Concealment (PLC). pcm: Output buffer for decoded samples. Must be large enough to hold frameSize * channels samples.

Returns the number of samples per channel decoded, or an error.

When data is nil, the decoder performs packet loss concealment using the last successfully decoded frame parameters.

func (*MultistreamDecoder) DecodeInt16

func (d *MultistreamDecoder) DecodeInt16(data []byte, pcm []int16) (int, error)

DecodeInt16 decodes an Opus multistream packet into int16 PCM samples.

data: Opus multistream packet data, or nil for PLC. pcm: Output buffer for decoded samples.

Returns the number of samples per channel decoded, or an error.

func (*MultistreamDecoder) Reset

func (d *MultistreamDecoder) Reset()

Reset clears the decoder state for a new stream. Call this when starting to decode a new audio stream.

func (*MultistreamDecoder) SampleRate

func (d *MultistreamDecoder) SampleRate() int

SampleRate returns the sample rate in Hz.

func (*MultistreamDecoder) Streams

func (d *MultistreamDecoder) Streams() int

Streams returns the total number of elementary streams.

type MultistreamEncoder

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

MultistreamEncoder encodes multi-channel PCM audio into Opus multistream packets.

A MultistreamEncoder instance maintains internal state and is NOT safe for concurrent use. Each goroutine should create its own MultistreamEncoder instance.

Multistream encoding is used for surround sound configurations (5.1, 7.1, etc.) where multiple coupled (stereo) and uncoupled (mono) streams are combined.

Reference: RFC 6716 Appendix B, RFC 7845 Section 5.1.1

func NewMultistreamEncoder

func NewMultistreamEncoder(sampleRate, channels, streams, coupledStreams int, mapping []byte, application Application) (*MultistreamEncoder, error)

NewMultistreamEncoder creates a new multistream encoder with explicit configuration.

Parameters:

  • sampleRate: input sample rate (8000, 12000, 16000, 24000, or 48000 Hz)
  • channels: total input channels (1-255)
  • streams: total elementary streams (N, 1-255)
  • coupledStreams: number of coupled stereo streams (M, 0 to streams)
  • mapping: channel mapping table (length must equal channels)
  • application: application hint for encoder optimization

The mapping table determines how input audio is routed to stream encoders:

  • Values 0 to 2*M-1: to coupled streams (even=left, odd=right of stereo pair)
  • Values 2*M to N+M-1: to uncoupled (mono) streams
  • Value 255: silent channel (input ignored)

Example for 5.1 surround (6 channels, 4 streams, 2 coupled):

mapping = [0, 4, 1, 2, 3, 5]
  Input 0 (FL): mapping[0]=0 -> coupled stream 0, left
  Input 1 (C):  mapping[1]=4 -> uncoupled stream 2 (2*2+0)
  Input 2 (FR): mapping[2]=1 -> coupled stream 0, right
  Input 3 (RL): mapping[3]=2 -> coupled stream 1, left
  Input 4 (RR): mapping[4]=3 -> coupled stream 1, right
  Input 5 (LFE): mapping[5]=5 -> uncoupled stream 3 (2*2+1)

func NewMultistreamEncoderDefault

func NewMultistreamEncoderDefault(sampleRate, channels int, application Application) (*MultistreamEncoder, error)

NewMultistreamEncoderDefault creates a multistream encoder with default Vorbis-style mapping for standard channel configurations (1-8 channels).

This is a convenience function that calls the internal DefaultMapping() to get the appropriate streams, coupledStreams, and mapping for the given channel count.

Supported channel counts:

  • 1: mono (1 stream, 0 coupled)
  • 2: stereo (1 stream, 1 coupled)
  • 3: 3.0 (2 streams, 1 coupled)
  • 4: quad (2 streams, 2 coupled)
  • 5: 5.0 (3 streams, 2 coupled)
  • 6: 5.1 surround (4 streams, 2 coupled)
  • 7: 6.1 surround (5 streams, 2 coupled)
  • 8: 7.1 surround (5 streams, 3 coupled)

func (*MultistreamEncoder) Application

func (e *MultistreamEncoder) Application() Application

Application returns the current encoder application hint.

func (*MultistreamEncoder) Bandwidth

func (e *MultistreamEncoder) Bandwidth() Bandwidth

Bandwidth returns the currently configured target bandwidth.

func (*MultistreamEncoder) Bitrate

func (e *MultistreamEncoder) Bitrate() int

Bitrate returns the current total target bitrate in bits per second.

func (*MultistreamEncoder) BitrateMode

func (e *MultistreamEncoder) BitrateMode() BitrateMode

BitrateMode returns the active bitrate control mode.

func (*MultistreamEncoder) Channels

func (e *MultistreamEncoder) Channels() int

Channels returns the number of audio channels.

func (*MultistreamEncoder) Complexity

func (e *MultistreamEncoder) Complexity() int

Complexity returns the current complexity setting.

func (*MultistreamEncoder) CoupledStreams

func (e *MultistreamEncoder) CoupledStreams() int

CoupledStreams returns the number of coupled (stereo) streams.

func (*MultistreamEncoder) DTXEnabled

func (e *MultistreamEncoder) DTXEnabled() bool

DTXEnabled returns whether DTX is enabled.

func (*MultistreamEncoder) Encode

func (e *MultistreamEncoder) Encode(pcm []float32, data []byte) (int, error)

Encode encodes float32 PCM samples into an Opus multistream packet.

pcm: Input samples (interleaved). Length must be frameSize * channels. data: Output buffer for the encoded packet. Recommended size is 4000 bytes per stream.

Returns the number of bytes written to data, or an error. Returns 0 bytes written if DTX suppresses all frames (silence detected in all streams).

func (*MultistreamEncoder) EncodeFloat32

func (e *MultistreamEncoder) EncodeFloat32(pcm []float32) ([]byte, error)

EncodeFloat32 encodes float32 PCM samples and returns a new byte slice.

This is a convenience method that allocates the output buffer. For performance-critical code, use Encode with a pre-allocated buffer.

pcm: Input samples (interleaved).

Returns the encoded packet or an error.

func (*MultistreamEncoder) EncodeInt16

func (e *MultistreamEncoder) EncodeInt16(pcm []int16, data []byte) (int, error)

EncodeInt16 encodes int16 PCM samples into an Opus multistream packet.

pcm: Input samples (interleaved). Length must be frameSize * channels. data: Output buffer for the encoded packet.

Returns the number of bytes written to data, or an error.

func (*MultistreamEncoder) EncodeInt16Slice

func (e *MultistreamEncoder) EncodeInt16Slice(pcm []int16) ([]byte, error)

EncodeInt16Slice encodes int16 PCM samples and returns a new byte slice.

This is a convenience method that allocates the output buffer. For performance-critical code, use EncodeInt16 with a pre-allocated buffer.

pcm: Input samples (interleaved).

Returns the encoded packet or an error.

func (*MultistreamEncoder) FECEnabled

func (e *MultistreamEncoder) FECEnabled() bool

FECEnabled returns whether FEC is enabled.

func (*MultistreamEncoder) FinalRange

func (e *MultistreamEncoder) FinalRange() uint32

FinalRange returns the final range coder state.

func (*MultistreamEncoder) ForceChannels

func (e *MultistreamEncoder) ForceChannels() int

ForceChannels returns the forced channel count (-1 = auto).

func (*MultistreamEncoder) GetFinalRange

func (e *MultistreamEncoder) GetFinalRange() uint32

GetFinalRange returns the final range coder state for all streams. The values from all streams are XOR combined to produce a single verification value. This matches libopus OPUS_GET_FINAL_RANGE for multistream encoders. Must be called after Encode() to get a meaningful value.

func (*MultistreamEncoder) LSBDepth

func (e *MultistreamEncoder) LSBDepth() int

LSBDepth returns the current LSB depth setting.

func (*MultistreamEncoder) Lookahead

func (e *MultistreamEncoder) Lookahead() int

Lookahead returns the encoder's algorithmic delay in samples.

Matches libopus OPUS_GET_LOOKAHEAD behavior:

  • Base lookahead is Fs/400 (2.5ms)
  • Delay compensation Fs/250 is included for VoIP/Audio
  • Delay compensation is omitted for LowDelay

func (*MultistreamEncoder) MaxBandwidth

func (e *MultistreamEncoder) MaxBandwidth() Bandwidth

MaxBandwidth returns the maximum bandwidth limit.

func (*MultistreamEncoder) PacketLoss

func (e *MultistreamEncoder) PacketLoss() int

PacketLoss returns expected packet loss percentage.

func (*MultistreamEncoder) PhaseInversionDisabled

func (e *MultistreamEncoder) PhaseInversionDisabled() bool

PhaseInversionDisabled reports whether stereo phase inversion is disabled.

func (*MultistreamEncoder) PredictionDisabled

func (e *MultistreamEncoder) PredictionDisabled() bool

PredictionDisabled reports whether inter-frame prediction is disabled.

func (*MultistreamEncoder) Reset

func (e *MultistreamEncoder) Reset()

Reset clears the encoder state for a new stream. Call this when starting to encode a new audio stream.

func (*MultistreamEncoder) SampleRate

func (e *MultistreamEncoder) SampleRate() int

SampleRate returns the sample rate in Hz.

func (*MultistreamEncoder) SetApplication

func (e *MultistreamEncoder) SetApplication(application Application) error

SetApplication updates the encoder application hint.

Valid values are ApplicationVoIP, ApplicationAudio, and ApplicationLowDelay.

func (*MultistreamEncoder) SetBandwidth

func (e *MultistreamEncoder) SetBandwidth(bw Bandwidth) error

SetBandwidth sets the target audio bandwidth.

func (*MultistreamEncoder) SetBitrate

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

SetBitrate sets the total target bitrate in bits per second.

The bitrate is distributed across streams with coupled streams getting proportionally more bits than mono streams.

Valid range is 6000 to 510000 per channel.

func (*MultistreamEncoder) SetBitrateMode

func (e *MultistreamEncoder) SetBitrateMode(mode BitrateMode) error

SetBitrateMode sets the multistream encoder bitrate control mode.

func (*MultistreamEncoder) SetComplexity

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

SetComplexity sets the encoder's computational complexity for all streams.

complexity must be 0-10, where:

  • 0-1: Minimal processing, fastest encoding
  • 2-4: Basic analysis, good for real-time with limited CPU
  • 5-7: Moderate analysis, balanced quality/speed
  • 8-10: Thorough analysis, highest quality

Returns ErrInvalidComplexity if out of range.

func (*MultistreamEncoder) SetDTX

func (e *MultistreamEncoder) SetDTX(enabled bool)

SetDTX enables or disables Discontinuous Transmission for all streams.

When enabled, the encoders reduce bitrate during silence by:

  • Suppressing packets entirely during silence
  • Sending periodic comfort noise frames

func (*MultistreamEncoder) SetFEC

func (e *MultistreamEncoder) SetFEC(enabled bool)

SetFEC enables or disables in-band Forward Error Correction for all streams.

When enabled, the encoders include redundant information for loss recovery.

func (*MultistreamEncoder) SetForceChannels

func (e *MultistreamEncoder) SetForceChannels(channels int) error

SetForceChannels forces channel count on all stream encoders.

channels must be -1 (auto), 1 (mono), or 2 (stereo).

func (*MultistreamEncoder) SetLSBDepth

func (e *MultistreamEncoder) SetLSBDepth(depth int) error

SetLSBDepth sets the input signal's LSB depth for all stream encoders. Valid range is 8-24 bits. This affects DTX sensitivity. Returns an error if the depth is out of range.

func (*MultistreamEncoder) SetMaxBandwidth

func (e *MultistreamEncoder) SetMaxBandwidth(bw Bandwidth) error

SetMaxBandwidth sets the maximum bandwidth limit for all stream encoders. The actual bandwidth will be clamped to this limit.

func (*MultistreamEncoder) SetPacketLoss

func (e *MultistreamEncoder) SetPacketLoss(lossPercent int) error

SetPacketLoss sets expected packet loss percentage for all stream encoders.

lossPercent must be in the range [0, 100].

func (*MultistreamEncoder) SetPhaseInversionDisabled

func (e *MultistreamEncoder) SetPhaseInversionDisabled(disabled bool)

SetPhaseInversionDisabled toggles stereo phase inversion on all stream encoders.

func (*MultistreamEncoder) SetPredictionDisabled

func (e *MultistreamEncoder) SetPredictionDisabled(disabled bool)

SetPredictionDisabled toggles inter-frame prediction on all stream encoders.

func (*MultistreamEncoder) SetSignal

func (e *MultistreamEncoder) SetSignal(signal Signal) error

SetSignal sets the signal type hint for all stream encoders. Use SignalVoice for speech content, SignalMusic for music content, or SignalAuto (default) for automatic detection.

func (*MultistreamEncoder) SetVBR

func (e *MultistreamEncoder) SetVBR(enabled bool)

SetVBR enables or disables VBR mode.

Disabling VBR switches to CBR. Enabling VBR restores VBR while preserving the current VBR constraint state.

func (*MultistreamEncoder) SetVBRConstraint

func (e *MultistreamEncoder) SetVBRConstraint(constrained bool)

SetVBRConstraint enables or disables constrained VBR mode. This setting is remembered even while VBR is disabled.

func (*MultistreamEncoder) Signal

func (e *MultistreamEncoder) Signal() Signal

Signal returns the current signal type hint. Returns SignalAuto, SignalVoice, or SignalMusic.

func (*MultistreamEncoder) Streams

func (e *MultistreamEncoder) Streams() int

Streams returns the total number of elementary streams.

func (*MultistreamEncoder) VBR

func (e *MultistreamEncoder) VBR() bool

VBR reports whether VBR mode is enabled.

func (*MultistreamEncoder) VBRConstraint

func (e *MultistreamEncoder) VBRConstraint() bool

VBRConstraint reports whether constrained VBR mode is enabled.

type PacketInfo

type PacketInfo struct {
	TOC        TOC   // Parsed TOC byte
	FrameCount int   // Number of frames (1-48 for code 3)
	FrameSizes []int // Size in bytes of each frame
	Padding    int   // Padding bytes (code 3 only)
	TotalSize  int   // Total packet size
}

PacketInfo contains parsed information about an Opus packet.

func ParsePacket

func ParsePacket(data []byte) (PacketInfo, error)

ParsePacket parses an Opus packet and returns information about its structure. It determines the frame boundaries based on the TOC byte's frame code (0-3).

type PacketReader

type PacketReader interface {
	// ReadPacketInto fills dst with the next Opus packet and returns the byte count.
	// Returns io.EOF when stream ends. Return 0, nil to trigger PLC.
	ReadPacketInto(dst []byte) (int, uint64, error)
}

PacketReader provides Opus packets for streaming decode. Implementations should return io.EOF when no more packets are available.

type PacketSink

type PacketSink interface {
	// WritePacket writes an encoded Opus packet.
	// Returns number of bytes written and any error.
	WritePacket(packet []byte) (int, error)
}

PacketSink receives encoded Opus packets from streaming encode.

type Reader

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

Reader decodes an Opus stream, implementing io.Reader. Output is PCM samples in the configured format.

The Reader handles frame boundaries internally, buffering decoded PCM samples and serving byte-oriented reads.

Example:

reader, err := gopus.NewReader(gopus.DefaultDecoderConfig(48000, 2), source, gopus.FormatFloat32LE)
io.Copy(audioOutput, reader)

func NewReader

func NewReader(cfg DecoderConfig, source PacketReader, format SampleFormat) (*Reader, error)

NewReader creates a streaming decoder.

Parameters:

  • cfg: decoder configuration
  • source: provides Opus packets for decoding
  • format: output sample format (FormatFloat32LE or FormatInt16LE)

func (*Reader) Channels

func (r *Reader) Channels() int

Channels returns the number of audio channels (1 or 2).

func (*Reader) Read

func (r *Reader) Read(p []byte) (int, error)

Read implements io.Reader, reading decoded PCM bytes.

The Reader handles frame boundaries internally, fetching and decoding packets as needed to fill the buffer.

func (*Reader) Reset

func (r *Reader) Reset()

Reset clears buffers and decoder state for a new stream.

func (*Reader) SampleRate

func (r *Reader) SampleRate() int

SampleRate returns the sample rate in Hz.

type Repacketizer

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

Repacketizer accumulates Opus packet frames and emits new packets assembled from any contiguous frame range.

It mirrors libopus repacketizer behavior:

  • all added packets must share TOC bits 7..2,
  • total stored duration must not exceed 120ms.

func NewRepacketizer

func NewRepacketizer() *Repacketizer

NewRepacketizer creates a new repacketizer state.

func (*Repacketizer) Cat

func (r *Repacketizer) Cat(packet []byte) error

Cat adds one Opus packet to the repacketizer state.

func (*Repacketizer) NumFrames

func (r *Repacketizer) NumFrames() int

NumFrames returns the number of frames currently accumulated.

func (*Repacketizer) Out

func (r *Repacketizer) Out(data []byte) (int, error)

Out assembles all accumulated frames into one Opus packet.

func (*Repacketizer) OutRange

func (r *Repacketizer) OutRange(begin, end int, data []byte) (int, error)

OutRange assembles frames [begin, end) into one Opus packet.

func (*Repacketizer) Reset

func (r *Repacketizer) Reset()

Reset clears repacketizer state.

type SampleFormat

type SampleFormat int

SampleFormat specifies the PCM sample format for streaming.

const (
	// FormatFloat32LE is 32-bit float, little-endian (4 bytes per sample).
	FormatFloat32LE SampleFormat = iota
	// FormatInt16LE is 16-bit signed integer, little-endian (2 bytes per sample).
	FormatInt16LE
)

func (SampleFormat) BytesPerSample

func (f SampleFormat) BytesPerSample() int

BytesPerSample returns the number of bytes per sample for the format.

type Signal

type Signal = types.Signal

Signal represents a hint about the input signal type. This helps the encoder optimize for speech or music content.

type TOC

type TOC struct {
	Config    uint8     // Configuration 0-31
	Mode      Mode      // Derived from config
	Bandwidth Bandwidth // Derived from config
	FrameSize int       // Frame size in samples at 48kHz
	Stereo    bool      // True if stereo
	FrameCode uint8     // Code 0-3
}

TOC represents the parsed Table of Contents byte from an Opus packet.

func ParseTOC

func ParseTOC(b byte) TOC

ParseTOC parses a TOC byte and returns the decoded fields.

type Writer

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

Writer encodes PCM samples to an Opus stream, implementing io.Writer. Input is PCM samples in the configured format.

The Writer buffers input samples until a complete frame is accumulated, then encodes and sends the packet to the sink.

Example:

writer, err := gopus.NewWriter(48000, 2, sink, gopus.FormatFloat32LE, gopus.ApplicationAudio)
io.Copy(writer, audioInput)
writer.Flush() // encode any remaining buffered samples

func NewWriter

func NewWriter(sampleRate, channels int, sink PacketSink, format SampleFormat, application Application) (*Writer, error)

NewWriter creates a streaming encoder.

Parameters:

  • sampleRate: input sample rate (8000, 12000, 16000, 24000, or 48000)
  • channels: number of audio channels (1 or 2)
  • sink: receives encoded Opus packets
  • format: input sample format (FormatFloat32LE or FormatInt16LE)
  • application: encoder application hint

func (*Writer) Channels

func (w *Writer) Channels() int

Channels returns the number of audio channels (1 or 2).

func (*Writer) Flush

func (w *Writer) Flush() error

Flush encodes any buffered samples. If samples don't fill a complete frame, they are zero-padded. Call Flush before closing the stream to ensure all audio is encoded.

func (*Writer) Reset

func (w *Writer) Reset()

Reset clears buffers and encoder state for a new stream.

func (*Writer) SampleRate

func (w *Writer) SampleRate() int

SampleRate returns the sample rate in Hz.

func (*Writer) SetBitrate

func (w *Writer) SetBitrate(bitrate int) error

SetBitrate sets the target bitrate in bits per second. Valid range is 6000 to 510000 (6 kbps to 510 kbps).

func (*Writer) SetComplexity

func (w *Writer) SetComplexity(complexity int) error

SetComplexity sets the encoder's computational complexity (0-10).

func (*Writer) SetDTX

func (w *Writer) SetDTX(enabled bool)

SetDTX enables or disables Discontinuous Transmission.

func (*Writer) SetFEC

func (w *Writer) SetFEC(enabled bool)

SetFEC enables or disables in-band Forward Error Correction.

func (*Writer) Write

func (w *Writer) Write(p []byte) (int, error)

Write implements io.Writer, encoding PCM bytes to Opus packets.

The Writer buffers input samples until a complete frame is accumulated, then encodes and sends the packet to the sink.

Directories

Path Synopsis
Package celt implements the CELT decoder per RFC 6716 Section 4.3.
Package celt implements the CELT decoder per RFC 6716 Section 4.3.
container
ogg
Package ogg implements the Ogg container format for Opus audio.
Package ogg implements the Ogg container format for Opus audio.
Package encoder provides bitrate and bandwidth control for the Opus encoder.
Package encoder provides bitrate and bandwidth control for the Opus encoder.
examples
bench-decode command
Package main benchmarks Opus decode throughput for gopus vs ffmpeg/libopus.
Package main benchmarks Opus decode throughput for gopus vs ffmpeg/libopus.
bench-encode command
Package main benchmarks Opus encode throughput for gopus vs ffmpeg/libopus.
Package main benchmarks Opus encode throughput for gopus vs ffmpeg/libopus.
decode-play command
Package main demonstrates decoding an Ogg Opus file to WAV with optional playback.
Package main demonstrates decoding an Ogg Opus file to WAV with optional playback.
encode-play command
Package main demonstrates encoding audio with gopus and playing the result.
Package main demonstrates encoding audio with gopus and playing the result.
ffmpeg-interop command
Package main demonstrates gopus interoperability with ffmpeg.
Package main demonstrates gopus interoperability with ffmpeg.
ogg-file command
Package main demonstrates Ogg Opus file creation and reading.
Package main demonstrates Ogg Opus file creation and reading.
roundtrip command
Package main demonstrates gopus encode-decode roundtrip with quality metrics.
Package main demonstrates gopus encode-decode roundtrip with quality metrics.
Package hybrid implements the Hybrid decoder for Opus.
Package hybrid implements the Hybrid decoder for Opus.
internal
Package multistream implements the multistream decoder for Opus surround sound.
Package multistream implements the multistream decoder for Opus surround sound.
Package plc implements Packet Loss Concealment (PLC) for Opus.
Package plc implements Packet Loss Concealment (PLC) for Opus.
Package rangecoding implements the range coder used by Opus per RFC 6716 Section 4.1.
Package rangecoding implements the range coder used by Opus per RFC 6716 Section 4.1.
Package silk implements LBRR (Low Bitrate Redundancy) encoding for FEC.
Package silk implements LBRR (Low Bitrate Redundancy) encoding for FEC.
Package testvectors provides utilities for parsing and validating against official RFC 8251 Opus test vectors.
Package testvectors provides utilities for parsing and validating against official RFC 8251 Opus test vectors.
benchguard command
Package types defines shared types used across gopus packages.
Package types defines shared types used across gopus packages.
Package util provides common utility functions for the gopus codec.
Package util provides common utility functions for the gopus codec.

Jump to

Keyboard shortcuts

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