1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[repr(u8)]
8pub enum RtcpType {
9 SenderReport = 200,
11 ReceiverReport = 201,
13 SourceDescription = 202,
15 Goodbye = 203,
17 ApplicationDefined = 204,
19}
20
21impl RtcpType {
22 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#[derive(Debug, Clone)]
37pub struct RtcpPacket {
38 pub packet_type: RtcpType,
40 pub ssrc: u32,
42 pub data: Vec<u8>,
44}
45
46impl RtcpPacket {
47 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
69pub fn build_rtcp_sr(ssrc: u32, packets_sent: u32, octets_sent: u32) -> Vec<u8> {
76 let mut buf = Vec::with_capacity(28);
77
78 buf.push(0x80);
80 buf.push(200);
81
82 buf.extend_from_slice(&6u16.to_be_bytes());
84
85 buf.extend_from_slice(&ssrc.to_be_bytes());
87
88 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; 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 let rtp_ts = (now.as_millis() * 8) as u32; buf.extend_from_slice(&rtp_ts.to_be_bytes());
100
101 buf.extend_from_slice(&packets_sent.to_be_bytes());
103
104 buf.extend_from_slice(&octets_sent.to_be_bytes());
106
107 buf
108}
109
110pub 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 buf.push(0x81);
131 buf.push(201);
132
133 buf.extend_from_slice(&7u16.to_be_bytes());
135
136 buf.extend_from_slice(&ssrc.to_be_bytes());
138
139 buf.extend_from_slice(&remote_ssrc.to_be_bytes());
141
142 let lost_word = ((loss_fraction as u32) << 24) | (cumulative_lost & 0x00FF_FFFF);
144 buf.extend_from_slice(&lost_word.to_be_bytes());
145
146 buf.extend_from_slice(&highest_seq.to_be_bytes());
148
149 buf.extend_from_slice(&jitter.to_be_bytes());
151
152 buf.extend_from_slice(&0u32.to_be_bytes());
154
155 buf.extend_from_slice(&0u32.to_be_bytes());
157
158 buf
159}
160
161pub fn build_rtcp_bye(ssrc: u32) -> Vec<u8> {
166 let mut buf = Vec::with_capacity(8);
167
168 buf.push(0x81);
170 buf.push(203);
171
172 buf.extend_from_slice(&1u16.to_be_bytes());
174
175 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 assert_eq!(sr[0] & 0xC0, 0x80); assert_eq!(sr[1], 200); 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); assert_eq!(rr[0] & 0x1F, 1); assert_eq!(rr[1], 201); let ssrc = u32::from_be_bytes([rr[4], rr[5], rr[6], rr[7]]);
208 assert_eq!(ssrc, 0xAAAAAAAA);
209
210 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); 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 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 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 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 assert_eq!(sr.len(), 28);
291
292 assert_eq!(sr[0] >> 6, 2); assert_eq!(sr[1], 200); let length = u16::from_be_bytes([sr[2], sr[3]]);
298 assert_eq!(length, 6); let packets = u32::from_be_bytes([sr[20], sr[21], sr[22], sr[23]]);
302 assert_eq!(packets, 1000);
303
304 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 assert_eq!(rr.len(), 32);
315
316 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 let ext_seq = u32::from_be_bytes([rr[16], rr[17], rr[18], rr[19]]);
325 assert_eq!(ext_seq, 0x00010064);
326
327 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 assert_eq!(bye[0] & 0x1F, 1);
338
339 assert_eq!(bye[1], 203);
341
342 let length = u16::from_be_bytes([bye[2], bye[3]]);
344 assert_eq!(length, 1);
345 }
346}