Skip to content

RTCP control

Relay - rtcp

REL-04 - status: review - audio, video

RTCP feedback/control packets on the call media path: a standard Sender Report (PT 200) plus two WhatsApp compact reports (PT 208, PT 209), and the rule for classifying a received packet as RTP or RTCP on a shared port.

RTCP shares the media 5-tuple with RTP and is protected as SRTCP (see srtp-hop-by-hop). Every packet uses RTP version 2 (top two bits of byte 0 = 0b10) and an 8-byte fixed header: version/padding/count, payload type, big-endian 16-bit length. length MUST be packet size in 32-bit words minus one. All multi-byte integers are big-endian.

Sender Report (PT 200). 28-byte cleartext. RC MUST be 0 (no reception report blocks). Layout:

 0               1               2               3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0|0|0 0 0 0 0|   PT = 200    |        length = 6             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        sender SSRC                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|              NTP timestamp, seconds (since 1900)              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|              NTP timestamp, fraction                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        RTP timestamp                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    sender's packet count                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    sender's octet count                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • byte 0 MUST be 0x80; byte 1 MUST be 200; length MUST be 6.
  • sender SSRC MUST be the sender's own SSRC (see ssrc).
  • NTP timestamp encodes wall-clock send time as 64-bit NTP: high 32 bits = (floor(now_ms / 1000) + 2208988800) mod 2^32; low 32 bits = floor((now_ms mod 1000) / 1000 * 2^32).
  • RTP timestamp MUST correspond to the same instant as the NTP timestamp, in the sender stream's clock units.
  • sender's packet count / sender's octet count MUST be the total RTP data packets / payload octets transmitted since stream start.

Compact report (PT 208). 12-byte cleartext binding local to remote source:

 0               1               2               3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0|0|0 0 0 0 1|   PT = 208    |        length = 2             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        local SSRC                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        remote SSRC                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • byte 0 MUST be 0x81; byte 1 MUST be 208; length MUST be 2.
  • First SSRC word MUST be local source; second MUST be remote source.

Compact report (PT 209). 8-byte cleartext, local source only, pre-speech:

 0               1               2               3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 0|0|0 0 0 0 1|   PT = 209    |        length = 1             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        local SSRC                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • byte 0 MUST be 0x81; byte 1 MUST be 209; length MUST be 1.

On-the-wire size with SRTCP. SRTCP appends a 14-byte authenticated trailer (E-flag/index word plus auth tag): PT 208 = 26 bytes, PT 209 = 22 bytes, Sender Report = 42 bytes on the wire.

Classification (RTP vs. RTCP). On a shared port, a receiver MUST treat a packet as RTCP only if ALL hold, else as RTP:

  • length >= 22 bytes (8-byte header + 14-byte SRTCP trailer);
  • version bits (top two bits of byte 0) == 2;
  • byte 1 as unsigned 8-bit >= 64.

WhatsApp RTP sets the extension bit (X=1, byte 0 0x90) and a 7-bit payload type in the low bits of byte 1: a receiver MUST NOT classify a packet as RTCP when byte 0's extension bit is set and the low 7 bits of byte 1 equal the Opus RTP payload type. The RTCP payload type is the full byte 1; sender SSRC is bytes 4..8.

Requires: srtp-hop-by-hop, ssrc, rtp-framing

Implemented by

Flavor Status Source Notes
whatsapp-rust working history - blame - commits 674e851
zapo-caller working origin of the rtcp.ts implementation this is ported from

Annotation wacrg:REL-04 — a flavor marks its implementation site in source with this comment; a script clones the source, finds it, and attaches the commit blame/permalink.

Contributors

Contributor Role
Rajeh Taher Rajeh Taher wrote initial spec

protocol history / diff - blame

Open questions - Trigger conditions and cadence for emitting PT 208 vs PT 209, and how often Sender Reports are sent. - Semantics consumed by the peer/relay from the PT 208/209 compact reports beyond the SSRC binding.

References - RFC 3550 — RTP/RTCP - RFC 3711 — SRTP/SRTCP

Changelog

  • 2026-06-21 — Initial spec entry.

Back to the full spec