WebRTC Basics Review
WebRTC Architecture Overview
WebRTC (Web Real-Time Communication) is an open-source project that enables real-time voice or video communication through web browsers. Its core architecture consists of the following key components:
- Media Engine: Handles audio and video capture, encoding, decoding, and rendering.
- Transport Components: Manages network connections, data transmission, and congestion control.
- Session Management: Handles signaling exchange and session state.
Core API Overview
WebRTC’s core APIs can be divided into three categories:
- Media Capture and Stream APIs:
getUserMedia(): Accesses user media devices (camera, microphone).MediaStream: Interface representing a media stream.MediaStreamTrack: Represents a single media track (audio or video).
- Peer Connection APIs:
RTCPeerConnection: Manages the connection between two peers.RTCDataChannel: Enables arbitrary data transmission between two peers.
- Data Channel APIs:
RTCDataChannel: Provides a bidirectional communication channel similar to WebSocket.
Signaling Mechanism
WebRTC itself does not include a signaling mechanism, requiring developers to implement it themselves. Common signaling approaches include:
- WebSocket: Full-duplex communication, suitable for real-time signaling exchange.
- Socket.io: A real-time framework based on WebSocket.
- HTTP Polling: Simple but less efficient.
// Example of using WebSocket for signaling exchange
const socket = new WebSocket('wss://example.com/signaling');
socket.onmessage = async (event) => {
const message = JSON.parse(event.data);
if (message.type === 'offer') {
// Handle offer
await peerConnection.setRemoteDescription(new RTCSessionDescription(message));
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
socket.send(JSON.stringify({
type: 'answer',
sdp: peerConnection.localDescription.sdp
}));
} else if (message.type === 'ice-candidate') {
// Handle ICE candidate
await peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
}
};
// Example of sending an offer
async function createOffer() {
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
socket.send(JSON.stringify({
type: 'offer',
sdp: peerConnection.localDescription.sdp
}));
}WebRTC Advanced APIs
RTCPeerConnection Advanced Configuration
RTCPeerConnection is the core interface of WebRTC, responsible for managing connections between two peers. Below are its advanced configuration options:
ICE Server Configuration
const configuration = {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302'
},
{
urls: 'turn:turn.example.com',
username: 'username',
credential: 'password'
}
],
iceTransportPolicy: 'all', // 'all' or 'relay'
bundlePolicy: 'balanced', // 'balanced', 'max-bundle', 'max-compat'
rtcpMuxPolicy: 'require', // 'require' or 'negotiate'
peerIdentity: 'user123', // Optional, for encryption
certificates: [ // Optional, for DTLS-SRTP
await RTCPeerConnection.generateCertificate({
name: 'ECDSA',
namedCurve: 'P-256'
})
],
iceCandidatePoolSize: 0 // Number of pre-fetched ICE candidates
};
const peerConnection = new RTCPeerConnection(configuration);Connection State Monitoring
peerConnection.oniceconnectionstatechange = () => {
console.log('ICE Connection State:', peerConnection.iceConnectionState);
};
peerConnection.onconnectionstatechange = () => {
console.log('Connection State:', peerConnection.connectionState);
};
peerConnection.onsignalingstatechange = () => {
console.log('Signaling State:', peerConnection.signalingState);
};
// Detailed statistics
setInterval(async () => {
const stats = await peerConnection.getStats();
stats.forEach(report => {
if (report.type === 'transport') {
console.log('Transport Stats:', report);
} else if (report.type === 'candidate-pair') {
console.log('Candidate Pair Stats:', report);
}
});
}, 5000);RTCDataChannel Advanced Usage
RTCDataChannel allows arbitrary data transmission between two peers, supporting both reliable and unreliable modes.
Creating a Data Channel
// Create a data channel on the initiator
const dataChannel = peerConnection.createDataChannel('chat', {
ordered: true, // Ensure message order
maxPacketLifeTime: 3000, // Maximum message lifetime (ms), effective for UDP
maxRetransmits: 3, // Maximum retransmissions, effective for UDP
protocol: 'sctp', // Protocol used
negotiated: false, // Whether negotiated by the application layer
id: 1 // Optional, specifies channel ID
});
// Listen for data channel creation on the receiver
peerConnection.ondatachannel = (event) => {
const dataChannel = event.channel;
setupDataChannel(dataChannel);
};Data Channel Event Handling
function setupDataChannel(channel) {
channel.onopen = () => {
console.log('Data channel opened');
channel.send('Hello from ' + localPeerId);
};
channel.onclose = () => {
console.log('Data channel closed');
};
channel.onmessage = (event) => {
console.log('Received message:', event.data);
// Process message...
};
channel.onerror = (error) => {
console.error('Data channel error:', error);
};
// Buffer status monitoring
channel.onbufferedamountlow = () => {
console.log('Buffer low, can send more data');
};
// Set buffer threshold
channel.bufferedAmountLowThreshold = 1024 * 1024; // 1MB
}Advanced Data Transmission Modes
// Binary data transmission
const buffer = new ArrayBuffer(1024);
const view = new Uint8Array(buffer);
// Fill data...
dataChannel.send(buffer);
// File transmission example
async function sendFile(file) {
// Send file metadata
dataChannel.send(JSON.stringify({
type: 'file-meta',
name: file.name,
size: file.size,
type: file.type
}));
// Send file content in chunks
const chunkSize = 64 * 1024; // 64KB
let offset = 0;
while (offset < file.size) {
const chunk = file.slice(offset, offset + chunkSize);
const arrayBuffer = await chunk.arrayBuffer();
dataChannel.send(arrayBuffer);
offset += chunkSize;
// Update progress
updateProgress(offset / file.size);
}
// Send completion notification
dataChannel.send(JSON.stringify({
type: 'file-complete'
}));
}Advanced Media Processing APIs
WebRTC provides rich media processing APIs, allowing developers to perform advanced operations on audio and video streams.
Media Stream Track Control
// Get media stream
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true
});
// Get tracks
const audioTrack = stream.getAudioTracks()[0];
const videoTrack = stream.getVideoTracks()[0];
// Enable/disable tracks
audioTrack.enabled = false; // Mute
videoTrack.enabled = false; // Disable video
// Replace track
const newVideoTrack = await navigator.mediaDevices.getUserMedia({
video: true
}).then(stream => stream.getVideoTracks()[0]);
videoTrack.replaceTrack(newVideoTrack);
// Add tracks to connection
peerConnection.addTrack(audioTrack, stream);
peerConnection.addTrack(videoTrack, stream);
// Remove track from connection
peerConnection.removeTrack(peerConnection.getSenders().find(
sender => sender.track === audioTrack
));Media Constraints and Advanced Configuration
// Advanced media constraints
const constraints = {
audio: {
echoCancellation: true,
noiseSuppression: true,
autoGainControl: true,
channelCount: 1,
sampleRate: 48000,
sampleSize: 16,
latency: 0.01
},
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
frameRate: { ideal: 30, max: 60 },
facingMode: 'user',
advanced: [
{ width: 1920, height: 1080 },
{ width: 1280, height: 720 }
]
}
};
const stream = await navigator.mediaDevices.getUserMedia(constraints);Media Recording
// Record media stream using MediaRecorder
const mediaRecorder = new MediaRecorder(stream, {
mimeType: 'video/webm;codecs=vp9,opus',
audioBitsPerSecond: 128000,
videoBitsPerSecond: 2500000,
bitsPerSecond: 2628000
});
const recordedChunks = [];
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
recordedChunks.push(event.data);
}
};
mediaRecorder.onstop = () => {
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'recording.webm';
a.click();
};
// Start recording
mediaRecorder.start(1000); // Generate a data chunk every 1 second
// Stop recording
setTimeout(() => {
mediaRecorder.stop();
}, 10000); // Record for 10 seconds



