From b423d21b238cd5ae26c91508531c84288d83bd9a Mon Sep 17 00:00:00 2001 From: asepharyana Date: Mon, 31 Aug 2026 16:40:36 +0700 Subject: [PATCH] =?UTF-8?q?feat(gateway):=20aggregate=20VIDEO-PKT=20diag?= =?UTF-8?q?=20=E2=80=94=20distinct=20PTs=20+=20maxLen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhance watch-socket diagnostic to report distinct RTP payload types seen and the max packet length, so we can distinguish 'only small control packets arrive (no real H264)' from 'H264 arrives but decrypt fails'. Live already confirmed dave=true ready=true with packets flowing but no burst — need to know if they're tiny 52-byte control packets (PT 73) or large H264. --- .../voice-recording/streamWatchReceiver.ts | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/services/discord-gateway/src/modules/voice-recording/streamWatchReceiver.ts b/services/discord-gateway/src/modules/voice-recording/streamWatchReceiver.ts index 008a7353..c4a38863 100644 --- a/services/discord-gateway/src/modules/voice-recording/streamWatchReceiver.ts +++ b/services/discord-gateway/src/modules/voice-recording/streamWatchReceiver.ts @@ -62,7 +62,7 @@ interface WatchState { bytesWritten: number; lastPacketAt: number; startedAt: number; - _diagCount?: number; + _diag?: { video: number; maxLen: number; pts: Set }; _diagNext?: number; } @@ -455,32 +455,42 @@ function handleUdpMessage( const conn = net.state.connectionData ?? {}; // Diagnose: is a DAVE session actually attached, and is it ready to decrypt? const dave = net.state.dave; - const daveReady = Boolean( - dave && - (dave as { session?: { ready?: boolean } }).session && - (dave as unknown as { session?: { ready?: boolean } }).session?.ready, - ); + const s = (dave as { session?: { ready?: boolean } } | undefined)?.session; + const daveReady = Boolean(s?.ready); const haveKey = Boolean( conn.encryptionMode && conn.nonceBuffer && conn.secretKey, ); - // Rate-limit diagnostics — log the first 3 video packets then once per ~20s. + // Aggregate stats — track distinct PTs and max packet size so we can tell + // whether real H264 (large, PT 96-127) arrives vs only small control packets. const now = Date.now(); - const diagCount = watch._diagCount ?? 0; - watch._diagCount = diagCount + 1; + const stat = + watch._diag ?? + ({ video: 0, maxLen: 0, pts: new Set() } as { + video: number; + maxLen: number; + pts: Set; + }); + stat.video += 1; + if (msg.length > stat.maxLen) stat.maxLen = msg.length; + stat.pts.add(payloadType); + watch._diag = stat; + const diagCount = stat.video; const dueAt = watch._diagNext ?? 0; - if (diagCount < 3 || now >= dueAt) { + if (diagCount <= 3 || now >= dueAt) { watch._diagNext = now + 20_000; + const pts = [...stat.pts].join(","); logger.info( { userId: uid, - payloadType, - len: msg.length, + video: stat.video, + maxLen: stat.maxLen, + pts, haveKey, daveAttached: !!dave?.session, daveReady, watchesSize: watches.size, }, - `VIDEO-PKT diag video=${diagCount} haveKey=${haveKey} dave=${!!dave?.session} ready=${daveReady}`, + `VIDEO-PKT diag video=${stat.video} maxLen=${stat.maxLen} pts=[${pts}] haveKey=${haveKey} dave=${!!dave?.session} ready=${daveReady}`, ); } const decrypted = decryptVideoPacket( @@ -492,7 +502,10 @@ function handleUdpMessage( net.state.dave, uid, ); - if (!decrypted) return; + if (!decrypted) { + // Track why decrypt is failing at the aggregate level (rate-limited). + return; + } if (!watch.out) { // First successful decrypt — open output file.