Crea i servizi di backend necessari per un'app WebRTC

Che cos'è la segnalazione?

La segnalazione è il processo di coordinamento della comunicazione. Per consentire a un'app WebRTC di configurare una chiamata, i client devono scambiarsi le seguenti informazioni:

  • Messaggi di controllo della sessione utilizzati per aprire o chiudere le comunicazioni
  • Messaggi di errore
  • Metadati dei contenuti multimediali, come codec, impostazioni dei codec, larghezza di banda e tipi di contenuti multimediali
  • Dati chiave utilizzati per stabilire connessioni sicure
  • Dati di rete, come l'indirizzo IP e la porta di un host così come sono visti dal mondo esterno

Questo processo di segnalazione richiede ai clienti un modo per far passare i messaggi. Questo meccanismo non è implementato dalle API WebRTC. Devi costruirla autonomamente. Più avanti in questo articolo, imparerai come creare un servizio di segnalazione. Per prima cosa, però, serve un po' di contesto.

Perché la segnalazione non è definita da WebRTC?

Per evitare ridondanza e per massimizzare la compatibilità con le tecnologie consolidate, i metodi e i protocolli di segnalazione non sono specificati dagli standard WebRTC. Questo approccio è descritto dal JavaScript Session Preparement Protocol (JSEP):

L'architettura di JSEP evita inoltre che un browser debba salvare lo stato, ovvero funzionare come una macchina a stato di segnalazione. Questo rappresenta un problema se, ad esempio, i dati di segnalazione vanno persi ogni volta che una pagina viene ricaricata. Lo stato di segnalazione può invece essere salvato su un server.

Diagramma dell'architettura JSEP
Architettura JSEP

Il protocollo JSEP richiede lo scambio tra peer di offer e answer, ovvero i metadati dei contenuti multimediali menzionati in precedenza. Le offerte e le risposte vengono comunicate in formato SDP (Session Description Protocol), che ha il seguente aspetto:

v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…

Vuoi sapere cosa significa davvero tutte queste sciocchezze dei contenuti SDP? Dai un'occhiata agli esempi della Internet Engineering Task Force (IETF).

Tieni presente che WebRTC è progettato in modo che l'offerta o la risposta possano essere modificate prima di essere impostate come descrizione locale o remota modificando i valori nel testo dell'SDP. Ad esempio, la funzione preferAudioCodec() in appr.tc può essere utilizzata per impostare il codec e la velocità in bit predefiniti. SDP è un po' difficile da manipolare con JavaScript e si discute se le versioni future di WebRTC debbano utilizzare JSON, ma ci sono alcuni vantaggi nel continuare a utilizzare SDP.

API e indicatori di RTCPeerConnection: offerta, risposta e candidato

RTCPeerConnection è l'API utilizzata dalle app WebRTC per creare una connessione tra peer e per comunicare audio e video.

Per inizializzare questo processo, RTCPeerConnection ha due attività:

  • Verifica le condizioni locali dei media, come la risoluzione e le funzionalità del codec. Si tratta dei metadati utilizzati per il meccanismo di offerta e risposta.
  • Recupera i potenziali indirizzi di rete dell'host dell'app, noti come candidati.

Una volta individuati questi dati locali, devono essere scambiati attraverso un meccanismo di segnalazione con il peer remoto.

Immagina che Alice stia cercando di chiamare Eva. Ecco il meccanismo di offerta/risposta completo in tutti i suoi dettagli cruenti:

  1. Alice crea un oggetto RTCPeerConnection.
  2. Alice crea un'offerta (una descrizione della sessione SDP) con il metodo RTCPeerConnection createOffer().
  3. Alice chiama setLocalDescription() per comunicare la sua offerta.
  4. Alice sottopone a stringa l'offerta e utilizza un meccanismo di segnalazione per inviarla a Eva.
  5. Eva chiama setRemoteDescription() per conoscere l'offerta di Alice, in modo che RTCPeerConnection sappia della configurazione di Alice.
  6. Eva chiama createAnswer() e il callback di successo ha ricevuto una descrizione della sessione locale: la risposta di Eva.
  7. Eva imposta la sua risposta come descrizione locale chiamando setLocalDescription().
  8. Eva usa quindi il meccanismo di segnalazione per inviare la sua risposta stringata ad Alice.
  9. Alice imposta la risposta di Eva come descrizione della sessione remota utilizzando setRemoteDescription().

