1pub mod gbp {
14 #[derive(Clone, PartialEq, prost::Message)]
16 pub struct GbpFrame {
17 #[prost(uint32, tag = "1")]
19 pub version: u32,
20 #[prost(bytes = "vec", tag = "2")]
22 pub group_id: Vec<u8>,
23 #[prost(uint64, tag = "3")]
25 pub epoch: u64,
26 #[prost(uint32, tag = "4")]
28 pub transition_id: u32,
29 #[prost(uint32, tag = "5")]
31 pub stream_type: u32,
32 #[prost(uint32, tag = "6")]
34 pub stream_id: u32,
35 #[prost(uint32, tag = "7")]
37 pub flags: u32,
38 #[prost(uint64, tag = "8")]
40 pub sequence_no: u64,
41 #[prost(bytes = "vec", tag = "9")]
43 pub encrypted_payload: Vec<u8>,
44 }
45
46 #[derive(Clone, PartialEq, prost::Message)]
48 pub struct ControlMessage {
49 #[prost(uint32, tag = "1")]
51 pub opcode: u32,
52 #[prost(uint32, tag = "2")]
54 pub request_id: u32,
55 #[prost(uint32, tag = "3")]
57 pub sender_id: u32,
58 #[prost(uint32, tag = "4")]
60 pub transition_id: u32,
61 #[prost(bytes = "vec", tag = "5")]
63 pub args: Vec<u8>,
64 }
65
66 #[derive(Clone, PartialEq, prost::Message)]
68 pub struct ErrorObject {
69 #[prost(uint32, tag = "1")]
71 pub code: u32,
72 #[prost(uint32, tag = "2")]
74 pub class: u32,
75 #[prost(bool, tag = "3")]
77 pub retryable: bool,
78 #[prost(bool, tag = "4")]
80 pub fatal: bool,
81 #[prost(string, tag = "5")]
83 pub reason: String,
84 }
85}
86
87pub mod gtp {
89 #[derive(Clone, PartialEq, prost::Message)]
91 pub struct GtpMessage {
92 #[prost(uint64, tag = "1")]
94 pub message_id: u64,
95 #[prost(uint32, tag = "2")]
97 pub sender_id: u32,
98 #[prost(uint64, tag = "3")]
100 pub timestamp_ms: u64,
101 #[prost(uint32, tag = "4")]
103 pub request_id: u32,
104 #[prost(uint32, tag = "5")]
106 pub flags: u32,
107 #[prost(uint32, tag = "6")]
109 pub content_type: u32,
110 #[prost(uint32, tag = "7")]
112 pub content_length: u32,
113 #[prost(bytes = "vec", tag = "8")]
115 pub content: Vec<u8>,
116 }
117
118 #[derive(Clone, PartialEq, prost::Message)]
120 pub struct AttachmentManifest {
121 #[prost(uint64, tag = "1")]
123 pub attachment_id: u64,
124 #[prost(string, tag = "2")]
126 pub filename: String,
127 #[prost(string, tag = "3")]
129 pub mime_type: String,
130 #[prost(uint64, tag = "4")]
132 pub total_size: u64,
133 #[prost(uint32, tag = "5")]
135 pub chunk_count: u32,
136 #[prost(bytes = "vec", tag = "6")]
138 pub sha256: Vec<u8>,
139 }
140
141 #[derive(Clone, PartialEq, prost::Message)]
143 pub struct AttachmentChunk {
144 #[prost(uint64, tag = "1")]
146 pub attachment_id: u64,
147 #[prost(uint32, tag = "2")]
149 pub chunk_index: u32,
150 #[prost(uint32, tag = "3")]
152 pub chunk_count: u32,
153 #[prost(bytes = "vec", tag = "4")]
155 pub data: Vec<u8>,
156 }
157}
158
159pub mod gap {
161 #[derive(Clone, PartialEq, prost::Message)]
163 pub struct GapPayload {
164 #[prost(uint32, tag = "1")]
166 pub media_source_id: u32,
167 #[prost(uint32, tag = "2")]
169 pub rtp_sequence: u32,
170 #[prost(uint64, tag = "3")]
172 pub rtp_timestamp: u64,
173 #[prost(uint32, tag = "4")]
175 pub key_phase: u32,
176 #[prost(bytes = "vec", tag = "5")]
178 pub opus_frame: Vec<u8>,
179 }
180}
181
182pub mod gsp {
184 #[derive(Clone, PartialEq, prost::Message)]
186 pub struct GspSignal {
187 #[prost(uint32, tag = "1")]
189 pub signal_type: u32,
190 #[prost(uint32, tag = "2")]
192 pub request_id: u32,
193 #[prost(uint32, tag = "3")]
195 pub sender_id: u32,
196 #[prost(uint32, tag = "4")]
198 pub role_claim: u32,
199 #[prost(uint32, tag = "5")]
201 pub args_length: u32,
202 #[prost(bytes = "vec", tag = "6")]
204 pub args: Vec<u8>,
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use prost::Message;
211
212 #[test]
213 fn gbp_frame_round_trip() {
214 let frame = crate::gbp::GbpFrame {
215 version: 1,
216 group_id: vec![0u8; 16],
217 epoch: 42,
218 transition_id: 7,
219 stream_type: 1,
220 stream_id: 0,
221 flags: 0,
222 sequence_no: 100,
223 encrypted_payload: b"hello".to_vec(),
224 };
225 let encoded = frame.encode_to_vec();
226 let decoded = crate::gbp::GbpFrame::decode(encoded.as_slice()).unwrap();
227 assert_eq!(frame, decoded);
228 }
229
230 #[test]
231 fn control_message_round_trip() {
232 let msg = crate::gbp::ControlMessage {
233 opcode: 3,
234 request_id: 99,
235 sender_id: 1,
236 transition_id: 2,
237 args: vec![0xA0],
238 };
239 let encoded = msg.encode_to_vec();
240 let decoded = crate::gbp::ControlMessage::decode(encoded.as_slice()).unwrap();
241 assert_eq!(msg, decoded);
242 }
243
244 #[test]
245 fn error_object_round_trip() {
246 let err = crate::gbp::ErrorObject {
247 code: 404,
248 class: 1,
249 retryable: true,
250 fatal: false,
251 reason: "not found".to_string(),
252 };
253 let encoded = err.encode_to_vec();
254 let decoded = crate::gbp::ErrorObject::decode(encoded.as_slice()).unwrap();
255 assert_eq!(err, decoded);
256 }
257
258 #[test]
259 fn gtp_message_round_trip() {
260 let msg = crate::gtp::GtpMessage {
261 message_id: 12345,
262 sender_id: 1,
263 timestamp_ms: 1_700_000_000_000,
264 request_id: 0,
265 flags: 0,
266 content_type: 1,
267 content_length: 5,
268 content: b"hello".to_vec(),
269 };
270 let encoded = msg.encode_to_vec();
271 let decoded = crate::gtp::GtpMessage::decode(encoded.as_slice()).unwrap();
272 assert_eq!(msg, decoded);
273 }
274
275 #[test]
276 fn attachment_manifest_round_trip() {
277 let m = crate::gtp::AttachmentManifest {
278 attachment_id: 1,
279 filename: "test.png".to_string(),
280 mime_type: "image/png".to_string(),
281 total_size: 1024,
282 chunk_count: 1,
283 sha256: vec![0u8; 32],
284 };
285 let encoded = m.encode_to_vec();
286 let decoded = crate::gtp::AttachmentManifest::decode(encoded.as_slice()).unwrap();
287 assert_eq!(m, decoded);
288 }
289
290 #[test]
291 fn attachment_chunk_round_trip() {
292 let c = crate::gtp::AttachmentChunk {
293 attachment_id: 1,
294 chunk_index: 0,
295 chunk_count: 1,
296 data: vec![1, 2, 3, 4],
297 };
298 let encoded = c.encode_to_vec();
299 let decoded = crate::gtp::AttachmentChunk::decode(encoded.as_slice()).unwrap();
300 assert_eq!(c, decoded);
301 }
302
303 #[test]
304 fn gap_payload_round_trip() {
305 let p = crate::gap::GapPayload {
306 media_source_id: 5,
307 rtp_sequence: 100,
308 rtp_timestamp: 960,
309 key_phase: 2,
310 opus_frame: vec![0xAB, 0xCD],
311 };
312 let encoded = p.encode_to_vec();
313 let decoded = crate::gap::GapPayload::decode(encoded.as_slice()).unwrap();
314 assert_eq!(p, decoded);
315 }
316
317 #[test]
318 fn gsp_signal_round_trip() {
319 let s = crate::gsp::GspSignal {
320 signal_type: 1,
321 request_id: 42,
322 sender_id: 3,
323 role_claim: 0,
324 args_length: 0,
325 args: vec![],
326 };
327 let encoded = s.encode_to_vec();
328 let decoded = crate::gsp::GspSignal::decode(encoded.as_slice()).unwrap();
329 assert_eq!(s, decoded);
330 }
331
332 #[test]
333 fn empty_frame_decodes_to_defaults() {
334 let decoded = crate::gbp::GbpFrame::decode(&[][..]).unwrap();
335 assert_eq!(decoded.version, 0);
336 assert!(decoded.encrypted_payload.is_empty());
337 }
338
339 #[test]
340 fn encoded_size_is_nonzero_for_nonempty_frame() {
341 let frame = crate::gbp::GbpFrame {
342 version: 1,
343 sequence_no: 1,
344 ..Default::default()
345 };
346 assert!(!frame.encode_to_vec().is_empty());
347 }
348}