rodio/source/
delay.rs

1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::Source;
6
7fn remaining_samples(
8    until_playback: Duration,
9    sample_rate: SampleRate,
10    channels: ChannelCount,
11) -> usize {
12    let ns = until_playback.as_secs() * 1_000_000_000 + until_playback.subsec_nanos() as u64;
13    let samples = ns * channels as u64 * sample_rate as u64 / 1_000_000_000;
14    samples as usize
15}
16
17/// Internal function that builds a `Delay` object.
18pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
19where
20    I: Source,
21{
22    Delay {
23        remaining_samples: remaining_samples(duration, input.sample_rate(), input.channels()),
24        requested_duration: duration,
25        input,
26    }
27}
28
29/// A source that delays the given source by a certain amount.
30#[derive(Clone, Debug)]
31pub struct Delay<I> {
32    input: I,
33    remaining_samples: usize,
34    requested_duration: Duration,
35}
36
37impl<I> Delay<I>
38where
39    I: Source,
40{
41    /// Returns a reference to the inner source.
42    #[inline]
43    pub fn inner(&self) -> &I {
44        &self.input
45    }
46
47    /// Returns a mutable reference to the inner source.
48    #[inline]
49    pub fn inner_mut(&mut self) -> &mut I {
50        &mut self.input
51    }
52
53    /// Returns the inner source.
54    #[inline]
55    pub fn into_inner(self) -> I {
56        self.input
57    }
58}
59
60impl<I> Iterator for Delay<I>
61where
62    I: Source,
63{
64    type Item = <I as Iterator>::Item;
65
66    #[inline]
67    fn next(&mut self) -> Option<<I as Iterator>::Item> {
68        if self.remaining_samples >= 1 {
69            self.remaining_samples -= 1;
70            Some(0.0)
71        } else {
72            self.input.next()
73        }
74    }
75
76    #[inline]
77    fn size_hint(&self) -> (usize, Option<usize>) {
78        let (min, max) = self.input.size_hint();
79        (
80            min + self.remaining_samples,
81            max.map(|v| v + self.remaining_samples),
82        )
83    }
84}
85
86impl<I> Source for Delay<I>
87where
88    I: Iterator + Source,
89{
90    #[inline]
91    fn current_span_len(&self) -> Option<usize> {
92        self.input
93            .current_span_len()
94            .map(|val| val + self.remaining_samples)
95    }
96
97    #[inline]
98    fn channels(&self) -> ChannelCount {
99        self.input.channels()
100    }
101
102    #[inline]
103    fn sample_rate(&self) -> SampleRate {
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}