Alice ed Eva devono anche scambiarsi informazioni di rete. L'espressione "candidati alla ricerca" si riferisce al processo di individuazione delle interfacce e delle porte di rete utilizzando il framework ICE.

  1. Alice crea un oggetto RTCPeerConnection con un gestore onicecandidate.
  2. Il gestore viene chiamato quando i candidati della rete sono disponibili.
  3. Nel gestore, Alice invia dati stringati del candidato a Eva attraverso il suo canale di segnalazione.
  4. Quando Eva riceve un messaggio da Alice, chiama addIceCandidate() per aggiungere il candidato alla descrizione delle app peer da remoto.

Il JSEP supporta la funzionalità ICE Candidate Trickling, che consente al chiamante di fornire in modo incrementale i candidati alla persona invitata dopo l'offerta iniziale e di iniziare a partecipare alla chiamata e stabilire una connessione senza attendere l'arrivo di tutti i candidati.

Codifica WebRTC per la segnalazione

Il seguente snippet di codice è un esempio di codice W3C che riassume il processo di segnalazione completo. Il codice presuppone l'esistenza di un meccanismo di segnalazione, SignalingChannel. La segnalazione sarà discussa in modo più dettagliato più avanti.

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // send the offer to the other peer
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

Per vedere i processi offerta/risposta e della piattaforma di scambio pubblicitario candidati, consulta simpl.info RTCPeerConnection e il log della console per un esempio di chat video di una sola pagina. Se vuoi saperne di più, scarica un dump completo delle statistiche e delle segnalazioni WebRTC dalla pagina about://webrtc-internals in Google Chrome o dalla pagina opera://webrtc-internals in Opera.

Rilevamento dei compagni

È un modo fantasioso di chiedere: "Come faccio a trovare qualcuno con cui parlare?".

Per le telefonate, hai a disposizione numeri di telefono e elenchi telefonici. Per la chat video e la messaggistica online, sono necessari sistemi di gestione di identità e presenza e un mezzo che consenta agli utenti di avviare sessioni. Le app WebRTC hanno bisogno di un modo con cui i client si segnalino tra di loro che vogliono avviare o partecipare a una chiamata.

I meccanismi di rilevamento peer non sono definiti da WebRTC e non vai alle opzioni qui. La procedura può essere semplice come inviare un URL tramite email o inviare un messaggio. Per le app di video chat, come Talky, tawk.to e Riunione del browser, puoi invitare persone a una chiamata condividendo un link personalizzato. Lo sviluppatore Chris Ball ha creato un interessante esperimento serverless-webrtc che consente ai partecipanti alla chiamata WebRTC di scambiare metadati tramite qualsiasi servizio di messaggistica preferito, come messaggistica immediata, email o homing pigeon.

Come puoi creare un servizio di segnalazione?

Per ribadire, i protocolli e i meccanismi di segnalazione non sono definiti dagli standard WebRTC. Qualunque sia la tua scelta, avrai bisogno di un server intermediario per scambiare messaggi di segnalazione e dati delle app tra i client. Purtroppo un'app web non può limitarsi a gridare a internet: "Connettimi al mio amico!".

Fortunatamente, i messaggi indicati sono di piccole dimensioni e vengono scambiati per lo più all'inizio di una chiamata. Durante il test con appr.tc per una sessione di chat video, il servizio di segnalazione ha gestito un totale di circa 30-45 messaggi, per una dimensione totale di circa 10 kB.

Oltre a essere relativamente poco impegnativi in termini di larghezza di banda, i servizi di segnalazione WebRTC non consumano molta elaborazione o memoria perché devono solo inoltrare messaggi e conservare una piccola quantità di dati sullo stato delle sessioni, ad esempio quali client sono connessi.

