1use std::fmt;
4use std::time::Duration;
5
6use crate::error::FrameError;
7use crate::{SampleFormat, Timestamp};
8
9use super::AudioFrame;
10
11impl AudioFrame {
12 pub fn new(
51 planes: Vec<Vec<u8>>,
52 samples: usize,
53 channels: u32,
54 sample_rate: u32,
55 format: SampleFormat,
56 timestamp: Timestamp,
57 ) -> Result<Self, FrameError> {
58 let expected_planes = if format.is_planar() {
59 channels as usize
60 } else {
61 1
62 };
63
64 if planes.len() != expected_planes {
65 return Err(FrameError::InvalidPlaneCount {
66 expected: expected_planes,
67 actual: planes.len(),
68 });
69 }
70
71 Ok(Self {
72 planes,
73 samples,
74 channels,
75 sample_rate,
76 format,
77 timestamp,
78 })
79 }
80
81 pub fn empty(
109 samples: usize,
110 channels: u32,
111 sample_rate: u32,
112 format: SampleFormat,
113 ) -> Result<Self, FrameError> {
114 if matches!(format, SampleFormat::Other(_)) {
115 return Err(FrameError::UnsupportedSampleFormat(format));
116 }
117
118 let planes = Self::allocate_planes(samples, channels, format);
119
120 Ok(Self {
121 planes,
122 samples,
123 channels,
124 sample_rate,
125 format,
126 timestamp: Timestamp::default(),
127 })
128 }
129
130 #[doc(hidden)]
136 #[must_use]
137 pub fn new_silent(sample_rate: u32, channels: u32, format: SampleFormat, pts_ms: i64) -> Self {
138 let samples = 1024usize;
139 let bps = format.bytes_per_sample();
140 let planes = if format.is_planar() {
141 (0..channels as usize)
142 .map(|_| vec![0u8; samples * bps])
143 .collect()
144 } else {
145 vec![vec![0u8; samples * channels as usize * bps]]
146 };
147 let timestamp = Timestamp::from_millis(pts_ms, crate::Rational::new(1, 1000));
148 Self {
149 planes,
150 samples,
151 channels,
152 sample_rate,
153 format,
154 timestamp,
155 }
156 }
157
158 pub(super) fn allocate_planes(
160 samples: usize,
161 channels: u32,
162 format: SampleFormat,
163 ) -> Vec<Vec<u8>> {
164 let bytes_per_sample = format.bytes_per_sample();
165
166 if format.is_planar() {
167 let plane_size = samples * bytes_per_sample;
169 (0..channels).map(|_| vec![0u8; plane_size]).collect()
170 } else {
171 let total_size = samples * channels as usize * bytes_per_sample;
173 vec![vec![0u8; total_size]]
174 }
175 }
176
177 #[must_use]
192 #[inline]
193 pub const fn samples(&self) -> usize {
194 self.samples
195 }
196
197 #[must_use]
217 #[inline]
218 pub const fn channels(&self) -> u32 {
219 self.channels
220 }
221
222 #[must_use]
233 #[inline]
234 pub const fn sample_rate(&self) -> u32 {
235 self.sample_rate
236 }
237
238 #[must_use]
250 #[inline]
251 pub const fn format(&self) -> SampleFormat {
252 self.format
253 }
254
255 #[must_use]
268 #[inline]
269 pub const fn timestamp(&self) -> Timestamp {
270 self.timestamp
271 }
272
273 #[inline]
286 pub fn set_timestamp(&mut self, timestamp: Timestamp) {
287 self.timestamp = timestamp;
288 }
289
290 #[must_use]
309 #[allow(clippy::cast_precision_loss)] pub fn duration(&self) -> Duration {
311 if self.sample_rate == 0 {
312 log::warn!(
313 "duration unavailable, sample_rate is 0, returning zero \
314 samples={} fallback=Duration::ZERO",
315 self.samples
316 );
317 return Duration::ZERO;
318 }
319 let secs = self.samples as f64 / f64::from(self.sample_rate);
320 Duration::from_secs_f64(secs)
321 }
322}
323
324impl fmt::Debug for AudioFrame {
325 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 f.debug_struct("AudioFrame")
327 .field("samples", &self.samples)
328 .field("channels", &self.channels)
329 .field("sample_rate", &self.sample_rate)
330 .field("format", &self.format)
331 .field("timestamp", &self.timestamp)
332 .field("num_planes", &self.planes.len())
333 .field(
334 "plane_sizes",
335 &self.planes.iter().map(Vec::len).collect::<Vec<_>>(),
336 )
337 .finish()
338 }
339}
340
341impl fmt::Display for AudioFrame {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 let duration_ms = self.duration().as_secs_f64() * 1000.0;
344 write!(
345 f,
346 "AudioFrame({} samples, {}ch, {}Hz, {} @ {}, {:.2}ms)",
347 self.samples, self.channels, self.sample_rate, self.format, self.timestamp, duration_ms
348 )
349 }
350}
351
352impl Default for AudioFrame {
353 fn default() -> Self {
355 Self {
356 planes: vec![vec![]],
357 samples: 0,
358 channels: 1,
359 sample_rate: 48000,
360 format: SampleFormat::F32,
361 timestamp: Timestamp::default(),
362 }
363 }
364}
365
366#[cfg(test)]
367#[allow(clippy::unwrap_used, clippy::redundant_closure_for_method_calls)]
368mod tests {
369 use super::*;
370 use crate::Rational;
371
372 #[test]
373 fn test_new_packed_f32() {
374 let samples = 1024;
375 let channels = 2u32;
376 let bytes_per_sample = 4;
377 let data = vec![0u8; samples * channels as usize * bytes_per_sample];
378
379 let frame = AudioFrame::new(
380 vec![data],
381 samples,
382 channels,
383 48000,
384 SampleFormat::F32,
385 Timestamp::default(),
386 )
387 .unwrap();
388
389 assert_eq!(frame.samples(), 1024);
390 assert_eq!(frame.channels(), 2);
391 assert_eq!(frame.sample_rate(), 48000);
392 assert_eq!(frame.format(), SampleFormat::F32);
393 assert_eq!(frame.num_planes(), 1);
394 }
395
396 #[test]
397 fn test_new_planar_f32p() {
398 let samples = 1024;
399 let channels = 2u32;
400 let bytes_per_sample = 4;
401 let plane_size = samples * bytes_per_sample;
402
403 let planes = vec![vec![0u8; plane_size], vec![0u8; plane_size]];
404
405 let frame = AudioFrame::new(
406 planes,
407 samples,
408 channels,
409 48000,
410 SampleFormat::F32p,
411 Timestamp::default(),
412 )
413 .unwrap();
414
415 assert_eq!(frame.samples(), 1024);
416 assert_eq!(frame.channels(), 2);
417 assert_eq!(frame.format(), SampleFormat::F32p);
418 assert_eq!(frame.num_planes(), 2);
419 }
420
421 #[test]
422 fn test_new_invalid_plane_count_packed() {
423 let result = AudioFrame::new(
425 vec![vec![0u8; 100], vec![0u8; 100]],
426 100,
427 2,
428 48000,
429 SampleFormat::F32,
430 Timestamp::default(),
431 );
432
433 assert!(result.is_err());
434 assert_eq!(
435 result.unwrap_err(),
436 FrameError::InvalidPlaneCount {
437 expected: 1,
438 actual: 2
439 }
440 );
441 }
442
443 #[test]
444 fn test_new_invalid_plane_count_planar() {
445 let result = AudioFrame::new(
447 vec![vec![0u8; 100]],
448 100,
449 2,
450 48000,
451 SampleFormat::F32p,
452 Timestamp::default(),
453 );
454
455 assert!(result.is_err());
456 assert_eq!(
457 result.unwrap_err(),
458 FrameError::InvalidPlaneCount {
459 expected: 2,
460 actual: 1
461 }
462 );
463 }
464
465 #[test]
466 fn test_empty_packed() {
467 let frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32).unwrap();
468
469 assert_eq!(frame.samples(), 1024);
470 assert_eq!(frame.channels(), 2);
471 assert_eq!(frame.sample_rate(), 48000);
472 assert_eq!(frame.format(), SampleFormat::F32);
473 assert_eq!(frame.num_planes(), 1);
474 assert_eq!(frame.total_size(), 1024 * 2 * 4);
475 }
476
477 #[test]
478 fn test_empty_planar() {
479 let frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32p).unwrap();
480
481 assert_eq!(frame.num_planes(), 2);
482 assert_eq!(frame.plane(0).map(|p| p.len()), Some(1024 * 4));
483 assert_eq!(frame.plane(1).map(|p| p.len()), Some(1024 * 4));
484 assert_eq!(frame.total_size(), 1024 * 2 * 4);
485 }
486
487 #[test]
488 fn test_empty_i16() {
489 let frame = AudioFrame::empty(1024, 2, 44100, SampleFormat::I16).unwrap();
490
491 assert_eq!(frame.bytes_per_sample(), 2);
492 assert_eq!(frame.total_size(), 1024 * 2 * 2);
493 }
494
495 #[test]
496 fn test_empty_other_format_error() {
497 let result = AudioFrame::empty(1024, 2, 48000, SampleFormat::Other(999));
498
499 assert!(result.is_err());
500 assert_eq!(
501 result.unwrap_err(),
502 FrameError::UnsupportedSampleFormat(SampleFormat::Other(999))
503 );
504 }
505
506 #[test]
507 fn test_default() {
508 let frame = AudioFrame::default();
509
510 assert_eq!(frame.samples(), 0);
511 assert_eq!(frame.channels(), 1);
512 assert_eq!(frame.sample_rate(), 48000);
513 assert_eq!(frame.format(), SampleFormat::F32);
514 }
515
516 #[test]
517 fn test_duration() {
518 let frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32).unwrap();
520 let duration = frame.duration();
521 assert!((duration.as_secs_f64() - 0.021_333_333).abs() < 0.000_001);
522
523 let frame = AudioFrame::empty(48000, 2, 48000, SampleFormat::F32).unwrap();
525 assert_eq!(frame.duration().as_secs(), 1);
526 }
527
528 #[test]
529 fn test_duration_zero_sample_rate() {
530 let frame = AudioFrame::new(
531 vec![vec![]],
532 0,
533 1,
534 0,
535 SampleFormat::F32,
536 Timestamp::default(),
537 )
538 .unwrap();
539
540 assert_eq!(frame.duration(), Duration::ZERO);
541 }
542
543 #[test]
544 fn test_set_timestamp() {
545 let mut frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32).unwrap();
546 let ts = Timestamp::new(48000, Rational::new(1, 48000));
547
548 frame.set_timestamp(ts);
549 assert_eq!(frame.timestamp(), ts);
550 }
551
552 #[test]
553 fn test_clone() {
554 let mut original = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32).unwrap();
555 original.set_timestamp(Timestamp::new(1000, Rational::new(1, 1000)));
556
557 if let Some(data) = original.plane_mut(0) {
559 data[0] = 42;
560 }
561
562 let cloned = original.clone();
563
564 assert_eq!(cloned.samples(), original.samples());
566 assert_eq!(cloned.channels(), original.channels());
567 assert_eq!(cloned.sample_rate(), original.sample_rate());
568 assert_eq!(cloned.format(), original.format());
569 assert_eq!(cloned.timestamp(), original.timestamp());
570
571 assert_eq!(cloned.plane(0).unwrap()[0], 42);
573
574 let mut cloned = cloned;
576 if let Some(data) = cloned.plane_mut(0) {
577 data[0] = 99;
578 }
579 assert_eq!(original.plane(0).unwrap()[0], 42);
580 assert_eq!(cloned.plane(0).unwrap()[0], 99);
581 }
582
583 #[test]
584 fn audio_frame_clone_should_have_identical_data() {
585 let samples = 512;
586 let channels = 2u32;
587 let bytes_per_sample = 4; let plane_data = vec![7u8; samples * bytes_per_sample];
589 let ts = Timestamp::new(500, Rational::new(1, 1000));
590
591 let original = AudioFrame::new(
592 vec![plane_data.clone()],
593 samples,
594 channels,
595 44100,
596 SampleFormat::F32,
597 ts,
598 )
599 .unwrap();
600
601 let clone = original.clone();
602
603 assert_eq!(clone.samples(), original.samples());
604 assert_eq!(clone.channels(), original.channels());
605 assert_eq!(clone.sample_rate(), original.sample_rate());
606 assert_eq!(clone.format(), original.format());
607 assert_eq!(clone.timestamp(), original.timestamp());
608 assert_eq!(clone.num_planes(), original.num_planes());
609 assert_eq!(clone.plane(0), original.plane(0));
610 }
611
612 #[test]
613 fn test_debug() {
614 let frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32).unwrap();
615 let debug = format!("{frame:?}");
616 assert!(debug.contains("AudioFrame"));
617 assert!(debug.contains("1024"));
618 assert!(debug.contains("48000"));
619 assert!(debug.contains("F32"));
620 }
621
622 #[test]
623 fn test_display() {
624 let frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32).unwrap();
625 let display = format!("{frame}");
626 assert!(display.contains("1024 samples"));
627 assert!(display.contains("2ch"));
628 assert!(display.contains("48000Hz"));
629 assert!(display.contains("flt")); }
631}