Tuning

Encoder tuning

Encoder tuning

Opus exposes a lot of knobs. libopus-wasm surfaces the common ones as typed options and named setters, and the rest through a curated CTL passthrough. Everything here can be set at construction time or changed later at runtime.

#Options at a glance

OptionTypeDefaultNotes
applicationApplicationAudioEncoding mode. Voip, Audio, RestrictedLowDelay.
bitratenumber | "auto" | "max"64000Target bits per second.
complexity01010Quality vs CPU.
signalSignalAutoHint: Auto, Voice, Music.
maxBandwidthBandwidthunsetUpper bound on coded bandwidth.
vbrbooleanlibopus defaultVariable vs constant bitrate.
vbrConstraintbooleanlibopus defaultConstrained VBR.
fecbooleanfalseIn-band forward error correction.
packetLossPercent01000Expected loss; drives FEC redundancy.
dtxbooleanfalseDiscontinuous transmission for silence.
frameSizenumber20 msDefault samples/channel per frame.
const encoder = await createEncoder({
  application: Application.Audio,
  bitrate: 96000,
  complexity: 10,
  signal: Signal.Music,
  vbr: true,
});

#Application mode

Set this at construction — it cannot change after the encoder is created.

ModeBest for
Application.VoipSpeech; optimizes for intelligibility.
Application.AudioMusic and general audio (the default).
Application.RestrictedLowDelayLowest latency; disables the speech-only modes.

#Bitrate

bitrate accepts an integer in bits per second, or one of two sentinels:

encoder.setBitrate(128000);     // 128 kbps
encoder.setBitrate("auto");     // let Opus choose from sample rate + channels
encoder.setBitrate("max");      // use the maximum the frame allows
encoder.getBitrate();           // read the resolved value back

The Bitrate enum exposes the same sentinels as values (Bitrate.Auto, Bitrate.Max) if you prefer them over the string forms.

#VBR vs CBR

encoder.setVbr(true);            // variable bitrate (default in libopus)
encoder.setVbr(false);           // constant bitrate
encoder.setVbrConstraint(true);  // constrained VBR — caps peaks for CBR-like budgets

Constant bitrate gives predictable packet sizes; VBR gives better quality for the same average bitrate. Use constrained VBR when a transport needs a tight ceiling but you still want some adaptivity.

#Complexity

encoder.setComplexity(10); // 0 (fastest, lowest quality) .. 10 (best)

10 is the default. Lower it only if CPU is the bottleneck; the quality cost is usually larger than the CPU saving on modern hardware.

#Signal type

A hint that nudges Opus toward the right internal model:

encoder.setSignal(Signal.Voice); // speech
encoder.setSignal(Signal.Music); // music
encoder.setSignal(Signal.Auto);  // let Opus decide (default)

#Bandwidth ceiling

Cap the coded audio bandwidth — handy when you deliberately want a narrower, cheaper stream:

import { Bandwidth } from "libopus-wasm";

encoder.setMaxBandwidth(Bandwidth.Wideband); // up to 8 kHz audio bandwidth

Bandwidth ranges from Narrowband (1) through Mediumband, Wideband, Superwideband, to Fullband (5).

#DTX

Discontinuous transmission emits much smaller packets during silence, saving bandwidth on a voice channel:

encoder.setDtx(true);
encoder.getInDtx(); // true while the encoder is currently in a DTX (silence) period

#Loss resilience

FEC and the expected loss percentage live here too; see Packet loss for how they pair with the decoder.

encoder.setFec(true);
encoder.setPacketLossPercent(10);

#Encoder delay

Opus adds a fixed look-ahead. Read it to align encoder and decoder timelines (for example, to trim the leading samples when comparing to a reference):

encoder.getLookahead(); // samples of algorithmic delay at the encoder's rate

#Anything else

Settings without a named helper are reachable through the typed CTL passthrough — see the CTL reference.

#Next