Push dei messaggi dal server al client

Un servizio di messaggistica per la segnalazione deve essere bidirezionale: da client a server e da server a client. La comunicazione bidirezionale va contro il modello di richiesta/risposta client/server HTTP, ma nel corso degli anni sono stati sviluppati diversi attacchi, ad esempio il polling lungo, per eseguire il push dei dati da un servizio in esecuzione su un server web a un'app web in esecuzione in un browser.

Più di recente, l'API EventSource è stata ampiamente implementata. Ciò consente gli eventi inviati dal server, ovvero i dati inviati da un server web a un client del browser tramite HTTP. EventSource è progettato per la messaggistica unidirezionale, ma può essere utilizzato in combinazione con l'XHR per creare un servizio per lo scambio di messaggi di segnalazione. Un servizio di segnalazione trasmette un messaggio di un chiamante, recapitato tramite richiesta XHR, inviandolo al destinatario tramite EventSource.

WebSocket è una soluzione più naturale, progettata per la comunicazione client-server full duplex, ovvero per i messaggi che possono fluire in entrambe le direzioni contemporaneamente. Un vantaggio di un servizio di segnalazione creato con WebSocket o eventi inviati dal server (EventSource) è che il backend di queste API può essere implementato su una varietà di framework web comuni alla maggior parte dei pacchetti di web hosting per linguaggi come PHP, Python e Ruby.

Tutti i browser moderni, ad eccezione di Opera Mini, supportano WebSocket e, soprattutto, tutti i browser che supportano WebRTC supportano anche WebSocket, sia su desktop che su dispositivi mobili. Utilizza TLS per tutte le connessioni per garantire che i messaggi non possano essere intercettati non criptati e anche per ridurre i problemi con l'attraversamento proxy. Per ulteriori informazioni su WebSocket e attraversamento proxy, consulta il capitolo WebRTC in High Performance Browser Networking di Ilya Grigorik.

È anche possibile gestire la segnalazione facendo in modo che i client WebRTC eseguano il polling di un server di messaggistica ripetutamente tramite Ajax, ma questo comporta molte richieste di rete ridondanti, il che è particolarmente problematico per i dispositivi mobili. Anche dopo aver stabilito una sessione, i peer devono fare un sondaggio per rilevare i messaggi di segnalazione in caso di cambiamenti o fine della sessione da parte di altri colleghi. L'esempio dell'app WebRTC Book utilizza questa opzione con alcune ottimizzazioni della frequenza di polling.

Indicatori della scalabilità

