Expand description
Opus codec (RFC 6716) — the wideband voice profile for telephony.
Wraps the reference C libopus via the opus
crate. The profile is fixed for the WaveKat call path: 16 kHz mono
(“wideband”), Application::Voip, in-band FEC on, DTX off. A 20 ms
frame is therefore 320 PCM samples in, one variable-size packet out.
§Wire constants vs. audio reality
Three numbers here look contradictory and are not:
- The SDP rtpmap is always
opus/48000/2and the RTP timestamp advances byOPUS_RTP_SAMPLES_PER_FRAME(960) per 20 ms packet. RFC 7587 §4.1 pins the RTP clock to 48 kHz and the channel count to 2 regardless of what the codec actually does — they are wire-format constants, not a description of the stream. - The PCM on either side of the codec is
OPUS_PCM_SAMPLE_RATE(16 kHz) mono. That’s the audio reality: wideband speech.
Confusing the 48 kHz wire clock with the 16 kHz PCM rate is the classic Opus-over-RTP interop bug; the constants below exist so consumers never re-derive these numbers.
§Loss recovery is driven by the consumer
Unlike G.711, Opus can recover lost packets — but only if the receive path notices the loss (an RTP sequence-number gap) and asks:
OpusDecoder::decode_fec— recover the lost frame from the next packet’s embedded redundancy (in-band FEC / LBRR). The encoder only embeds that redundancy because we set a nonzero expected packet loss;set_inband_fec(true)alone puts nothing on the wire.OpusDecoder::conceal— packet-loss concealment when nothing usable arrived at all: the decoder extrapolates a plausible frame instead of emitting a click or silence.
Opus lives in wavekat-core (not wavekat-sip) for the same reason
G.711 does: codecs are a consumer-layer choice — wavekat-sip
deliberately stays codec-agnostic.
Structs§
- Opus
Decoder - Stateful Opus decoder for one inbound stream.
- Opus
Encoder - Stateful Opus encoder with the fixed WaveKat voice profile.
Constants§
- OPUS_
DEFAULT_ BITRATE - Target bitrate: the middle of the 24–32 kbps wideband-voice sweet spot from doc 45 — a large quality jump over G.711’s 64 kbps narrowband at under half the bandwidth.
- OPUS_
DEFAULT_ PACKET_ LOSS_ PERC - Expected packet-loss percentage told to the encoder. Nonzero is what makes libopus actually spend bits on in-band FEC redundancy.
- OPUS_
DEFAULT_ PAYLOAD_ TYPE - De-facto default dynamic RTP payload type for Opus in SDP offers.
- OPUS_
FRAME_ SAMPLES - PCM samples in one 20 ms frame at
OPUS_PCM_SAMPLE_RATE: whatOpusEncoder::encodeconsumes per call and what a normal 20 ms packet decodes to. - OPUS_
MAX_ FRAME_ SAMPLES - PCM samples in the largest legal Opus frame (120 ms) at
OPUS_PCM_SAMPLE_RATE. The far end chooses its own frame size, so decode buffers must size for this, not for 20 ms. - OPUS_
PCM_ SAMPLE_ RATE - PCM sample rate on both sides of the codec: 16 kHz wideband, the locked profile from doc 45. This — not 48 kHz — is the rate the microphone is resampled to before encode and the rate decoded frames come out at.
- OPUS_
RTP_ CLOCK_ RATE - The RTP timestamp clock rate for Opus — always 48 kHz per RFC 7587 §4.1, independent of the actual encode rate. Wire constant.
- OPUS_
RTP_ SAMPLES_ PER_ FRAME - RTP timestamp advance per 20 ms Opus packet: 20 ms at the mandatory
48 kHz wire clock. Feed this to the RTP sender’s
samples_per_frame(the G.711 equivalent is 160).