From 1c7b7e6398ccf8dfcb418a2a148cc4299835e824 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Mon, 8 Jun 2026 21:18:11 +0700 Subject: [PATCH] fix(backend): handle voice PCM as JSON instead of binary - Add discord:voice:pcm to SUBSCRIPTIONS as regular JSON channel - Remove BINARY_CHANNELS and handleBinaryMessage function - Discord-gateway sends PCM as JSON with base64, not raw binary - This fixes PCM data not reaching browser via WebSocket The issue was backend expected binary format but gateway sends: {"type":"voice_pcm_data","data":{"userId":"...","pcm":"base64..."}} Now backend correctly subscribes and broadcasts this to WebSocket clients. Co-Authored-By: Claude Opus 4.8 --- services/backend/src/ws/redis-bridge.ts | 45 +------------------------ 1 file changed, 1 insertion(+), 44 deletions(-) diff --git a/services/backend/src/ws/redis-bridge.ts b/services/backend/src/ws/redis-bridge.ts index 4127bbd..651642d 100644 --- a/services/backend/src/ws/redis-bridge.ts +++ b/services/backend/src/ws/redis-bridge.ts @@ -26,11 +26,9 @@ const SUBSCRIPTIONS: ChannelMapping[] = [ eventType: "analysis_queue_status", }, { channel: "discord:voice:active_user", eventType: "voice_active_user" }, + { channel: "discord:voice:pcm", eventType: "voice_pcm_data" }, ]; -// Binary channels that need special handling (messageBuffer event) -const BINARY_CHANNELS = ["discord:voice:pcm"]; - let subscriber: Redis | null = null; function createSubscriber(): Redis { @@ -94,41 +92,6 @@ function handleSubscriptionMessage(channel: string, message: string): void { broadcastRaw(mapping.eventType, data); } -/** - * Handle binary messages from Redis (e.g. voice PCM data). - * Expected format: 4-byte userId hash + PCM buffer - */ -function handleBinaryMessage(channel: Buffer, message: Buffer): void { - const channelStr = channel.toString(); - - if (channelStr === "discord:voice:pcm") { - if (message.length < 4) { - logger.warn( - { channel: channelStr, size: message.length }, - "Received PCM message too short to contain userId", - ); - return; - } - - // First 4 bytes = userId hash, rest = PCM data - const userIdHash = message.readUInt32LE(0); - const pcmData = message.subarray(4); - - logger.debug( - { channel: channelStr, userIdHash, pcmSize: pcmData.length }, - "Broadcasting voice PCM data", - ); - - // Broadcast as binary: userId (4 bytes) + PCM data - broadcastRaw("voice_pcm", message); - } else { - logger.warn( - { channel: channelStr }, - "Received binary message for unmapped channel", - ); - } -} - export async function startRedisBridge(): Promise { if (!config.REDIS_URL && !config.REDIS_HOST) { logger.info("Redis not configured, skipping Redis bridge"); @@ -155,7 +118,6 @@ export async function startRedisBridge(): Promise { }); subscriber.on("message", handleSubscriptionMessage); - subscriber.on("messageBuffer", handleBinaryMessage); await subscriber.ping(); logger.info("Redis ping OK"); @@ -164,11 +126,6 @@ export async function startRedisBridge(): Promise { await subscriber.subscribe(...channels); logger.info({ channels }, "Subscribed to Redis channels"); - if (BINARY_CHANNELS.length > 0) { - await subscriber.subscribe(...BINARY_CHANNELS); - logger.info({ channels: BINARY_CHANNELS }, "Subscribed to binary Redis channels"); - } - logger.info("Redis bridge started"); } catch (err) { logger.error({ err }, "Failed to start Redis bridge");