Anche se un servizio di segnalazione consuma relativamente poca larghezza di banda e CPU per client, i server di segnalazione per un'app molto usata potrebbero dover gestire molti messaggi da località diverse con livelli elevati di contemporaneità. Le app WebRTC che ricevono molto traffico devono segnalare i server in grado di gestire un carico considerevole. Non spieghiamo i dettagli qui, ma esistono diverse opzioni per la messaggistica ad alto volume e ad alte prestazioni, tra cui:

  • XMPP (eXtensible Messaging and Presence Protocol), originariamente noto come Jabber, un protocollo sviluppato per la messaggistica immediata che può essere utilizzato per la segnalazione. Le implementazioni server includono ejabberd e Openfire. I client JavaScript, come Strophe.js, utilizzano BOSH per emulare lo streaming bidirezionale; tuttavia, per vari motivi, BOSH potrebbe non essere efficiente come WebSocket e, per gli stessi motivi, potrebbe non scalare bene.) (Su una tangente, Jingle è un'estensione XMPP per attivare voce e video. Il progetto WebRTC utilizza componenti di rete e di trasporto della libreria libjingle, un'implementazione C++ di Jingle).

  • Librerie open source, come ZeroMQ (utilizzato da TokBox per il servizio Rumour) e OpenMQ (NullMQ applica i concetti ZeroMQ alle piattaforme web utilizzando il protocollo STOMP su WebSocket).

  • Piattaforme commerciali di messaggistica cloud che utilizzano WebSocket (anche se possono ricorrere a un lungo polling), come Pusher, Kaazing e PubNub (PubNub dispone anche di un'API per WebRTC).

  • Piattaforme WebRTC commerciali, come vLine

(La Real-Time Web Technologies Guide dello sviluppatore Phil Leggetter) fornisce un elenco completo di servizi di messaggistica e librerie.

Crea un servizio di segnalazione con Socket.io su Node

Di seguito è riportato il codice per una semplice app web che utilizza un servizio di segnalazione creato con Socket.io su Node. Il design di Socket.io semplifica la creazione di un servizio per lo scambio di messaggi e Socket.io è particolarmente adatto alla segnalazione WebRTC per via del suo concetto integrato di stanze. Questo esempio non è progettato per scalare come servizio di segnalazione a livello di produzione, ma è semplice da capire per un numero relativamente ridotto di utenti.

Socket.io utilizza WebSocket con fallback: polling lungo AJAX, streaming multiparte AJAX, iframe Forever e polling JSONP. È stato portato su vari backend, ma forse è meglio noto per la sua versione Node utilizzata in questo esempio.

In questo esempio non è presente WebRTC. È progettato solo per mostrare come creare segnalazioni in un'app web. Visualizza il log della console per vedere cosa succede quando i clienti entrano in una stanza virtuale e scambiano messaggi. Questo codelab WebRTC fornisce istruzioni dettagliate su come integrarlo in un'app di chat video WebRTC completa.

Ecco il client index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>WebRTC client</title>
  </head>
  <body>
    <script src='/socket.io/socket.io.js'></script>
    <script src='js/main.js'></script>
  </body>
</html>

Ecco il file JavaScript main.js a cui viene fatto riferimento nel client:

const isInitiator;

room = prompt('Enter room name:');

const socket = io.connect();

if (room !== '') {
  console.log('Joining room ' + room);
  socket.emit('create or join', room);
}

socket.on('full', (room) => {
  console.log('Room ' + room + ' is full');
});

socket.on('empty', (room) => {
  isInitiator = true;
  console.log('Room ' + room + ' is empty');
});

socket.on('join', (room) => {
  console.log('Making request to join room ' + room);
  console.log('You are the initiator!');
});

socket.on('log', (array) => {
  console.log.apply(console, array);
});

Ecco l'app server completa:

const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
  file.serve(req, res);
}).listen(2013);

const io = require('socket.io').listen(app);

io.sockets.on('connection', (socket) => {

  // Convenience function to log server messages to the client
  function log(){
    const array = ['>>> Message from server: '];
    for (const i = 0; i < arguments.length; i++) {
      array.push(arguments[i]);
    }
      socket.emit('log', array);
  }

  socket.on('message', (message) => {
    log('Got message:', message);
    // For a real app, would be room only (not broadcast)
    socket.broadcast.emit('message', message);
  });

  socket.on('create or join', (room) => {
    const numClients = io.sockets.clients(room).length;

    log('Room ' + room + ' has ' + numClients + ' client(s)');
    log('Request to create or join room ' + room);

    if (numClients === 0){
      socket.join(room);
      socket.emit('created', room);
    } else if (numClients === 1) {
      io.sockets.in(room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room);
    } else { // max two clients
      socket.emit('full', room);
    }
    socket.emit('emit(): client ' + socket.id +
      ' joined room ' + room);
    socket.broadcast.emit('broadcast(): client ' + socket.id +
      ' joined room ' + room);

  });

});

Per questa operazione non è necessario conoscere i nodi statici. In questo esempio viene utilizzato.)

