Overview
opus wraps libopus — the open, royalty-free audio codec standardized in RFC 6716. It combines the SILK speech layer and the CELT music layer to cover everything from narrow-band telephony to high-fidelity stereo music in a single unified codec.
Opus is the codec of choice for WebRTC, Discord, Zoom, Mumble, WhatsApp, and YouTube live streams. The PascalAI binding exposes encoder/decoder creation, per-frame PCM encode/decode, packet analysis helpers, and convenience file encode/decode.
Requires libopus-dev. Ubuntu/Debian: sudo apt install libopus-dev
Key Characteristics
| Property | Value |
|---|---|
| Bitrate range | 6–510 kbps (variable or constant) |
| Frame latency | 2.5–60 ms per frame (configurable) |
| Sample rates | 8, 12, 16, 24, 48 kHz (always encoded internally at 48 kHz) |
| Channels | Mono and stereo |
| Complexity | 0–10 (0 = fastest, 10 = best quality) |
| VBR | Variable bitrate supported (recommended) |
| DTX | Discontinuous transmission — silence suppression for VoIP |
| PLC | Packet loss concealment built in |
Applications
Choose the application mode when creating an encoder. It controls the internal codec layers and trade-offs between latency, quality, and CPU.
| Mode | Value | Best for |
|---|---|---|
| oaVoIP | 2048 | Voice calls, telephony, conferencing — SILK-heavy, optimized for speech intelligibility at low bitrates |
| oaAudio | 2049 | Music, podcasts, general audio — CELT-heavy, higher fidelity, slightly more CPU |
| oaLowDelay | 2051 | Real-time instruments, live monitoring — CELT only, minimal latency (2.5 ms possible), no DTX |
Codec Comparison
| Compared to | Result |
|---|---|
| MP3 | Opus better at all bitrates, especially low-bitrate speech; lower latency; open standard |
| AAC | Opus better below 128 kbps; comparable quality above that threshold |
| Vorbis | Opus is the direct successor — better quality, lower latency, equally open |
| FLAC | Different use cases: Opus is lossy, FLAC is lossless; Opus wins on size and streaming |
Quick Start
Encode PCM to Opus
uses opus;
{ Create a VoIP encoder at 48 kHz, mono }
var enc := NewEncoder(48000, 1, oaVoIP);
SetBitrate(enc, 32000); { 32 kbps }
SetVBR(enc, True);
SetDTX(enc, True); { suppress silence }
{ pcm is array of SmallInt, 960 samples = 20 ms at 48 kHz }
var packet := Encode(enc, pcm, 960);
WriteLn('Compressed: ' + IntToStr(Length(packet)) + ' bytes');
FreeEncoder(enc);
Decode Opus to PCM
uses opus;
{ Create a decoder matching the encoder's sample rate and channel count }
var dec := NewDecoder(48000, 1);
{ Decode one packet — FrameSize is max output samples per channel }
var pcm := Decode(dec, packet, 5760); { 5760 = 120 ms at 48 kHz }
WriteLn('PCM samples: ' + IntToStr(Length(pcm)));
{ Simulate a lost packet with PLC }
var concealed := DecodePLC(dec, 960);
FreeDecoder(dec);
Encode a WAV file to .opus
uses opus;
{ High-quality music encode at 128 kbps }
EncodeFile('input.wav', 'output.opus', 128000, oaAudio);
WriteLn('Encoded. Codec version: ' + OpusVersion());
{ Decode back to float PCM }
var samples := DecodeFile('output.opus');
WriteLn('Total float samples: ' + IntToStr(Length(samples)));
Types
TOpusEncoder
type TOpusEncoder = Integer; { opaque encoder handle }
Handle returned by NewEncoder. Pass to all encoder functions. Free with FreeEncoder when done.
TOpusDecoder
type TOpusDecoder = Integer; { opaque decoder handle }
Handle returned by NewDecoder. Pass to all decoder functions. Free with FreeDecoder when done.
TOpusApplication
type
TOpusApplication = (
oaVoIP = 2048, { optimized for voice (SILK-heavy) }
oaAudio = 2049, { optimized for music (CELT-heavy) }
oaLowDelay = 2051 { minimal latency, music (CELT only) }
);
TOpusSignal
type
TOpusSignal = (
osAuto = -1000, { auto-detect signal type }
osVoice = 3001, { hint: voice signal }
osMusic = 3002 { hint: music signal }
);
Signal hint passed to SetSignal. Helps the encoder choose SILK vs CELT weighting at hybrid bitrates.
TOpusInfo
type
TOpusInfo = record
SampleRate : Integer; { 8000/12000/16000/24000/48000 }
Channels : Integer; { 1 = mono, 2 = stereo }
Application : TOpusApplication;
Bitrate : Integer; { bits per second }
Complexity : Integer; { 0-10; higher = better quality, slower }
UseDTX : Boolean; { discontinuous transmission }
UseVBR : Boolean; { variable bitrate }
FrameSizeMs : Double; { 2.5, 5, 10, 20, 40, or 60 ms }
end;
Convenience record for describing encoder configuration. Populate it and pass individual fields to the encoder API.
Encoder API
Create one encoder per stream. Encoders are stateful — they maintain predictor history across frames. Reset with ResetEncoder when starting a new independent stream without reallocating.
| Function | Description |
|---|---|
| NewEncoder(SampleRate, Channels, App) | Create an encoder. SampleRate: 8000/12000/16000/24000/48000. Returns a TOpusEncoder handle. |
| FreeEncoder(E) | Destroy the encoder and release its memory. |
| SetBitrate(E, Bitrate) | Set target bitrate in bits/sec. Pass -1 for auto (encoder decides). |
| SetComplexity(E, Complexity) | Set CPU complexity 0–10. 0 = fastest, 10 = best quality. Default is 9. |
| SetVBR(E, Enable) | Enable or disable variable bitrate. VBR is recommended for most uses. |
| SetDTX(E, Enable) | Enable or disable DTX (silence suppression). Reduces bandwidth during pauses in speech. |
| SetSignal(E, Signal) | Hint the encoder about the signal type (voice, music, or auto). Affects SILK/CELT balance. |
| Encode(E, PCM, FrameSize) | Encode a frame of 16-bit integer PCM. FrameSize is samples per channel (e.g. 960 = 20 ms at 48 kHz). Returns compressed bytes as string. |
| EncodeFloat(E, PCM, FrameSize) | Encode a frame of 32-bit float PCM in the −1.0..1.0 range. |
| ResetEncoder(E) | Reset encoder state for a new stream without reallocating the encoder. |
Decoder API
Create one decoder per stream. The decoder tracks state for PLC and redundancy. Reset with ResetDecoder between independent streams.
| Function | Description |
|---|---|
| NewDecoder(SampleRate, Channels) | Create a decoder. SampleRate and Channels must match the encoder settings. |
| FreeDecoder(D) | Destroy the decoder and release its memory. |
| Decode(D, Packet, FrameSize) | Decode an Opus packet to 16-bit integer PCM. FrameSize is the maximum output samples per channel. Returns array of SmallInt. |
| DecodeFloat(D, Packet, FrameSize) | Decode an Opus packet to 32-bit float PCM in the −1.0..1.0 range. |
| DecodePLC(D, FrameSize) | Generate a concealment frame for a lost packet. Call instead of Decode when a packet does not arrive. |
| ResetDecoder(D) | Reset decoder state for a new stream. |
When a packet is lost in transit, call DecodePLC(dec, frameSize) instead of Decode. Opus synthesizes a plausible continuation of the signal so the listener hears smooth audio rather than a gap or click.
Packet Analysis API
Inspect Opus packet metadata without fully decoding. Useful for jitter-buffer management and stream diagnostics.
| Function | Description |
|---|---|
| PacketSamples(Packet, SampleRate) | Return the number of PCM samples contained in the packet at the given sample rate, without decoding. |
| PacketFrameCount(Packet) | Return the number of Opus frames packed into the packet (1, 2, or arbitrary with CELT code 3). |
| PacketBandwidth(Packet) | Return the bandwidth identifier used in the packet: 1105=NB, 1106=MB, 1107=WB, 1108=SWB, 1109=FB. |
uses opus;
var n := PacketSamples(packet, 48000);
var frames := PacketFrameCount(packet);
var bw := PacketBandwidth(packet);
WriteLn(IntToStr(n) + ' samples, ' + IntToStr(frames) + ' frame(s), bw=' + IntToStr(bw));
File API
Convenience functions that handle the full encode or decode pipeline for files. Internally they use libopusfile and handle container framing, header writing, and multi-page Ogg streams.
| Function | Description |
|---|---|
| EncodeFile(WavPath, OpusPath, Bitrate, App) | Encode a WAV file to an .opus Ogg container at the given bitrate (bits/sec) and application mode. |
| DecodeFile(OpusPath) | Decode a .opus file entirely to an array of 32-bit float PCM samples (interleaved channels). |
| OpusVersion() | Return the libopus version string, e.g. libopus 1.3.1. |
Key Concepts
Frame sizes
Opus operates on fixed frame sizes: 2.5, 5, 10, 20, 40, or 60 ms. At 48 kHz, 20 ms = 960 samples per channel. Smaller frames reduce latency but increase overhead per packet; 20 ms is the standard choice for most applications.
Internal 48 kHz resampling
Regardless of the SampleRate passed to NewEncoder, the codec always processes audio at 48 kHz internally. Passing a lower sample rate simply tells the codec the input bandwidth — it resamples automatically. Always prefer 48 kHz input to avoid any quality loss from the internal resampler.
VBR vs CBR
Variable bitrate (SetVBR(enc, True)) is recommended for most applications. CBR is useful when the channel requires a strictly constant data rate, such as some satellite links or legacy VoIP systems that expect constant RTP packet sizes.
DTX and silence
When DTX is enabled, the encoder emits very short comfort-noise packets during silence instead of full-size frames. This can reduce bandwidth by 60–80% in a typical voice call with natural pauses.
Package Info
System Requirements
libopus-devUbuntu/Debian:
sudo apt install libopus-dev
TOpusApplication Modes
oaVoIP — voice / telephonyoaAudio — music / generaloaLowDelay — real-time / instruments
Functions
- NewEncoder / FreeEncoder
- SetBitrate
- SetComplexity
- SetVBR / SetDTX
- SetSignal
- Encode / EncodeFloat
- ResetEncoder
- NewDecoder / FreeDecoder
- Decode / DecodeFloat
- DecodePLC
- ResetDecoder
- PacketSamples
- PacketFrameCount
- PacketBandwidth
- EncodeFile / DecodeFile
- OpusVersion
See Also
- libsndfile (WAV/AIFF/FLAC I/O)
- portaudio (audio I/O device)
- ffmpeg (transcode / mux)