fix(voice): screen share GoLive died instantly — neutralize node-av custom ffmpeg filters

prepareStream (from @dank074/discord-video-stream) unconditionally appends
audio filters 'volume@internal_lib' + 'azmq' that exist ONLY in its custom
node-av jellyfin-ffmpeg build. The Nix deployment runs plain ffmpeg-headless
on PATH, so fluent-ffmpeg died instantly with 'Filter not found' (exit 8),
the NUT output stream stayed empty, and playStream's node-av demux failed
with 'Failed to open input from Readable stream: Invalid data found when
processing input' — every screen share failed ~100ms after start.

Fix: pass customFfmpegFlags ['-filter:a','anull'] — ffmpeg applies the LAST
-filter:a for a stream, so the trailing no-op filter overrides the custom
chain (verified: command ends with '-filter:a anull', transcode runs, node-av
demux finds video+audio). Realtime volume control was already removed from
GMW (a690e5b), so dropping the filters is lossless.

Verified end-to-end with the failing URL (youtu.be/fONoh7Pc6VU, AV1+Opus
DASH): getDirectScreenInput → NUT merge → patched prepareStream → node-av
demux finds H264 video + Opus audio streams.
This commit is contained in:
asepharyana
2026-08-11 10:56:49 +07:00
parent c18431bdbf
commit a53d7b71da
@@ -107,6 +107,15 @@ export class ScreenShareController {
bitrateVideoMax: 4000,
includeAudio: true,
videoCodec: Utils.normalizeVideoCodec("H264"),
// The library unconditionally appends `volume@internal_lib` + `azmq`
// audio filters that only exist in its custom node-av ffmpeg build
// (jellyfin-ffmpeg) — NOT in the Nix ffmpeg-headless on PATH. Without
// an override fluent-ffmpeg dies instantly with "Filter not found",
// the NUT output stays empty and playStream fails with "Invalid data
// found when processing input". ffmpeg applies the LAST -filter:a for
// a stream, so a trailing no-op filter neutralizes the custom chain.
// Realtime volume control was removed from GMW, so this is lossless.
customFfmpegFlags: ["-filter:a", "anull"],
});
let stopped = false;