Per eseguire questa app su localhost, devi avere installato Node, Socket.IO e node-static. Il nodo può essere scaricato da Node.js (l'installazione è semplice e rapida). Per installare Socket.IO e node-static, esegui Gestione pacchetti dei nodi da un terminale nella directory dell'app:

npm install socket.io
npm install node-static

Per avviare il server, esegui questo comando da un terminale nella directory dell'app:

node server.js

Nel browser, apri localhost:2013. Apri una nuova scheda o finestra in qualsiasi browser e apri di nuovo localhost:2013. Per vedere cosa sta succedendo, controlla la console. In Chrome e Opera, puoi accedere alla console tramite gli Strumenti per sviluppatori di Google Chrome utilizzando Ctrl+Shift+J (o Command+Option+J su Mac).

Qualunque sia l'approccio che scegli per la segnalazione, il tuo backend e l'app client, almeno, devono fornire servizi simili a questo esempio.

Segnali negativi

  • RTCPeerConnection non inizierà a raccogliere candidati finché non verrà chiamata la parola setLocalDescription(). Questo è obbligatorio nella bozza JSEP IETF.
  • Sfrutta Trickle ICE. Chiama il numero addIceCandidate() non appena arrivano i candidati.

Server di segnalazione già pronti

Se preferisci non eseguire il rollback, sono disponibili diversi server di segnalazione WebRTC, che utilizzano Socket.IO come nell'esempio precedente e sono integrati con le librerie JavaScript client WebRTC:

  • webRTC.io è una delle prime librerie di astrazioni per WebRTC.
  • Signalmaster è un server di segnalazione creato per essere utilizzato con la libreria client JavaScript SimpleWebRTC.

Se non vuoi scrivere proprio codice, sono disponibili piattaforme WebRTC commerciali complete come vLine, OpenTok e Asterisk.

Per la cronaca, Ericsson ha creato un server di segnalazione utilizzando PHP su Apache sin dagli inizi di WebRTC. Ora il codice è piuttosto obsoleto, ma vale la pena esaminare il codice se stai prendendo in considerazione qualcosa di simile.

Sicurezza segnalazioni

"La sicurezza è l'arte di non fare nulla."

Salman Rushdie

La crittografia è obbligatoria per tutti i componenti WebRTC.

Tuttavia, i meccanismi di segnalazione non sono definiti dagli standard WebRTC, quindi spetta a te rendere sicura la segnalazione. Se un aggressore riesce a dirottare le segnalazioni, può interrompere le sessioni, reindirizzare le connessioni e registrare, alterare o inserire contenuti.

Il fattore più importante per la protezione della segnalazione è l'uso di protocolli sicuri, HTTPS e WSS (ad esempio TLS), che impediscono l'intercettazione dei messaggi senza crittografia. Inoltre, fai attenzione a non trasmettere messaggi di segnalazione in modo che siano accessibili ad altri chiamanti che utilizzano lo stesso server di segnalazione.

Dopo la segnalazione: utilizza ICE per gestire i NAT e i firewall

Per la segnalazione dei metadati, le app WebRTC utilizzano un server intermedio, ma per i contenuti multimediali e lo streaming di dati effettivi una volta stabilita una sessione, RTCPeerConnection tenta di connettere i client direttamente o peer-to-peer.

In un mondo più semplice, ogni endpoint WebRTC avrà un indirizzo univoco che potrebbe scambiare con altri peer per comunicare direttamente.

Connessione peer-to-peer semplice
Un mondo senza NAT e firewall

In realtà, la maggior parte dei dispositivi è protetta da uno o più livelli di NAT, alcuni hanno un software antivirus che blocca determinati protocolli e porte e molti sono protetti da proxy e firewall aziendali. Un firewall e il servizio NAT possono infatti essere implementati dallo stesso dispositivo, ad esempio un router Wi-Fi di casa.

Concorrenti protetti da NAT e firewall
Il mondo reale

Le app WebRTC possono utilizzare il framework ICE per superare le complessità del networking reale. Affinché ciò accada, la tua app deve trasmettere gli URL del server ICE a RTCPeerConnection, come descritto in questo articolo.

ICE cerca di trovare il percorso migliore per connettere i colleghi. Prova tutte le possibilità in parallelo e sceglie l'opzione più efficiente. ICE prima tenta di stabilire una connessione utilizzando l'indirizzo host ottenuto dal sistema operativo e dalla scheda di rete di un dispositivo. In caso di errore (operazione che avviene per i dispositivi protetti da NAT), ICE ottiene un indirizzo esterno utilizzando un server STUN e, in caso di errore, il traffico viene instradato tramite un server di inoltro TURN.

In altre parole, un server STUN viene utilizzato per ottenere un indirizzo di rete esterno e i server TURN vengono utilizzati per inoltrare il traffico in caso di interruzione della connessione diretta (peer-to-peer).

Ogni server TURN supporta lo STUN. Un server TURN è un server STUN con una funzionalità di inoltro integrata aggiuntiva. L'ICE è anche in grado di affrontare le complessità delle configurazioni NAT. In realtà, il hole-punching della NAT può richiedere più di un semplice indirizzo IP:porta pubblico.

Gli URL per i server STUN e/o TURN vengono (facoltativamente) specificati da un'app WebRTC nell'oggetto di configurazione iceServers, che è il primo argomento del costruttore RTCPeerConnection. Per appr.tc, il valore sarà simile al seguente:

{
  'iceServers': [
    {
      'urls': 'stun:stun.l.google.com:19302'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=udp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    },
    {
      'urls': 'turn:192.158.29.39:3478?transport=tcp',
      'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
      'username': '28224511:1379330808'
    }
  ]
}

Una volta che RTCPeerConnection ha queste informazioni, l'ICE accade automaticamente. RTCPeerConnection utilizza il framework ICE per individuare il percorso migliore tra peer, lavorando con i server STUN e TURN in base alle esigenze.

STUN

I NAT forniscono un dispositivo con un indirizzo IP da utilizzare all'interno di una rete locale privata, ma questo indirizzo non può essere utilizzato esternamente. Senza un indirizzo pubblico, i peer WebRTC non possono comunicare. Per risolvere questo problema, WebRTC utilizza STUN.

I server STUN risiedono nella rete internet pubblica e hanno una semplice attività: controllare l'indirizzo IP:porta di una richiesta in entrata (da un'app in esecuzione su un NAT) e inviare l'indirizzo come risposta. In altre parole, l'app utilizza un server STUN per scoprire la sua porta IP da un punto di vista pubblico. Questo processo consente a un peer WebRTC di ottenere un indirizzo pubblicamente accessibile e quindi di passarlo a un altro peer attraverso un meccanismo di segnalazione per configurare un link diretto. (In pratica, NAT diversi funzionano in modi diversi e potrebbero esserci più livelli NAT, ma il principio è lo stesso).

I server STUN non devono fare molto o ricordare molto, per cui le specifiche relativamente basse dei server STUN sono in grado di gestire un numero elevato di richieste.

La maggior parte delle chiamate WebRTC esegue correttamente una connessione utilizzando STUN (86%), secondo Webrtcstats.com, anche se questo valore potrebbe essere inferiore per le chiamate tra peer dietro firewall e configurazioni NAT complesse.

Connessione peer-to-peer mediante un server STUN
Utilizzo dei server STUN per ottenere indirizzi IP:porta pubblici

GIRA

RTCPeerConnection cerca di configurare una comunicazione diretta tra peer su UDP. Se questo errore non va a buon fine, RTCPeerConnection ricorre a TCP. Se questo errore non va a buon fine, i server TURN possono essere utilizzati come riserva, inoltrando i dati tra gli endpoint.

Giusto per ribadire, TURN viene utilizzato per trasmettere audio, video e dati in streaming tra peer, non per segnalare dati.

I server TURN hanno indirizzi pubblici, pertanto possono essere contattati dai peer anche se i peer sono protetti da firewall o proxy. I server di TURN hanno un'attività concettualmente semplice: l'inoltro di uno stream. Tuttavia, a differenza dei server STUN, consumano intrinsecamente molta larghezza di banda. In altre parole, i server TURN devono essere più robusti.

Connessione peer-to-peer mediante un server STUN
Il Monty completo: STUN, TURN e segnalazione

Questo diagramma mostra TURN in azione. Puro STUN non è riuscito, quindi ogni collega ricorre all'utilizzo di un server TURN.

Deployment dei server STUN e TURN

Per i test, Google esegue un server STUN pubblico, stun.l.google.com:19302, utilizzato da appr.tc. Per un servizio STUN/TURN di produzione, utilizza rfc5766-turn-server. Il codice sorgente per i server STUN e TURN è disponibile su GitHub, dove puoi anche trovare link a diverse fonti di informazioni sull'installazione dei server. È disponibile anche un'immagine VM per Amazon Web Services.

Un server TURN alternativo è disponibile come codice sorgente e anche per AWS. Ecco le istruzioni per configurare il REST su Compute Engine.

  1. Apri il firewall come necessario per tcp=443, udp/tcp=3478.
  2. Crea quattro istanze, una per ogni IP pubblico, immagine Ubuntu 12.06 standard.
  3. Configura la configurazione locale del firewall (consenti QUALSIASI da QUALSIASI).
  4. Installa strumenti: shell sudo apt-get install make sudo apt-get install gcc
  5. Installa libre da creytiv.com/re.html.
  6. Recupera il risultato da creytiv.com/restund.html e decomprimilo./
  7. wget hancke.name/restund-auth.patch e applica con patch -p1 < restund-auth.patch.
  8. Esegui make, sudo make install per libre e ripristino.
  9. Adatta restund.conf alle tue esigenze (sostituisci gli indirizzi IP e assicurati che contenga lo stesso secret condiviso) e copialo in /etc.
  10. Copia restund/etc/restund in /etc/init.d/.
  11. Configura il ripristino:
    1. Imposta LD_LIBRARY_PATH.
    2. Copia restund.conf in /etc/restund.conf.
    3. Imposta restund.conf per usare le 10 giuste. Indirizzo IP.
  12. Esegui ripristino
  13. Esegui un test utilizzando un client stund dalla macchina remota: ./client IP:port

Oltre il one-to-one: WebRTC multiparti

Puoi anche dare un'occhiata allo standard IETF proposto da Justin Uberti per un'API REST per l'accesso ai servizi TURN.

È facile immaginare casi d'uso per lo streaming di contenuti multimediali che vadano oltre una semplice chiamata one-to-one. Ad esempio, una videoconferenza tra un gruppo di colleghi o un evento pubblico con un oratore e centinaia o milioni di spettatori.

Un'app WebRTC può utilizzare più connessioni RTCPeerConnection in modo che ogni endpoint si connetta a tutti gli altri endpoint in una configurazione mesh. Questo è l'approccio adottato da app come talky.io e funziona molto bene per un numero ridotto di colleghi. Oltre a ciò, il consumo di elaborazione e di larghezza di banda diventa eccessivo, in particolare per i client mobili.

Mesh: chiamata N-way ridotta
Topologia mesh completa: tutti connessi a tutti

In alternativa, un'app WebRTC potrebbe scegliere un endpoint per la distribuzione degli stream a tutti gli altri in una configurazione a stella. Puoi anche eseguire un endpoint WebRTC su un server e creare il tuo meccanismo di ridistribuzione (un'app client di esempio è fornita da webrtc.org).

A partire da Chrome 31 e Opera 18, è possibile utilizzare un MediaStream di un RTCPeerConnection come input per un altro. Questo può attivare architetture più flessibili perché consente a un'app web di gestire il routing delle chiamate scegliendo a quale altro peer connettersi. Per vedere come funziona, consulta Inoltro di connessione peer per esempi WebRTC e Esempi di connessioni peer WebRTC per più connessioni peer.

Unità di controllo multipunto

