fuchsia_bluetooth/assigned_numbers/
ltv.rs
1use bitflags::bitflags;
6
7#[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, 0x02, 0x02, 0x00, 0x05, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x04, 0x3A, 0x00, 0x02, 0x05, 0x28,
133 ]
134 );
135 assert_eq!(
136 config.to_be_bytes(),
137 vec![
138 0x02, 0x01, 0x06, 0x02, 0x02, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x04, 0x00, 0x3A, 0x02, 0x05, 0x28, ]
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, 0x02, 0x02, 0x01, 0x03, 0x04, 0x28, 0x00, ]
160 );
161 assert_eq!(
162 config.to_be_bytes(),
163 vec![
164 0x02, 0x01, 0x06, 0x02, 0x02, 0x01, 0x03, 0x04, 0x00, 0x28, ]
168 );
169 }
170}