From 5816e94a635bc0b37fc3b975a5194d8e50388e0c Mon Sep 17 00:00:00 2001 From: asepharyana Date: Thu, 13 Aug 2026 19:06:36 +0700 Subject: [PATCH] =?UTF-8?q?fix(goLive):=20remove=20syncStream=20=E2=80=94?= =?UTF-8?q?=20synthetic=20PTS=20timebases=20make=20A/V=20sync=20deadlock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symptom: video plays ~1s then freezes. BaseMediaStream sync logic: - video _pts advances 33.3ms/frame (timeBase 1/fps), audio _pts advances 20ms/packet (timeBase 1/48000) — two synthetic frame-index timebases that never share a clock. - If audio starts late (ffmpeg audio init / Ogg header), ptsDelta = video-audio stays positive → isAhead() true → video loops 'await sleep(frametime) while isAhead()' → video freezes. Downchain: vPipe fills → proc.stdout paused → demuxer emits ~15fps (log: 30 frames per 2s). Upstream dank sets syncStream because node-av provides REAL PTS from NUT in a consistent timebase. Our raw-h264 demuxer has no real PTS; per-stream sleep-PTS pacing alone keeps both at 1000ms/s, which is correct without a shared clock. Re-enable sync only if real PTS is added. --- .../discord-gateway/src/goLive/prepareStream.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/services/discord-gateway/src/goLive/prepareStream.ts b/services/discord-gateway/src/goLive/prepareStream.ts index ba8ef50..a730df4 100644 --- a/services/discord-gateway/src/goLive/prepareStream.ts +++ b/services/discord-gateway/src/goLive/prepareStream.ts @@ -369,10 +369,15 @@ export async function playStream( console.log( `[goLive:playStream] audio stream attached (${audio.codecName})`, ); - // A/V sync (faithful to @dank074 newApi.js): audio is the master clock. - // Video sleeps/wakes based on ptsDelta(video - audio) so they can't drift - // apart under variable encoder throughput. - vStream.syncStream = aStream; + // NOTE: NO syncStream wiring here. Upstream dank sets + // `vStream.syncStream = aStream` because node-av provides real PTS from the + // NUT container, so ptsDelta() is meaningful (both streams in media time). + // Our raw-h264 demuxer synthesizes PTS per-stream from frame indexes in + // DIFFERENT timebases (video 1/fps, audio 1/48000). If audio starts late + // (ffmpeg audio init, Ogg header), ptsDelta stays positive forever → + // isAhead() → video sleeps in a loop → video freezes after ~1s. Per-stream + // sleep-PTS pacing alone keeps both at 1000ms/s, which is correct without + // a shared clock. (If real PTS is ever added, re-enable syncStream.) } const cleanup = () => {