revert: simplify listen to PCM-only, remove WebCodecs complexity
- Remove broadcastOpusToWeb from types and webserver - Revert recorder to PCM-only broadcast path - Remove WebCodecs AudioDecoder from dashboard.js - Simplify WebSocket handler to just play PCM frames - Remove Howler.js and Tone.js dependencies - Keep simple AudioContext playback that works reliably
This commit is contained in:
@@ -24,6 +24,7 @@
|
|||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
"fluent-ffmpeg": "^2.1.3",
|
"fluent-ffmpeg": "^2.1.3",
|
||||||
"helmet": "^8.1.0",
|
"helmet": "^8.1.0",
|
||||||
|
"howler": "^2.2.4",
|
||||||
"libsodium-wrappers": "^0.8.2",
|
"libsodium-wrappers": "^0.8.2",
|
||||||
"p-retry": "^6.2.0",
|
"p-retry": "^6.2.0",
|
||||||
"pino": "^9.4.0",
|
"pino": "^9.4.0",
|
||||||
@@ -33,7 +34,6 @@
|
|||||||
"react": "^19.2.6",
|
"react": "^19.2.6",
|
||||||
"react-dom": "^19.2.6",
|
"react-dom": "^19.2.6",
|
||||||
"sodium-native": "^4.3.2",
|
"sodium-native": "^4.3.2",
|
||||||
"tone": "^15.1.22",
|
|
||||||
"ws": "^8.20.1",
|
"ws": "^8.20.1",
|
||||||
"zod": "^4.4.3"
|
"zod": "^4.4.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ const state = {
|
|||||||
processor: null,
|
processor: null,
|
||||||
nextStartTime: 0,
|
nextStartTime: 0,
|
||||||
noiseGateHold: 0,
|
noiseGateHold: 0,
|
||||||
opusDecoder: null,
|
|
||||||
opusDecoderReady: false,
|
|
||||||
opusDecodeQueue: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const SAMPLE_RATE = 24000;
|
const SAMPLE_RATE = 24000;
|
||||||
@@ -165,19 +162,7 @@ const state = {
|
|||||||
handleJsonEvent(event.data);
|
handleJsonEvent(event.data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!state.isListening) return;
|
if (state.isListening) playPcm(event.data);
|
||||||
const bytes = new Uint8Array(event.data);
|
|
||||||
if (bytes.byteLength < 5) {
|
|
||||||
playPcm(event.data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const mode = bytes[0];
|
|
||||||
if (mode === 1) {
|
|
||||||
const opusData = bytes.slice(5);
|
|
||||||
decodeOpus(opusData);
|
|
||||||
} else {
|
|
||||||
playPcm(event.data);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,7 +176,6 @@ export async function startRecording(
|
|||||||
onPacket: (chunk) => {
|
onPacket: (chunk) => {
|
||||||
if (chunk.length < 8) return;
|
if (chunk.length < 8) return;
|
||||||
segmentManager.rotateIfNeeded(oggPacketStream);
|
segmentManager.rotateIfNeeded(oggPacketStream);
|
||||||
broadcaster.broadcastOpusToWeb?.(chunk, userId);
|
|
||||||
if (!broadcaster.broadcastPcmToWeb) return;
|
if (!broadcaster.broadcastPcmToWeb) return;
|
||||||
decoder.rotateIfNeeded();
|
decoder.rotateIfNeeded();
|
||||||
decoder.write(chunk);
|
decoder.write(chunk);
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ export interface SegmentMetadata extends UserMetadata {
|
|||||||
|
|
||||||
export interface PcmBroadcaster {
|
export interface PcmBroadcaster {
|
||||||
broadcastPcmToWeb?: (chunk: Buffer, userId: string) => void;
|
broadcastPcmToWeb?: (chunk: Buffer, userId: string) => void;
|
||||||
broadcastOpusToWeb?: (chunk: Buffer, userId: string) => void;
|
|
||||||
updateActiveUser?: (
|
updateActiveUser?: (
|
||||||
userId: string,
|
userId: string,
|
||||||
data: { username: string; avatar: string; speaking: boolean },
|
data: { username: string; avatar: string; speaking: boolean },
|
||||||
|
|||||||
@@ -238,22 +238,6 @@ export function startWebserver(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inbound: Discord Opus → tagged chunks → browser (WebCodecs decode)
|
|
||||||
(global as any).broadcastOpusToWeb = (chunk: Buffer, userId: string) => {
|
|
||||||
let hash = 0;
|
|
||||||
for (let i = 0; i < userId.length; i++) {
|
|
||||||
hash = (hash << 5) - hash + userId.charCodeAt(i);
|
|
||||||
hash |= 0;
|
|
||||||
}
|
|
||||||
const header = Buffer.alloc(5);
|
|
||||||
header.writeUInt8(1, 0); // mode: 1 = Opus
|
|
||||||
header.writeInt32LE(hash, 1);
|
|
||||||
const packet = Buffer.concat([header, chunk]);
|
|
||||||
wsClients.forEach((client) => {
|
|
||||||
if (client.readyState === 1) client.send(packet);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
(global as any).updateActiveUser = (
|
(global as any).updateActiveUser = (
|
||||||
userId: string,
|
userId: string,
|
||||||
data: { username: string; avatar: string; speaking: boolean },
|
data: { username: string; avatar: string; speaking: boolean },
|
||||||
|
|||||||
Reference in New Issue
Block a user