Speed::try_seek incorrectly multiplies seek position by speed factor

Ouverte
#876 4 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

  • #881 par @FrogSnot — fermée sans fusion

Évaluation

Difficulté
2/5
Temps estimé
1-3 heures
Accessibilité débutants
35/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
À l'abandon
Stack technique
rust
Domaine
audio-video-rtc

Piste de recherche

Read src/source/speed.rs and compare Speed::try_seek with the seek behavior of Amplify and Stoppable. Check the seek path for a speed other than 1x, especially the 215-second file example seeking to 150 seconds. Done means the inner source receives the requested position unchanged and seeking no longer reaches EOF prematurely.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

Hey, I found this while debugging a really frustrating issue in my music player (Sunder). When playing audio at non-1x speeds and seeking via the progress bar, tracks would immediately end as if the file was over.

After a lot of head-scratching, I traced it down to Speed::try_seek in src/source/speed.rs:

fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
        /* TODO: This might be wrong, I do not know how speed achieves its speedup
         * so I can not reason about the correctness.
         * <dvdsk [email protected]> */

        // even after 24 hours of playback f32 has enough precision
        let pos_accounting_for_speedup = pos.mul_f32(self.factor);
        self.input.try_seek(pos_accounting_for_speedup)
    }

The multiplication causes the inner decoder to receive a position that's factor times larger than intended. Since Speed achieves its speedup by modifying sample_rate() (not by resampling or skipping), the inner source still operates in source-time. Multiplying the position overshoots the actual file duration and the source immediately hits EOF.

Example:

215-second audio file, speed set to 2x
User seeks to the 150s mark: sink.try_seek(Duration::from_secs(150))
Speed::try_seek multiplies: 150 * 2.0 = 300s
The decoder receives try_seek(300s) on a 215s file, past EOF
sink.empty() returns true immediately, track skips
This happens for any seek past duration / speed. At 1x the bug is invisible since multiplying by 1.0 is a no-op, which is probably why it went unnoticed.

The TODO comment in the code already notes the uncertainty here, so I figured this was worth reporting.

Suggested fix:

Pass the position through unchanged, like Amplify, Stoppable, and all other sources that don't alter the time domain:

fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
    self.input.try_seek(pos)
}

Current workaround:

Pre-divide the seek position by the speed factor before calling try_seek:

let seek_pos = source_secs / speed as f64;
sink.try_seek(Duration::from_secs_f64(seek_pos));
Langage dominant
Rust
Étoiles
2.5k
Forks
338
Merge moyen
1 j 3 h
PR mergées (30 j)
1

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de RustAudio/rodio

Toutes les issues de RustAudio/rodio

Issues similaires

Plus d'issues Rust

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.