Skip to main content

rtp_engine/rtp/
rtcp.rs

1//! RTCP (RTP Control Protocol) implementation.
2//!
3//! Provides Sender Reports (SR) and Receiver Reports (RR) per RFC 3550.
4
5/// RTCP packet types.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[repr(u8)]
8pub enum RtcpType {
9    /// Sender Report
10    SenderReport = 200,
11    /// Receiver Report
12    ReceiverReport = 201,
13    /// Source Description
14    SourceDescription = 202,
15    /// Goodbye
16    Goodbye = 203,
17    /// Application-defined
18    ApplicationDefined = 204,
19}
20
21impl RtcpType {
22    /// Parse an RTCP type from a byte.
23    pub fn from_byte(b: u8) -> Option<Self> {
24        match b {
25            200 => Some(Self::SenderReport),
26            201 => Some(Self::ReceiverReport),
27            202 => Some(Self::SourceDescription),
28            203 => Some(Self::Goodbye),
29            204 => Some(Self::ApplicationDefined),
30            _ => None,
31        }
32    }
33}
34
35/// A parsed RTCP packet.
36#[derive(Debug, Clone)]
37pub struct RtcpPacket {
38    /// Packet type.
39    pub packet_type: RtcpType,
40    /// SSRC of the sender.
41    pub ssrc: u32,
42    /// Raw packet data.
43    pub data: Vec<u8>,
44}
45
46impl RtcpPacket {
47    /// Parse an RTCP packet from raw bytes.
48    pub fn parse(data: &[u8]) -> Option<Self> {
49        if data.len() < 8 {
50            return None;
51        }
52
53        let version = (data[0] >> 6) & 0x03;
54        if version != 2 {
55            return None;
56        }
57
58        let packet_type = RtcpType::from_byte(data[1])?;
59        let ssrc = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
60
61        Some(Self {
62            packet_type,
63            ssrc,
64            data: data.to_vec(),
65        })
66    }
67}
68
69/// Build an RTCP Sender Report (SR) packet.
70///
71/// # Arguments
72/// * `ssrc` - Synchronization source identifier
73/// * `packets_sent` - Total RTP packets sent
74/// * `octets_sent` - Total payload octets sent
75pub fn build_rtcp_sr(ssrc: u32, packets_sent: u32, octets_sent: u32) -> Vec<u8> {
76    let mut buf = Vec::with_capacity(28);
77
78    // V=2, P=0, RC=0, PT=200 (SR)
79    buf.push(0x80);
80    buf.push(200);
81
82    // Length in 32-bit words minus one = 6
83    buf.extend_from_slice(&6u16.to_be_bytes());
84
85    // SSRC
86    buf.extend_from_slice(&ssrc.to_be_bytes());
87
88    // NTP timestamp (simplified: use system time)
89    let now = std::time::SystemTime::now()
90        .duration_since(std::time::UNIX_EPOCH)
91        .unwrap_or_default();
92    let ntp_sec = now.as_secs() + 2_208_988_800; // NTP epoch offset
93    let ntp_frac = ((now.subsec_nanos() as u64) << 32) / 1_000_000_000;
94    buf.extend_from_slice(&(ntp_sec as u32).to_be_bytes());
95    buf.extend_from_slice(&(ntp_frac as u32).to_be_bytes());
96
97    // RTP timestamp (approximate)
98    let rtp_ts = (now.as_millis() * 8) as u32; // 8kHz clock
99    buf.extend_from_slice(&rtp_ts.to_be_bytes());
100
101    // Sender's packet count
102    buf.extend_from_slice(&packets_sent.to_be_bytes());
103
104    // Sender's octet count
105    buf.extend_from_slice(&octets_sent.to_be_bytes());
106
107    buf
108}
109
110/// Build an RTCP Receiver Report (RR) packet.
111///
112/// # Arguments
113/// * `ssrc` - Our SSRC
114/// * `remote_ssrc` - SSRC of the source we're reporting on
115/// * `loss_fraction` - Fraction of packets lost (0-255)
116/// * `cumulative_lost` - Total packets lost (24-bit)
117/// * `highest_seq` - Highest sequence number received (with cycles)
118/// * `jitter` - Interarrival jitter
119pub fn build_rtcp_rr(
120    ssrc: u32,
121    remote_ssrc: u32,
122    loss_fraction: u8,
123    cumulative_lost: u32,
124    highest_seq: u32,
125    jitter: u32,
126) -> Vec<u8> {
127    let mut buf = Vec::with_capacity(32);
128
129    // V=2, P=0, RC=1, PT=201 (RR)
130    buf.push(0x81);
131    buf.push(201);
132
133    // Length = 7 (32-bit words minus one)
134    buf.extend_from_slice(&7u16.to_be_bytes());
135
136    // Our SSRC
137    buf.extend_from_slice(&ssrc.to_be_bytes());
138
139    // Report block
140    buf.extend_from_slice(&remote_ssrc.to_be_bytes());
141
142    // Fraction lost (8 bits) + cumulative lost (24 bits)
143    let lost_word = ((loss_fraction as u32) << 24) | (cumulative_lost & 0x00FF_FFFF);
144    buf.extend_from_slice(&lost_word.to_be_bytes());
145
146    // Extended highest sequence number
147    buf.extend_from_slice(&highest_seq.to_be_bytes());
148
149    // Interarrival jitter
150    buf.extend_from_slice(&jitter.to_be_bytes());
151
152    // Last SR timestamp (0 for now)
153    buf.extend_from_slice(&0u32.to_be_bytes());
154
155    // Delay since last SR (0 for now)
156    buf.extend_from_slice(&0u32.to_be_bytes());
157
158    buf
159}
160
161/// Build an RTCP BYE packet.
162///
163/// # Arguments
164/// * `ssrc` - SSRC of the source leaving
165pub fn build_rtcp_bye(ssrc: u32) -> Vec<u8> {
166    let mut buf = Vec::with_capacity(8);
167
168    // V=2, P=0, SC=1, PT=203 (BYE)
169    buf.push(0x81);
170    buf.push(203);
171
172    // Length = 1 (one 32-bit word of SSRC)
173    buf.extend_from_slice(&1u16.to_be_bytes());
174
175    // SSRC
176    buf.extend_from_slice(&ssrc.to_be_bytes());
177
178    buf
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    #[test]
186    fn test_build_rtcp_sr() {
187        let sr = build_rtcp_sr(0x12345678, 100, 16000);
188
189        // Check header
190        assert_eq!(sr[0] & 0xC0, 0x80); // V=2
191        assert_eq!(sr[1], 200); // PT=SR
192
193        // Check SSRC
194        let ssrc = u32::from_be_bytes([sr[4], sr[5], sr[6], sr[7]]);
195        assert_eq!(ssrc, 0x12345678);
196    }
197
198    #[test]
199    fn test_build_rtcp_rr() {
200        let rr = build_rtcp_rr(0xAAAAAAAA, 0xBBBBBBBB, 25, 100, 5000, 160);
201
202        assert_eq!(rr[0] & 0xC0, 0x80); // V=2
203        assert_eq!(rr[0] & 0x1F, 1); // RC=1
204        assert_eq!(rr[1], 201); // PT=RR
205
206        // Check our SSRC
207        let ssrc = u32::from_be_bytes([rr[4], rr[5], rr[6], rr[7]]);
208        assert_eq!(ssrc, 0xAAAAAAAA);
209
210        // Check remote SSRC
211        let remote_ssrc = u32::from_be_bytes([rr[8], rr[9], rr[10], rr[11]]);
212        assert_eq!(remote_ssrc, 0xBBBBBBBB);
213    }
214
215    #[test]
216    fn test_build_rtcp_bye() {
217        let bye = build_rtcp_bye(0xDEADBEEF);
218
219        assert_eq!(bye.len(), 8);
220        assert_eq!(bye[1], 203); // PT=BYE
221
222        let ssrc = u32::from_be_bytes([bye[4], bye[5], bye[6], bye[7]]);
223        assert_eq!(ssrc, 0xDEADBEEF);
224    }
225
226    #[test]
227    fn test_parse_rtcp() {
228        let sr = build_rtcp_sr(0x12345678, 100, 16000);
229        let parsed = RtcpPacket::parse(&sr).unwrap();
230
231        assert_eq!(parsed.packet_type, RtcpType::SenderReport);
232        assert_eq!(parsed.ssrc, 0x12345678);
233    }
234
235    #[test]
236    fn test_parse_rtcp_rr() {
237        let rr = build_rtcp_rr(0xAAAAAAAA, 0xBBBBBBBB, 25, 100, 5000, 160);
238        let parsed = RtcpPacket::parse(&rr).unwrap();
239
240        assert_eq!(parsed.packet_type, RtcpType::ReceiverReport);
241        assert_eq!(parsed.ssrc, 0xAAAAAAAA);
242    }
243
244    #[test]
245    fn test_parse_rtcp_bye() {
246        let bye = build_rtcp_bye(0xDEADBEEF);
247        let parsed = RtcpPacket::parse(&bye).unwrap();
248
249        assert_eq!(parsed.packet_type, RtcpType::Goodbye);
250        assert_eq!(parsed.ssrc, 0xDEADBEEF);
251    }
252
253    #[test]
254    fn test_parse_rtcp_too_short() {
255        // Less than 8 bytes
256        assert!(RtcpPacket::parse(&[0x80, 200, 0x00, 0x01]).is_none());
257        assert!(RtcpPacket::parse(&[]).is_none());
258    }
259
260    #[test]
261    fn test_parse_rtcp_invalid_version() {
262        // Version 0
263        let invalid = [0x00, 200, 0x00, 0x06, 0x12, 0x34, 0x56, 0x78];
264        assert!(RtcpPacket::parse(&invalid).is_none());
265    }
266
267    #[test]
268    fn test_parse_rtcp_unknown_type() {
269        // Unknown packet type 199
270        let unknown = [0x80, 199, 0x00, 0x01, 0x12, 0x34, 0x56, 0x78];
271        assert!(RtcpPacket::parse(&unknown).is_none());
272    }
273
274    #[test]
275    fn test_rtcp_type_from_byte() {
276        assert_eq!(RtcpType::from_byte(200), Some(RtcpType::SenderReport));
277        assert_eq!(RtcpType::from_byte(201), Some(RtcpType::ReceiverReport));
278        assert_eq!(RtcpType::from_byte(202), Some(RtcpType::SourceDescription));
279        assert_eq!(RtcpType::from_byte(203), Some(RtcpType::Goodbye));
280        assert_eq!(RtcpType::from_byte(204), Some(RtcpType::ApplicationDefined));
281        assert_eq!(RtcpType::from_byte(199), None);
282        assert_eq!(RtcpType::from_byte(205), None);
283    }
284
285    #[test]
286    fn test_rtcp_sr_structure() {
287        let sr = build_rtcp_sr(0x12345678, 1000, 160000);
288
289        // Length check: header(4) + SSRC(4) + NTP(8) + RTP-ts(4) + counts(8) = 28 bytes
290        assert_eq!(sr.len(), 28);
291
292        // Version and type
293        assert_eq!(sr[0] >> 6, 2); // V=2
294        assert_eq!(sr[1], 200); // PT=SR
295
296        // Length field (in 32-bit words minus 1)
297        let length = u16::from_be_bytes([sr[2], sr[3]]);
298        assert_eq!(length, 6); // (28 - 4) / 4 = 6
299
300        // Packet count
301        let packets = u32::from_be_bytes([sr[20], sr[21], sr[22], sr[23]]);
302        assert_eq!(packets, 1000);
303
304        // Octet count
305        let octets = u32::from_be_bytes([sr[24], sr[25], sr[26], sr[27]]);
306        assert_eq!(octets, 160000);
307    }
308
309    #[test]
310    fn test_rtcp_rr_structure() {
311        let rr = build_rtcp_rr(0xAAAAAAAA, 0xBBBBBBBB, 64, 256, 0x00010064, 320);
312
313        // Length check: header(4) + SSRC(4) + report_block(24) = 32 bytes
314        assert_eq!(rr.len(), 32);
315
316        // Loss fraction and cumulative
317        let loss_word = u32::from_be_bytes([rr[12], rr[13], rr[14], rr[15]]);
318        let loss_fraction = (loss_word >> 24) as u8;
319        let cumulative_lost = loss_word & 0x00FFFFFF;
320        assert_eq!(loss_fraction, 64);
321        assert_eq!(cumulative_lost, 256);
322
323        // Extended highest seq
324        let ext_seq = u32::from_be_bytes([rr[16], rr[17], rr[18], rr[19]]);
325        assert_eq!(ext_seq, 0x00010064);
326
327        // Jitter
328        let jitter = u32::from_be_bytes([rr[20], rr[21], rr[22], rr[23]]);
329        assert_eq!(jitter, 320);
330    }
331
332    #[test]
333    fn test_rtcp_bye_structure() {
334        let bye = build_rtcp_bye(0xCAFEBABE);
335
336        // SC=1 in first byte
337        assert_eq!(bye[0] & 0x1F, 1);
338
339        // PT=BYE (203)
340        assert_eq!(bye[1], 203);
341
342        // Length = 1
343        let length = u16::from_be_bytes([bye[2], bye[3]]);
344        assert_eq!(length, 1);
345    }
346}