1use std::collections::HashSet;
6use std::ops::RangeBounds;
7
8use crate::core::ltv::LtValue;
9
10#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
11pub enum CodecCapabilityType {
12 SupportedSamplingFrequencies,
13 SupportedFrameDurations,
14 SupportedAudioChannelCounts,
15 SupportedOctetsPerCodecFrame,
16 SupportedMaxCodecFramesPerSdu,
17}
18
19impl From<CodecCapabilityType> for u8 {
20 fn from(value: CodecCapabilityType) -> Self {
21 match value {
22 CodecCapabilityType::SupportedSamplingFrequencies => 1,
23 CodecCapabilityType::SupportedFrameDurations => 2,
24 CodecCapabilityType::SupportedAudioChannelCounts => 3,
25 CodecCapabilityType::SupportedOctetsPerCodecFrame => 4,
26 CodecCapabilityType::SupportedMaxCodecFramesPerSdu => 5,
27 }
28 }
29}
30
31#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
32pub enum FrameDurationSupport {
33 SevenFiveMs,
34 TenMs,
35 BothNoPreference,
36 PreferSevenFiveMs,
37 PreferTenMs,
38}
39
40#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
41pub enum SamplingFrequency {
42 F8000Hz,
43 F11025Hz,
44 F16000Hz,
45 F22050Hz,
46 F24000Hz,
47 F32000Hz,
48 F44100Hz,
49 F48000Hz,
50 F88200Hz,
51 F96000Hz,
52 F176400Hz,
53 F192000Hz,
54 F384000Hz,
55}
56
57impl SamplingFrequency {
58 fn bitpos(&self) -> u8 {
59 match self {
60 SamplingFrequency::F8000Hz => 0,
61 SamplingFrequency::F11025Hz => 1,
62 SamplingFrequency::F16000Hz => 2,
63 SamplingFrequency::F22050Hz => 3,
64 SamplingFrequency::F24000Hz => 4,
65 SamplingFrequency::F32000Hz => 5,
66 SamplingFrequency::F44100Hz => 6,
67 SamplingFrequency::F48000Hz => 7,
68 SamplingFrequency::F88200Hz => 8,
69 SamplingFrequency::F96000Hz => 9,
70 SamplingFrequency::F176400Hz => 10,
71 SamplingFrequency::F192000Hz => 11,
72 SamplingFrequency::F384000Hz => 12,
73 }
74 }
75
76 fn from_bitpos(value: u8) -> Option<Self> {
77 match value {
78 0 => Some(SamplingFrequency::F8000Hz),
79 1 => Some(SamplingFrequency::F11025Hz),
80 2 => Some(SamplingFrequency::F16000Hz),
81 3 => Some(SamplingFrequency::F22050Hz),
82 4 => Some(SamplingFrequency::F24000Hz),
83 5 => Some(SamplingFrequency::F32000Hz),
84 6 => Some(SamplingFrequency::F44100Hz),
85 7 => Some(SamplingFrequency::F48000Hz),
86 8 => Some(SamplingFrequency::F88200Hz),
87 9 => Some(SamplingFrequency::F96000Hz),
88 10 => Some(SamplingFrequency::F176400Hz),
89 11 => Some(SamplingFrequency::F192000Hz),
90 12 => Some(SamplingFrequency::F384000Hz),
91 _ => None,
92 }
93 }
94}
95
96#[derive(Clone, PartialEq, Eq, Debug)]
100pub enum CodecCapability {
101 SupportedSamplingFrequencies(std::collections::HashSet<SamplingFrequency>),
102 SupportedFrameDurations(FrameDurationSupport),
103 SupportedAudioChannelCounts(std::collections::HashSet<u8>),
104 SupportedMaxCodecFramesPerSdu(u8),
105 SupportedOctetsPerCodecFrame { min: u16, max: u16 },
106}
107
108impl LtValue for CodecCapability {
109 type Type = CodecCapabilityType;
110
111 const NAME: &'static str = "Codec Compatability";
112
113 fn type_from_octet(x: u8) -> Option<Self::Type> {
114 match x {
115 1 => Some(CodecCapabilityType::SupportedSamplingFrequencies),
116 2 => Some(CodecCapabilityType::SupportedFrameDurations),
117 3 => Some(CodecCapabilityType::SupportedAudioChannelCounts),
118 4 => Some(CodecCapabilityType::SupportedOctetsPerCodecFrame),
119 5 => Some(CodecCapabilityType::SupportedMaxCodecFramesPerSdu),
120 _ => None,
121 }
122 }
123
124 fn length_range_from_type(ty: Self::Type) -> std::ops::RangeInclusive<u8> {
125 match ty {
126 CodecCapabilityType::SupportedAudioChannelCounts => 2..=2,
127 CodecCapabilityType::SupportedFrameDurations => 2..=2,
128 CodecCapabilityType::SupportedMaxCodecFramesPerSdu => 2..=2,
129 CodecCapabilityType::SupportedOctetsPerCodecFrame => 5..=5,
130 CodecCapabilityType::SupportedSamplingFrequencies => 3..=3,
131 }
132 }
133
134 fn into_type(&self) -> Self::Type {
135 match self {
136 CodecCapability::SupportedAudioChannelCounts(_) => {
137 CodecCapabilityType::SupportedAudioChannelCounts
138 }
139 CodecCapability::SupportedFrameDurations(_) => {
140 CodecCapabilityType::SupportedFrameDurations
141 }
142 CodecCapability::SupportedMaxCodecFramesPerSdu(_) => {
143 CodecCapabilityType::SupportedMaxCodecFramesPerSdu
144 }
145 CodecCapability::SupportedOctetsPerCodecFrame { .. } => {
146 CodecCapabilityType::SupportedOctetsPerCodecFrame
147 }
148 CodecCapability::SupportedSamplingFrequencies(_) => {
149 CodecCapabilityType::SupportedSamplingFrequencies
150 }
151 }
152 }
153
154 fn value_encoded_len(&self) -> u8 {
155 let range = Self::length_range_from_type(self.into_type());
157 let std::ops::Bound::Included(len) = range.start_bound() else {
158 unreachable!();
159 };
160 (len - 1).into()
161 }
162
163 fn encode_value(&self, buf: &mut [u8]) -> Result<(), crate::packet_encoding::Error> {
164 match self {
165 CodecCapability::SupportedAudioChannelCounts(counts) => {
166 buf[0] = counts
167 .iter()
168 .fold(0, |acc, count| if *count > 8 { acc } else { acc | (1 << (*count - 1)) });
169 }
170 CodecCapability::SupportedFrameDurations(support) => {
171 buf[0] = match support {
172 FrameDurationSupport::SevenFiveMs => 0b000001,
173 FrameDurationSupport::TenMs => 0b000010,
174 FrameDurationSupport::BothNoPreference => 0b000011,
175 FrameDurationSupport::PreferSevenFiveMs => 0b010011,
176 FrameDurationSupport::PreferTenMs => 0b100011,
177 };
178 }
179 CodecCapability::SupportedMaxCodecFramesPerSdu(max) => {
180 buf[0] = *max;
181 }
182 CodecCapability::SupportedOctetsPerCodecFrame { min, max } => {
183 let min_bytes = min.to_le_bytes();
184 buf[0..=1].copy_from_slice(&min_bytes);
185
186 let max_bytes = max.to_le_bytes();
187 buf[2..=3].copy_from_slice(&max_bytes);
188 }
189 CodecCapability::SupportedSamplingFrequencies(supported) => {
190 let sup_bytes = supported
191 .iter()
192 .fold(0u16, |acc, freq| acc | (1 << freq.bitpos()))
193 .to_le_bytes();
194 buf[0..=1].copy_from_slice(&sup_bytes)
195 }
196 };
197 Ok(())
198 }
199
200 fn decode_value(
201 ty: &CodecCapabilityType,
202 buf: &[u8],
203 ) -> Result<Self, crate::packet_encoding::Error> {
204 match ty {
205 CodecCapabilityType::SupportedAudioChannelCounts => {
206 let mut supported = HashSet::new();
207 for bitpos in 0..8 {
208 if (buf[0] & (1 << bitpos)) != 0 {
209 supported.insert(bitpos + 1);
210 }
211 }
212 Ok(Self::SupportedAudioChannelCounts(supported))
213 }
214 CodecCapabilityType::SupportedFrameDurations => {
215 let support = match buf[0] & 0b110011 {
216 0b000001 => FrameDurationSupport::SevenFiveMs,
217 0b000010 => FrameDurationSupport::TenMs,
218 0b000011 => FrameDurationSupport::BothNoPreference,
219 0b010011 => FrameDurationSupport::PreferSevenFiveMs,
220 0b100011 => FrameDurationSupport::PreferTenMs,
221 _ => {
222 return Err(crate::packet_encoding::Error::InvalidParameter(format!(
223 "Unrecognized bit pattern: {:#b}",
224 buf[0]
225 )));
226 }
227 };
228 Ok(Self::SupportedFrameDurations(support))
229 }
230 CodecCapabilityType::SupportedMaxCodecFramesPerSdu => {
231 Ok(Self::SupportedMaxCodecFramesPerSdu(buf[0]))
232 }
233 CodecCapabilityType::SupportedOctetsPerCodecFrame => {
234 let min = u16::from_le_bytes([buf[0], buf[1]]);
235 let max = u16::from_le_bytes([buf[2], buf[3]]);
236 Ok(Self::SupportedOctetsPerCodecFrame { min, max })
237 }
238 CodecCapabilityType::SupportedSamplingFrequencies => {
239 let bitflags = u16::from_le_bytes([buf[0], buf[1]]);
240 let mut supported = HashSet::new();
241 for bitpos in 0..13 {
242 if bitflags & (1 << bitpos) != 0 {
243 let Some(f) = SamplingFrequency::from_bitpos(bitpos) else {
244 continue;
245 };
246 let _ = supported.insert(f);
247 }
248 }
249 Ok(Self::SupportedSamplingFrequencies(supported))
250 }
251 }
252 }
253}
254
255#[cfg(test)]
256mod tests {}