rodio/source/
delay.rs

1use std::time::Duration;
2
3use crate::{Sample, Source};
4
5use super::SeekError;
6
7fn remaining_samples(until_playback: Duration, sample_rate: u32, channels: u16) -> usize {
8    let ns = until_playback.as_secs() * 1_000_000_000 + until_playback.subsec_nanos() as u64;
9    let samples = ns * channels as u64 * sample_rate as u64 / 1_000_000_000;
10    samples as usize
11}
12
13/// Internal function that builds a `Delay` object.
14pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
15where
16    I: Source,
17    I::Item: Sample,
18{
19    Delay {
20        remaining_samples: remaining_samples(duration, input.sample_rate(), input.channels()),
21        requested_duration: duration,
22        input,
23    }
24}
25
26/// A source that delays the given source by a certain amount.
27#[derive(Clone, Debug)]
28pub struct Delay<I> {
29    input: I,
30    remaining_samples: usize,
31    requested_duration: Duration,
32}
33
34impl<I> Delay<I>
35where
36    I: Source,
37    I::Item: Sample,
38{
39    /// Returns a reference to the inner source.
40    #[inline]
41    pub fn inner(&self) -> &I {
42        &self.input
43    }
44
45    /// Returns a mutable reference to the inner source.
46    #[inline]
47    pub fn inner_mut(&mut self) -> &mut I {
48        &mut self.input
49    }
50
51    /// Returns the inner source.
52    #[inline]
53    pub fn into_inner(self) -> I {
54        self.input
55    }
56}
57
58impl<I> Iterator for Delay<I>
59where
60    I: Source,
61    I::Item: Sample,
62{
63    type Item = <I as Iterator>::Item;
64
65    #[inline]
66    fn next(&mut self) -> Option<<I as Iterator>::Item> {
67        if self.remaining_samples >= 1 {
68            self.remaining_samples -= 1;
69            Some(Sample::zero_value())
70        } else {
71            self.input.next()
72        }
73    }
74
75    #[inline]
76    fn size_hint(&self) -> (usize, Option<usize>) {
77        let (min, max) = self.input.size_hint();
78        (
79            min + self.remaining_samples,
80            max.map(|v| v + self.remaining_samples),
81        )
82    }
83}
84
85impl<I> Source for Delay<I>
86where
87    I: Iterator + Source,
88    I::Item: Sample,
89{
90    #[inline]
91    fn current_frame_len(&self) -> Option<usize> {
92        self.input
93            .current_frame_len()
94            .map(|val| val + self.remaining_samples)
95    }
96
97    #[inline]
98    fn channels(&self) -> u16 {
99        self.input.channels()
100    }
101
102    #[inline]
103    fn sample_rate(&self) -> u32 {
104        self.input.sample_rate()
105    }
106
107    #[inline]
108    fn total_duration(&self) -> Option<Duration> {
109        self.input
110            .total_duration()
111            .map(|val| val + self.requested_duration)
112    }
113
114    /// Pos is seen from the perspective of the api user.
115    ///
116    /// # Example
117    ///
118    /// ```ignore
119    /// use std::time::Duration;
120    ///
121    /// let mut source = inner_source.delay(Duration::from_secs(10));
122    /// source.try_seek(Duration::from_secs(15));
123    ///
124    /// // inner_source is now at pos: Duration::from_secs(5);
125    /// ```
126    ///
127    #[inline]
128    fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
129        if pos < self.requested_duration {
130            self.input.try_seek(Duration::ZERO)?;
131            let until_playback = self.requested_duration - pos;
132            self.remaining_samples =
133                remaining_samples(until_playback, self.sample_rate(), self.channels());
134        }
135        let compensated_for_delay = pos.saturating_sub(self.requested_duration);
136        self.input.try_seek(compensated_for_delay)
137    }
138}