bt_common/generic_audio/
codec_capabilities.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// Codec Capability LTV Structures
97///
98/// Defined in Assigned Numbers Section 6.12.4.
99#[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        // All the CodecCapabilities are constant length. Remove the type octet.
156        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 {}