fuchsia_bluetooth/assigned_numbers/
ltv.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 bitflags::bitflags;
6
7/// See Assigned Numbers section 6.12.5
8/// Codec_Specific_Configuration LTV structures.
9#[derive(Default)]
10pub struct CodecSpecificConfigLTV {
11    pub sampling_frequency: Option<SamplingFrequency>,
12    pub frame_duration: Option<FrameDuration>,
13    pub audio_channel_alloc: Option<AudioLocation>,
14    pub octets_per_codec_frame: Option<u16>,
15    pub codec_frame_blocks_per_sdu: Option<u8>,
16}
17
18bitflags! {
19    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20    pub struct AudioLocation: u32 {
21        const FRONT_LEFT = 0x00000001;
22        const FRONT_RIGHT = 0x00000002;
23        const FRONT_CENTER = 0x00000004;
24        const LOW_FREQUENCY_EFFECTS_1 = 0x00000008;
25        const BACK_LEFT = 0x00000010;
26        const BACK_RIGHT = 0x00000020;
27        const FRONT_LEFT_OF_CENTER = 0x00000040;
28        const FRONT_RIGHT_OF_CENTER = 0x00000080;
29        const BACK_CENTER = 0x00000100;
30        const LOW_FREQUENCY_EFFECTS_2 = 0x00000200;
31        const SIDE_LEFT = 0x00000400;
32        const SIDE_RIGHT = 0x00000800;
33        const TOP_FRONT_LEFT = 0x00001000;
34        const TOP_FRONT_RIGHT = 0x00002000;
35        const TOP_FRONT_CENTER = 0x00004000;
36        const TOP_CENTER = 0x00008000;
37        const TOP_BACK_LEFT = 0x00010000;
38        const TOP_BACK_RIGHT = 0x00020000;
39        const TOP_SIDE_LEFT = 0x00040000;
40        const TOP_SIDE_RIGHT = 0x00080000;
41        const TOP_BACK_CENTER = 0x00100000;
42        const BOTTOM_FRONT_CENTER = 0x00200000;
43        const BOTTOM_FRONT_LEFT = 0x00400000;
44        const BOTTOM_FRONT_RIGHT = 0x00800000;
45        const FRONT_LEFT_WIDE = 0x01000000;
46        const FRONT_RIGHT_WIDE = 0x02000000;
47        const LEFT_SURROUND = 0x04000000;
48        const RIGHT_SURROUND = 0x08000000;
49    }
50}
51
52#[derive(Clone, Copy, Debug)]
53#[repr(u8)]
54pub enum SamplingFrequency {
55    F8000Hz = 0x01,
56    F11025Hz = 0x02,
57    F16000Hz = 0x03,
58    F22050Hz = 0x04,
59    F24000Hz = 0x05,
60    F32000Hz = 0x06,
61    F44100Hz = 0x07,
62    F48000Hz = 0x08,
63    F88200Hz = 0x09,
64    F96000Hz = 0x0A,
65    F176400Hz = 0x0B,
66    F192000Hz = 0x0C,
67    F384000Hz = 0x0D,
68}
69
70#[derive(Clone, Copy, Debug)]
71#[repr(u8)]
72pub enum FrameDuration {
73    D7p5Ms = 0x00,
74    D10Ms = 0x01,
75}
76
77impl CodecSpecificConfigLTV {
78    fn to_bytes(&self, big_endian: bool) -> Vec<u8> {
79        let mut bytes = Vec::new();
80        if let Some(sf) = &self.sampling_frequency {
81            bytes.extend_from_slice(&[0x02, 0x01, *sf as u8]);
82        }
83        if let Some(fd) = &self.frame_duration {
84            bytes.extend_from_slice(&[0x02, 0x02, *fd as u8]);
85        }
86        if let Some(alloc) = &self.audio_channel_alloc {
87            bytes.extend_from_slice(&[0x05, 0x03]);
88            let alloc_bytes =
89                if big_endian { alloc.bits().to_be_bytes() } else { alloc.bits().to_le_bytes() };
90            bytes.extend_from_slice(&alloc_bytes);
91        }
92        if let Some(o) = &self.octets_per_codec_frame {
93            bytes.extend_from_slice(&[0x03, 0x04]);
94            let octet_bytes = if big_endian { o.to_be_bytes() } else { o.to_le_bytes() };
95            bytes.extend_from_slice(&octet_bytes);
96        }
97        if let Some(fb) = &self.codec_frame_blocks_per_sdu {
98            bytes.extend_from_slice(&[0x02, 0x05, *fb]);
99        }
100        return bytes;
101    }
102
103    pub fn to_le_bytes(&self) -> Vec<u8> {
104        self.to_bytes(false)
105    }
106
107    pub fn to_be_bytes(&self) -> Vec<u8> {
108        self.to_bytes(true)
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn test_codec_specific_config_ltv() {
118        let config = CodecSpecificConfigLTV {
119            sampling_frequency: Some(SamplingFrequency::F32000Hz),
120            frame_duration: Some(FrameDuration::D7p5Ms),
121            audio_channel_alloc: Some(AudioLocation::FRONT_LEFT | AudioLocation::FRONT_RIGHT),
122            octets_per_codec_frame: Some(58),
123            codec_frame_blocks_per_sdu: Some(40),
124        };
125        assert_eq!(
126            config.to_le_bytes(),
127            vec![
128                0x02, 0x01, 0x06, // 32kHz sampling freq.
129                0x02, 0x02, 0x00, // 7.5ms frame duration.
130                0x05, 0x03, 0x03, 0x00, 0x00, 0x00, // LF and RF.
131                0x03, 0x04, 0x3A, 0x00, // 58 octets per codec frame.
132                0x02, 0x05, 0x28,
133            ]
134        );
135        assert_eq!(
136            config.to_be_bytes(),
137            vec![
138                0x02, 0x01, 0x06, // 32kHz sampling freq.
139                0x02, 0x02, 0x00, // 7.5ms frame duration.
140                0x05, 0x03, 0x00, 0x00, 0x00, 0x03, // LF and RF.
141                0x03, 0x04, 0x00, 0x3A, // 58 octets per codec frame.
142                0x02, 0x05, 0x28, // 40 frame block.
143            ]
144        );
145
146        let config = CodecSpecificConfigLTV {
147            sampling_frequency: Some(SamplingFrequency::F32000Hz),
148            frame_duration: Some(FrameDuration::D10Ms),
149            audio_channel_alloc: None,
150            octets_per_codec_frame: Some(40),
151            codec_frame_blocks_per_sdu: None,
152        };
153        assert_eq!(
154            config.to_le_bytes(),
155            vec![
156                0x02, 0x01, 0x06, // 32kHz sampling freq.
157                0x02, 0x02, 0x01, // 10ms frame duration.
158                0x03, 0x04, 0x28, 0x00, // 40 octets per codec frame.
159            ]
160        );
161        assert_eq!(
162            config.to_be_bytes(),
163            vec![
164                0x02, 0x01, 0x06, // 32kHz sampling freq.
165                0x02, 0x02, 0x01, // 10ms frame duration.
166                0x03, 0x04, 0x00, 0x28, // 40 octets per codec frame.
167            ]
168        );
169    }
170}