This commit is contained in:
2025-10-13 02:20:56 +03:00
Unverified
parent f810d58e06
commit f22e3b23b4
5 changed files with 9 additions and 321 deletions
+3 -59
View File
@@ -34,7 +34,7 @@ export interface WorkerOptions {
* For RTCEncodedVideoFrame/AudioFrame, we use the frame's metadata if available,
* otherwise fall back to extracting from RTP header
*/
function makeIV(encodedFrame: EncodedFrame, frameCount: number, mode: 'encrypt' | 'decrypt'): ArrayBuffer {
function makeIV(encodedFrame: EncodedFrame): ArrayBuffer {
// Create IV using ONLY RTP metadata - this ensures sender and receiver use identical IVs
// Frame data can differ between sender/receiver due to encoding differences
const ivBuffer = new ArrayBuffer(12);
@@ -49,14 +49,6 @@ function makeIV(encodedFrame: EncodedFrame, frameCount: number, mode: 'encrypt'
view.setUint32(4, metadata.synchronizationSource || 0, false); // Middle 4 bytes
view.setUint32(8, 0, false); // Last 4 bytes (padding for 12-byte IV)
// Debug first few frames only
if (frameCount <= 3) {
console.log(`${mode.toUpperCase()} IV for frame #${frameCount}:`, {
rtpTimestamp: metadata.rtpTimestamp,
syncSource: metadata.synchronizationSource,
mimeType: metadata.mimeType
});
}
return ivBuffer;
}
@@ -82,8 +74,6 @@ addEventListener("rtctransform", (event) => {
console.log(`E2EE Worker started in ${mode.toUpperCase()} mode`);
let frameCount = 0;
let lastLogTime = 0;
let lastKeyCheck = Date.now();
async function transform(encodedFrame: EncodedFrame, controller: TransformStreamDefaultController<EncodedFrame>) {
try {
@@ -92,35 +82,8 @@ addEventListener("rtctransform", (event) => {
// Increment frame counter
frameCount++;
// Log every frame for debugging (only first 3)
if (frameCount <= 3) {
console.log(`${mode.toUpperCase()} Processing frame #${frameCount}, size: ${data.length}`);
}
// Create IV using RTP timestamp from metadata (synchronized between peers)
const iv = makeIV(encodedFrame, frameCount, mode);
// Log first few frames and periodically for debugging
const now = Date.now();
if (frameCount <= 5 || now - lastLogTime > 5000) {
console.log(`E2EE ${mode} frame #${frameCount}, size: ${data.length} bytes`);
lastLogTime = now;
}
// For screen share, check if we need to request key rotation more frequently
// Screen share generates much more data and can benefit from more frequent key rotation
if (data.length > 50000 && now - lastKeyCheck > 60000) { // 1 minute for large frames
console.log("Large frame detected, suggesting key rotation for screen share");
lastKeyCheck = now;
}
// Detect potential browser window glitching - frames with specific characteristics
if (data.length > 100000 && frameCount > 10) { // Large frames after initial setup
const frameType = encodedFrame.type || 'unknown';
if (frameType === 'key' && data.length > 200000) {
console.log("Large keyframe detected - possible browser window glitch, frame size:", data.length);
}
}
const iv = makeIV(encodedFrame);
// Ensure IV is properly typed
const ivArray = new Uint8Array(iv);
@@ -168,16 +131,6 @@ addEventListener("rtctransform", (event) => {
result.set(encryptedArray, 0);
}
// Log first few frames for debugging
if (frameCount <= 3) {
console.log(`E2EE ${mode} frame #${frameCount}: ${data.length} -> ${result.length} bytes (header: ${headerSize})`);
}
// For video frames, check if we need to force keyframes more frequently
// This helps prevent "stuck at first frame" issues with encrypted video
if (data.length > 10000 && frameCount > 0 && frameCount % 30 === 0) {
console.log(`Large video frame #${frameCount} - suggesting keyframe for stability`);
}
// CRITICAL: Video frames need ArrayBuffer, not Uint8Array
encodedFrame.data = result.buffer;
@@ -187,16 +140,7 @@ addEventListener("rtctransform", (event) => {
// FAIL SECURELY: Never send unencrypted frames
const data = new Uint8Array(encodedFrame.data);
console.error(`E2EE ${mode} FAILED - dropping frame #${frameCount}, size: ${data.length}`, e);
console.error('Frame type:', encodedFrame.type || 'unknown');
// For screen share, be more aggressive about dropping corrupted frames
// to prevent progressive glitch accumulation
if (mode === 'decrypt' && frameCount > 10) {
console.warn(`Dropping corrupted frame #${frameCount} to prevent glitch accumulation`);
}
// Drop the frame completely - don't enqueue anything
return;
return; // Drop the frame completely
}
}
-10
View File
@@ -109,7 +109,6 @@ async function getIceServers(): Promise<RTCIceServer[]> {
if (response.ok) {
const data = await response.json() as IceServersResponse;
console.log("Received ICE servers:", data.iceServers);
return data.iceServers || [];
} else {
console.warn("Failed to fetch ICE servers:", response.status, response.statusText);
@@ -162,8 +161,6 @@ async function createPeerConnection(userId: number): Promise<RTCPeerConnection>
// Add ICE candidate event listener for debugging and sending
peerConnection.addEventListener("icecandidate", async (event) => {
if (event.candidate) {
console.log("Local ICE candidate:", event.candidate.candidate);
// Send ICE candidate to remote peer
try {
await sendSignalingMessage({
@@ -179,8 +176,6 @@ async function createPeerConnection(userId: number): Promise<RTCPeerConnection>
} catch (error) {
console.error("Failed to send ICE candidate:", error);
}
} else {
console.log("ICE gathering complete");
}
});
@@ -195,27 +190,22 @@ async function createPeerConnection(userId: number): Promise<RTCPeerConnection>
// Handle renegotiation when tracks are added/removed
peerConnection.addEventListener("negotiationneeded", async () => {
try {
console.log("Negotiation needed for user", userId);
const call = calls.get(userId);
if (!call) {
console.log("Skipping renegotiation - call not found");
return;
}
// Prevent multiple simultaneous negotiations
if (call.isNegotiating) {
console.log("Already negotiating, skipping");
return;
}
// Skip if we're in "stable" state and haven't finished the initial handshake
if (peerConnection.signalingState !== "stable") {
console.log("Skipping renegotiation - signaling state is", peerConnection.signalingState);
return;
}
call.isNegotiating = true;
console.log("Creating new offer for renegotiation (signalingState:", peerConnection.signalingState + ")");
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);