@@ -2,29 +2,29 @@ use std::time::Duration;
2
2
3
3
use super :: SeekError ;
4
4
use crate :: common:: { ChannelCount , SampleRate } ;
5
+ use crate :: math:: PrevMultipleOf ;
5
6
use crate :: Source ;
6
7
7
- const US_PER_SECOND : u64 = 1_000_000 ;
8
-
9
- /// Internal function that builds a `SkipDuration` object.
10
- pub fn skip_duration < I > ( mut input : I , duration : Duration ) -> SkipDuration < I >
11
- where
12
- I : Source ,
13
- {
14
- do_skip_duration ( & mut input, duration) ;
15
- SkipDuration {
16
- input,
17
- skipped_duration : duration,
18
- }
19
- }
20
-
21
8
/// A source that skips specified duration of the given source from it's current position.
22
9
#[ derive( Clone , Debug ) ]
23
10
pub struct SkipDuration < I > {
24
11
input : I ,
25
12
skipped_duration : Duration ,
26
13
}
27
14
15
+ impl < I > SkipDuration < I > {
16
+ pub ( crate ) fn new ( mut input : I , duration : Duration ) -> SkipDuration < I >
17
+ where
18
+ I : Source ,
19
+ {
20
+ do_skip_duration ( & mut input, duration) ;
21
+ Self {
22
+ input,
23
+ skipped_duration : duration,
24
+ }
25
+ }
26
+ }
27
+
28
28
impl < I > SkipDuration < I >
29
29
where
30
30
I : Source ,
@@ -99,26 +99,46 @@ where
99
99
}
100
100
101
101
/// Skips specified `duration` of the given `input` source from it's current position.
102
- fn do_skip_duration < I > ( input : & mut I , mut duration : Duration )
102
+ ///
103
+ /// # Panics
104
+ /// If trying to skip more than 584 days ahead. If you need that functionality
105
+ /// please open an issue I would love to know why (and help out).
106
+ fn do_skip_duration < I > ( input : & mut I , duration : Duration )
103
107
where
104
108
I : Source ,
105
109
{
106
- while !duration. is_zero ( ) {
107
- let us_per_sample: u64 =
108
- US_PER_SECOND / input. sample_rate ( ) as u64 / input. channels ( ) as u64 ;
109
- let mut samples_to_skip = duration. as_micros ( ) as u64 / us_per_sample;
110
-
111
- while samples_to_skip > 0 && !input. parameters_changed ( ) {
112
- samples_to_skip -= 1 ;
110
+ const NS_PER_SECOND : u64 = 1_000_000_000 ;
111
+
112
+ // `u64::MAX` can store 584 days of nanosecond precision time. To not be off by
113
+ // a single sample (that would be regression) we first multiply the time by
114
+ // `samples_per second`. Which for a 96kHz 10 channel audio stream is
115
+ // 960_000 samples. That would only leave 0.87 hour of potential skip time. Hence
116
+ // we use an `u128` to calculate samples to skip.
117
+ let mut duration: u64 = duration
118
+ . as_nanos ( )
119
+ . try_into ( )
120
+ . expect ( "can not skip more then 584 days of audio" ) ;
121
+ let mut ns_per_frame: u64 = 0 ;
122
+
123
+ while duration > ns_per_frame {
124
+ ns_per_frame = NS_PER_SECOND / input. sample_rate ( ) as u64 ;
125
+
126
+ let samples_per_second = input. sample_rate ( ) as u64 * input. channels ( ) as u64 ;
127
+ let samples_to_skip =
128
+ ( duration as u128 * samples_per_second as u128 / NS_PER_SECOND as u128 ) as u64 ;
129
+ let samples_to_skip = samples_to_skip. prev_multiple_of ( input. channels ( ) ) ;
130
+
131
+ let mut skipped = 0 ;
132
+ while skipped < samples_to_skip {
113
133
if input. next ( ) . is_none ( ) {
114
134
return ;
115
135
}
136
+ skipped += 1 ;
137
+ if input. parameters_changed ( ) {
138
+ break ;
139
+ }
116
140
}
117
141
118
- if samples_to_skip == 0 {
119
- return ;
120
- } else {
121
- duration -= Duration :: from_micros ( samples_to_skip * us_per_sample) ;
122
- }
142
+ duration -= skipped * NS_PER_SECOND / samples_per_second;
123
143
}
124
144
}
0 commit comments