Skip to content

Instantly share code, notes, and snippets.

@tiagocoutinho
Created October 29, 2025 13:42
Show Gist options
  • Select an option

  • Save tiagocoutinho/e89e9d4a414abcc4451a44f9b2011a12 to your computer and use it in GitHub Desktop.

Select an option

Save tiagocoutinho/e89e9d4a414abcc4451a44f9b2011a12 to your computer and use it in GitHub Desktop.
WebRTC browser, no signaling
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>WebRTC Demo</title>
<style>
textarea { width: 100%; height: 100px;}
.video-player { border: 2px solid greenyellow; background-color: gray; width: 100%; }
</style>
</head>
<body>
<div>
<h2>WebRTC, Passing SDP with no signaling.</h2>
<p><b>Instructions: </b>
Start by opening two tabs side by side and follow the steps below to pass SDP offer and answer.
I will refer to each tab as <i><b>User 1</b></i> and <i><b>User 2</b></i>.
</p>
<ul>
<li>User 1 & 2: <button onclick="init()">Initialize</button></li>
<li>User 1:<button id="create-offer" onclick="createOffer()">Create offer</button></li>
<li>User 2: paste offer generated by user 1 into offer field and <button id="create-answer"
onclick="createAnswer()">Create answer</button></li>
<li>User 1: paste offer generated by user 2 into answer field and <button id="add-answer"
onclick="addAnswer()">Add answer</button></li>
</ul>
<div style="display: flex; column-gap: 1em;width: 100%;">
<div style="width: 100%;">
<label for="offer-sdp">SDP OFFER:</label>
<textarea id="offer-sdp" placeholder='User 1 click create offer; User 2, paste offer here...'></textarea>
<video class="video-player" id="user-1" autoplay playsinline></video>
</div>
<div style="width: 100%;">
<label for="answer-sdp">SDP Answer:</label>
<textarea id="answer-sdp" placeholder="User 2: click create answer; User 1: paste answer here..."></textarea>
<video class="video-player" id="user-2" autoplay playsinline></video>
</div>
</div>
</body>
<script>
let peerConnection = null;
const offerTextArea = document.getElementById('offer-sdp');
const answerTextArea = document.getElementById('answer-sdp');
let init = async () => {
offerTextArea.value = "";
answerTextArea.value = "";
if (peerConnection != null) {
peerConnection.close();
}
peerConnection = new RTCPeerConnection();
const localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false })
const remoteStream = new MediaStream();
document.getElementById('user-1').srcObject = localStream
document.getElementById('user-2').srcObject = remoteStream;
localStream.getTracks().forEach((track) => {
peerConnection.addTrack(track, localStream);
});
peerConnection.ontrack = (event) => {
event.streams[0].getTracks().forEach((track) => {
remoteStream.addTrack(track);
});
};
}
function onIceFor(textArea) {
return async event => {
if (event.candidate) {
textArea.value = JSON.stringify(peerConnection.localDescription);
navigator.clipboard.writeText(textArea.value);
}
}
}
let createOffer = async () => {
peerConnection.onicecandidate = onIceFor(offerTextArea);
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
}
let createAnswer = async () => {
let offer = JSON.parse(offerTextArea.value)
peerConnection.onicecandidate = onIceFor(answerTextArea);
await peerConnection.setRemoteDescription(offer);
let answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
}
let addAnswer = async () => {
let answer = JSON.parse(answerTextArea.value);
if (!peerConnection.currentRemoteDescription) {
peerConnection.setRemoteDescription(answer);
}
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment