1use crate::error::OaatError;
2use crate::format::AudioFormat;
3
4pub const AUDIO_HEADER_SIZE: usize = 32;
5
6bitflags::bitflags! {
7 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
8 pub struct PacketFlags: u8 {
9 const FIRST_PACKET = 0x01;
10 const LAST_PACKET = 0x02;
11 const FEC = 0x04;
12 const FORMAT_CHANGE = 0x08;
13 }
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct AudioPacketHeader {
33 pub version: u8,
34 pub flags: PacketFlags,
35 pub format: AudioFormat,
36 pub sequence: u16,
37 pub stream_id: u32,
38 pub pts_ns: u64,
39 pub sample_offset: u64,
40 pub payload_len: u16,
41}
42
43impl AudioPacketHeader {
44 pub const CURRENT_VERSION: u8 = 1;
45
46 pub fn encode(&self, buf: &mut [u8; AUDIO_HEADER_SIZE]) {
47 let ver_flags = (self.version << 4) | self.flags.bits();
48 buf[0] = ver_flags;
49 buf[1] = self.format.wire_id();
50 buf[2..4].copy_from_slice(&self.sequence.to_be_bytes());
51 buf[4..8].copy_from_slice(&self.stream_id.to_be_bytes());
52 buf[8..16].copy_from_slice(&self.pts_ns.to_be_bytes());
53 buf[16..24].copy_from_slice(&self.sample_offset.to_be_bytes());
54 buf[24..26].copy_from_slice(&self.payload_len.to_be_bytes());
55 buf[26..28].copy_from_slice(&0u16.to_be_bytes());
56 buf[28..32].fill(0);
57 }
58
59 pub fn decode(buf: &[u8; AUDIO_HEADER_SIZE]) -> Result<Self, OaatError> {
60 let version = buf[0] >> 4;
61 let flags = PacketFlags::from_bits(buf[0] & 0x0F)
62 .ok_or(OaatError::InvalidPacketFlags(buf[0] & 0x0F))?;
63 let format = AudioFormat::from_wire_id(buf[1]).ok_or(OaatError::UnknownFormat(buf[1]))?;
64 let sequence = u16::from_be_bytes([buf[2], buf[3]]);
65 let stream_id = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]);
66 let pts_ns = u64::from_be_bytes(buf[8..16].try_into().unwrap());
67 let sample_offset = u64::from_be_bytes(buf[16..24].try_into().unwrap());
68 let payload_len = u16::from_be_bytes([buf[24], buf[25]]);
69
70 Ok(Self {
71 version,
72 flags,
73 format,
74 sequence,
75 stream_id,
76 pts_ns,
77 sample_offset,
78 payload_len,
79 })
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub struct ClockSyncPacket {
87 pub version: u8,
88 pub kind: ClockSyncType,
89 pub sequence: u16,
90 pub t1: u64,
91 pub t2: u64,
92 pub t3: u64,
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub enum ClockSyncType {
97 Request = 0x01,
98 Response = 0x02,
99}
100
101impl ClockSyncPacket {
102 pub const SIZE: usize = 28;
103
104 pub fn encode(&self, buf: &mut [u8; Self::SIZE]) {
105 let ver_type = (self.version << 4) | (self.kind as u8);
106 buf[0] = ver_type;
107 buf[1] = 0; buf[2..4].copy_from_slice(&self.sequence.to_be_bytes());
109 buf[4..12].copy_from_slice(&self.t1.to_be_bytes());
110 buf[12..20].copy_from_slice(&self.t2.to_be_bytes());
111 buf[20..28].copy_from_slice(&self.t3.to_be_bytes());
112 }
113
114 pub fn decode(buf: &[u8; Self::SIZE]) -> Result<Self, OaatError> {
115 let version = buf[0] >> 4;
116 let kind = match buf[0] & 0x0F {
117 0x01 => ClockSyncType::Request,
118 0x02 => ClockSyncType::Response,
119 other => return Err(OaatError::InvalidClockSyncType(other)),
120 };
121 let sequence = u16::from_be_bytes([buf[2], buf[3]]);
122 let t1 = u64::from_be_bytes(buf[4..12].try_into().unwrap());
123 let t2 = u64::from_be_bytes(buf[12..20].try_into().unwrap());
124 let t3 = u64::from_be_bytes(buf[20..28].try_into().unwrap());
125
126 Ok(Self {
127 version,
128 kind,
129 sequence,
130 t1,
131 t2,
132 t3,
133 })
134 }
135
136 pub fn compute_offset(t1: u64, t2: u64, t3: u64, t4: u64) -> i64 {
137 let a = t2 as i64 - t1 as i64;
138 let b = t3 as i64 - t4 as i64;
139 (a + b) / 2
140 }
141
142 pub fn compute_rtt(t1: u64, t2: u64, t3: u64, t4: u64) -> u64 {
143 let total = t4.wrapping_sub(t1);
144 let server = t3.wrapping_sub(t2);
145 total.wrapping_sub(server)
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn audio_header_roundtrip() {
155 let hdr = AudioPacketHeader {
156 version: 1,
157 flags: PacketFlags::FIRST_PACKET | PacketFlags::FEC,
158 format: AudioFormat::PcmS24le,
159 sequence: 42,
160 stream_id: 0xDEADBEEF,
161 pts_ns: 1_000_000_000,
162 sample_offset: 192000,
163 payload_len: 1440,
164 };
165 let mut buf = [0u8; AUDIO_HEADER_SIZE];
166 hdr.encode(&mut buf);
167 let decoded = AudioPacketHeader::decode(&buf).unwrap();
168 assert_eq!(hdr, decoded);
169 }
170
171 #[test]
172 fn clock_sync_roundtrip() {
173 let pkt = ClockSyncPacket {
174 version: 1,
175 kind: ClockSyncType::Response,
176 sequence: 7,
177 t1: 100_000,
178 t2: 100_050,
179 t3: 100_060,
180 };
181 let mut buf = [0u8; ClockSyncPacket::SIZE];
182 pkt.encode(&mut buf);
183 let decoded = ClockSyncPacket::decode(&buf).unwrap();
184 assert_eq!(pkt, decoded);
185 }
186
187 #[test]
188 fn clock_offset_calculation() {
189 let offset = ClockSyncPacket::compute_offset(100, 200, 210, 310);
190 assert_eq!(offset, 0);
191
192 let rtt = ClockSyncPacket::compute_rtt(100, 200, 210, 310);
193 assert_eq!(rtt, 200);
194 }
195}