Crea servizi di backend per app WebRTC

Data di pubblicazione: 4 novembre 2013

WebRTC consente la comunicazione peer-to-peer. Richiede server in modo che i client possano scambiare metadati e coordinare la comunicazione tramite un processo chiamato signaling. I server aiutano inoltre i client a gestire i Network Address Translator (NAT) e i firewall.

Qui imparerai a creare un servizio di segnalazione e ad affrontare le peculiarità della connettività reale con i server STUN e TURN. Inoltre, capirai come le app WebRTC possono gestire le chiamate tra più partecipanti e interagire con servizi come VoIP e PSTN (noti anche come telefoni).

Che cos'è la segnalazione?

La segnalazione è il processo di coordinamento della comunicazione. Affinché un'app WebRTC possa configurare una chiamata, i suoi client devono scambiarsi le seguenti informazioni:

  • Messaggi di controllo della sessione utilizzati per aprire o chiudere la comunicazione
  • 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 visibili al mondo esterno

Questo processo di segnalazione richiede un modo per consentire ai client di scambiarsi messaggi. Questo meccanismo non è implementato dalle API WebRTC. Devi invece crearlo tu.

Perché la segnalazione non è definita da WebRTC?

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

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

Diagramma dell'architettura JSEP

JSEP richiede lo scambio tra peer di offerta e risposta, i metadati dei contenuti multimediali. Le offerte e le risposte vengono comunicate nel formato Session Description Protocol (SDP), 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 effettivamente tutto questo gergo dell'SDP? Dai un'occhiata agli esempi dell'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 SDP. Ad esempio, la funzione preferAudioCodec() in appr.tc può essere utilizzata per impostare il codec e il bitrate predefiniti. SDP è un po' difficile da manipolare con JavaScript e si sta discutendo se le versioni future di WebRTC debbano utilizzare JSON, ma ci sono alcuni vantaggi nel continuare a utilizzare SDP.

API RTCPeerConnection e segnalazione: offerta, risposta e candidato

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

Per inizializzare questo processo, RTCPeerConnection ha due attività:

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

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

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

  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() con la sua offerta.
  4. Alice converte l'offerta in stringa e utilizza un meccanismo di segnalazione per inviarla a Eve.
  5. Eve chiama setRemoteDescription() con l'offerta di Alice, in modo che il suo RTCPeerConnection conosca la configurazione di Alice.
  6. Eva chiama createAnswer() e il callback di esito positivo per questa operazione riceve una descrizione della sessione locale, ovvero la risposta di Eva.
  7. Eve imposta la sua risposta come descrizione locale chiamando setLocalDescription().
  8. Eve utilizza quindi il meccanismo di segnalazione per inviare la sua risposta stringificata ad Alice.
  9. Alice imposta la risposta di Eve come descrizione della sessione remota utilizzando setRemoteDescription().

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

  1. Alice crea un oggetto RTCPeerConnection con un gestore onicecandidate.
  2. Il gestore viene chiamato quando diventano disponibili i candidati di rete.
  3. Nel gestore, Alice invia i dati dei candidati convertiti in stringa a Eve tramite il loro canale di segnalazione.
  4. Quando Eve riceve un messaggio di un candidato da Alice, chiama addIceCandidate() per aggiungere il candidato alla descrizione del peer remoto.

JSEP supporta l'ICE Candidate Trickling, che consente al chiamante di fornire in modo incrementale i candidati al chiamato dopo l'offerta iniziale e al chiamato di iniziare ad agire sulla chiamata e configurare una connessione senza attendere l'arrivo di tutti i candidati.

Codice WebRTC per la segnalazione

Il seguente snippet di codice è un esempio di codice W3C che riassume l'intero processo di segnalazione. Il codice presuppone l'esistenza di un meccanismo di segnalazione, SignalingChannel. La segnalazione viene discussa in maggiore dettaglio 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 in azione i processi di offerta-risposta e scambio di candidati, visita simpl.info RTCPeerConnection e guarda il log della console per un esempio di videochiamata su una singola pagina. Puoi scaricare un dump completo degli indicatori e delle statistiche di WebRTC dalla pagina about://webrtc-internals in Google Chrome o dalla pagina opera://webrtc-internals in Opera.

Rilevamento dei peer

È un modo elegante per chiedere: "Come faccio a trovare qualcuno con cui parlare?"

Per le chiamate telefoniche, hai numeri di telefono ed elenchi. Per la videochiamata e la messaggistica online, sono necessari sistemi di gestione dell'identità e della presenza, nonché un mezzo per consentire agli utenti di avviare le sessioni. Le app WebRTC hanno bisogno di un modo per consentire ai client di segnalarsi a vicenda che vogliono avviare o partecipare a una chiamata.

I meccanismi di rilevamento dei peer non sono definiti da WebRTC e non vengono descritti qui. La procedura può essere semplice come inviare un URL via email o messaggio. Per le app di videochat, come Talky, tawk.to e Browser Meeting, puoi invitare le persone a una chiamata condividendo un link personalizzato. Lo sviluppatore Chris Ball ha creato un interessante esperimento serverless-webrtc che consente ai partecipanti alle chiamate WebRTC di scambiare metadati tramite qualsiasi servizio di messaggistica, ad esempio messaggistica istantanea, email o piccione viaggiatore.

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, hai bisogno di un server intermediario per scambiare messaggi di segnalazione e dati delle app tra i client. Purtroppo, un'app web non può gridare su internet: "Connettimi al mio amico!".

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

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

Invia messaggi push dal server al client

Browser Support

  • Chrome: 6.
  • Edge: 79.
  • Firefox: 6.
  • Safari: 5.

Source

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 vari hack, come il long polling, per eseguire il push dei dati da un servizio in esecuzione su un server web a un'app web in esecuzione in un browser.

L'API EventSource consente gli eventi inviati dal server, ovvero i dati inviati da un server web a un client browser tramite HTTP. EventSource è progettato per la messaggistica unidirezionale, ma può essere utilizzato in combinazione con XHR per creare un servizio per lo scambio di messaggi di segnalazione. Un servizio di segnalazione trasmette un messaggio da un chiamante, inviato tramite richiesta XHR, inviandolo tramite EventSource al destinatario della chiamata.

Browser Support

  • Chrome: 5.
  • Edge: 12.
  • Firefox: 11.
  • Safari: 5.

Source

WebSocket è progettato per la comunicazione client-server full duplex, il che significa che i messaggi possono fluire in entrambe le direzioni contemporaneamente. Un vantaggio di un servizio di segnalazione creato con WebSocket puro 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 hosting web per linguaggi come PHP, Python e Ruby.

Tutti i browser che supportano WebRTC supportano anche WebSocket. TLS deve essere utilizzato per tutte le connessioni per garantire che i messaggi non possano essere intercettati senza crittografia e anche per ridurre i problemi di attraversamento del proxy. Per saperne di più su WebSocket e sull'attraversamento del proxy, leggi il capitolo su WebRTC in High Performance Browser Networking di Ilya Grigorik.

Puoi gestire l'invio di segnali facendo in modo che i client WebRTC eseguano il polling di un server di messaggistica ripetutamente tramite Ajax, ma ciò comporta molte richieste di rete ridondanti, il che è particolarmente problematico per i dispositivi mobili. Anche dopo che una sessione è stata stabilita, i peer devono eseguire il polling dei messaggi di segnalazione in caso di modifiche o di interruzione della sessione da parte di altri peer. L'esempio di app WebRTC Book utilizza questa opzione con alcune ottimizzazioni per la frequenza di polling.

Segnalazione di scalabilità

Sebbene un servizio di segnalazione consumi relativamente poca larghezza di banda e CPU per client, i server di segnalazione per un'app molto utilizzata potrebbero dover gestire molti messaggi provenienti da località diverse con livelli elevati di contemporaneità. Le app WebRTC che ricevono molto traffico richiedono server di segnalazione in grado di gestire un carico considerevole. Non entreremo nei dettagli, ma esistono diverse opzioni per la messaggistica ad alte prestazioni e ad alto volume, tra cui:

  • eXtensible Messaging and Presence Protocol (XMPP) è un protocollo sviluppato per la messaggistica immediata che può essere utilizzato per la segnalazione. Le implementazioni del server includono ejabberd e Openfire. I client JavaScript, come Strophe.js, utilizzano BOSH per emulare lo streaming bidirezionale, ma BOSH potrebbe essere inefficiente e scalare male rispetto a WebSocket.

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

  • Piattaforme di messaggistica cloud commerciali che utilizzano WebSocket (anche se possono ricorrere al long polling), come Pusher e Kaazing.

  • Piattaforme WebRTC commerciali, come vLine

Crea un servizio di segnalazione con Socket.io su Node

Di seguito è riportato il codice di un'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 grazie al suo concetto integrato di stanze. Questo esempio è progettato per un numero relativamente ridotto di utenti, non per l'uso in produzione.

Socket.io utilizza WebSocket con i seguenti fallback: polling lungo AJAX, streaming multipart AJAX, Forever Iframe e polling JSONP. È stato trasferito su vari backend, ma è forse più noto per la sua versione Node utilizzata in questo esempio.

In questo esempio non è presente WebRTC. È progettata per mostrare come creare la segnalazione in un'app web. Visualizza il log della console per vedere cosa succede quando i client entrano in una stanza e si scambiano messaggi. Questo codelab WebRTC fornisce istruzioni passo passo su come integrarlo in un'app di videochat 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 eseguire questa app su localhost, devi avere Node.js, Socket.IO e node-static. Per installare Socket.IO e node-static, esegui npm 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

