/* eslint-disable */ // @ts-nocheck import fs from 'fs'; const filePath = 'C:/X/workspace/jumpa.id/vc/lib/xcu-quantum-decoder.ts'; let content = fs.readFileSync(filePath, 'utf-8'); // 1. Add videoEngineMode property content = content.replace( 'public participantRole: "PANELIST" | "AUDIENCE" = "PANELIST";', 'public participantRole: "PANELIST" | "AUDIENCE" = "PANELIST";\n\tpublic videoEngineMode: "canvas" | "webcodecs" = "canvas";\n\tprivate trackProcessor: any = null;\n\tprivate trackGenerator: any = null;\n\tprivate activeCodecStr: string = "avc1.42E01F";' ); // 2. Add Codec auto-discovery and Dynamic Decoder creation const decoderLogic = ` private async detectBestCodec(): Promise { const codecs = [ "av01.0.04M.08", // AV1 "vp09.00.10.08", // VP9 "avc1.42E01F" // H.264 ]; for (const c of codecs) { try { const support = await VideoEncoder.isConfigSupported({ codec: c, width: 1280, height: 720, bitrate: 2_500_000, framerate: 30 }); if (support.supported) { console.log(\`[QUANTUM WEBCODECS] Hardware GPU Codec Terdeteksi: \${c}\`); return c; } } catch (e) {} } return "avc1.42E01F"; // Fallback H.264 } private createDecoderForParticipant(senderId: number, codecStr: string = "avc1.42E01F") { // Jika decoder sudah ada dan codec-nya berbeda, tutup dulu if (this.videoDecoders.has(senderId)) { try { this.videoDecoders.get(senderId)!.close(); } catch(e){} this.videoDecoders.delete(senderId); } const decoder = new VideoDecoder({ output: (frame: any) => { this.tryAutoRegisterCanvas(senderId); const ctx = this.canvasCtxMap.get(senderId); if (ctx) { ctx.drawImage(frame, 0, 0, ctx.canvas.width, ctx.canvas.height); } frame.close(); }, error: (e: any) => console.error(\`Decoder Error untuk \${senderId}:\`, e), }); try { decoder.configure({ codec: codecStr, codedWidth: 1280, codedHeight: 720 }); this.videoDecoders.set(senderId, decoder); this.firstKeyFrameReceived.set(senderId, false); console.log(\`[QUANTUM WEBCODECS] Hardware Decoder (\${codecStr}) siap untuk Partisipan \${senderId}\`); } catch (e) { console.error("[QUANTUM WEBCODECS] Gagal konfigurasi decoder:", e); } } `; content = content.replace( /private createDecoderForParticipant\(senderId: number\) \{[\s\S]*?this\.firstKeyFrameReceived\.set\(senderId, false\);\s*?\n\s*?\/\/ Notifikasi React untuk merender tile/, decoderLogic + '\n\n\t\t// Notifikasi React untuk merender tile' ); // 3. Modify `activateUplink` to support WebCodecs const uplinkOld = ` const videoTrack = this.mediaStream.getVideoTracks()[0]; // === Canvas JPEG Pipeline: Works on ALL browsers === const captureVideo = document.createElement("video");`; const uplinkNew = ` const videoTrack = this.mediaStream.getVideoTracks()[0]; if (this.videoEngineMode === "webcodecs") { // === XCU QUANTUM WEBCODECS (HARDWARE GPU PIPELINE) === console.log("[UPLINK] XCU Quantum WebCodecs (GPU) Diaktifkan!"); this.activeCodecStr = await this.detectBestCodec(); let codecId = 0; if (this.activeCodecStr.startsWith("av01")) codecId = 2; else if (this.activeCodecStr.startsWith("vp09")) codecId = 1; this.videoEncoder = new VideoEncoder({ output: async (chunk: any, meta: any) => { if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; const chunkData = new Uint8Array(chunk.byteLength); chunk.copyTo(chunkData); // ENCRYPTION let finalPayload = chunkData; let isEncrypted = 0; let iv = new Uint8Array(12); if (this.e2eeKey) { window.crypto.getRandomValues(iv); const cipherBuffer = await window.crypto.subtle.encrypt( { name: "AES-GCM", iv: iv }, this.e2eeKey, chunkData ); finalPayload = new Uint8Array(cipherBuffer); isEncrypted = 2; } const frameType = chunk.type === "key" ? FRAME_VIDEO_KEY : FRAME_VIDEO_DELTA; // Jika KeyFrame, sisipkan 1 byte Codec ID di awal payload let packetLen = 8 + finalPayload.length; if (frameType === FRAME_VIDEO_KEY) packetLen += 1; if (isEncrypted) packetLen += 12; // tambah IV const packet = new Uint8Array(packetLen); packet[0] = frameType; packet[1] = isEncrypted ? 2 : 1; const view = new DataView(packet.buffer); view.setUint16(2, this.participantId, true); let offset = 8; if (isEncrypted) { view.setUint32(4, packetLen - 8, true); packet.set(iv, offset); offset += 12; } else { view.setUint32(4, packetLen - 8, true); } if (frameType === FRAME_VIDEO_KEY) { packet[offset] = codecId; // Sisipkan Codec ID offset += 1; } packet.set(finalPayload, offset); this.ws!.send(packet); this._frameCount++; }, error: (e: any) => console.error("[QUANTUM WEBCODECS] Encoder Error:", e) }); this.videoEncoder.configure({ codec: this.activeCodecStr, width: 1280, height: 720, hardwareAcceleration: "require", bitrate: 2_500_000, framerate: 30, latencyMode: "realtime" }); // Extract frames directly from camera using MediaStreamTrackProcessor if (typeof (window as any).MediaStreamTrackProcessor !== "undefined") { this.trackProcessor = new (window as any).MediaStreamTrackProcessor({ track: videoTrack }); const reader = this.trackProcessor.readable.getReader(); // Asynchronous background encoding loop (async () => { while (this.isRunning && this.videoEngineMode === "webcodecs") { try { const { done, value: frame } = await reader.read(); if (done || !frame) break; if (this.videoEncoder && this.videoEncoder.state === "configured") { // Force KeyFrame every 30 frames (1 second) for resilience this.videoEncoder.encode(frame, { keyFrame: this._frameCount % 30 === 0 }); } frame.close(); } catch (e) { break; } } })(); } } // === Canvas JPEG Pipeline: Works on ALL browsers === const captureVideo = document.createElement("video");`; content = content.replace(uplinkOld, uplinkNew); // 4. Wrap setInterval to only run when canvas mode content = content.replace( `const jpegInterval = setInterval(() => {`, `const jpegInterval = setInterval(() => {\n\t\t\t\tif (this.videoEngineMode === "webcodecs") return; // Bypass if using Quantum Engine` ); // 5. Update receiver to handle Codec ID for FRAME_VIDEO_KEY and Decryption const receiverOld = ` if (frameType === FRAME_VIDEO_DELTA || frameType === FRAME_VIDEO_KEY) { if (!this.videoDecoders.has(senderId)) { this.createDecoderForParticipant(senderId); } if (frameType === FRAME_VIDEO_DELTA && !this.firstKeyFrameReceived.get(senderId)) { continue; } if (frameType === FRAME_VIDEO_KEY) { this.firstKeyFrameReceived.set(senderId, true); } this.tryAutoRegisterCanvas(senderId); const decoder = this.videoDecoders.get(senderId); if (decoder && decoder.state === "configured") { const chunk = new EncodedVideoChunk({ type: frameType === FRAME_VIDEO_KEY ? "key" : "delta", timestamp: performance.now() * 1000, data: payloadData, }); decoder.decode(chunk); } continue; }`; const receiverNew = ` if (frameType === FRAME_VIDEO_DELTA || frameType === FRAME_VIDEO_KEY) { let rawData = payloadData; let isDecryptionFailed = false; if (quality === 2) { // Encrypted WebCodecs chunk if (this.e2eeKey && payloadData.length > 12) { const iv = payloadData.slice(0, 12); const cipher = payloadData.slice(12); try { const plainBuf = await window.crypto.subtle.decrypt( { name: "AES-GCM", iv: iv }, this.e2eeKey, cipher ); rawData = new Uint8Array(plainBuf); } catch (e) { isDecryptionFailed = true; } } else { isDecryptionFailed = true; } } if (isDecryptionFailed) continue; // Extract Codec ID if KeyFrame let chunkData = rawData; let codecStr = "avc1.42E01F"; // Default if (frameType === FRAME_VIDEO_KEY) { const codecId = rawData[0]; chunkData = rawData.slice(1); if (codecId === 2) codecStr = "av01.0.04M.08"; else if (codecId === 1) codecStr = "vp09.00.10.08"; // Re-create decoder if codec changes or not exists const existing = this.videoDecoders.get(senderId); if (!existing || (existing as any)._currentCodec !== codecStr) { this.createDecoderForParticipant(senderId, codecStr); const newDec = this.videoDecoders.get(senderId); if (newDec) (newDec as any)._currentCodec = codecStr; } this.firstKeyFrameReceived.set(senderId, true); } else { if (!this.videoDecoders.has(senderId)) { this.createDecoderForParticipant(senderId); } } if (frameType === FRAME_VIDEO_DELTA && !this.firstKeyFrameReceived.get(senderId)) { continue; } this.tryAutoRegisterCanvas(senderId); const decoder = this.videoDecoders.get(senderId); if (decoder && decoder.state === "configured") { try { const chunk = new (window as any).EncodedVideoChunk({ type: frameType === FRAME_VIDEO_KEY ? "key" : "delta", timestamp: performance.now() * 1000, data: chunkData, }); decoder.decode(chunk); } catch (e) { // Ignore decode errors to ensure Zero Error crash } } continue; }`; content = content.replace(receiverOld, receiverNew); // 6. Update deactivateUplink to cleanly close trackProcessor content = content.replace( `if (this.videoEncoder && this.videoEncoder.state !== "closed") {`, `if (this.videoEncoder && this.videoEncoder.state !== "closed") {\n\t\t\tthis.videoEncoder.close();\n\t\t\tthis.videoEncoder = null;\n\t\t}\n\t\tif (this.trackProcessor) {\n\t\t\ttry { /* Let GC handle trackProcessor */ } catch(e){}\n\t\t\tthis.trackProcessor = null;\n\t\t}\n\t\tif (false) {` ); // Hot Swap Method const hotSwap = ` public async hotSwapVideoEngine(mode: "canvas" | "webcodecs") { if (this.videoEngineMode === mode) return; console.log(\`[QUANTUM HOT-SWAP] Mengalihkan Engine ke: \${mode}\`); this.videoEngineMode = mode; // Jika kamera sedang nyala, kita matikan lalu nyalakan secara instan tanpa mematikan koneksi WebTransport if (this.mediaStream) { await this.deactivateUplink(); await this.activateUplink('camera'); } } `; content = content.replace('public unlockAudio() {', hotSwap + '\n\tpublic unlockAudio() {'); fs.writeFileSync(filePath, content, 'utf-8'); console.log('Successfully updated xcu-quantum-decoder.ts');