WebRTC
WebRTC (Web Real-Time Communication) è uno standard aperto e un insieme di API del browser che consentono la comunicazione in tempo reale direttamente tra browser e applicazioni web.
WebRTC: comunicazione in tempo reale nel browser
WebRTC (Web Real-Time Communication) è uno standard aperto e un insieme di API del browser che consentono a due browser di scambiarsi audio, video e dati arbitrari direttamente tra loro — peer-to-peer — senza instradare i contenuti multimediali attraverso un server e senza alcun plugin. Viene utilizzato per videoconferenze, chiamate vocali, condivisione dello schermo, stato di gioco in tempo reale e trasferimento di file a bassa latenza.
Questo capitolo spiega cosa offre WebRTC, le tre API su cui è costruito, i concetti di signaling e NAT traversal che confondono la maggior parte dei principianti, e un esempio completo con canale dati funzionante che puoi eseguire su questa pagina.
Cosa fa effettivamente WebRTC
Il browser sa già come comunicare con un server (vedi Fetch API e WebSockets). WebRTC aggiunge il pezzo mancante: un modo per due client di parlare tra loro. Una volta aperta una connessione peer, i media e i dati viaggiano lungo il percorso più breve possibile — spesso direttamente tra le due macchine — il che spiega perché la latenza di WebRTC è molto inferiore rispetto all'instradamento di tutto attraverso il backend.
Utilizzi tipici:
- Chiamate audio e video — voce/video in tempo reale, come Zoom o Google Meet.
- Condivisione dello schermo — acquisisci uno schermo o una finestra con
getDisplayMedia()e trasmettila a un peer. - Dati in tempo reale — stato di gioco, chat, posizioni del cursore o blocchi di file tramite un
RTCDataChannel.
Perché usare WebRTC
- Peer-to-peer, bassa latenza. I media fluiscono direttamente tra i peer, non attraverso il tuo server, quindi i round-trip sono brevi e i costi di banda rimangono contenuti.
- Senza plugin. Integrato in ogni browser moderno — niente Flash, niente app native, niente download.
- Crittografato per impostazione predefinita. I media usano SRTP e i canali dati usano DTLS; la crittografia è obbligatoria e non può essere disattivata.
- Multipiattaforma. Funziona su browser desktop e mobile e da app native tramite lo stesso standard.
- Standard aperto. Mantenuto da W3C e IETF, quindi continua a migliorare senza vendor lock-in.
Le tre API principali
WebRTC è in realtà tre API che lavorano insieme:
- MediaStream API (
getUserMedia) — acquisisce audio/video dal microfono, dalla fotocamera o dallo schermo comeMediaStream. - RTCPeerConnection — il cuore di WebRTC. Negozia, cripta e mantiene la connessione tra due peer e trasporta le tracce multimediali.
- RTCDataChannel — un canale bidirezionale per l'invio di dati arbitrari (stringhe o binari) peer-to-peer, simile a WebSockets ma senza un server nel mezzo.
Signaling: la parte che WebRTC non fa
Due browser non possono trovarsi dal nulla. Prima che una connessione peer possa aprirsi, i peer devono scambiare due tipi di informazioni:
- SDP (Session Description Protocol) — un'«offerta» e una «risposta» che descrivono codec, formati multimediali e parametri di connessione.
- Candidati ICE — possibili indirizzi di rete (coppie IP/porta) a cui ciascun peer può essere raggiunto.
WebRTC non definisce come avvenga questo scambio — questo è compito tuo, e si chiama signaling. Costruisci un canale di signaling con qualsiasi trasporto server desideri; WebSockets è la scelta più comune. Il flusso è sempre:
- Il chiamante crea un'offerta e la invia tramite il server di signaling.
- Il chiamato riceve l'offerta, crea una risposta e la rimanda indietro.
- Entrambi i peer scambiano i candidati ICE man mano che vengono scoperti.
- La connessione peer-to-peer diretta viene stabilita; il server di signaling non è più necessario.
STUN e TURN: superare i firewall
La maggior parte dei dispositivi si trova dietro NAT (Network Address Translation) e firewall, quindi un peer raramente conosce il proprio indirizzo pubblico. Due tipi di server risolvono questo problema:
- STUN server — indica a un peer il proprio IP/porta pubblico, così i peer possono tentare una connessione diretta. Economico e stateless; Google ne gestisce alcuni pubblici gratuiti.
- TURN server — instrada i media quando una connessione diretta è impossibile (firewall aziendali rigidi). Costa banda, quindi è un fallback, non l'impostazione predefinita.
Elenchi questi server nella configurazione iceServers passata a RTCPeerConnection:
const configuration = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
// A TURN server is added for hard-to-reach networks:
// { urls: 'turn:turn.example.com', username: 'user', credential: 'pass' }
],
};
const peerConnection = new RTCPeerConnection(configuration);Esempio: acquisire la fotocamera con getUserMedia
Il primo passo di qualsiasi videochiamata è ottenere lo stream locale. getUserMedia restituisce una Promise, quindi puoi usare async/await:
<video id="localVideo" autoplay playsinline muted></video>const localVideo = document.getElementById('localVideo');
async function startCamera() {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
localVideo.srcObject = stream; // show the live camera feed
return stream;
} catch (error) {
console.error('Could not access camera/microphone:', error.message);
}
}
startCamera();getUserMedia funziona solo in un contesto sicuro (HTTPS o localhost) e chiede all'utente il permesso — non puoi mai registrare qualcuno silenziosamente.
Esempio: un canale dati completo tra due peer
Il modo più chiaro per vedere WebRTC funzionare è connettere due oggetti RTCPeerConnection tra loro in un singolo script. Qui entrambi i peer vivono nella stessa pagina, quindi possiamo collegare il loro signaling direttamente invece che tramite un server — lo scambio SDP/ICE è esattamente quello che un vero server di signaling trasporterebbe. Incolla questo in una console del browser su qualsiasi pagina HTTPS per vederlo funzionare:
// Two peers, normally on different machines.
const caller = new RTCPeerConnection();
const callee = new RTCPeerConnection();
// --- Signaling: hand each peer's ICE candidates to the other.
// In production this travels over WebSockets; here we call directly.
caller.onicecandidate = (e) => e.candidate && callee.addIceCandidate(e.candidate);
callee.onicecandidate = (e) => e.candidate && caller.addIceCandidate(e.candidate);
// The callee listens for the channel the caller opens.
callee.ondatachannel = (event) => {
const channel = event.channel;
channel.onmessage = (e) => {
console.log('Callee received:', e.data);
channel.send('pong'); // reply over the same channel
};
};
// The caller creates the data channel.
const channel = caller.createDataChannel('chat');
channel.onopen = () => channel.send('ping');
channel.onmessage = (e) => console.log('Caller received:', e.data);
// --- Offer / answer negotiation.
async function connect() {
const offer = await caller.createOffer();
await caller.setLocalDescription(offer);
await callee.setRemoteDescription(offer);
const answer = await callee.createAnswer();
await callee.setLocalDescription(answer);
await caller.setRemoteDescription(answer);
}
connect();
// Logs:
// Callee received: ping
// Caller received: pongIl pattern è lo stesso per il video: invece di createDataChannel, chiami peerConnection.addTrack(track, stream) per ogni traccia da getUserMedia, e leggi i media in arrivo in un handler ontrack:
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
stream.getTracks().forEach((track) => peerConnection.addTrack(track, stream));
// The remote peer's media arrives here:
peerConnection.ontrack = (event) => {
document.getElementById('remoteVideo').srcObject = event.streams[0];
};Errori comuni
- Richiede HTTPS.
getUserMediaegetDisplayMediafalliscono al di fuori di un contesto sicuro (HTTPS olocalhost). - Hai comunque bisogno di un server di signaling. WebRTC gestisce i media, ma devi costruire tu stesso lo scambio offerta/risposta/ICE — di solito tramite WebSockets.
- Crea sempre offerta/risposta nell'ordine corretto.
setLocalDescriptiondeve essere eseguito prima disetRemoteDescriptionper il lato corrispondente, altrimenti la negoziazione fallisce. - Non dimenticare un server TURN in produzione. Solo STUN fallisce sulle reti restrittive; senza TURN, circa il 10–20% delle connessioni reali non si stabilirà.
- I permessi possono essere negati. Racchiudi
getUserMediain un try/catch e gestisci il rifiuto in modo elegante.
Riepilogo
WebRTC offre al browser vero audio, video e dati peer-to-peer. Usa getUserMedia per acquisire i media, RTCPeerConnection per negoziare e mantenere la connessione, e RTCDataChannel per dati arbitrari. WebRTC non fornisce il signaling — scambi tu stesso offerte/risposte SDP e candidati ICE, tipicamente tramite WebSockets, e configuri server STUN/TURN per attraversare il NAT. Con questi elementi in place puoi costruire videochiamate, condivisione dello schermo e collaborazione in tempo reale interamente nel browser.