mirror of
https://github.com/RustAudio/rodio
synced 2024-12-13 13:42:34 +00:00
fix(seek/delay) seek < delay duration ate up the delay
This commit is contained in:
parent
aa0880ddee
commit
7cf0451a1e
4 changed files with 41 additions and 8 deletions
|
@ -170,6 +170,15 @@ where
|
|||
None
|
||||
}
|
||||
|
||||
/// Only seeks within the current source.
|
||||
// We can not go back to previous sources. We could implement seek such
|
||||
// that it advances the queue if the position is beyond the current song.
|
||||
//
|
||||
// We would then however need to enable seeking backwards across sources too.
|
||||
// That no longer seems in line with the queue behaviour.
|
||||
//
|
||||
// A final pain point is that we would need the total duration for the
|
||||
// next few songs.
|
||||
#[inline]
|
||||
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
|
||||
self.current.try_seek(pos)
|
||||
|
|
|
@ -205,7 +205,7 @@ impl Sink {
|
|||
///
|
||||
/// This blocks between 0 and ~5 milliseconds.
|
||||
///
|
||||
/// As long as the duration of the source is known seek is guaranteed to saturate
|
||||
/// As long as the duration of the source is known, seek is guaranteed to saturate
|
||||
/// at the end of the source. For example given a source that reports a total duration
|
||||
/// of 42 seconds calling `try_seek()` with 60 seconds as argument will seek to
|
||||
/// 42 seconds.
|
||||
|
|
|
@ -242,6 +242,8 @@ where
|
|||
self.total_duration
|
||||
}
|
||||
|
||||
/// Can not support seek, in the end state we lose the underlying source
|
||||
/// which makes seeking back impossible.
|
||||
#[inline]
|
||||
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
|
||||
Err(SeekError::NotSupported {
|
||||
|
|
|
@ -4,19 +4,22 @@ use crate::{Sample, Source};
|
|||
|
||||
use super::SeekError;
|
||||
|
||||
fn remaining_samples(until_playback: Duration, sample_rate: u32, channels: u16) -> usize {
|
||||
let ns = until_playback.as_secs() * 1_000_000_000 + until_playback.subsec_nanos() as u64;
|
||||
let samples = ns * channels as u64 * sample_rate as u64 / 1_000_000_000;
|
||||
samples as usize
|
||||
}
|
||||
|
||||
/// Internal function that builds a `Delay` object.
|
||||
pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
|
||||
where
|
||||
I: Source,
|
||||
I::Item: Sample,
|
||||
{
|
||||
let duration_ns = duration.as_secs() * 1000000000 + duration.subsec_nanos() as u64;
|
||||
let samples = duration_ns * input.sample_rate() as u64 / 1000000000 * input.channels() as u64;
|
||||
|
||||
Delay {
|
||||
input,
|
||||
remaining_samples: samples as usize,
|
||||
remaining_samples: remaining_samples(duration, input.sample_rate(), input.channels()),
|
||||
requested_duration: duration,
|
||||
input,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,9 +111,28 @@ where
|
|||
.map(|val| val + self.requested_duration)
|
||||
}
|
||||
|
||||
/// Pos is seen from the perspective of the api user.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let mut source = inner_source.delay(Duration::from_secs(10));
|
||||
/// source.try_seek(Duration::from_secs(15));
|
||||
///
|
||||
/// // inner_source is now at pos: Duration::from_secs(5);
|
||||
/// ```
|
||||
///
|
||||
#[inline]
|
||||
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
|
||||
let pos_without_delay = pos.saturating_sub(self.requested_duration);
|
||||
self.input.try_seek(pos_without_delay)
|
||||
if pos < self.requested_duration {
|
||||
self.input.try_seek(Duration::ZERO)?;
|
||||
let until_playback = self.requested_duration - pos;
|
||||
self.remaining_samples =
|
||||
remaining_samples(until_playback, self.sample_rate(), self.channels());
|
||||
}
|
||||
let compensated_for_delay = pos.saturating_sub(self.requested_duration);
|
||||
self.input.try_seek(compensated_for_delay)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue