W3docs

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:

  1. MediaStream API (getUserMedia) — acquisisce audio/video dal microfono, dalla fotocamera o dallo schermo come MediaStream.
  2. RTCPeerConnection — il cuore di WebRTC. Negozia, cripta e mantiene la connessione tra due peer e trasporta le tracce multimediali.
  3. 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:

  1. Il chiamante crea un'offerta e la invia tramite il server di signaling.
  2. Il chiamato riceve l'offerta, crea una risposta e la rimanda indietro.
  3. Entrambi i peer scambiano i candidati ICE man mano che vengono scoperti.
  4. 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: pong

Il 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. getUserMedia e getDisplayMedia falliscono al di fuori di un contesto sicuro (HTTPS o localhost).
  • 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. setLocalDescription deve essere eseguito prima di setRemoteDescription per 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 getUserMedia in un try/catch e gestisci il rifiuto in modo elegante.

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.

Practice

Pratica
Quale delle seguenti sono vere capacità di WebRTC?
Quale delle seguenti sono vere capacità di WebRTC?
Was this page helpful?