Un'opzione migliore per un numero elevato di endpoint è l'utilizzo di un'unità di controllo multipunto (MCU). Si tratta di un server che funge da collegamento per distribuire i contenuti multimediali tra un numero elevato di partecipanti. Le MCU sono in grado di gestire risoluzioni, codec e frequenze fotogrammi diverse in una videoconferenza, gestire la transcodifica, effettuare l'inoltro dello streaming selettivo e combinare o registrare audio e video. Per le chiamate con più parti, è necessario considerare una serie di problemi, in particolare la modalità di visualizzazione di più ingressi video e di mixare audio da più sorgenti. Anche le piattaforme cloud, come vLine, tentano di ottimizzare il routing del traffico.

È possibile acquistare un pacchetto hardware MCU completo o crearne uno personalizzato.

Vista posteriore di Cisco MCU5300
Il retro di un MCU Cisco

Sono disponibili diverse opzioni software per MCU open source. Ad esempio, Licode (precedentemente noto come Lynckia) produce una MCU open source per WebRTC. OpenTok ha Mantis.

Oltre i browser: VoIP, telefoni e messaggistica

La natura standardizzata di WebRTC consente di stabilire una comunicazione tra un'app WebRTC in esecuzione in un browser e un dispositivo o una piattaforma in esecuzione su un'altra piattaforma di comunicazione, come un telefono o un sistema di videoconferenza.

SIP è un protocollo di segnalazione utilizzato dai sistemi VoIP e di videoconferenza. Per attivare la comunicazione tra un'app web WebRTC e un client SIP, ad esempio un sistema di videoconferenza, WebRTC ha bisogno di un server proxy per mediare la segnalazione. La segnalazione deve passare attraverso il gateway ma, una volta stabilita la comunicazione, il traffico SRTP (video e audio) può passare direttamente al peer-to-peer.

La RTG (Public Switched Telephone Network) è la rete a commutazione di circuito di tutti i "normali vecchi telefoni" analogici. Per le chiamate tra app web e telefoni WebRTC, il traffico deve passare attraverso un gateway PSTN. Allo stesso modo, le app web WebRTC hanno bisogno di un server XMPP intermedio per comunicare con endpoint Jingle, come i client IM. Jingle è stato sviluppato da Google come estensione di XMPP per abilitare voce e video per i servizi di messaggistica. Le attuali implementazioni di WebRTC si basano sulla libreria C++ libjingle, un'implementazione di Jingle sviluppata inizialmente per Talk.

Diverse app, librerie e piattaforme sfruttano la capacità di WebRTC di comunicare con il mondo esterno:

  • sipML5: un client SIP JavaScript open source
  • jsSIP: libreria SIP JavaScript
  • Phono: API open source JavaScript Phone creata come plug-in
  • Zingaya: un widget telefono incorporabile
  • Twilio: voce e messaggistica
  • Uberconference: conferenza

Gli sviluppatori sipML5 hanno creato anche il gateway webrtc2sip. Tethr e Tropo hanno dimostrato un framework per le comunicazioni in caso di emergenza "in una valigetta" utilizzando una cella OpenBTS per consentire la comunicazione tra feature phone e computer tramite WebRTC. È una comunicazione telefonica senza operatore!

Scopri di più

Il codelab WebRTC fornisce istruzioni dettagliate su come creare un'app di chat video e di testo utilizzando un servizio di segnalazione Socket.io in esecuzione su Node.

Presentazione WebRTC alla conferenza Google I/O del 2013 con il lead tecnico WebRTC, Justin Uberti

Presentazione SFHTML5 di Chris Wilson - Introduzione alle app WebRTC

Il libro di 350 pagine WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web fornisce molti dettagli sui dati e sui percorsi di segnalazione e include una serie di diagrammi di topologia di rete dettagliati.

WebRTC and Signaling: What Two Years Has Taught Us - Post del blog di TokBox sul perché è stata una buona idea non usare le segnalazioni al di fuori delle specifiche

La guida pratica alla creazione di app WebRTC di Ben Strong fornisce molte informazioni sulle topologie e sull'infrastruttura WebRTC.

Il capitolo WebRTC di Ilya Grigorik High Performance Browser Networking approfondisce l'architettura, i casi d'uso e le prestazioni di WebRTC.