Cos’è e come funziona WebRTC

APPUNTI, INFORMATICA, TUTORIAL

In questa serie di articoli cercherò di spiegare come attivare una comunicazione  real-time via  web sfruttando WebRTC e condividerò allo scopo anche alcuni  esempi per entrare operativamente nel vivo del protocollo. Prima di iniziare con la spiegazione più tecnica voglio precisare che sebbene il protocollo WebRTC siano noto per le comunicazioni audio/video in realtà è uno strumento molto potente e più generale anche per far scambiare  semplicemente dati  tra due peer.

Che cosa è WebRTC

WebRTC acronimo di Web Real-Time Comunication, è un progetto open source che permette ad un browser web e/o ad applicazioni mobile la comunicazione in real time tramite l’uso di API (Application Programming Interface). Esso garantisce il collegamento audio/video all’interno di pagine web/webview permettendo comunicazioni peer-to-peer senza  la necessità di plug-in supplementari.

Il protocollo WebRTC, infatti, è supportato diffusamente dai principali browser ed è stato standardizzato dal World Wide Web Consortium (W3c) e dall’Internet Engineering task Force (IETF).

WebRTC come detto permette la comunicazione  peer-to-peer, ma per funzionare ha comunque bisogno di uno o più  server a supporto per poter gestire le varie fasi della della comunicazione e per consentire ai client di:

  1. scambiare metadati e coordinare le comunicazione tra i client ( signaling )
  2. gestire le comunicazione attraverso i firewall.

Il server di  signaling, assume un ruolo molto importante in quanto il meccanismo di segnalazione è fondamentale per la corretta gestione di una connessione WebRTC,  perché di fatto è il processo che si occupa di coordinare la comunicazione e di consentire ad un’applicazione WebRTC di instaurare una chiamata. Il processo di signaling gestisce, infatti,  l’intero ciclo di vita di una chiamata e consente di scambiare informazioni quali:

  • Messaggi di controllo per aprire e chiudere la comunicazione
  • Messaggi di errore
  • Metadati sulle caratteristiche del media, quali ad esempio codec, impostazioni, larghezza di banda, tipo di media (audio/video)
  • Dati per stabilire connessione sicure
  • Dati di rete quali ad esempio l’indirizzo ip dei peer e la porte della socket

In una connessione  WebRTC possono entrare in gioco , anche altri server quali : il turn e lo stun necessari in taluni casi per risolvere  problematiche di rete e di visibilità dei peer derivanti dall’uso di NAT o dalla presenza di Firewall.

Come funziona?

Cerchiamo di capire quali sono le varie fasi per inizializzare  una connessione WebRTC e quale entità verranno coinvolte nei vari step.

Come già anticipato per instaurare una connessione, i due client dovranno in prima istanza connettersi ad un server di segnalazione che consentirà ai due peer di entrare in contatto. L’inizializzazione e la terminazione della chiamata, infatti è determinata da messaggi di segnalazione scambiati con il server mediante protocolli HTTP o WebSocket, mentre lo scambio dei contenuti avverrà direttamente tra i client senza l’ausilio di server intermedi, tranne nel caso  in cui i due clienti non siano direttamente visibili, in tal caso  sarà necessario utilizzare un server intermedio quale il turn.  E’ importante ricordare che il protocollo di  segnalazione tra il client ed il server non è oggetto di standardizzazione in WebRTC,  pertanto l’implementazione viene stata demandata all’applicazione e lasciata libera ad uso del progettista.

Come più volte ripetuto, prima che i due peer possano iniziare a scambiare dati tra di loro tramite WebRTC, è necessario che gli stessi si scambino  informazioni  preliminari, attraverso il server  di segnalazione, necessarie per la negoziazione ed   il rilevamento del formato e dei media.

Tutto ciò  viene fatto tramite i seguenti protocolli.

  • Session Description Protocol (SDP) che viene utilizzato per fornire i metadati del contenuto multimediale come risoluzione, codifica, bitrate, ecc.
  • Interactive Connectivity Establishment (ICE) viene utilizzato per instaurare la connessione peer to peer.
N.B. nel caso i cui  i due peer non si trovassero sulla stessa rete, si renderà necessario l’utilizzo di  un server STUN (Session Traversal Utilities NAT) per ottenere l’indirizzo pubblico dei peer mentre  nel caso in cui una qualsiasi delle reti fosse protetta da firewall, allora diventerebbe mandatorio l’ uso di  TURN server ( Traversal Using Relays NAT ).

Ipotizziamo, pertanto,  per comprendere  il flusso di collocarci nel  caso generale, in cui i due peer siano protetti da Firewall e non stiano sulla stessa rete; inoltre darò per scontato, per la descrizione che segue, che i due peer abbiano già stabilito un connessione websocket con il server di segnalazione.

Di seguito riporto un tipico flusso WebRTC:

webrtc flow

A questo punto cercherò di approfondire le entità coinvolte nel processo, dando qualche definizione e spiegazione generale, con la speranza di essere il più esaustivo possibile.

Che cosa è lo STUN

Come anticipato l’uso dello STUN si rende necessario quando i due peer non si trovano sulla stessa rete e si trovano su reti private nattate. Un server STUN, infatti,  permetterà ai client dietro NAT di impostare opportunamente le chiamate webRTC all’esterno della rete locale ed  ha il compito di fornire ai client alcune informazioni, quali il loro indirizzo pubblico, il tipo di NAT dietro al quale si trovano e il lato della porta internet associato dal NAT con una particolare porta locale. Questa informazione è usata per impostare la comunicazione  tra i peer in modo da stabilire una connessione. Il protocollo STUN è spiegato nella RFC 3489.

NAT

Che cosa è Il NAT

Il NAT ( Network Address Translation) è un meccanismo che consente di mascherare indirizzi di rete privati su rete pubblica e viene implementato sul gateway per consentire ad un host con indirizzo di rete privata di poter  comunicare con host su rete pubblica (internet). Il NAT è spiegato nella RFC2663, RFC1631

Che cosa è il TURN

Poiché la maggior parte delle applicazioni WebRTC funzioni, in via generale è necessario utilizzare un server per inoltrare il traffico tra peer, poiché spesso essi non sono in  diretto contatto  (a meno che non risiedano sulla stessa rete locale). Per risolvere il problema  è possibile utilizzare un server TURN (  Traversal Using Relay NAT ) che di fatto implementa  un protocollo per l’inoltro del traffico di rete.

Esistono attualmente diverse possibilità per utilizzare server TURN. C’è ne sono, infatti,  disponibili online, sia come applicazioni self-hosted (come il progetto COTURN open source) sia come servizi forniti in cloud.

Una volta individuato/installato  un server TURN, tutto ciò che serve è la corretta configurazione RTCC affinché l’applicazione client possa utilizzarlo. Il pezzo di codice seguente illustra una configurazione di esempio per RTCPeerConnection il cui server TURN ha il nome host my-turn-server.mycompany.com ed è in esecuzione sulla porta 19403.

const iceConfiguration = {
    iceServers: [
        {
            urls: 'turn:my-turn-server.mycompany.com:19403',
            username: 'optional-username',
            credentials: 'auth-token'
        }
    ]
}

const peerConnection = new RTCPeerConnection(iceConfiguration);

 

API WebRTC

Di seguito riporto  le API principali messe a disposizione dal protocollo  WebRTC delle quali proverò a spiegarne il significato ed il modo di utilizzarle:

  1. getUserMedia: acquisisce i media audio e video, il metodo consente di accedere alla telecamera ed al microfono del pc o dello smartphone.
  2. RTCPeerConnection: permette il collegamento audio/video tra peer. Questo metodo provvede alla gestione della codifica e della decodifica, alla comunicazione peer-to-peer, alla sicurezza ed alla gestione della banda.
  3. RTCDataChannel: permette la comunicazione bidirezionale dei dati tra i peer attraverso un connessione WebSocket a bassa latenza.
  4. getStats, che permettono all’applicazione di raccogliere un insieme di statistiche inerenti la sessione attiva.

getUserMedia

Le Media Stream API (dette anche getUserMedia) danno la possibilità, previo consenso dell’utente, di accedere al flusso video proveniente dalla webcam ed al flusso audio proveniente dal microfono situati sul device che l’utente sta utilizzando in quel momento.

Per usare getUserMedia è molto semplice :

<html>
  <head>
 </head>
  <body>
    <div id="Container">
            <video autoplay="true" width="640" height="480" id="videoElement"></video>
            <input type="button" id="start" Value="START"  />
    </div>
  </body>
</html>
<script>
jQuery(document).ready(function(){
     jQuery("#start").click(function () {
startVideo();
})
})
    function startVideo() {
        var video = document.querySelector('video'),canvas;
        imageElement=video;
        console.log("navigator  " + navigator.mediaDevices)
        if (navigator.mediaDevices) {
           // access the web cam
            navigator.mediaDevices.getUserMedia({ video: true })
                // permission granted:
                .then(function(stream) {
                 //video.src = window.URL.createObjectURL(stream);
                     video.srcObject = stream;
                })

                // permission denied:
                .catch(function(error) {
                    document.body.textContent = 'Could not access the camera.Error:' + error.name;
                });
        }
        return imageElement;
    }
</script>

Live Demo

Attivazione della connessione

A questo punto dovrebbe essere abbastanza chiara la procedura per  ottenere un flusso video da una camera usando getUserMedia,  per cui possiamo andare oltre e capire come si può  inoltrare il flusso ad  un peer remoto. A tal proposito dobbiamo capire come funziona una tipica connessione WebRTC ed approfondire in prima istanza :

RTCPeerConnection

La funzione di RTCPeerConnection è quella di mettere in contatto due device in modalità peer-to-peer. La procedura che ci consente di attuare questo collegamento è la seguente :

Dati due device, A e B. Supponiamo che A voglia contattare B , per aprire un canale peer-to-peer :

  1. A dovrà creare un oggetto RTCPeerConnection e dovrà mettersi in ascolto dell’evento onicecandidate che verrà restituito da B
  2. A dovrà comunicare a B l’identificatore univoco del proprio canale peer-to-peer quando riceverà l’evento onicecandidate
  3. B dovrà utilizzare il metodo addIceCandidate sul proprio oggetto RTCPeerConnection per aggiungere A come destinatario.
  4. A dovrà invocare  createOffer e per generare una stringa SDP  (Session Description Protocol)  che dovrà essere  inviata a B. Nel SDP saranno  descritti i costraints al flusso audio/video (codec, etc.) del device.
  5. B riceverà la stringa SDP di A e genererà una SDP di risposta con il metodo createAnswer, che verrà inviata ad A.
  6. Sia A che B riceveranno l’evento addstream che conterrà il flusso dati del partner e potranno decidere di caricarlo in un elemento video come visto nell’esempio precedente.

Rivediamo il flusso da un punto di vista operativo:

Step 1 : Creare un’istanza dell’oggetto RTCPeerConnection  che userà i server STUN per risolvere i problemi di NAT.

Step 2 : Una volta creta la RTCPeerConnection  dovranno essere implementate  tre funzioni di callback (onIceCandidate, onNegotiationNeeded e onAddStream) e assegnarle a RTCPeerConnection.

Step 3 : Creare onIceCandidate. Questo evento gestisce le risposte del  server STUN al tuo client in merito all’attraversamento NAT / Firewall.  Sarà necessario pertanto creare una funzione che accetta un oggetto RTCIceCandidate,

Step 4 : Creare onNegotiationNeeded. Questo evento si attiva nel caso in cui  succede qualcosa che richiede una nuova negoziazione di sessione.

Step 5 : Creare onAddStream. Questo evento viene chiamato quando si chiama setRemoteDescription con le informazioni SDP o il proprio peer remoto. Quando scatta questo evento potrai  gestire il flusso video.

Add dello stream

Per aggiungere uno stream alla connessione, sarà necessario innanzitutto crearlo, e per farlo dovremo usare  getUserMedia che ci consente di ottenere il flusso video della videocamera o del microfono. Tenete in considerazione che il getUserMedia può essere invocato passando dei contraints e restituisce un success o un  failure

        if (navigator.mediaDevices) {
           // access the web cam
            navigator.mediaDevices.getUserMedia({ video: true })
                .then(function(stream) {
                     .
                     .
                     addStream(stream);
                     console.log( 'stream ok');

                })
                .catch(function(error) {
                     console.log( 'Could not access the camera.Error:' + error.name);
                });

I constraints  sono dei parametri per definire ad esempio se la chiamata è video o audio o entrambe.  Di che dimensione dovrebbe essere lo stream, il colore delle immagini trasmesse, eventuali filtri.

Success è un evento che scatta qualora sia andato tutto  per il meglio ed in tal caso dovresti avere ottenuto la sessione video.

Failure evento che scatta nel  caso di errore di accesso al device.

 

Esempio software per la realizzazione di una connessione WebRTC

seconda parte >>


Comments