Created
July 11, 2025 14:48
-
-
Save derekmcloughlin/f6bc62ab8d30476c5e5767eb5cb3c161 to your computer and use it in GitHub Desktop.
WebRTC Demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <body> | |
| <h3>Local SDP (copy this to remote)</h3> | |
| <textarea id="local" style="width:100%;height:150px"></textarea> | |
| <h3>Remote SDP (paste from other peer)</h3> | |
| <textarea id="remote" style="width:100%;height:150px"></textarea> | |
| <br /> | |
| <button onclick="createOffer()">Create Offer</button> | |
| <button onclick="createAnswer()">Create Answer</button> | |
| <button onclick="connect()">Set Remote Description</button> | |
| <br /><br /> | |
| <div> | |
| <input type="text" id="messageInput" placeholder="Type a message..."> | |
| <button onclick="sendMessage()">Send Message</button> | |
| </div> | |
| <div id="messages"></div> | |
| <script> | |
| const pc = new RTCPeerConnection({ | |
| iceServers: [ | |
| { urls: 'stun:stun.l.google.com:19302' }, | |
| { urls: 'stun:stun1.l.google.com:19302' } | |
| ] | |
| }); | |
| let dataChannel = null; | |
| let isInitiator = false; | |
| // Handle ICE candidates | |
| pc.onicecandidate = (e) => { | |
| if (e.candidate === null) { | |
| // ICE gathering complete, display the SDP | |
| document.getElementById('local').value = JSON.stringify(pc.localDescription); | |
| } | |
| }; | |
| // Handle incoming data channel (for answerer) | |
| pc.ondatachannel = (event) => { | |
| const receiveChannel = event.channel; | |
| setupDataChannel(receiveChannel); | |
| }; | |
| // Handle connection state changes | |
| pc.onconnectionstatechange = () => { | |
| console.log('Connection state:', pc.connectionState); | |
| if (pc.connectionState === 'connected') { | |
| addMessage('Connected to peer!'); | |
| } | |
| }; | |
| function setupDataChannel(channel) { | |
| dataChannel = channel; | |
| channel.onopen = () => { | |
| console.log('Data channel opened'); | |
| addMessage('Data channel opened'); | |
| if (isInitiator) { | |
| channel.send("Hello from initiator!"); | |
| } else { | |
| channel.send("Hello from answerer!"); | |
| } | |
| }; | |
| channel.onmessage = (e) => { | |
| console.log("Received:", e.data); | |
| addMessage(`Received: ${e.data}`); | |
| }; | |
| channel.onclose = () => { | |
| console.log('Data channel closed'); | |
| addMessage('Data channel closed'); | |
| }; | |
| } | |
| window.createOffer = async () => { | |
| isInitiator = true; | |
| // Create data channel first for initiator | |
| const channel = pc.createDataChannel("chat"); | |
| setupDataChannel(channel); | |
| const offer = await pc.createOffer(); | |
| await pc.setLocalDescription(offer); | |
| addMessage('Offer created. Copy the Local SDP to the other peer.'); | |
| }; | |
| window.createAnswer = async () => { | |
| isInitiator = false; | |
| const remoteSDP = JSON.parse(document.getElementById('remote').value); | |
| await pc.setRemoteDescription(new RTCSessionDescription(remoteSDP)); | |
| const answer = await pc.createAnswer(); | |
| await pc.setLocalDescription(answer); | |
| addMessage('Answer created. Copy the Local SDP back to the initiator.'); | |
| }; | |
| window.connect = async () => { | |
| const remoteSDP = JSON.parse(document.getElementById('remote').value); | |
| await pc.setRemoteDescription(new RTCSessionDescription(remoteSDP)); | |
| addMessage('Remote description set. Connection should establish shortly.'); | |
| }; | |
| window.sendMessage = () => { | |
| const input = document.getElementById('messageInput'); | |
| const message = input.value.trim(); | |
| if (message && dataChannel && dataChannel.readyState === 'open') { | |
| dataChannel.send(message); | |
| addMessage(`Sent: ${message}`); | |
| input.value = ''; | |
| } else { | |
| addMessage('Data channel not ready or message empty'); | |
| } | |
| }; | |
| function addMessage(message) { | |
| const messagesDiv = document.getElementById('messages'); | |
| const messageElement = document.createElement('div'); | |
| messageElement.textContent = `${new Date().toLocaleTimeString()}: ${message}`; | |
| messagesDiv.appendChild(messageElement); | |
| messagesDiv.scrollTop = messagesDiv.scrollHeight; | |
| } | |
| // Allow Enter key to send message | |
| document.getElementById('messageInput').addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| sendMessage(); | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment