1use crate::{CodecError, CodecResult};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum SampleFormat {
11 F32,
13 I16,
15 I32,
17 U8,
19}
20
21impl SampleFormat {
22 #[must_use]
24 pub const fn sample_size(&self) -> usize {
25 match self {
26 Self::F32 => 4,
27 Self::I16 => 2,
28 Self::I32 => 4,
29 Self::U8 => 1,
30 }
31 }
32
33 #[must_use]
35 pub const fn is_float(&self) -> bool {
36 matches!(self, Self::F32)
37 }
38
39 #[must_use]
41 pub const fn is_signed(&self) -> bool {
42 !matches!(self, Self::U8)
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum ChannelLayout {
49 Mono,
51 Stereo,
53 Surround51,
55 Surround71,
57 Custom(u8),
59}
60
61impl ChannelLayout {
62 #[must_use]
64 pub const fn channel_count(&self) -> usize {
65 match self {
66 Self::Mono => 1,
67 Self::Stereo => 2,
68 Self::Surround51 => 6,
69 Self::Surround71 => 8,
70 Self::Custom(n) => *n as usize,
71 }
72 }
73}
74
75#[derive(Debug, Clone)]
80pub struct AudioFrame {
81 pub samples: Vec<u8>,
83 pub sample_count: usize,
85 pub sample_rate: u32,
87 pub channels: usize,
89 pub format: SampleFormat,
91 pub pts: Option<i64>,
93 pub duration: Option<u64>,
95}
96
97impl AudioFrame {
98 pub fn new(
108 samples: Vec<u8>,
109 sample_count: usize,
110 sample_rate: u32,
111 channels: usize,
112 format: SampleFormat,
113 ) -> Self {
114 Self {
115 samples,
116 sample_count,
117 sample_rate,
118 channels,
119 format,
120 pts: None,
121 duration: None,
122 }
123 }
124
125 pub fn with_timing(
127 samples: Vec<u8>,
128 sample_count: usize,
129 sample_rate: u32,
130 channels: usize,
131 format: SampleFormat,
132 pts: i64,
133 duration: u64,
134 ) -> Self {
135 Self {
136 samples,
137 sample_count,
138 sample_rate,
139 channels,
140 format,
141 pts: Some(pts),
142 duration: Some(duration),
143 }
144 }
145
146 #[must_use]
148 pub const fn total_samples(&self) -> usize {
149 self.sample_count * self.channels
150 }
151
152 #[must_use]
154 pub fn byte_size(&self) -> usize {
155 self.total_samples() * self.format.sample_size()
156 }
157
158 #[must_use]
160 pub fn duration_seconds(&self) -> f64 {
161 f64::from(self.sample_count as u32) / f64::from(self.sample_rate)
162 }
163
164 #[allow(dead_code)]
169 fn as_f32_internal(&self) -> CodecResult<Vec<f32>> {
170 if self.format != SampleFormat::F32 {
171 return Err(CodecError::InvalidData(
172 "Sample format is not F32".to_string(),
173 ));
174 }
175 if self.samples.len() % 4 != 0 {
176 return Err(CodecError::InvalidData(
177 "Sample data length is not a multiple of 4".to_string(),
178 ));
179 }
180 let mut result = Vec::with_capacity(self.samples.len() / 4);
181 for chunk in self.samples.chunks_exact(4) {
182 let bytes: [u8; 4] = [chunk[0], chunk[1], chunk[2], chunk[3]];
183 result.push(f32::from_le_bytes(bytes));
184 }
185 Ok(result)
186 }
187
188 #[allow(dead_code)]
193 fn as_i16_internal(&self) -> CodecResult<Vec<i16>> {
194 if self.format != SampleFormat::I16 {
195 return Err(CodecError::InvalidData(
196 "Sample format is not I16".to_string(),
197 ));
198 }
199 if self.samples.len() % 2 != 0 {
200 return Err(CodecError::InvalidData(
201 "Sample data length is not a multiple of 2".to_string(),
202 ));
203 }
204 let mut result = Vec::with_capacity(self.samples.len() / 2);
205 for chunk in self.samples.chunks_exact(2) {
206 let bytes: [u8; 2] = [chunk[0], chunk[1]];
207 result.push(i16::from_le_bytes(bytes));
208 }
209 Ok(result)
210 }
211
212 pub fn to_f32(&self) -> CodecResult<Vec<f32>> {
214 match self.format {
215 SampleFormat::F32 => {
216 if self.samples.len() % 4 != 0 {
217 return Err(CodecError::InvalidData(
218 "Sample data length is not a multiple of 4".to_string(),
219 ));
220 }
221 let mut result = Vec::with_capacity(self.samples.len() / 4);
222 for chunk in self.samples.chunks_exact(4) {
223 let bytes: [u8; 4] = [chunk[0], chunk[1], chunk[2], chunk[3]];
224 result.push(f32::from_le_bytes(bytes));
225 }
226 Ok(result)
227 }
228 SampleFormat::I16 => {
229 if self.samples.len() % 2 != 0 {
230 return Err(CodecError::InvalidData(
231 "Sample data length is not a multiple of 2".to_string(),
232 ));
233 }
234 let mut result = Vec::with_capacity(self.samples.len() / 2);
235 for chunk in self.samples.chunks_exact(2) {
236 let bytes: [u8; 2] = [chunk[0], chunk[1]];
237 let i16_val = i16::from_le_bytes(bytes);
238 result.push(f32::from(i16_val) / 32768.0);
239 }
240 Ok(result)
241 }
242 _ => Err(CodecError::InvalidData(
243 "Unsupported format conversion".to_string(),
244 )),
245 }
246 }
247
248 pub fn to_i16(&self) -> CodecResult<Vec<i16>> {
250 match self.format {
251 SampleFormat::I16 => {
252 if self.samples.len() % 2 != 0 {
253 return Err(CodecError::InvalidData(
254 "Sample data length is not a multiple of 2".to_string(),
255 ));
256 }
257 let mut result = Vec::with_capacity(self.samples.len() / 2);
258 for chunk in self.samples.chunks_exact(2) {
259 let bytes: [u8; 2] = [chunk[0], chunk[1]];
260 result.push(i16::from_le_bytes(bytes));
261 }
262 Ok(result)
263 }
264 SampleFormat::F32 => {
265 if self.samples.len() % 4 != 0 {
266 return Err(CodecError::InvalidData(
267 "Sample data length is not a multiple of 4".to_string(),
268 ));
269 }
270 let mut result = Vec::with_capacity(self.samples.len() / 4);
271 for chunk in self.samples.chunks_exact(4) {
272 let bytes: [u8; 4] = [chunk[0], chunk[1], chunk[2], chunk[3]];
273 let f32_val = f32::from_le_bytes(bytes);
274 result.push((f32_val.clamp(-1.0, 1.0) * 32767.0) as i16);
275 }
276 Ok(result)
277 }
278 _ => Err(CodecError::InvalidData(
279 "Unsupported format conversion".to_string(),
280 )),
281 }
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 #[test]
290 fn test_sample_format_size() {
291 assert_eq!(SampleFormat::F32.sample_size(), 4);
292 assert_eq!(SampleFormat::I16.sample_size(), 2);
293 assert_eq!(SampleFormat::I32.sample_size(), 4);
294 assert_eq!(SampleFormat::U8.sample_size(), 1);
295 }
296
297 #[test]
298 fn test_channel_layout_count() {
299 assert_eq!(ChannelLayout::Mono.channel_count(), 1);
300 assert_eq!(ChannelLayout::Stereo.channel_count(), 2);
301 assert_eq!(ChannelLayout::Surround51.channel_count(), 6);
302 assert_eq!(ChannelLayout::Surround71.channel_count(), 8);
303 assert_eq!(ChannelLayout::Custom(4).channel_count(), 4);
304 }
305
306 #[test]
307 fn test_audio_frame_creation() {
308 let samples = vec![0u8; 1920 * 2 * 4]; let frame = AudioFrame::new(samples, 1920, 48000, 2, SampleFormat::F32);
310 assert_eq!(frame.sample_count, 1920);
311 assert_eq!(frame.sample_rate, 48000);
312 assert_eq!(frame.channels, 2);
313 assert_eq!(frame.total_samples(), 3840);
314 assert_eq!(frame.byte_size(), 15360);
315 }
316
317 #[test]
318 fn test_audio_frame_duration() {
319 let samples = vec![0u8; 480 * 2 * 4];
320 let frame = AudioFrame::new(samples, 480, 48000, 2, SampleFormat::F32);
321 assert!((frame.duration_seconds() - 0.01).abs() < 0.0001);
322 }
323}