From 89f1097729659c3af5fdc8544bde87a57c9cfe4e Mon Sep 17 00:00:00 2001 From: asepharyana Date: Thu, 13 Aug 2026 16:18:51 +0700 Subject: [PATCH] fix(goLive): add -re throttle at encoder for screen-share pipe input Previous code only added ffmpeg -re when input was a string URL. Screen share passes a Readable pipe (yt-dlp merge -> stdout) delivered at network speed (bursts + stalls). Without -re the encoder slurps it instantly and, when the merge stalls, x264 -r 30 force-duplicates the last held frame ~30x -> viewer sees ~1fps while WebRTC still paces 30fps. Add -re for all inputs so the encoder paces at the stream's native PTS rate and emits a fresh picture every frame. --- .../discord-gateway/src/goLive/prepareStream.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/services/discord-gateway/src/goLive/prepareStream.ts b/services/discord-gateway/src/goLive/prepareStream.ts index dfa19be..15e426c 100644 --- a/services/discord-gateway/src/goLive/prepareStream.ts +++ b/services/discord-gateway/src/goLive/prepareStream.ts @@ -127,10 +127,18 @@ export function prepareStream( "-hide_banner", "-loglevel", "error", - // Real-time throttle: when the input is a URL/VOD, read it at 1x so the - // encoder paces with wall-clock (see `realtime` option above). For live - // pipe (PassThrough) input we DON'T add -re — the producer already paces. - ...(mergedOptions.realtime && typeof input === "string" ? ["-re"] : []), + // Real-time throttle: read the input at 1x so the encoder paces with + // wall-clock and does NOT force-duplicate frames to fill -r 30. This + // applies to BOTH URL and live-Pipe (Readable) inputs: a screen-share + // pipe (yt-dlp merge → ffmpeg → stdout) is delivered at NETWORK speed + // (bursts, stalls) and is NOT self-paced — without -re the encoder slurps + // it instantly and, when the merge stalls, x264 -r 30 repeats the last + // held frame ~30x → the viewer sees ~1fps while WebRTC still pushes + // 30fps. -re reads the pipe at the stream's native PTS rate so each + // output frame is a fresh picture. (Previous builds only added -re for + // string URLs, so the screen-share pipe got none — root of the 1fps + // symptom.) + ...(mergedOptions.realtime ? ["-re"] : []), ...(typeof input === "string" ? ["-i", input] : ["-i", "pipe:0"]), ...mergedOptions.customInputOptions, ];