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
|
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]
|
#[inline]
|
||||||
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
|
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
|
||||||
self.current.try_seek(pos)
|
self.current.try_seek(pos)
|
||||||
|
|
|
@ -205,7 +205,7 @@ impl Sink {
|
||||||
///
|
///
|
||||||
/// This blocks between 0 and ~5 milliseconds.
|
/// 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
|
/// 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
|
/// of 42 seconds calling `try_seek()` with 60 seconds as argument will seek to
|
||||||
/// 42 seconds.
|
/// 42 seconds.
|
||||||
|
|
|
@ -242,6 +242,8 @@ where
|
||||||
self.total_duration
|
self.total_duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Can not support seek, in the end state we lose the underlying source
|
||||||
|
/// which makes seeking back impossible.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
|
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
|
||||||
Err(SeekError::NotSupported {
|
Err(SeekError::NotSupported {
|
||||||
|
|
|
@ -4,19 +4,22 @@ use crate::{Sample, Source};
|
||||||
|
|
||||||
use super::SeekError;
|
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.
|
/// Internal function that builds a `Delay` object.
|
||||||
pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
|
pub fn delay<I>(input: I, duration: Duration) -> Delay<I>
|
||||||
where
|
where
|
||||||
I: Source,
|
I: Source,
|
||||||
I::Item: Sample,
|
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 {
|
Delay {
|
||||||
input,
|
remaining_samples: remaining_samples(duration, input.sample_rate(), input.channels()),
|
||||||
remaining_samples: samples as usize,
|
|
||||||
requested_duration: duration,
|
requested_duration: duration,
|
||||||
|
input,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,9 +111,28 @@ where
|
||||||
.map(|val| val + self.requested_duration)
|
.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]
|
#[inline]
|
||||||
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
|
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
|
||||||
let pos_without_delay = pos.saturating_sub(self.requested_duration);
|
if pos < self.requested_duration {
|
||||||
self.input.try_seek(pos_without_delay)
|
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