Fix Opus duration reporting so seekbar and visualizer work

Surface the sidecar duration on the first Opus chunk instead of gating it on the first decoded buffers; C# locks UI Duration on chunk 1, and async WebCodecs decode left it at 0 — killing seek and the duration-gated visualizer.
This commit is contained in:
daniel-c-harvey
2026-06-23 21:23:43 -04:00
parent d80b777e9f
commit eb58ae4a72
2 changed files with 45 additions and 4 deletions
+11 -4
View File
@@ -229,14 +229,21 @@ export class AudioPlayer {
const decoder = this.opusDecoder!;
const buffers = await decoder.push(chunk);
// Duration is known up front from the sidecar — surface it as soon as the decoder reports it,
// NOT gated on the first decoded buffers. The C# layer locks Duration on the first chunk whose
// result carries a value (the `Duration == null` guard), and WebCodecs decode is async, so the
// earliest chunks can return zero buffers; gating duration on buffers means C# captures the
// initial 0 and never overwrites it — the WAV header path sets duration on chunk 1 because its
// header parses synchronously, which is the asymmetry this closes. Set once so a seek (which
// reinitialises the decoder) cannot overwrite it.
if (this.duration === 0 && decoder.totalDuration) {
this.duration = decoder.totalDuration;
}
if (buffers.length > 0) {
for (const buffer of buffers) {
this.scheduler.addBuffer(buffer);
}
// Duration is known up front from the sidecar; set once (a seek must not overwrite it).
if (this.duration === 0 && decoder.totalDuration) {
this.duration = decoder.totalDuration;
}
if (this.streamingStarted && this.isPlaying) {
this.scheduler.scheduleNewBuffers();
}