Understanding WebRTC: Building a Real-Time Interactive Portal
A guide to building a WebRTC-based collaborative portal with video, screen sharing, messaging, file transfer, Monaco, and Yjs-powered collaboration.
Real Time Interactive Portal
This guide explores how to build a peer-to-peer collaborative application using WebRTC, complete with video sharing, screen sharing, messaging, and file transfer capabilities.
Key Features
- Peer-to-peer collaborative application with video sharing, screen sharing, messaging, and file transfer
- Synchronized YouTube video playback across multiple tabs
- Integrated code editor with peer-to-peer video call functionality (perfect for technical interviews)
- Multi-language code editor support (C, C++, Java, Python, JavaScript/TypeScript, Golang, and more)
Technology Stack
Frontend
- ReactJS with TailwindCSS for UI
- WebRTC for peer-to-peer communication
- Monaco editor for code editing
- Yjs for collaborative editing features
- Socket.io client for signaling
Backend
- NodeJS with Express
- Socket.io for signaling server implementation
Understanding WebRTC
WebRTC (Web Real-Time Communication) enables powerful peer-to-peer video and voice communication directly in the browser. Let’s dive into the key concepts and components.
WebRTC Architecture
WebRTC uses SRTP (Secure Real-time Transport Protocol) for encrypting, authenticating, and protecting data and conversations.
Connection Types
-
P2P (Peer-to-Peer)
- Ideal for 1:1 connections
- Limited scalability due to connection overhead
-
Mesh
- Supports multiple connections (1:Many)
- Resource-intensive for many connections
- High CPU and bandwidth requirements
- Limited scalability
-
SFU (Selective Forwarding Unit)
- More efficient than mesh for multiple participants
- Only requires sending/receiving media from each party once
- Better scalability for larger groups
-
MCU (Multipoint Control Unit)
- Centralized processing unit
- Handles media mixing and distribution
Essential WebRTC Concepts
ICE (Interactive Connectivity Establishment)
ICE is a framework that allows browsers to connect with peers, overcoming challenges posed by firewalls and NAT:
const peerConnection = new RTCPeerConnection({
iceServers: [{
urls: "stun:stun.l.google.com:19302",
}]
});
STUN and TURN Servers
STUN (Session Traversal Utilities for NAT)
- Helps discover public IP addresses
- Determines router restrictions
TURN (Traversal Using Relays around NAT)
- Enhanced version of STUN
- Provides relay services when direct connection fails
const iceConfiguration = {
iceServers: [
{
urls: 'turn:my-turn-server.mycompany.com:19403',
username: 'optional-username',
credential: 'auth-token'
}
]
};
NAT (Network Address Translation)
NAT enables private networks to interact with the internet by translating private IP addresses to public ones. This process is crucial for:
- Managing private network addressing
- Enabling internet connectivity for multiple devices
- Providing security through address translation
SDP (Session Description Protocol)
SDP describes multimedia content of the connection:
- Resolution specifications
- Format details
- Codec information
- Encryption parameters
Implementation Guide
1. Setting Up Media Access
// Access camera and microphone
window.navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then((stream) => {
setLocalStream(stream);
});
// Enable screen sharing
const screenStream = await window.navigator.mediaDevices.getDisplayMedia({
video: true
});
const screenTrack = screenStream.getVideoTracks()[0];
2. Establishing Peer Connection
// Create and configure peer connection
const peerConnection = new RTCPeerConnection(iceConfiguration);
// Add media tracks
peerConnection.addTrack(localStream.getVideoTracks()[0]);
// Create and set offer
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
3. Implementing Screen Sharing
async function handleScreenShare() {
if (!option.isScreenSharing) {
try {
const screenStream = await window.navigator.mediaDevices.getDisplayMedia({
video: true
});
const screenTrack = screenStream.getVideoTracks()[0];
// Replace video track
const senders = peerConnection.getSenders();
const videoSender = senders.find(sender =>
sender.track.kind === 'video'
);
videoSender.replaceTrack(screenTrack);
setLocalStream(screenStream);
setOption((s) => ({ ...s, isScreenSharing: true }));
screenTrack.onended = () => {
handleStopScreenShare();
};
} catch (err) {
console.error("Error sharing screen: ", err);
}
} else {
handleStopScreenShare();
}
}
4. Data Channel Implementation
const channel = peerConnection.createDataChannel('sendMessage');
channel.onopen = () => {
console.log('Data channel is open');
setOption((s) => ({ ...s, disabled: false }));
};
channel.onclose = () => {
console.log('Data channel is closed');
setOption((s) => ({ ...s, disabled: true }));
};
channel.onmessage = handleReceiveMessage;
5. Video Recording
async function RecordWindow() {
const recordedChunks = [];
const options = { mimeType: "video/webm; codecs=vp9" };
const mediaRecorder = new MediaRecorder(
recordOption === 'localStream' ? localStream : remoteStream,
options
);
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start();
function handleDataAvailable(e) {
if (e.data.size > 0) {
recordedChunks.push(e.data);
download();
}
}
function download() {
const blob = new Blob(recordedChunks, {
type: "video/webm",
});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = "recording.webm";
a.click();
window.URL.revokeObjectURL(url);
}
}
Debugging
For debugging WebRTC connections, you can use Chrome’s built-in WebRTC internals:
- Open
chrome://webrtc-internals/in your Chrome browser - Monitor connection statistics, ICE candidates, and media metrics
Conclusion
WebRTC provides a powerful foundation for building real-time communication applications. By understanding its core concepts and implementing proper connection handling, you can create robust peer-to-peer applications with features like video calls, screen sharing, and file transfer.
For the complete source code and more details, visit the project repository.
More posts
WebScraping Using Puppeteer
Dec 15, 2024 3 min readNotes from experimenting with Puppeteer, stealth plugins, randomized user agents, and scraping tweet content in a more resilient way.
Generate Random User Agent - Custom Script
Dec 19, 2024 3 min readA small custom TypeScript utility for generating newer, randomized browser user agents instead of relying on stale package defaults.
Informer implementation with the NewSharedInformerFactoryWithOptions
Feb 18, 2025 5 min readA focused look at scoping Kubernetes informers to a specific deployment and streaming targeted workload updates over WebSocket.
Written by Rahul Vishwakarma — this is the first-party home for this article on rahulxf.com.