1use std::time::Duration;
2
3use super::SeekError;
4use crate::common::{ChannelCount, SampleRate};
5use crate::Source;
6
7const NS_PER_SECOND: u128 = 1_000_000_000;
8
9pub fn skip_duration<I>(mut input: I, duration: Duration) -> SkipDuration<I>
11where
12 I: Source,
13{
14 do_skip_duration(&mut input, duration);
15 SkipDuration {
16 input,
17 skipped_duration: duration,
18 }
19}
20
21fn do_skip_duration<I>(input: &mut I, mut duration: Duration)
23where
24 I: Source,
25{
26 while duration > Duration::new(0, 0) {
27 if input.current_span_len().is_none() {
28 do_skip_duration_unchecked(input, duration);
30 return;
31 }
32
33 let span_len: usize = input.current_span_len().unwrap();
36 if span_len == 0 {
39 return;
40 }
41
42 let ns_per_sample: u128 =
43 NS_PER_SECOND / input.sample_rate() as u128 / input.channels() as u128;
44
45 if span_len as u128 * ns_per_sample > duration.as_nanos() {
47 skip_samples(input, (duration.as_nanos() / ns_per_sample) as usize);
48 return;
49 }
50
51 skip_samples(input, span_len);
52
53 duration -= Duration::from_nanos((span_len * ns_per_sample as usize) as u64);
54 }
55}
56
57fn do_skip_duration_unchecked<I>(input: &mut I, duration: Duration)
60where
61 I: Source,
62{
63 let samples_per_channel: u128 =
64 duration.as_nanos() * input.sample_rate() as u128 / NS_PER_SECOND;
65 let samples_to_skip: u128 = samples_per_channel * input.channels() as u128;
66
67 skip_samples(input, samples_to_skip as usize);
68}
69
70fn skip_samples<I>(input: &mut I, n: usize)
72where
73 I: Source,
74{
75 for _ in 0..n {
76 if input.next().is_none() {
77 break;
78 }
79 }
80}
81
82#[derive(Clone, Debug)]
84pub struct SkipDuration<I> {
85 input: I,
86 skipped_duration: Duration,
87}
88
89impl<I> SkipDuration<I>
90where
91 I: Source,
92{
93 #[inline]
95 pub fn inner(&self) -> &I {
96 &self.input
97 }
98
99 #[inline]
101 pub fn inner_mut(&mut self) -> &mut I {
102 &mut self.input
103 }
104
105 #[inline]
107 pub fn into_inner(self) -> I {
108 self.input
109 }
110}
111
112impl<I> Iterator for SkipDuration<I>
113where
114 I: Source,
115{
116 type Item = <I as Iterator>::Item;
117
118 #[inline]
119 fn next(&mut self) -> Option<Self::Item> {
120 self.input.next()
121 }
122
123 #[inline]
124 fn size_hint(&self) -> (usize, Option<usize>) {
125 self.input.size_hint()
126 }
127}
128
129impl<I> Source for SkipDuration<I>
130where
131 I: Source,
132{
133 #[inline]
134 fn current_span_len(&self) -> Option<usize> {
135 self.input.current_span_len()
136 }
137
138 #[inline]
139 fn channels(&self) -> ChannelCount {
140 self.input.channels()
141 }
142
143 #[inline]
144 fn sample_rate(&self) -> SampleRate {
145 self.input.sample_rate()
146 }
147
148 #[inline]
149 fn total_duration(&self) -> Option<Duration> {
150 self.input.total_duration().map(|val| {
151 val.checked_sub(self.skipped_duration)
152 .unwrap_or_else(|| Duration::from_secs(0))
153 })
154 }
155
156 #[inline]
157 fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
158 self.input.try_seek(pos)
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use std::time::Duration;
165
166 use crate::buffer::SamplesBuffer;
167 use crate::common::{ChannelCount, SampleRate};
168 use crate::source::Source;
169
170 fn test_skip_duration_samples_left(
171 channels: ChannelCount,
172 sample_rate: SampleRate,
173 seconds: u32,
174 seconds_to_skip: u32,
175 ) {
176 let buf_len = (sample_rate * channels as u32 * seconds) as usize;
177 assert!(buf_len < 10 * 1024 * 1024);
178 let data: Vec<f32> = vec![0f32; buf_len];
179 let test_buffer = SamplesBuffer::new(channels, sample_rate, data);
180 let seconds_left = seconds.saturating_sub(seconds_to_skip);
181
182 let samples_left_expected = (sample_rate * channels as u32 * seconds_left) as usize;
183 let samples_left = test_buffer
184 .skip_duration(Duration::from_secs(seconds_to_skip as u64))
185 .count();
186
187 assert_eq!(samples_left, samples_left_expected);
188 }
189
190 macro_rules! skip_duration_test_block {
191 ($(channels: $ch:expr, sample rate: $sr:expr, seconds: $sec:expr, seconds to skip: $sec_to_skip:expr;)+) => {
192 $(
193 test_skip_duration_samples_left($ch, $sr, $sec, $sec_to_skip);
194 )+
195 }
196 }
197
198 #[test]
199 fn skip_duration_shorter_than_source() {
200 skip_duration_test_block! {
201 channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 3;
202 channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 3;
203
204 channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 3;
205 channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 3;
206
207 channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 3;
208 channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 3;
209 }
210 }
211
212 #[test]
213 fn skip_duration_zero_duration() {
214 skip_duration_test_block! {
215 channels: 1, sample rate: 44100, seconds: 5, seconds to skip: 0;
216 channels: 1, sample rate: 96000, seconds: 5, seconds to skip: 0;
217
218 channels: 2, sample rate: 44100, seconds: 5, seconds to skip: 0;
219 channels: 2, sample rate: 96000, seconds: 5, seconds to skip: 0;
220
221 channels: 4, sample rate: 44100, seconds: 5, seconds to skip: 0;
222 channels: 4, sample rate: 96000, seconds: 5, seconds to skip: 0;
223 }
224 }
225
226 #[test]
227 fn skip_duration_longer_than_source() {
228 skip_duration_test_block! {
229 channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 5;
230 channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 11;
231
232 channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 5;
233 channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 11;
234
235 channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 5;
236 channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 11;
237 }
238 }
239
240 #[test]
241 fn skip_duration_equal_to_source_length() {
242 skip_duration_test_block! {
243 channels: 1, sample rate: 44100, seconds: 1, seconds to skip: 1;
244 channels: 1, sample rate: 96000, seconds: 10, seconds to skip: 10;
245
246 channels: 2, sample rate: 44100, seconds: 1, seconds to skip: 1;
247 channels: 2, sample rate: 96000, seconds: 10, seconds to skip: 10;
248
249 channels: 4, sample rate: 44100, seconds: 1, seconds to skip: 1;
250 channels: 4, sample rate: 96000, seconds: 10, seconds to skip: 10;
251 }
252 }
253}