1use crate::{
9 AudioBuffer, CancellationToken, Error, ErrorKind, FrameIndex, Limits, Result, SampleRange,
10 Timeline,
11};
12use std::collections::BTreeMap;
13
14#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct EncodedAudioSample {
21 pub decoded_range: SampleRange,
22 pub data: Vec<u8>,
23}
24
25pub trait AudioDecoder {
29 fn decode(
30 &mut self,
31 sample: &EncodedAudioSample,
32 cancellation: &CancellationToken,
33 ) -> Result<AudioBuffer>;
34 fn reset(&mut self) -> Result<()>;
35}
36
37pub use self::AudioDecoder as AacDecoder;
39
40impl<D: AudioDecoder + ?Sized> AudioDecoder for Box<D> {
41 fn decode(
42 &mut self,
43 sample: &EncodedAudioSample,
44 cancellation: &CancellationToken,
45 ) -> Result<AudioBuffer> {
46 (**self).decode(sample, cancellation)
47 }
48
49 fn reset(&mut self) -> Result<()> {
50 (**self).reset()
51 }
52}
53
54#[derive(Clone, Copy, Debug, Eq, PartialEq)]
59pub struct AudioEdit {
60 pub presentation: SampleRange,
61 pub media_start: Option<u64>,
62}
63
64#[derive(Clone, Debug, Default, Eq, PartialEq)]
66pub struct AudioTrackTiming {
67 pub priming: u32,
68 pub padding: u32,
69 pub track_offset: i64,
71 pub edits: Vec<AudioEdit>,
72}
73
74pub struct AudioSampleReader<D> {
76 decoder: D,
77 packets: Vec<EncodedAudioSample>,
78 decoded: BTreeMap<u64, AudioBuffer>,
79 resident: Option<(usize, usize)>,
85 resident_bytes: u64,
86 timing: AudioTrackTiming,
87 sample_rate: u32,
88 channels: u16,
89 decoded_length: u64,
90 presentation_length: u64,
91 preroll_packets: usize,
92 limits: Limits,
93}
94
95pub type AacSampleReader<D> = AudioSampleReader<D>;
97
98impl<D: AudioDecoder> AudioSampleReader<D> {
99 pub fn new(
103 decoder: D,
104 packets: Vec<EncodedAudioSample>,
105 sample_rate: u32,
106 channels: u16,
107 timing: AudioTrackTiming,
108 preroll_packets: usize,
109 limits: Limits,
110 ) -> Result<Self> {
111 if packets.is_empty() {
112 return Err(invalid("an audio reader requires at least one packet"));
113 }
114 if sample_rate == 0 || sample_rate > limits.max_sample_rate {
115 return Err(limit("audio sample rate is outside configured limits"));
116 }
117 if channels == 0 || channels > limits.max_audio_channels {
118 return Err(limit("audio channel count is outside configured limits"));
119 }
120 let mut expected = 0;
121 for packet in &packets {
122 if packet.decoded_range.start != expected {
123 return Err(invalid("audio packet sample intervals must be contiguous"));
124 }
125 expected = packet.decoded_range.end;
126 }
127 if expected == 0 {
128 return Err(invalid("audio packets decode no samples"));
129 }
130 let trimmed = expected
131 .checked_sub(u64::from(timing.priming) + u64::from(timing.padding))
132 .ok_or_else(|| invalid("audio priming and padding exceed decoded duration"))?;
133 validate_edits(&timing, expected)?;
134 let presentation_length = if timing.edits.is_empty() {
135 if timing.track_offset >= 0 {
136 trimmed.checked_add(timing.track_offset.unsigned_abs())
137 } else {
138 trimmed.checked_sub(timing.track_offset.unsigned_abs())
139 }
140 .ok_or_else(|| invalid("track offset exceeds gapless audio duration"))?
141 } else {
142 timing.edits.iter().try_fold(0, |length, edit| {
143 Ok::<_, Error>(
144 length.max(
145 shifted_edit(*edit, timing.track_offset)?
146 .map_or(0, |shifted| shifted.presentation.end),
147 ),
148 )
149 })?
150 };
151 Ok(Self {
152 decoder,
153 packets,
154 decoded: BTreeMap::new(),
155 resident: None,
156 resident_bytes: 0,
157 timing,
158 sample_rate,
159 channels,
160 decoded_length: expected,
161 presentation_length,
162 preroll_packets,
163 limits,
164 })
165 }
166
167 pub const fn sample_rate(&self) -> u32 {
168 self.sample_rate
169 }
170 pub const fn channels(&self) -> u16 {
171 self.channels
172 }
173 pub const fn presentation_length(&self) -> u64 {
174 self.presentation_length
175 }
176 pub fn timing(&self) -> &AudioTrackTiming {
177 &self.timing
178 }
179
180 pub fn get_range(
182 &mut self,
183 range: SampleRange,
184 cancellation: &CancellationToken,
185 ) -> Result<AudioBuffer> {
186 let (mut output, mappings) = self.start_request(range, cancellation)?;
187 for mapping in mappings {
188 let Some(media) = mapping.media else { continue };
189 if let Some(plan) = self.plan_decode(media)? {
190 if plan.reset {
191 self.decoder.reset()?;
192 }
193 for index in plan.from..=plan.last {
194 if cancellation.is_canceled() {
195 return Err(canceled());
196 }
197 let buffer = self.decoder.decode(&self.packets[index], cancellation)?;
198 self.accept_decoded(&plan, index, buffer)?;
199 }
200 self.evict_behind(plan.first);
201 }
202 self.copy_media(media, mapping.output_offset, &mut output)?;
203 }
204 AudioBuffer::new(range, self.sample_rate, self.channels, output, &self.limits)
205 }
206
207 #[doc(hidden)]
216 pub async fn get_range_with<F>(
217 &mut self,
218 range: SampleRange,
219 cancellation: &CancellationToken,
220 mut decode: F,
221 ) -> Result<AudioBuffer>
222 where
223 F: AsyncFnMut(bool, &[EncodedAudioSample]) -> Result<Vec<AudioBuffer>>,
224 {
225 let (mut output, mappings) = self.start_request(range, cancellation)?;
226 for mapping in mappings {
227 let Some(media) = mapping.media else { continue };
228 if let Some(plan) = self.plan_decode(media)? {
229 let buffers = decode(plan.reset, &self.packets[plan.from..=plan.last]).await?;
230 if cancellation.is_canceled() {
231 return Err(canceled());
232 }
233 if buffers.len() != plan.last - plan.from + 1 {
234 return Err(Error::new(
235 ErrorKind::Codec,
236 "audio decoder returned the wrong number of packets",
237 ));
238 }
239 for (index, buffer) in (plan.from..=plan.last).zip(buffers) {
240 self.accept_decoded(&plan, index, buffer)?;
241 }
242 self.evict_behind(plan.first);
243 }
244 self.copy_media(media, mapping.output_offset, &mut output)?;
245 }
246 AudioBuffer::new(range, self.sample_rate, self.channels, output, &self.limits)
247 }
248
249 fn start_request(
251 &self,
252 range: SampleRange,
253 cancellation: &CancellationToken,
254 ) -> Result<(Vec<f32>, Vec<Mapping>)> {
255 if range.end > self.presentation_length {
256 return Err(invalid("audio request exceeds the presentation duration"));
257 }
258 if cancellation.is_canceled() {
259 return Err(canceled());
260 }
261 let sample_count = range
262 .len()
263 .checked_mul(u64::from(self.channels))
264 .ok_or_else(|| limit("audio request size overflow"))?;
265 let bytes = sample_count
266 .checked_mul(std::mem::size_of::<f32>() as u64)
267 .ok_or_else(|| limit("audio request allocation overflow"))?;
268 if bytes > self.limits.max_allocation_bytes {
269 return Err(limit("audio request exceeds the allocation limit"));
270 }
271 let output = vec![
272 0.0;
273 usize::try_from(sample_count)
274 .map_err(|_| limit("audio request cannot be represented"))?
275 ];
276 Ok((output, self.mappings(range)?))
277 }
278
279 pub fn get(
280 &mut self,
281 timeline: Timeline,
282 frame: FrameIndex,
283 cancellation: &CancellationToken,
284 ) -> Result<AudioBuffer> {
285 if timeline.audio_sample_rate() != self.sample_rate {
286 return Err(invalid("timeline and audio sample rates do not match"));
287 }
288 self.get_range(timeline.audio_interval_for_frame(frame)?, cancellation)
289 }
290
291 pub fn reset(&mut self) -> Result<()> {
293 self.decoder.reset()?;
294 self.discard_resident();
295 Ok(())
296 }
297
298 fn discard_resident(&mut self) {
299 self.decoded.clear();
300 self.resident = None;
301 self.resident_bytes = 0;
302 }
303
304 fn evict_behind(&mut self, keep_from: usize) {
311 let Some((mut start, end)) = self.resident else {
312 return;
313 };
314 let max_packets = self.limits.max_decode_samples_per_seek as usize;
315 while start < keep_from
316 && (end - start + 1 > max_packets
317 || self.resident_bytes > self.limits.max_allocation_bytes)
318 {
319 let range = self.packets[start].decoded_range;
322 if !range.is_empty()
323 && let Some(buffer) = self.decoded.remove(&range.start)
324 {
325 self.resident_bytes = self.resident_bytes.saturating_sub(buffer_bytes(&buffer));
326 }
327 start += 1;
328 }
329 self.resident = Some((start, end));
330 }
331
332 fn mappings(&self, request: SampleRange) -> Result<Vec<Mapping>> {
333 let mut mappings = Vec::new();
334 if self.timing.edits.is_empty() {
335 let presentation_start = self.timing.track_offset.max(0) as u64;
336 let media_start = u64::from(self.timing.priming)
337 .checked_add(self.timing.track_offset.min(0).unsigned_abs())
338 .ok_or_else(|| limit("audio media offset overflow"))?;
339 let playable_end = self.decoded_length - u64::from(self.timing.padding);
340 let length = playable_end.saturating_sub(media_start);
341 let presentation_end = presentation_start
342 .checked_add(length)
343 .ok_or_else(|| limit("audio presentation range overflow"))?;
344 push_intersection(
345 &mut mappings,
346 request,
347 SampleRange::new(presentation_start, presentation_end)?,
348 Some(media_start),
349 )?;
350 } else {
351 for edit in &self.timing.edits {
352 let Some(edit) = shifted_edit(*edit, self.timing.track_offset)? else {
353 continue;
354 };
355 push_intersection(&mut mappings, request, edit.presentation, edit.media_start)?;
356 }
357 }
358 Ok(mappings)
359 }
360
361 fn plan_decode(&mut self, range: SampleRange) -> Result<Option<DecodePlan>> {
372 let first = self
373 .packets
374 .iter()
375 .position(|packet| packet.decoded_range.end > range.start)
376 .ok_or_else(|| invalid("audio edit maps beyond decoded samples"))?;
377 let last = self
378 .packets
379 .iter()
380 .rposition(|packet| packet.decoded_range.start < range.end)
381 .ok_or_else(|| invalid("audio edit maps before decoded samples"))?;
382 let seek_start = first.saturating_sub(self.preroll_packets);
383 if last - seek_start + 1 > self.limits.max_decode_samples_per_seek as usize {
384 return Err(limit(
385 "audio request exceeded the configured decode-work limit",
386 ));
387 }
388 match self.resident {
389 Some((resident_start, resident_end))
390 if first >= resident_start && first <= resident_end + 1 =>
391 {
392 if last <= resident_end {
393 self.evict_behind(first);
394 return Ok(None);
395 }
396 Ok(Some(DecodePlan {
397 reset: false,
398 from: resident_end + 1,
399 last,
400 first,
401 preroll_end: resident_end + 1,
402 }))
403 }
404 _ => {
405 self.discard_resident();
406 Ok(Some(DecodePlan {
407 reset: true,
408 from: seek_start,
409 last,
410 first,
411 preroll_end: first,
412 }))
413 }
414 }
415 }
416
417 fn accept_decoded(
419 &mut self,
420 plan: &DecodePlan,
421 index: usize,
422 buffer: AudioBuffer,
423 ) -> Result<()> {
424 let packet = &self.packets[index];
425 if buffer.range != packet.decoded_range
426 || buffer.sample_rate != self.sample_rate
427 || buffer.channels != self.channels
428 {
429 return Err(Error::new(
430 ErrorKind::Codec,
431 "audio decoder output does not match its packet interval or format",
432 ));
433 }
434 if index < plan.preroll_end {
439 return Ok(());
440 }
441 if !buffer.range.is_empty() {
442 self.resident_bytes = self.resident_bytes.saturating_add(buffer_bytes(&buffer));
443 self.decoded.insert(buffer.range.start, buffer);
444 }
445 self.resident = Some((self.resident.map_or(index, |(start, _)| start), index));
446 Ok(())
447 }
448
449 fn copy_media(&self, range: SampleRange, output_offset: u64, output: &mut [f32]) -> Result<()> {
450 let channels = usize::from(self.channels);
451 for buffer in self
455 .decoded
456 .range(..range.end)
457 .rev()
458 .map(|(_, buffer)| buffer)
459 {
460 if buffer.range.end <= range.start {
461 break;
462 }
463 let start = range.start.max(buffer.range.start);
464 let end = range.end.min(buffer.range.end);
465 if start >= end {
466 continue;
467 }
468 let input_start =
469 usize::try_from((start - buffer.range.start) * u64::from(self.channels))
470 .map_err(|_| limit("audio input offset overflow"))?;
471 let output_start =
472 usize::try_from((output_offset + start - range.start) * u64::from(self.channels))
473 .map_err(|_| limit("audio output offset overflow"))?;
474 let count = usize::try_from(end - start)
475 .map_err(|_| limit("audio copy size overflow"))?
476 .checked_mul(channels)
477 .ok_or_else(|| limit("audio copy size overflow"))?;
478 output[output_start..output_start + count]
479 .copy_from_slice(&buffer.samples[input_start..input_start + count]);
480 }
481 Ok(())
482 }
483}
484
485struct Mapping {
486 media: Option<SampleRange>,
487 output_offset: u64,
488}
489
490struct DecodePlan {
492 reset: bool,
494 from: usize,
495 last: usize,
496 first: usize,
498 preroll_end: usize,
500}
501
502fn push_intersection(
503 out: &mut Vec<Mapping>,
504 request: SampleRange,
505 presentation: SampleRange,
506 media_start: Option<u64>,
507) -> Result<()> {
508 let start = request.start.max(presentation.start);
509 let end = request.end.min(presentation.end);
510 if start >= end {
511 return Ok(());
512 }
513 let media = media_start
514 .map(|base| {
515 let source_start = base
516 .checked_add(start - presentation.start)
517 .ok_or_else(|| limit("audio edit mapping overflow"))?;
518 let source_end = base
519 .checked_add(end - presentation.start)
520 .ok_or_else(|| limit("audio edit mapping overflow"))?;
521 SampleRange::new(source_start, source_end)
522 })
523 .transpose()?;
524 out.push(Mapping {
525 media,
526 output_offset: start - request.start,
527 });
528 Ok(())
529}
530
531fn validate_edits(timing: &AudioTrackTiming, decoded_length: u64) -> Result<()> {
532 let mut end = 0;
533 for edit in &timing.edits {
534 if edit.presentation.start < end || edit.presentation.is_empty() {
535 return Err(invalid(
536 "audio edits must be nonempty and ordered without overlap",
537 ));
538 }
539 if let Some(media_start) = edit.media_start {
540 let media_end = media_start
541 .checked_add(edit.presentation.len())
542 .ok_or_else(|| limit("audio edit range overflow"))?;
543 if media_start < u64::from(timing.priming)
544 || media_end > decoded_length - u64::from(timing.padding)
545 {
546 return Err(invalid(
547 "audio edit includes priming, padding, or samples outside the track",
548 ));
549 }
550 }
551 end = edit.presentation.end;
552 }
553 Ok(())
554}
555
556fn shifted_edit(edit: AudioEdit, offset: i64) -> Result<Option<AudioEdit>> {
557 let shifted_start = i128::from(edit.presentation.start) + i128::from(offset);
558 let shifted_end = i128::from(edit.presentation.end) + i128::from(offset);
559 if shifted_end <= 0 {
560 return Ok(None);
561 }
562 let clipped = shifted_start.min(0).unsigned_abs();
563 let start = u64::try_from(shifted_start.max(0))
564 .map_err(|_| limit("shifted audio edit start cannot be represented"))?;
565 let end = u64::try_from(shifted_end)
566 .map_err(|_| limit("shifted audio edit end cannot be represented"))?;
567 let media_start = edit
568 .media_start
569 .map(|value| {
570 value
571 .checked_add(
572 u64::try_from(clipped)
573 .map_err(|_| limit("shifted audio edit clip cannot be represented"))?,
574 )
575 .ok_or_else(|| limit("shifted audio edit media offset overflow"))
576 })
577 .transpose()?;
578 Ok(Some(AudioEdit {
579 presentation: SampleRange::new(start, end)?,
580 media_start,
581 }))
582}
583
584fn buffer_bytes(buffer: &AudioBuffer) -> u64 {
585 buffer.samples.len() as u64 * std::mem::size_of::<f32>() as u64
586}
587
588fn invalid(message: &str) -> Error {
589 Error::new(ErrorKind::InvalidInput, message)
590}
591fn limit(message: &str) -> Error {
592 Error::new(ErrorKind::ResourceLimit, message)
593}
594fn canceled() -> Error {
595 Error::new(ErrorKind::Canceled, "audio decode canceled")
596}
597
598#[cfg(test)]
599mod tests {
600 use super::*;
601
602 #[derive(Clone, Default)]
603 struct DecoderCounts {
604 resets: std::rc::Rc<std::cell::Cell<usize>>,
605 decodes: std::rc::Rc<std::cell::Cell<usize>>,
606 }
607
608 #[derive(Default)]
609 struct FixtureDecoder {
610 counts: DecoderCounts,
611 }
612
613 impl AudioDecoder for FixtureDecoder {
614 fn decode(
615 &mut self,
616 sample: &EncodedAudioSample,
617 cancellation: &CancellationToken,
618 ) -> Result<AudioBuffer> {
619 if cancellation.is_canceled() {
620 return Err(canceled());
621 }
622 self.counts.decodes.set(self.counts.decodes.get() + 1);
623 let values = (sample.decoded_range.start..sample.decoded_range.end)
624 .map(|value| value as f32)
625 .collect();
626 AudioBuffer::new(sample.decoded_range, 48_000, 1, values, &Limits::default())
627 }
628
629 fn reset(&mut self) -> Result<()> {
630 self.counts.resets.set(self.counts.resets.get() + 1);
631 Ok(())
632 }
633 }
634
635 fn packets_of(count: u64) -> Vec<EncodedAudioSample> {
636 (0..count)
637 .map(|index| EncodedAudioSample {
638 decoded_range: SampleRange::new(index * 4, index * 4 + 4).unwrap(),
639 data: vec![index as u8],
640 })
641 .collect()
642 }
643
644 fn counted_reader(
646 count: u64,
647 preroll: usize,
648 limits: Limits,
649 ) -> (AudioSampleReader<FixtureDecoder>, DecoderCounts) {
650 let decoder = FixtureDecoder::default();
651 let counts = decoder.counts.clone();
652 let reader = AudioSampleReader::new(
653 decoder,
654 packets_of(count),
655 48_000,
656 1,
657 AudioTrackTiming::default(),
658 preroll,
659 limits,
660 )
661 .unwrap();
662 (reader, counts)
663 }
664
665 fn packets() -> Vec<EncodedAudioSample> {
666 (0..3)
667 .map(|index| EncodedAudioSample {
668 decoded_range: SampleRange::new(index * 4, index * 4 + 4).unwrap(),
669 data: vec![index as u8],
670 })
671 .collect()
672 }
673
674 #[test]
675 fn gapless_offset_reads_return_exact_contiguous_ranges() {
676 let timing = AudioTrackTiming {
677 priming: 2,
678 padding: 2,
679 track_offset: 1,
680 edits: Vec::new(),
681 };
682 let mut reader = AudioSampleReader::new(
683 FixtureDecoder::default(),
684 packets(),
685 48_000,
686 1,
687 timing.clone(),
688 1,
689 Limits::default(),
690 )
691 .unwrap();
692 assert_eq!(reader.timing(), &timing);
693 assert_eq!(reader.presentation_length(), 9);
694 let buffer = reader
695 .get_range(SampleRange::new(0, 9).unwrap(), &CancellationToken::new())
696 .unwrap();
697 assert_eq!(buffer.range, SampleRange { start: 0, end: 9 });
698 assert_eq!(
699 buffer.samples,
700 vec![0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
701 );
702 }
703
704 #[test]
705 fn edit_lists_preserve_empty_edits_and_media_mapping() {
706 let timing = AudioTrackTiming {
707 priming: 1,
708 padding: 1,
709 track_offset: 1,
710 edits: vec![
711 AudioEdit {
712 presentation: SampleRange::new(0, 2).unwrap(),
713 media_start: None,
714 },
715 AudioEdit {
716 presentation: SampleRange::new(2, 5).unwrap(),
717 media_start: Some(4),
718 },
719 ],
720 };
721 let mut reader = AudioSampleReader::new(
722 FixtureDecoder::default(),
723 packets(),
724 48_000,
725 1,
726 timing,
727 0,
728 Limits::default(),
729 )
730 .unwrap();
731 let buffer = reader
732 .get_range(SampleRange::new(0, 6).unwrap(), &CancellationToken::new())
733 .unwrap();
734 assert_eq!(buffer.samples, vec![0.0, 0.0, 0.0, 4.0, 5.0, 6.0]);
735 }
736
737 #[test]
738 fn cancellation_stops_decode_before_queued_work_runs() {
739 let mut reader = AudioSampleReader::new(
740 FixtureDecoder::default(),
741 packets(),
742 48_000,
743 1,
744 AudioTrackTiming::default(),
745 0,
746 Limits::default(),
747 )
748 .unwrap();
749 let cancellation = CancellationToken::new();
750 cancellation.cancel();
751 let error = reader
752 .get_range(SampleRange::new(0, 1).unwrap(), &cancellation)
753 .unwrap_err();
754 assert_eq!(error.kind(), ErrorKind::Canceled);
755 }
756
757 #[test]
758 fn forward_sequential_reads_decode_each_packet_once() {
759 let (mut reader, counts) = counted_reader(8, 2, Limits::default());
760 let cancellation = CancellationToken::new();
761 for step in 3..8 {
764 let range = SampleRange::new(step * 4, step * 4 + 4).unwrap();
765 let buffer = reader.get_range(range, &cancellation).unwrap();
766 assert_eq!(
767 buffer.samples,
768 (step * 4..step * 4 + 4)
769 .map(|v| v as f32)
770 .collect::<Vec<_>>()
771 );
772 }
773 assert_eq!(counts.decodes.get(), 7);
776 assert_eq!(counts.resets.get(), 1);
777 }
778
779 #[test]
780 fn backward_and_distant_requests_still_reset_with_preroll() {
781 let (mut reader, counts) = counted_reader(8, 1, Limits::default());
782 let cancellation = CancellationToken::new();
783 reader
784 .get_range(SampleRange::new(12, 16).unwrap(), &cancellation)
785 .unwrap();
786 assert_eq!(counts.resets.get(), 1);
787 reader
789 .get_range(SampleRange::new(0, 4).unwrap(), &cancellation)
790 .unwrap();
791 assert_eq!(counts.resets.get(), 2);
792 let buffer = reader
794 .get_range(SampleRange::new(28, 32).unwrap(), &cancellation)
795 .unwrap();
796 assert_eq!(counts.resets.get(), 3);
797 assert_eq!(buffer.samples, vec![28.0, 29.0, 30.0, 31.0]);
798 }
799
800 #[test]
801 fn resident_packets_stay_within_the_configured_bound() {
802 let limits = Limits {
803 max_decode_samples_per_seek: 3,
804 ..Limits::default()
805 };
806 let (mut reader, _) = counted_reader(16, 0, limits);
807 let cancellation = CancellationToken::new();
808 for step in 0..16 {
809 reader
810 .get_range(
811 SampleRange::new(step * 4, step * 4 + 4).unwrap(),
812 &cancellation,
813 )
814 .unwrap();
815 assert!(reader.decoded.len() <= 3, "resident run grew unbounded");
816 }
817 let limits = Limits {
819 max_allocation_bytes: 16,
822 ..Limits::default()
823 };
824 let (mut reader, _) = counted_reader(16, 0, limits);
825 for step in 0..16 {
826 reader
827 .get_range(
828 SampleRange::new(step * 4, step * 4 + 4).unwrap(),
829 &cancellation,
830 )
831 .unwrap();
832 assert!(reader.decoded.len() <= 2, "allocation bound did not evict");
833 }
834 }
835
836 fn packets_after_an_empty_one(count: u64) -> Vec<EncodedAudioSample> {
839 std::iter::once(EncodedAudioSample {
840 decoded_range: SampleRange::new(0, 0).unwrap(),
841 data: vec![0xff],
842 })
843 .chain(packets_of(count))
844 .collect()
845 }
846
847 #[test]
848 fn a_packet_that_decodes_nothing_is_decoded_but_never_cached() {
849 let decoder = FixtureDecoder::default();
850 let counts = decoder.counts.clone();
851 let mut reader = AudioSampleReader::new(
852 decoder,
853 packets_after_an_empty_one(4),
854 48_000,
855 1,
856 AudioTrackTiming::default(),
857 1,
858 Limits::default(),
859 )
860 .unwrap();
861 assert_eq!(reader.presentation_length(), 16);
862 let cancellation = CancellationToken::new();
863 let buffer = reader
864 .get_range(SampleRange::new(0, 6).unwrap(), &cancellation)
865 .unwrap();
866 assert_eq!(buffer.samples, vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
867 assert_eq!(counts.decodes.get(), 3);
870 assert_eq!(reader.decoded.len(), 2);
871 }
872
873 #[derive(Default)]
876 struct ColdStartDecoder {
877 cold: bool,
878 }
879
880 impl AudioDecoder for ColdStartDecoder {
881 fn decode(
882 &mut self,
883 sample: &EncodedAudioSample,
884 _: &CancellationToken,
885 ) -> Result<AudioBuffer> {
886 let cold = std::mem::take(&mut self.cold);
887 let values = (sample.decoded_range.start..sample.decoded_range.end)
888 .map(|value| if cold { -1.0 } else { value as f32 })
889 .collect();
890 AudioBuffer::new(sample.decoded_range, 48_000, 1, values, &Limits::default())
891 }
892
893 fn reset(&mut self) -> Result<()> {
894 self.cold = true;
895 Ok(())
896 }
897 }
898
899 #[test]
900 fn preroll_output_is_never_served_to_a_later_request() {
901 let mut reader = AudioSampleReader::new(
902 ColdStartDecoder::default(),
903 packets_of(4),
904 48_000,
905 1,
906 AudioTrackTiming::default(),
907 1,
908 Limits::default(),
909 )
910 .unwrap();
911 let cancellation = CancellationToken::new();
912 let later = reader
913 .get_range(SampleRange::new(8, 12).unwrap(), &cancellation)
914 .unwrap();
915 assert_eq!(later.samples, vec![8.0, 9.0, 10.0, 11.0]);
916 let earlier = reader
919 .get_range(SampleRange::new(4, 8).unwrap(), &cancellation)
920 .unwrap();
921 assert_eq!(earlier.samples, vec![4.0, 5.0, 6.0, 7.0]);
922 }
923
924 fn block_on<T>(future: impl std::future::Future<Output = T>) -> T {
925 let mut future = std::pin::pin!(future);
926 let mut context = std::task::Context::from_waker(std::task::Waker::noop());
927 match future.as_mut().poll(&mut context) {
928 std::task::Poll::Ready(value) => value,
929 std::task::Poll::Pending => panic!("the decode closure never suspends"),
930 }
931 }
932
933 #[test]
934 fn an_asynchronous_decoder_is_driven_as_the_readers_own_would_be() {
935 let (mut reader, _) = counted_reader(8, 1, Limits::default());
936 let mut fixture = FixtureDecoder::default();
937 let mut calls = Vec::new();
938 let cancellation = CancellationToken::new();
939 let mut read = |reader: &mut AudioSampleReader<FixtureDecoder>, start: u64, end: u64| {
940 block_on(reader.get_range_with(
941 SampleRange::new(start, end).unwrap(),
942 &cancellation,
943 async |reset, packets: &[EncodedAudioSample]| {
944 calls.push((reset, packets.len()));
945 packets
946 .iter()
947 .map(|packet| fixture.decode(packet, &CancellationToken::new()))
948 .collect()
949 },
950 ))
951 .unwrap()
952 .samples
953 };
954 assert_eq!(read(&mut reader, 12, 16), vec![12.0, 13.0, 14.0, 15.0]);
956 assert_eq!(read(&mut reader, 16, 20), vec![16.0, 17.0, 18.0, 19.0]);
958 assert_eq!(
960 read(&mut reader, 13, 18),
961 vec![13.0, 14.0, 15.0, 16.0, 17.0]
962 );
963 assert_eq!(read(&mut reader, 0, 2), vec![0.0, 1.0]);
965 assert_eq!(calls, vec![(true, 2), (false, 1), (true, 1)]);
966 }
967
968 #[test]
969 fn packets_that_decode_nothing_at_all_are_rejected() {
970 let error = AudioSampleReader::new(
971 FixtureDecoder::default(),
972 vec![EncodedAudioSample {
973 decoded_range: SampleRange::new(0, 0).unwrap(),
974 data: vec![0],
975 }],
976 48_000,
977 1,
978 AudioTrackTiming::default(),
979 0,
980 Limits::default(),
981 )
982 .err()
983 .unwrap();
984 assert_eq!(error.kind(), ErrorKind::InvalidInput);
985 }
986}