arcly_stream/protocol/srt/
packet.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[non_exhaustive]
9pub enum ControlType {
10 Handshake,
12 Keepalive,
14 Ack,
16 Nak,
18 Shutdown,
20 AckAck,
22 Other(u16),
24}
25
26impl ControlType {
27 fn from_u16(v: u16) -> ControlType {
28 match v {
29 0x0000 => ControlType::Handshake,
30 0x0001 => ControlType::Keepalive,
31 0x0002 => ControlType::Ack,
32 0x0003 => ControlType::Nak,
33 0x0005 => ControlType::Shutdown,
34 0x0006 => ControlType::AckAck,
35 other => ControlType::Other(other),
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
43pub enum SrtPacket {
44 Control {
46 control_type: ControlType,
48 dest_socket_id: u32,
50 },
51 Data {
53 sequence: u32,
55 dest_socket_id: u32,
57 payload_offset: usize,
59 },
60}
61
62impl SrtPacket {
63 pub fn parse(buf: &[u8]) -> Option<SrtPacket> {
66 use crate::protocol::byteops::ByteReader;
67 let mut r = ByteReader::new(buf);
68 let word0 = r.u32_be()?;
69 r.skip(8)?; let dest_socket_id = r.u32_be()?;
71
72 if word0 & 0x8000_0000 == 0 {
73 Some(SrtPacket::Data {
75 sequence: word0 & 0x7FFF_FFFF,
76 dest_socket_id,
77 payload_offset: 16,
78 })
79 } else {
80 let control_type = ((word0 >> 16) & 0x7FFF) as u16;
82 Some(SrtPacket::Control {
83 control_type: ControlType::from_u16(control_type),
84 dest_socket_id,
85 })
86 }
87 }
88}
89
90pub fn build_data_packet(
96 sequence: u32,
97 message_number: u32,
98 timestamp: u32,
99 dest_socket_id: u32,
100 payload: &[u8],
101) -> Vec<u8> {
102 let mut out = Vec::with_capacity(16 + payload.len());
103 out.extend_from_slice(&(sequence & 0x7FFF_FFFF).to_be_bytes());
104 let word1 = (0b11u32 << 30) | (1 << 29) | (message_number & 0x03FF_FFFF);
106 out.extend_from_slice(&word1.to_be_bytes());
107 out.extend_from_slice(×tamp.to_be_bytes());
108 out.extend_from_slice(&dest_socket_id.to_be_bytes());
109 out.extend_from_slice(payload);
110 out
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 fn header(word0: u32, dest: u32) -> Vec<u8> {
118 let mut b = word0.to_be_bytes().to_vec();
119 b.extend_from_slice(&[0; 8]); b.extend_from_slice(&dest.to_be_bytes());
121 b
122 }
123
124 #[test]
125 fn parses_data_packet() {
126 let pkt = SrtPacket::parse(&header(0x0000_002A, 99)).unwrap();
127 assert_eq!(
128 pkt,
129 SrtPacket::Data {
130 sequence: 42,
131 dest_socket_id: 99,
132 payload_offset: 16,
133 }
134 );
135 }
136
137 #[test]
138 fn built_data_packet_round_trips() {
139 let payload = [0x47u8, 0x40, 0x00, 0x10, 0xAA, 0xBB]; let pkt = build_data_packet(1234, 7, 90_000, 0xDEAD_BEEF, &payload);
141 match SrtPacket::parse(&pkt).unwrap() {
142 SrtPacket::Data {
143 sequence,
144 dest_socket_id,
145 payload_offset,
146 } => {
147 assert_eq!(sequence, 1234);
148 assert_eq!(dest_socket_id, 0xDEAD_BEEF);
149 assert_eq!(&pkt[payload_offset..], &payload);
150 }
151 other => panic!("expected data packet, got {other:?}"),
152 }
153 }
154
155 #[test]
156 fn parses_control_handshake() {
157 let pkt = SrtPacket::parse(&header(0x8000_0000, 7)).unwrap();
159 assert_eq!(
160 pkt,
161 SrtPacket::Control {
162 control_type: ControlType::Handshake,
163 dest_socket_id: 7,
164 }
165 );
166 }
167
168 #[test]
169 fn parses_control_nak() {
170 let pkt = SrtPacket::parse(&header(0x8003_0000, 1)).unwrap();
171 match pkt {
172 SrtPacket::Control { control_type, .. } => assert_eq!(control_type, ControlType::Nak),
173 _ => panic!("expected control"),
174 }
175 }
176
177 #[test]
178 fn rejects_short_buffer() {
179 assert!(SrtPacket::parse(&[0u8; 8]).is_none());
180 }
181}