moq_mux/codec/flac/
mod.rs1mod import;
10
11pub use import::*;
12
13use bytes::{Buf, BufMut, Bytes};
14
15const MARKER: [u8; 4] = *b"fLaC";
18
19const STREAMINFO_LEN: usize = 34;
21
22#[derive(Debug, Clone, thiserror::Error)]
24#[non_exhaustive]
25pub enum Error {
26 #[error("buffer too short for FLAC STREAMINFO")]
28 Short,
29
30 #[error("invalid FLAC stream marker")]
32 InvalidMarker,
33
34 #[error("first metadata block is not STREAMINFO")]
36 MissingStreamInfo,
37}
38
39pub type Result<T> = std::result::Result<T, Error>;
40
41#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct Config {
45 pub min_block_size: u16,
47 pub max_block_size: u16,
49 pub min_frame_size: u32,
51 pub max_frame_size: u32,
53 pub sample_rate: u32,
55 pub channel_count: u32,
57 pub bits_per_sample: u32,
59 pub total_samples: u64,
61 pub md5: [u8; 16],
63}
64
65impl Config {
66 pub fn parse_stream_info<T: Buf>(buf: &mut T) -> Result<Self> {
69 if buf.remaining() < STREAMINFO_LEN {
70 return Err(Error::Short);
71 }
72
73 let min_block_size = buf.get_u16();
74 let max_block_size = buf.get_u16();
75 let min_frame_size = buf.get_uint(3) as u32;
76 let max_frame_size = buf.get_uint(3) as u32;
77
78 let packed = buf.get_u64();
81 let sample_rate = (packed >> 44) as u32;
82 let channel_count = (((packed >> 41) & 0x7) as u32) + 1;
83 let bits_per_sample = (((packed >> 36) & 0x1f) as u32) + 1;
84 let total_samples = packed & 0xF_FFFF_FFFF;
85
86 let mut md5 = [0u8; 16];
87 buf.copy_to_slice(&mut md5);
88
89 Ok(Self {
90 min_block_size,
91 max_block_size,
92 min_frame_size,
93 max_frame_size,
94 sample_rate,
95 channel_count,
96 bits_per_sample,
97 total_samples,
98 md5,
99 })
100 }
101
102 pub fn parse<T: Buf>(buf: &mut T) -> Result<Self> {
107 if buf.remaining() < 4 {
108 return Err(Error::Short);
109 }
110 let mut marker = [0u8; 4];
111 buf.copy_to_slice(&mut marker);
112 if marker != MARKER {
113 return Err(Error::InvalidMarker);
114 }
115
116 if buf.remaining() < 4 {
117 return Err(Error::Short);
118 }
119 let header = buf.get_u32();
121 let block_type = ((header >> 24) & 0x7f) as u8;
122 if block_type != 0 {
123 return Err(Error::MissingStreamInfo);
124 }
125
126 Self::parse_stream_info(buf)
127 }
128
129 pub fn encode_stream_info(&self) -> Bytes {
131 let mut buf = Vec::with_capacity(STREAMINFO_LEN);
132 buf.put_u16(self.min_block_size);
133 buf.put_u16(self.max_block_size);
134 buf.put_uint(self.min_frame_size as u64, 3);
135 buf.put_uint(self.max_frame_size as u64, 3);
136
137 let packed = ((self.sample_rate as u64 & 0xF_FFFF) << 44)
138 | ((self.channel_count.saturating_sub(1) as u64 & 0x7) << 41)
139 | ((self.bits_per_sample.saturating_sub(1) as u64 & 0x1f) << 36)
140 | (self.total_samples & 0xF_FFFF_FFFF);
141 buf.put_u64(packed);
142 buf.put_slice(&self.md5);
143
144 buf.into()
145 }
146
147 pub fn description(&self) -> Bytes {
152 let stream_info = self.encode_stream_info();
153 let mut buf = Vec::with_capacity(MARKER.len() + 4 + stream_info.len());
154 buf.put_slice(&MARKER);
155 buf.put_u8(0x80);
157 buf.put_uint(stream_info.len() as u64, 3);
158 buf.put_slice(&stream_info);
159 buf.into()
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 fn sample() -> Config {
168 Config {
169 min_block_size: 4608,
170 max_block_size: 4608,
171 min_frame_size: 16,
172 max_frame_size: 9102,
173 sample_rate: 44_100,
174 channel_count: 2,
175 bits_per_sample: 24,
176 total_samples: 120_832,
177 md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
178 }
179 }
180
181 #[test]
182 fn stream_info_roundtrip() {
183 let cfg = sample();
184 let encoded = cfg.encode_stream_info();
185 assert_eq!(encoded.len(), STREAMINFO_LEN);
186 let parsed = Config::parse_stream_info(&mut encoded.as_ref()).unwrap();
187 assert_eq!(parsed, cfg);
188 }
189
190 #[test]
191 fn description_roundtrip() {
192 let cfg = sample();
193 let desc = cfg.description();
194 assert_eq!(desc.len(), 4 + 4 + STREAMINFO_LEN);
196 assert_eq!(&desc[..4], b"fLaC");
197 assert_eq!(desc[4], 0x80);
199
200 let parsed = Config::parse(&mut desc.as_ref()).unwrap();
202 assert_eq!(parsed, cfg);
203 }
204
205 #[test]
206 fn parse_rejects_bad_marker() {
207 let mut desc = sample().description().to_vec();
208 desc[0] = b'X';
209 assert!(matches!(Config::parse(&mut desc.as_slice()), Err(Error::InvalidMarker)));
210 }
211
212 #[test]
213 fn parse_rejects_non_streaminfo_first_block() {
214 let mut desc = sample().description().to_vec();
215 desc[4] = 0x80 | 0x04; assert!(matches!(
218 Config::parse(&mut desc.as_slice()),
219 Err(Error::MissingStreamInfo)
220 ));
221 }
222}