rodio/source/
pausable.rs

1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::Source;
6
7/// Builds a `Pausable` object.
8pub fn pausable<I>(source: I, paused: bool) -> Pausable<I>
9where
10    I: Source,
11{
12    let paused_channels = if paused {
13        Some(source.channels())
14    } else {
15        None
16    };
17    Pausable {
18        input: source,
19        paused_channels,
20        remaining_paused_samples: 0,
21    }
22}
23
24/// Wraps a source and makes it pausable by calling [`Pausable::set_paused`] on
25/// this object. When the source is paused it returns zero value samples.
26///
27/// You can usually still use this from another source wrapping this one by
28/// calling `inner_mut` on it. Similarly this provides [`Pausable::inner`] and
29/// mutable/destructing variants for accessing the underlying source.
30#[derive(Clone, Debug)]
31pub struct Pausable<I> {
32    input: I,
33    paused_channels: Option<ChannelCount>,
34    remaining_paused_samples: ChannelCount,
35}
36
37impl<I> Pausable<I>
38where
39    I: Source,
40{
41    /// Sets whether the filter applies.
42    ///
43    /// If set to true, the inner sound stops playing and no samples are processed from it.
44    #[inline]
45    pub fn set_paused(&mut self, paused: bool) {
46        match (self.paused_channels, paused) {
47            (None, true) => self.paused_channels = Some(self.input.channels()),
48            (Some(_), false) => self.paused_channels = None,
49            _ => (),
50        }
51    }
52
53    /// Indicates if the data source is in a paused state.
54    #[inline]
55    pub fn is_paused(&self) -> bool {
56        self.paused_channels.is_some()
57    }
58
59    /// Returns a reference to the inner source.
60    #[inline]
61    pub fn inner(&self) -> &I {
62        &self.input
63    }
64
65    /// Returns a mutable reference to the inner source.
66    #[inline]
67    pub fn inner_mut(&mut self) -> &mut I {
68        &mut self.input
69    }
70
71    /// Returns the inner source.
72    #[inline]
73    pub fn into_inner(self) -> I {
74        self.input
75    }
76}
77
78impl<I> Iterator for Pausable<I>
79where
80    I: Source,
81{
82    type Item = I::Item;
83
84    #[inline]
85    fn next(&mut self) -> Option<I::Item> {
86        if self.remaining_paused_samples > 0 {
87            self.remaining_paused_samples -= 1;
88            return Some(0.0);
89        }
90
91        if let Some(paused_channels) = self.paused_channels {
92            self.remaining_paused_samples = paused_channels - 1;
93            return Some(0.0);
94        }
95
96        self.input.next()
97    }
98
99    #[inline]
100    fn size_hint(&self) -> (usize, Option<usize>) {
101        self.input.size_hint()
102    }
103}
104
105impl<I> Source for Pausable<I>
106where
107    I: Source,
108{
109    #[inline]
110    fn current_span_len(&self) -> Option<usize> {
111        self.input.current_span_len()
112    }
113
114    #[inline]
115    fn channels(&self) -> ChannelCount {
116        self.input.channels()
117    }
118
119    #[inline]
120    fn sample_rate(&self) -> SampleRate {
121        self.input.sample_rate()
122    }
123
124    #[inline]
125    fn total_duration(&self) -> Option<Duration> {
126        self.input.total_duration()
127    }
128
129    #[inline]
130    fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
131        self.input.try_seek(pos)
132    }
133}