I'm trying to make a simple and straightforward example for WebRTC without a signaling server. The code works (whole HTML file below), but it feels like I'm overshadowing something in the logic that I can't pinpoint. I need help simplifying this code for easier readability. There are little limitations in regards to legacy.
<!DOCTYPE html>
<meta charset="utf-8">
<title>miniWebRTC</title>
<div id="createRoom">
<h3>Create or join a room?</h3>
<button id="createBtn">BOB: Create</button>
<button id="joinBtn">ALICE: Join</button>
</div>
<div id="bobPrompt">
<h3>BOB: Send your local offer to ALICE</h3>
<input id="localOffer">
<h3>Then, paste the "answer" you received</h3>
<input id="remoteAnswer">
<br>
<br>
<button id="answerRecdBtn">Okay, I pasted it.</button>
</div>
<div id="alicePrompt">
<h3>ALICE: Paste the "offer" you received</h3>
<input id="remoteOffer">
<br>
<br>
<button id="offerRecdBtn">Okay, I pasted it.</button>
<h3>Then, send your local answer to BOB</h3>
<input id="localAnswer">
</div>
<div id="chatPrompt">
<h1>Chat</h1>
<br>
<div id="chatlog" style="height:200px; overflow:auto; border:1px solid"></div>
<br>
<input type="text" id="messageTextBox" placeholder="Type your message here">
<button onclick="sendMessage()">Send message</button>
</div>
<script>
// @ts-check
const config = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
// The local browser's RTCPeerConnection
const peerConnection = new RTCPeerConnection(config)
/** @type {RTCDataChannel | null} data channel */
let activeDataChannel = null;
function sendMessage() {
if (messageTextBox.value) {
activeDataChannel.send(JSON.stringify({ message: messageTextBox.value }));
chatlog.innerHTML += `<span>ME: ${messageTextBox.value}</span><br/>`;
messageTextBox.value = "";
}
}
/**
* Shows one of the 4 div elements in the webpage, and hides the rest.
*
* @param {part} part The part to show.
*/
function showPart(part) {
const divList = [createRoom, bobPrompt, alicePrompt, chatPrompt]
// Hide all elements that are not part
divList.forEach(div => div.style.display = (part == div ? "block" : "none"));
}
showPart(createRoom);
// BOB: create room
createBtn.addEventListener("click", async () => {
showPart(bobPrompt);
const dataChannel = peerConnection.createDataChannel('chat');
activeDataChannel = dataChannel;
peerConnection.setLocalDescription(await peerConnection.createOffer())
// Once all ice candidates are collected, set the value
peerConnection.addEventListener("icecandidate", ({ candidate }) => {
if (candidate == null) {
localOffer.value = JSON.stringify(peerConnection.localDescription);
}
})
// BOB: pasted Alice's answer
answerRecdBtn.addEventListener("click", async () => {
const answer = remoteAnswer.value;
const answerDesc = new RTCSessionDescription(JSON.parse(answer))
await peerConnection.setRemoteDescription(answerDesc);
}, { once: true });
// ALICE sent a message to BOB
dataChannel.addEventListener("message", e => {
const data = JSON.parse(e.data)
chatlog.innerHTML += `<span>THEM: ${data.message}</span><br/>`;
chatlog.scrollTop = chatlog.scrollHeight
})
peerConnection.addEventListener("connectionstatechange", e => {
if (peerConnection.connectionState === "connected") {
// Connected!
showPart(chatPrompt);
}
})
}, { once: true });
// ALICE: listen to room
joinBtn.addEventListener("click", () => {
showPart(alicePrompt);
// ALICE: pasted Bob's answer
offerRecdBtn.addEventListener("click", async () => {
const offer = remoteOffer.value;
const offerDesc = new RTCSessionDescription(JSON.parse(offer))
await peerConnection.setRemoteDescription(offerDesc)
await peerConnection.setLocalDescription(await peerConnection.createAnswer())
peerConnection.addEventListener("icecandidate", e => {
if (e.candidate == null) {
localAnswer.value = JSON.stringify(peerConnection.localDescription);
}
})
}, { once: true });
peerConnection.addEventListener("datachannel", ({ channel }) => {
// Connected!
activeDataChannel = channel;
showPart(chatPrompt);
activeDataChannel.addEventListener("message", e => {
const data = JSON.parse(e.data)
chatlog.innerHTML += `<span>THEM: ${data.message}</span><br/>`;
chatlog.scrollTop = chatlog.scrollHeight
})
})
}, { once: true });
</script>