Dal 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 con Ctrl+Shift+J (o Command+Option+J su Mac).

Indipendentemente dall'approccio scelto per la segnalazione, il backend e l'app client devono fornire servizi simili a questo esempio.

Problemi con gli indicatori

  • RTCPeerConnection non inizierà a raccogliere candidati finché non viene chiamato setLocalDescription(). Questo è un requisito della bozza JSEP IETF.
  • Sfrutta Trickle ICE. Chiama addIceCandidate() non appena arrivano i candidati.

Server di indicatori pronti all'uso

Se non vuoi creare il tuo, 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 astrazione per WebRTC.
  • Signalmaster è un server di segnalazione creato per l'utilizzo con la libreria client JavaScript SimpleWebRTC.

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

Per la cronaca, Ericsson ha creato un server di segnalazione utilizzando PHP su Apache nei primi giorni di WebRTC. Questo è ormai un po' obsoleto, ma vale la pena esaminare il codice se stai prendendo in considerazione qualcosa di simile.

Sicurezza del segnale

La crittografia è obbligatoria per tutti i componenti WebRTC.

Tuttavia, i meccanismi di segnalazione non sono definiti dagli standard WebRTC, quindi spetta a te renderli sicuri. Se un malintenzionato riesce a intercettare la segnalazione, può interrompere le sessioni, reindirizzare le connessioni e registrare, alterare o inserire contenuti.

Il fattore più importante per proteggere la segnalazione è l'utilizzo di protocolli sicuri: HTTPS e WSS, come TLS. In questo modo, i messaggi non possono essere intercettati senza criptazione. Inoltre, fai attenzione a non trasmettere messaggi di segnalazione in modo che possano essere accessibili ad altri chiamanti che utilizzano lo stesso server di segnalazione.

Gestire NAT e firewall

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

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

Semplice connessione peer-to-peer
Un mondo senza NAT e firewall

In realtà, la maggior parte dei dispositivi si trova dietro uno o più livelli di NAT, alcuni dispongono di software antivirus che blocca determinate porte e protocolli e molti si trovano dietro proxy e firewall aziendali. Un firewall e un NAT possono infatti essere implementati dallo stesso dispositivo, ad esempio un router Wi-Fi di casa.

Peer dietro NAT e firewall
Il mondo reale

Le app WebRTC possono utilizzare il framework ICE per superare le complessità del networking reale. Per attivare questa funzionalità, la tua app deve passare gli URL del server ICE a RTCPeerConnection.

ICE cerca di trovare il percorso migliore per connettere i peer. Prova tutte le possibilità in parallelo e sceglie l'opzione più efficiente che funziona. ICE tenta innanzitutto di stabilire una connessione utilizzando l'indirizzo host ottenuto dal sistema operativo e dalla scheda di rete di un dispositivo. Se questo tentativo non va a buon fine (come accade per i dispositivi dietro NAT), ICE ottiene un indirizzo esterno utilizzando un server STUN e, se anche questo tentativo non va a buon fine, 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 se la connessione diretta (peer-to-peer) non va a buon fine.

Ogni server TURN supporta STUN. Un server TURN è un server STUN con funzionalità di inoltro integrate aggiuntive. ICE gestisce anche le complessità delle configurazioni NAT. In realtà, l'hole punching NAT potrebbe richiedere più di un semplice indirizzo IP:porta pubblico.

Gli URL dei server STUN e TURN vengono specificati (facoltativamente) da un'app WebRTC nell'oggetto di configurazione iceServers, che è il primo argomento del costruttore RTCPeerConnection. Per appr.tc, il valore è il 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, la magia di ICE avviene automaticamente. RTCPeerConnection utilizza il framework ICE per determinare il percorso migliore tra i peer, collaborando con i server STUN e TURN, se necessario.

STUN

I NAT forniscono a un dispositivo 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 aggirare questo problema, WebRTC utilizza STUN.

I server STUN si trovano sulla rete internet pubblica e hanno un solo compito: controllare l'indirizzo IP:porta di una richiesta in entrata (da un'app in esecuzione dietro un NAT) e inviare l'indirizzo come risposta. In altre parole, l'app utilizza un server STUN per scoprire la propria combinazione IP:porta da una prospettiva pubblica. Questo processo consente a un peer WebRTC di ottenere un indirizzo accessibile pubblicamente per se stesso e di passarlo a un altro peer tramite un meccanismo di segnalazione per configurare un link diretto.

I server STUN non devono fare molto o ricordare molto, quindi i server STUN con specifiche relativamente basse possono gestire un numero elevato di richieste.

La maggior parte delle chiamate WebRTC stabilisce una connessione utilizzando STUN, anche se potrebbe essere inferiore per le chiamate tra peer dietro firewall e configurazioni NAT complesse.

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

