Speed::try_seek incorrectly multiplies seek position by speed factor

Offen
#876 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

  • #881 von @FrogSnot — ohne Merge geschlossen

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
35/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Veraltet
Tech-Stack
rust
Bereich
audio-video-rtc

Rechercherichtung

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.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

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));
Vorherrschende Sprache
Rust
Sterne
2.5k
Forks
338
Ø Merge
1 T. 3 Std.
Gemergte PRs (30 T.)
1

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus RustAudio/rodio

Alle Issues in RustAudio/rodio

Ähnliche Issues

Weitere Issues zu Rust

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.