Fix complete-without-start hang for ultra-short tracks; add Opus rebuffer hysteresis

Tracks whose total audio falls below the playback-start threshold (Opus <1s lead, WAV <6 buffers) silently hung loaded-but-not-playing. After MarkStreamCompleteAsync, call TryStartPlaybackAsync when _streamingPlaybackStarted is still false so the scheduler drains its buffers and fires onPlaybackEnded exactly once.
This commit is contained in:
daniel-c-harvey
2026-06-25 15:54:53 -04:00
parent 48e58c266d
commit 4ab430d232
4 changed files with 275 additions and 44 deletions
+8 -3
View File
@@ -285,10 +285,15 @@ export class AudioPlayer {
return { success: false, error: 'Opus decode failed' };
}
// "headerParsed" maps to the decoder being configured (codec ready). canStart needs the
// min buffer count, exactly as the WAV path requires before first playback.
// "headerParsed" maps to the decoder being configured (codec ready). canStart needs a
// healthy decoded lead before first playback — measured in SECONDS, not a buffer count.
// An Opus WebCodecs packet is ~20 ms, so the WAV-tuned 6-BUFFER minimum is only ~0.12 s of
// lead: playback would start, drain it before the async decode ramps, and underrun
// immediately. The seconds-based lead gate (same threshold the scheduler's underrun-resume
// hysteresis uses) gives Opus the cushion its decode ramp needs. WAV keeps the buffer-count
// gate below — its large synchronous segments rarely underrun and its start must not change.
const headerParsed = decoder.ready;
const canStart = headerParsed && this.scheduler.hasMinimumBuffers(this.minBuffersForPlayback);
const canStart = headerParsed && this.scheduler.hasMinimumPlaybackLead();
return {
success: true,