TURN

RTCPeerConnection tenta di configurare la comunicazione diretta tra i peer tramite UDP. Se l'operazione non riesce, RTCPeerConnection ricorre a TCP. Se questo non funziona, i server TURN possono essere utilizzati come riserva, inoltrando i dati tra gli endpoint.

Per ribadire, TURN viene utilizzato per trasmettere audio, video e flussi di dati tra peer, non per i dati di segnalazione.

I server TURN hanno indirizzi pubblici, quindi possono essere contattati dai peer anche se questi si trovano dietro firewall o proxy. I server TURN hanno un solo compito: inoltrare uno stream. A differenza dei server STUN, consumano intrinsecamente molta larghezza di banda.

Connessione peer-to-peer tramite un server STUN
The full Monty: STUN, TURN, and signaling

Questo diagramma mostra TURN in azione. STUN puro non è riuscito, quindi ogni peer 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 è restund, disponibile come codice sorgente e anche per AWS. Puoi configurare un server restund su Compute :

  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 il firewall locale (consenti QUALSIASI da QUALSIASI).
  4. Installa gli strumenti: shell sudo apt-get install make sudo apt-get install gcc
  5. Installa libre da creytiv.com/re.html.
  6. Scarica restund da creytiv.com/restund.html e decomprimilo.
  7. wget hancke.name/restund-auth.patch e applicala con patch -p1 < restund-auth.patch.
  8. Esegui make, sudo make install per libre e restund.
  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 restund:
    1. Imposta LD_LIBRARY_PATH.
    2. Copia restund.conf in /etc/restund.conf.
    3. Imposta restund.conf per utilizzare i 10 bit di destra. Indirizzo IP.
  12. Esegui restund
  13. Esegui il test utilizzando il client stund dalla macchina remota: ./client IP:port

WebRTC multiparte

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

Esistono numerosi casi d'uso per lo streaming multimediale che vanno oltre una chiamata one-to-one. Ad esempio, una videoconferenza tra un gruppo di colleghi o un evento pubblico con un relatore e centinaia o milioni di spettatori.

Un'app WebRTC può utilizzare più RTCPeerConnection in modo che ogni endpoint si connetta a ogni altro endpoint in una configurazione mesh. Questo è l'approccio adottato da app come talky.io e funziona molto bene per un numero ridotto di peer. Oltre questo limite, l'elaborazione e il consumo di larghezza di banda diventano eccessivi, soprattutto per i client mobile.

Mesh: chiamata N-way di piccole dimensioni
Topologia mesh completa: tutti connessi con tutti

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

Un MediaStream di un RTCPeerConnection può essere utilizzato come input per un altro. Ciò può consentire architetture più flessibili perché consente a un'app web di gestire il routing delle chiamate scegliendo l'altro peer a cui connettersi. Per vedere questo processo in azione, consulta Esempi di WebRTC: inoltro della connessione peer ed Esempi di WebRTC: connessioni peer multiple.

Unità di controllo multipunto

Un'opzione migliore per un numero elevato di endpoint è l'utilizzo di una unità di controllo multipunto (MCU). Si tratta di un server che funge da ponte per distribuire i contenuti multimediali tra un gran numero di partecipanti. Le MCU possono gestire diverse risoluzioni, codec e frequenze fotogrammi in una videoconferenza, gestire la transcodifica, eseguire l'inoltro selettivo degli stream e combinare o registrare audio e video. Per le chiamate con più partecipanti, ci sono una serie di problemi da considerare, in particolare come visualizzare più input video e mixare l'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 di software MCU open source. Ad esempio, Licode (precedentemente noto come Lynckia) produce un MCU open source per WebRTC. OpenTok ha Mantis.

Oltre i browser: VoIP, telefoni e messaggistica

La natura standardizzata di WebRTC consente di stabilire la 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 consentire la comunicazione tra un'app web WebRTC e un client SIP, ad esempio un sistema di videoconferenza, WebRTC richiede 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 in modalità peer-to-peer.

La rete telefonica generale (RTG) è la rete a commutazione di circuito di tutti i telefoni analogici "tradizionali". Per le chiamate tra app web WebRTC e telefoni, il traffico deve passare attraverso un gateway PSTN. Analogamente, le app web WebRTC richiedono un server XMPP intermediario per comunicare con gli endpoint Jingle, come i client di messaggistica istantanea. 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 inizialmente sviluppata per Talk.

Numerose app, librerie e piattaforme sfruttano la capacità di WebRTC di comunicare con il mondo esterno. Ad esempio:

  • jsSIP: libreria SIP JavaScript
  • Phono: API di telefonia JavaScript open source creata come plug-in
  • Twilio: voce e messaggistica

Scopri di più

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