From d6f81ff72ba4e65d14cd80d7b1a4be674c7b54ac Mon Sep 17 00:00:00 2001 From: david Date: Fri, 4 Apr 2025 13:58:42 -0700 Subject: [PATCH 1/2] add turn server --- src/static/js/video.ts | 25 ++++++++++++++++++++----- src/ws.ts | 23 +++++++++++++++++------ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/static/js/video.ts b/src/static/js/video.ts index 1b6e5d3..371b49c 100644 --- a/src/static/js/video.ts +++ b/src/static/js/video.ts @@ -1,8 +1,23 @@ -const host = window.location.hostname -const ws0 = new WebSocket(`ws://${host}:3001`); -const ws1 = new WebSocket(`ws://${host}:3002`); -const pc0 = new RTCPeerConnection({ iceServers: [] }); -const pc1 = new RTCPeerConnection({ iceServers: [] }); +const isSecure = window.location.protocol === 'https:'; +const host = window.location.hostname; +const ws0builder = isSecure ? `wss://${host}/ws0` : `ws://${host}:3001`; +const ws1builder = isSecure ? `wss://${host}/ws1` : `ws://${host}:3002`; +const ws0 = new WebSocket(ws0builder); +const ws1 = new WebSocket(ws1builder); +const pc0 = new RTCPeerConnection({ iceServers: [ + { + urls: 'turn:dwestgate.us:3478?transport=udp', + username: 'webrtcuser', + credential: 'webrtccred' + } +] }); +const pc1 = new RTCPeerConnection({ iceServers: [ + { + urls: 'turn:dwestgate.us:3478?transport=udp', + username: 'webrtcuser', + credential: 'webrtccred' + } +] }); const video0 = document.getElementById('video0') as HTMLVideoElement; const video1 = document.getElementById('video1') as HTMLVideoElement; diff --git a/src/ws.ts b/src/ws.ts index 4c0b0a3..95afcab 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -9,14 +9,14 @@ const FRAME_SIZE = WIDTH * HEIGHT * 1.5; // YUV420p frame size (460800 bytes) export default class TVWebSocket { videoDevice: string; - public constructor(port: number, videoDevice) { - this.videoDevice = videoDevice + public constructor(port: number, videoDevice) { + this.videoDevice = videoDevice const ffmpegProcess = this.startFFmpeg(); const videoTrack = this.createVideoTrack(ffmpegProcess); const audioTrack = this.createAudioTrack(ffmpegProcess); - ffmpegProcess.stdio[2].on('data',data=>{ + ffmpegProcess.stdio[2].on('data', data => { // console.log("stdio[2] ",data.toString()) }) @@ -24,7 +24,7 @@ export default class TVWebSocket { const wss = new ws.WebSocketServer({ port }); wss.on('connection', async (ws: ws.WebSocket) => { - const peerConnection: RTCPeerConnection = this.createPeerConnection(videoTrack, audioTrack); + const peerConnection: RTCPeerConnection = this.createPeerConnection(videoTrack, audioTrack); ws.on('message', async (message: Buffer) => { const { type, data } = JSON.parse(message.toString()); @@ -113,7 +113,7 @@ export default class TVWebSocket { return p; } - + createVideoTrack = (ffmpegProcess: ChildProcessWithoutNullStreams) => { let videoBuffer = Buffer.alloc(0); const videoSource = new nonstandard.RTCVideoSource(); @@ -185,7 +185,18 @@ export default class TVWebSocket { } createPeerConnection = (videoTrack: MediaStreamTrack, audioTrack: MediaStreamTrack): RTCPeerConnection => { - const peerConnection = new RTCPeerConnection({ iceServers: [] }); + const peerConnection = new RTCPeerConnection({ + iceServers: [ + { + urls: 'stun:192.168.0.3:3478' + }, + { + urls: 'turn:192.168.0.3:3478?transport=udp', + username: 'webrtcuser', + credential: 'webrtccred' + } + ] + }); const stream = new MediaStream() stream.addTrack(videoTrack) stream.addTrack(audioTrack); From 803de093058028fae5e9c10324bddf2e30a379de Mon Sep 17 00:00:00 2001 From: david Date: Fri, 4 Apr 2025 14:28:13 -0700 Subject: [PATCH 2/2] abstract config --- src/static/js/video.ts | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/static/js/video.ts b/src/static/js/video.ts index 371b49c..c6fc4ba 100644 --- a/src/static/js/video.ts +++ b/src/static/js/video.ts @@ -4,20 +4,17 @@ const ws0builder = isSecure ? `wss://${host}/ws0` : `ws://${host}:3001`; const ws1builder = isSecure ? `wss://${host}/ws1` : `ws://${host}:3002`; const ws0 = new WebSocket(ws0builder); const ws1 = new WebSocket(ws1builder); -const pc0 = new RTCPeerConnection({ iceServers: [ - { - urls: 'turn:dwestgate.us:3478?transport=udp', - username: 'webrtcuser', - credential: 'webrtccred' - } -] }); -const pc1 = new RTCPeerConnection({ iceServers: [ - { - urls: 'turn:dwestgate.us:3478?transport=udp', - username: 'webrtcuser', - credential: 'webrtccred' - } -] }); +const config = { + iceServers: [ + { + urls: ['stun:dwestgate.us:3478','turn:dwestgate.us:3478?transport=udp'], + username: 'webrtcuser', + credential: 'webrtccred' + } + ] +}; +const pc0 = new RTCPeerConnection(config); +const pc1 = new RTCPeerConnection(config); const video0 = document.getElementById('video0') as HTMLVideoElement; const video1 = document.getElementById('video1') as HTMLVideoElement; @@ -80,3 +77,20 @@ ws1.onmessage = async (message) => { await pc1.addIceCandidate(msg.data); } }; + +// TODO: Not yet working +// const dc0 = pc0.createDataChannel("keepalive"); +// dc0.onopen = () =>{ +// console.log("Data channel 0 open"); +// setInterval(()=>{ +// dc0.send("ping"); +// },10000) +// } + +// const dc1 = pc1.createDataChannel("keepalive"); +// dc1.onopen = () =>{ +// console.log("Data channel 1 open"); +// setInterval(()=>{ +// dc1.send("ping"); +// },10000) +// }