1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
12#[repr(u8)]
13pub enum PacketClass {
14 #[default]
18 Core = 0x00,
19
20 Perceptual = 0x01,
24
25 Enhancement = 0x02,
29
30 Cosmetic = 0x03,
34
35 Repair = 0x04,
39}
40
41impl PacketClass {
42 pub fn from_byte(b: u8) -> Option<Self> {
44 match b {
45 0x00 => Some(PacketClass::Core),
46 0x01 => Some(PacketClass::Perceptual),
47 0x02 => Some(PacketClass::Enhancement),
48 0x03 => Some(PacketClass::Cosmetic),
49 0x04 => Some(PacketClass::Repair),
50 _ => None,
51 }
52 }
53
54 #[inline]
56 pub fn to_byte(self) -> u8 {
57 self as u8
58 }
59
60 pub fn redundancy(self) -> u8 {
62 match self {
63 PacketClass::Core => 3,
64 PacketClass::Perceptual => 1,
65 PacketClass::Enhancement => 1,
66 PacketClass::Cosmetic => 1,
67 PacketClass::Repair => 2,
68 }
69 }
70
71 pub fn is_droppable(self) -> bool {
73 match self {
74 PacketClass::Core => false,
75 PacketClass::Perceptual => false, PacketClass::Enhancement => true,
77 PacketClass::Cosmetic => true,
78 PacketClass::Repair => false,
79 }
80 }
81
82 pub fn priority(self) -> u8 {
84 match self {
85 PacketClass::Core => 0,
86 PacketClass::Perceptual => 1,
87 PacketClass::Repair => 2,
88 PacketClass::Enhancement => 3,
89 PacketClass::Cosmetic => 4,
90 }
91 }
92
93 pub fn ratchet_frequency(self) -> u32 {
95 match self {
96 PacketClass::Core => 100,
97 PacketClass::Perceptual => 1000,
98 PacketClass::Enhancement => 500,
99 PacketClass::Cosmetic => 2000,
100 PacketClass::Repair => 50,
101 }
102 }
103
104 pub fn replay_window_size(self) -> u16 {
106 match self {
107 PacketClass::Core => 64,
108 PacketClass::Perceptual => 256, PacketClass::Enhancement => 128,
110 PacketClass::Cosmetic => 32,
111 PacketClass::Repair => 32,
112 }
113 }
114}
115
116#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
118#[repr(u8)]
119pub enum RepresentationProfile {
120 #[default]
122 Textual = 0x00,
123
124 VoiceMinimal = 0x10,
126 VoiceStandard = 0x11,
128 VoiceHigh = 0x12,
130
131 VideoLow = 0x20,
133 VideoStandard = 0x21,
135 VideoHigh = 0x22,
137
138 StreamAsymmetric = 0x30,
140
141 Agent = 0x40,
143
144 Custom = 0xFF,
146}
147
148impl RepresentationProfile {
149 pub fn from_byte(b: u8) -> Self {
150 match b {
151 0x00 => RepresentationProfile::Textual,
152 0x10 => RepresentationProfile::VoiceMinimal,
153 0x11 => RepresentationProfile::VoiceStandard,
154 0x12 => RepresentationProfile::VoiceHigh,
155 0x20 => RepresentationProfile::VideoLow,
156 0x21 => RepresentationProfile::VideoStandard,
157 0x22 => RepresentationProfile::VideoHigh,
158 0x30 => RepresentationProfile::StreamAsymmetric,
159 0x40 => RepresentationProfile::Agent,
160 _ => RepresentationProfile::Custom,
161 }
162 }
163
164 #[inline]
165 pub fn to_byte(self) -> u8 {
166 self as u8
167 }
168
169 pub fn is_msp_supported(self) -> bool {
171 matches!(
172 self,
173 RepresentationProfile::Textual | RepresentationProfile::VoiceMinimal
174 )
175 }
176}
177
178#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
180pub enum StateType {
181 Core,
183 Perceptual,
185 Enhancement,
187 Cosmetic,
189}
190
191impl StateType {
192 pub fn to_packet_class(self) -> PacketClass {
194 match self {
195 StateType::Core => PacketClass::Core,
196 StateType::Perceptual => PacketClass::Perceptual,
197 StateType::Enhancement => PacketClass::Enhancement,
198 StateType::Cosmetic => PacketClass::Cosmetic,
199 }
200 }
201
202 pub fn importance(self) -> f64 {
204 match self {
205 StateType::Core => 1.0,
206 StateType::Perceptual => 0.7,
207 StateType::Enhancement => 0.3,
208 StateType::Cosmetic => 0.1,
209 }
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
218 fn test_packet_class_roundtrip() {
219 for class in [
220 PacketClass::Core,
221 PacketClass::Perceptual,
222 PacketClass::Enhancement,
223 PacketClass::Cosmetic,
224 PacketClass::Repair,
225 ] {
226 let byte = class.to_byte();
227 let recovered = PacketClass::from_byte(byte).unwrap();
228 assert_eq!(class, recovered);
229 }
230 }
231
232 #[test]
233 fn test_profile_msp_support() {
234 assert!(RepresentationProfile::Textual.is_msp_supported());
235 assert!(RepresentationProfile::VoiceMinimal.is_msp_supported());
236 assert!(!RepresentationProfile::VideoStandard.is_msp_supported());
237 }
238
239 #[test]
240 fn test_class_priority_ordering() {
241 assert!(PacketClass::Core.priority() < PacketClass::Perceptual.priority());
242 assert!(PacketClass::Perceptual.priority() < PacketClass::Enhancement.priority());
243 assert!(PacketClass::Enhancement.priority() < PacketClass::Cosmetic.priority());
244 }
245}