← Tutti gli episodi

Stagione 94  /  Episodio 6

I carri sul ponte

Audio e video in WebRTC: tracce e vincoli, i codec obbligatori e quelli moderni, RTP e RTCP, il buffer contro il jitter, come si recuperano i pacchetti persi e come il controllo della congestione adatta la qualità alla banda disponibile.

Note dell'episodio

Bentornati sulle due rive. Il ponte è costruito, protetto dalla parola d'ordine. Oggi guardiamo finalmente cosa ci passa sopra: i carri, cioè l'audio e il video.

È la parte che gli utenti vedono e sentono. Nessuno si accorge di ICE o di DTLS, ma tutti si accorgono di una voce metallica, di un video che si blocca, di un ritardo che fa parlare le persone una sopra l'altra.

Tutto comincia dalle tracce.

La chiamata getUserMedia vi restituisce un flusso fatto di tracce, e a ognuna potete chiedere caratteristiche precise, che si chiamano vincoli. Per il video, la risoluzione e la frequenza dei fotogrammi. Per l'audio, cose meno ovvie ma fondamentali: la cancellazione dell'eco, la riduzione del rumore, il controllo automatico del volume. Sono le eredità più preziose di quel motore di Global IP Solutions di cui parlavamo nel primo episodio, e sono attive per impostazione predefinita. C'è un solo caso in cui spegnerle: quando trasmettete musica, perché la riduzione del rumore la tratta come rumore.

Per condividere lo schermo esiste una chiamata sorella, getDisplayMedia. E un dettaglio che fa una grande differenza: alle tracce video potete dare un suggerimento sul contenuto. Per lo schermo, dettaglio: il browser preferirà mantenere il testo nitido a costo di pochi fotogrammi al secondo. Per una persona davanti alla videocamera, movimento: meglio fluido che nitido.

Prima di partire, il carico va compresso. Un video non compresso in alta definizione richiederebbe centinaia di megabit al secondo.

Lo standard impone alcuni codec che tutti i browser devono saper usare, così che le due rive trovino sempre un accordo. Per l'audio, Opus, un codec straordinario e aperto che va dalla voce in banda stretta alla musica in alta qualità, e il vecchio G punto settecentoundici per la compatibilità con la telefonia. Per il video, due codec obbligatori: H punto duecentosessantaquattro, nel profilo più semplice, e VP8. Sì, proprio lui: lo stesso VP8 da cui, come abbiamo raccontato nella stagione scorsa, WebP aveva preso le sue tessere. Fu il frutto di un lungo compromesso: chi voleva solo codec liberi da brevetti e chi voleva il codec già presente nei chip dei telefoni.

Oltre ai codec obbligatori, i browser moderni supportano VP9 e AV1. AV1 comprime molto meglio, a parità di qualità, ma richiede più calcolo per codificare: su un portatile vecchio può scaldare il processore e far calare i fotogrammi. Potete indicare le vostre preferenze con una chiamata, setCodecPreferences, prima di creare l'offerta.

I fotogrammi compressi viaggiano su RTP, un protocollo per il tempo reale nato negli anni Novanta.

Ogni pacchetto RTP porta un numero di sequenza, per sapere se qualcosa manca o è arrivato fuori ordine, e una marca temporale, per sapere quando quel pezzo di audio o di video va riprodotto. Accanto a RTP viaggia RTCP, il suo compagno di controllo. RTCP non trasporta il carico, trasporta le bolle di accompagnamento: rapporti del ricevente su quanti pacchetti ha perso, quanto variano i tempi di arrivo, quanto tempo impiega un pacchetto ad andare e tornare.

È grazie a queste bolle che il mittente sa come sta andando il viaggio dall'altra parte. Senza RTCP, chi manda il video guiderebbe a occhi chiusi.

Chi ha seguito la stagione sulle reti SCADA ritroverà qui vecchi nemici: la latenza, il jitter e la congestione. Ma con una differenza: lì il messaggio doveva arrivare in tempo a ogni costo. Qui la regola è opposta: se un pacchetto arriva troppo tardi, è inutile. Una parola che arriva dopo la frase successiva non serve più a nessuno.

Il jitter è la variazione dei tempi di arrivo: pacchetti partiti a intervalli regolari arrivano a scatti. Per riprodurli in modo fluido, il ricevente usa un buffer: aspetta un poco, mette in ordine i pacchetti, e li riproduce con ritmo regolare. È un compromesso continuo. Un buffer lungo assorbe tutto il jitter, ma aggiunge ritardo. Un buffer corto è reattivo, ma si svuota alla prima irregolarità. WebRTC lo regola da solo, in continuazione, osservando la rete.

E i pacchetti persi? WebRTC ha tre strumenti, e li usa a seconda della situazione.

Il primo è la richiesta di ritrasmissione, chiamata NACK: il ricevente dice, mi manca il pacchetto numero tal dei tali, e il mittente lo rimanda. Funziona solo se il viaggio è breve: se andare e tornare richiede trecento millisecondi, la ritrasmissione arriva troppo tardi.

Il secondo è la correzione in anticipo, FEC: il mittente manda un po' di dati ridondanti insieme al carico, così che il ricevente possa ricostruire un pacchetto perso senza chiederlo. Costa banda, ma non costa tempo. Opus ha una versione integrata di questa tecnica, molto efficace per la voce.

Il terzo riguarda il video. Nella compressione video, la maggior parte dei fotogrammi descrive solo le differenze rispetto al precedente: se se ne perde uno, gli errori si propagano. Allora il ricevente chiede un nuovo fotogramma chiave, completo, con un messaggio chiamato PLI. Quando vedete un video che si riempie di blocchi e poi improvvisamente torna nitido, avete visto arrivare un fotogramma chiave.

L'ultimo pezzo è forse il più ingegnoso: il controllo della congestione.

La banda disponibile tra due rive non è nota, e cambia di continuo. Qualcuno in casa avvia un aggiornamento, il treno entra in galleria. Se il mittente manda più di quanto la rete regga, i pacchetti si accodano nei router, il ritardo esplode, e poi cominciano le perdite.

WebRTC stima la banda in tempo reale. L'algoritmo usato da Chrome si chiama Google Congestion Control, e il suo trucco è guardare non solo le perdite, ma il ritardo. Se i pacchetti cominciano ad arrivare sempre un po' più distanziati di come sono partiti, significa che una coda si sta riempiendo da qualche parte. Il mittente rallenta prima che la coda trabocchi. Per farlo, il ricevente riferisce l'ora di arrivo di ogni singolo pacchetto, con un'estensione chiamata transport wide congestion control.

Quando la banda cala, il codificatore deve scegliere cosa sacrificare: risoluzione o fluidità. Anche qui potete dire la vostra, con la preferenza di degrado, e potete imporre un tetto con setParameters, senza rinegoziare nulla. Per esempio, ottocento kilobit al secondo per una chiamata in cui il video è secondario.

Quindi, ricapitolando: le tracce si caricano con vincoli precisi, si comprimono con codec scelti tra quelli obbligatori e quelli moderni, viaggiano su RTP accompagnate dalle bolle di RTCP. Il buffer assorbe il jitter, NACK, FEC e fotogrammi chiave recuperano le perdite, e il controllo della congestione adatta il carico al peso che il ponte regge in ogni momento.

Ma su un ponte non passano solo carri. Nel prossimo episodio parliamo della passerella accanto alla carreggiata: i canali dati, per mandare tutto quello che non è audio o video. Ci sentiamo lì.