Créer les services de backend nécessaires à une application WebRTC

Qu'est-ce que le signalement ?

Le signal est le processus de coordination de la communication. Pour qu'une application WebRTC puisse configurer un appel, ses clients doivent échanger les informations suivantes:

  • Messages de contrôle de session utilisés pour ouvrir ou fermer la communication
  • Messages d'erreur
  • Métadonnées multimédias (codecs, paramètres de codec, bande passante, types de contenus, etc.)
  • Données clés utilisées pour établir des connexions sécurisées
  • Données réseau, telles que l'adresse IP et le port d'un hôte vus par le monde extérieur

Ce processus de signalement a besoin d'un moyen pour les clients de transmettre des messages dans les deux sens. Ce mécanisme n'est pas implémenté par les API WebRTC. Vous devez le créer vous-même. Plus loin dans cet article, vous découvrirez comment créer un service de signalement. Mais tout d'abord, vous avez besoin d'un peu de contexte.

Pourquoi la signalisation n'est-elle pas définie par WebRTC ?

Pour éviter les redondances et optimiser la compatibilité avec les technologies établies, les méthodes et protocoles de signalement ne sont pas spécifiés par les normes WebRTC. Cette approche est décrite par le protocole JavaScript Session Establishment Protocol (JSEP):

L'architecture JSEP évite également à un navigateur d'enregistrer l'état, c'est-à-dire de fonctionner comme une machine d'état de signalisation. Cela poserait problème si, par exemple, des données étaient perdues à chaque actualisation d'une page. Au lieu de cela, l'état du signalement peut être enregistré sur un serveur.

Schéma de l'architecture JSEP
Architecture JSEP

JSEP nécessite un échange entre les pairs des propriétés offer et answer (les métadonnées multimédias mentionnées ci-dessus). Les offres et les réponses sont communiquées au format SDP (Session Description Protocol), qui se présente comme suit:

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
…

Vous voulez savoir ce que ce SDP glouglou signifie réellement ? Examinez les exemples de l'IETF (Internet Engineering Task Force).

Gardez à l'esprit que WebRTC est conçu de sorte que l'offre ou la réponse puisse être modifiée avant d'être définie comme description locale ou distante en modifiant les valeurs dans le texte du SDP. Par exemple, la fonction preferAudioCodec() dans appr.tc peut être utilisée pour définir le codec et le débit par défaut. La manipulation du SDP avec JavaScript est assez pénible, et la question est de savoir si les futures versions de WebRTC devraient plutôt utiliser JSON. Toutefois, il y a quelques avantages à adopter le SDP.

API RTCPeerConnection et signalement: offre, réponse et candidat

RTCPeerConnection est l'API utilisée par les applications WebRTC pour créer une connexion entre pairs, et communiquer des contenus audio et vidéo.

Pour initialiser ce processus, RTCPeerConnection comporte deux tâches:

  • Vérifiez les conditions des médias locaux, telles que la résolution et les capacités de codec. Il s'agit des métadonnées utilisées pour le mécanisme d'offre et de réponse.
  • Obtenez les adresses réseau potentielles de l'hôte de l'application, appelées candidats.

Une fois ces données locales vérifiées, elles doivent être échangées avec le pair distant via un mécanisme de signalement.

Imaginez qu'Alice essaie d'appeler Ève. Voici le mécanisme d'offre/réponse complet:

  1. Alice crée un objet RTCPeerConnection.
  2. Alice crée une offre (une description de session SDP) avec la méthode createOffer() RTCPeerConnection.
  3. Alice appelle setLocalDescription() pour lui faire part de son offre.
  4. Alice concatène l'offre et l'envoie à Ève à l'aide d'un mécanisme de signalement.
  5. Ève appelle setRemoteDescription() avec l'offre d'Alice afin que son RTCPeerConnection soit informé de la configuration d'Alice.
  6. Eve appelle createAnswer(), et le rappel de réussite reçoit une description de session locale : la réponse d'Eve.
  7. Eve définit sa réponse comme description locale en appelant setLocalDescription().
  8. Eve utilise ensuite le mécanisme de signalement pour envoyer sa réponse concaténée à Alice.
  9. Alice définit la réponse d'Eve comme description de la session à distance à l'aide de setRemoteDescription().

Alice et Eve doivent également échanger des informations sur le réseau. L'expression "rechercher des candidats" fait référence au processus de recherche d'interfaces réseau et de ports à l'aide du framework ICE.

  1. Alice crée un objet RTCPeerConnection avec un gestionnaire onicecandidate.
  2. Le gestionnaire est appelé lorsque des candidats au réseau sont disponibles.
  3. Dans le gestionnaire, Alice envoie à Eve une chaîne de données sur les candidats via leur canal de signalement.
  4. Lorsqu'Alice reçoit un message de candidat d'Alice, elle appelle addIceCandidate() pour ajouter le candidat à la description du pair distant.

JSEP est compatible avec le trickling de candidats ICE, qui permet à l'appelant de proposer progressivement des candidats à l'appelé après l'offre initiale, et à ce dernier de commencer à répondre à l'appel et d'établir une connexion sans attendre l'arrivée de tous les candidats.

Code WebRTC pour signaler

L'extrait de code suivant est un exemple de code W3C qui résume l'ensemble du processus de signalement. Le code suppose l'existence d'un mécanisme de signalement, SignalingChannel. Le signal est abordé plus en détail ultérieurement.

// 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);
  }
};

Pour voir concrètement les processus d'offre/réponse et de candidat-échange, consultez la page simpl.info RTCPeerConnection et consultez le journal de la console pour voir un exemple de chat vidéo sur une seule page. Pour en savoir plus, téléchargez un fichier de vidage complet des signaux et des statistiques WebRTC à partir de la page about://webrtc-internals de Google Chrome ou de la page opera://webrtc-internals d'Opera.

Découverte de pairs

C'est une façon compliquée de se demander "comment trouver quelqu'un à qui parler ?".

Pour les appels téléphoniques, vous disposez de numéros de téléphone et d'annuaires. Pour le chat vidéo et la messagerie en ligne, vous devez disposer de systèmes de gestion de l'authentification et de la présence, et d'un moyen permettant aux utilisateurs de lancer des sessions. Les applications WebRTC doivent permettre aux clients de se signaler mutuellement qu'ils souhaitent démarrer ou rejoindre un appel.

Les mécanismes de détection de pairs ne sont pas définis par WebRTC et vous n'entrez pas dans les options ici. Il peut s'agir d'envoyer une URL par e-mail ou par message. Pour les applications de chat vidéo telles que Talky, tawk.to et Browser Meeting, vous pouvez inviter des personnes à participer à un appel en partageant un lien personnalisé. Le développeur Chris Ball a conçu une expérience intrigante serverless-webrtc qui permet aux participants à l'appel WebRTC d'échanger des métadonnées avec le service de messagerie de leur choix, comme la messagerie instantanée, les e-mails ou le pigeon d'accueil.

Comment créer un service de signalement ?

Pour rappel, les protocoles et mécanismes de signalement ne sont pas définis par les normes WebRTC. Quel que soit votre choix, vous avez besoin d'un serveur intermédiaire pour échanger les messages de signalisation et les données de l'application entre les clients. Malheureusement, une application Web ne peut pas simplement crier dans Internet : "Connectez-moi à un ami !"

Heureusement, les messages de signalisation sont petits et principalement échangés au début d'un appel. Lors du test d'une session de chat vidéo avec appr.tc, le service de signalement a traité au total environ 30 à 45 messages, avec une taille totale d'environ 10 Ko.

En plus d'être relativement peu exigeants en termes de bande passante, les services de signalement WebRTC ne consomment pas beaucoup de mémoire ni de traitement, car ils doivent simplement relayer des messages et conserver une petite quantité de données d'état de session, telles que les clients connectés.

Transmettre des messages du serveur au client

Pour la signalisation, un service de messagerie doit être bidirectionnel: de client à serveur et de serveur à client. La communication bidirectionnelle va à l'encontre du modèle requête/réponse client/serveur HTTP, mais plusieurs techniques de piratage telles que la consultation longue ont été développées au fil des années afin de transférer les données d'un service exécuté sur un serveur Web vers une application Web exécutée dans un navigateur.

Plus récemment, l'API EventSource a été largement implémentée. Cela active les événements envoyés par le serveur, c'est-à-dire des données envoyées d'un serveur Web vers un client de navigateur via HTTP. EventSource est conçu pour les messages à sens unique, mais peut être utilisé en combinaison avec XHR pour créer un service d'échange de messages de signalisation. Un service de signalement transmet un message d'un appelant, transmis par une requête XHR, en le transmettant via EventSource à l'appelé.

WebSocket est une solution plus naturelle, conçue pour la communication client-serveur full-duplex, c'est-à-dire les messages qui peuvent circuler dans les deux sens en même temps. L'un des avantages d'un service de signalement créé à partir d'événements WebSocket pur ou envoyés par le serveur (EventSource) est que le backend de ces API peut être implémenté sur divers frameworks Web communs à la plupart des packages d'hébergement Web pour des langages tels que PHP, Python et Ruby.

Tous les navigateurs récents à l'exception d'Opera Mini sont compatibles avec WebSocket. Plus important encore, tous les navigateurs compatibles avec WebRTC l'acceptent également sur ordinateur et sur mobile. Le protocole TLS doit être utilisé pour toutes les connexions afin de garantir que les messages ne peuvent pas être interceptés et chiffrés et pour réduire les problèmes de traversée de proxy. (Pour en savoir plus sur WebSocket et la traversée de proxy, consultez le chapitre WebRTC du document High Performance Browser Networking d'Ilya Grigorik.)

Il est également possible de gérer la signalisation en demandant aux clients WebRTC d'interroger un serveur de messagerie de façon répétée via Ajax, mais cela génère de nombreuses requêtes réseau redondantes, ce qui est particulièrement problématique pour les appareils mobiles. Même après qu'une session a été établie, les pairs doivent interroger les messages pour signaler des changements ou une fermeture de session par d'autres pairs. L'exemple d'application WebRTC Book utilise cette option avec quelques optimisations pour la fréquence d'interrogation.

Signalisation de mise à l'échelle

Bien qu'un service de signalement consomme relativement peu de bande passante et de processeur par client, les serveurs d'une application populaire peuvent être amenés à gérer un grand nombre de messages provenant de différents emplacements avec des niveaux de simultanéité élevés. Les applications WebRTC qui reçoivent beaucoup de trafic doivent signaler des serveurs capables de gérer une charge considérable. Vous n'entrez pas dans les détails ici, mais il existe un certain nombre d'options pour un message hautes performances et à volume élevé, dont les suivantes:

  • eXtensible Messaging and Presence Protocol (XMPP), à l'origine connu sous le nom de protocole Jabber-a et développé pour la messagerie instantanée pouvant être utilisée pour la signalisation (les implémentations de serveurs incluent ejabberd et Openfire). Les clients JavaScript, tels que Strophe.js, utilisent BOSH pour émuler un flux bidirectionnel, mais pour diverses raisons, BOSH peut ne pas être aussi efficace que WebSocket et, pour les mêmes raisons, ne pas s'adapter correctement.) (Sur la tangente, Jingle est une extension XMPP permettant d'activer les fonctionnalités vocales et vidéo. Le projet WebRTC utilise des composants de réseau et de transport de la bibliothèque libjingle, une implémentation C++ de Jingle.)

  • Des bibliothèques Open Source telles que ZeroMQ (utilisées par TokBox pour son service Rumour) et OpenMQ (NullMQ appliquent les concepts ZeroMQ aux plates-formes Web utilisant le protocole STOMP sur WebSocket).

  • Les plates-formes commerciales de messagerie dans le cloud qui utilisent WebSocket (bien qu'elles puissent s'appuyer sur un long sondage), telles que Pusher, Kaazing et PubNub (PubNub dispose également d'une API pour WebRTC).

  • Plates-formes WebRTC commerciales telles que vLine

(Le Guide des technologies Web en temps réel du développeur Phil Leggetter fournit une liste complète des bibliothèques et des services de messagerie.)

Créer un service de signalement avec Socket.io sur Node

Voici le code d'une application Web simple qui utilise un service de signalement créé avec Socket.io sur Node. La conception de Socket.io permet de créer facilement un service pour échanger des messages. Socket.io est particulièrement adapté à la signalisation WebRTC en raison de son concept intégré de salles. Cet exemple n'est pas conçu pour évoluer en tant que service de signalisation de niveau production, mais il est simple à comprendre pour un nombre relativement faible d'utilisateurs.

Socket.io utilise WebSocket avec des solutions de secours: interrogation longue AJAX, interrogation en plusieurs parties AJAX, interrogation Iframe Forever et interrogation JSONP. Il a été transféré vers différents backends, mais il est surtout connu pour la version de nœud utilisée dans cet exemple.

Il n'y a pas de WebRTC dans cet exemple. Il est conçu uniquement pour montrer comment intégrer le signalement dans une application Web. Consultez le journal de la console pour savoir ce qui se passe lorsque des clients rejoignent un salon et échangent des messages. Cet atelier de programmation WebRTC fournit des instructions détaillées pour l'intégrer à une application complète de chat vidéo WebRTC.

Voici le 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>

Voici le fichier JavaScript main.js référencé dans le 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);
});

Voici l'application de serveur complète:

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);

  });

});

(Vous n'avez pas besoin d'en savoir plus sur l'utilisation statique des nœuds pour cela. Il se trouve être utilisé dans cet exemple.)

Pour exécuter cette application sur localhost, vous devez installer Node, Socket.IO et node-static. Le nœud peut être téléchargé à partir de Node.js (l'installation est simple et rapide). Pour installer Socket.IO et node-static, exécutez le gestionnaire de packages de nœuds à partir d'un terminal du répertoire de votre application:

npm install socket.io
npm install node-static

Pour démarrer le serveur, exécutez la commande suivante à partir d'un terminal dans le répertoire de votre application:

node server.js

Dans votre navigateur, ouvrez localhost:2013. Ouvrez un nouvel onglet ou une nouvelle fenêtre dans un navigateur, puis rouvrez localhost:2013. Pour savoir ce qui se passe, consultez la console. Dans Chrome et Opera, vous pouvez accéder à la console via les outils pour les développeurs Google Chrome avec Ctrl+Shift+J (ou Command+Option+J sur Mac).

Quelle que soit l'approche que vous choisissez pour le signalement, votre backend et votre application cliente doivent, au minimum, fournir des services semblables à cet exemple.

Pièges de signalisation

  • RTCPeerConnection ne commencera pas à rassembler des candidats tant que setLocalDescription() n'aura pas été appelé. Cette pratique est exigée dans la version préliminaire de l'IETF JSEP.
  • Profitez de Trickle ICE. Appelez le addIceCandidate() dès l'arrivée des candidats.

Serveurs de signalisation prêts à l'emploi

Si vous ne voulez pas lancer le vôtre, plusieurs serveurs de signalement WebRTC sont disponibles. Ils utilisent Socket.IO comme dans l'exemple précédent et sont intégrés aux bibliothèques JavaScript clientes WebRTC:

  • webRTC.io est l'une des premières bibliothèques d'abstraction pour WebRTC.
  • Signalmaster est un serveur de signalement créé pour être utilisé avec la bibliothèque cliente JavaScript SimpleWebRTC.

Si vous ne souhaitez pas écrire de code, vous pouvez vous procurer des plates-formes WebRTC commerciales complètes, telles que vLine, OpenTok et Asterisk.

Pour information, Ericsson a créé un serveur de signalisation à l'aide de PHP sur Apache dès les débuts de WebRTC. Cette version est désormais obsolète, mais cela vaut la peine d'examiner le code si vous envisagez d'utiliser un code similaire.

Sécurité du signal

"La sécurité est l'art de ne rien faire."

Salman Rushdie

Le chiffrement est obligatoire pour tous les composants WebRTC.

Toutefois, les mécanismes de signalement ne sont pas définis par les normes WebRTC. C'est donc à vous de les sécuriser. Si un pirate informatique parvient à pirater les signaux, il peut arrêter des sessions, rediriger les connexions, et enregistrer, modifier ou injecter du contenu.

Le facteur le plus important pour sécuriser les signaux est l'utilisation de protocoles sécurisés, HTTPS et WSS (par exemple, TLS) qui garantissent que les messages ne peuvent pas être interceptés après avoir été chiffrés. Veillez également à ne pas diffuser de messages de signalement de telle sorte que d'autres appelants puissent y accéder à l'aide du même serveur de signalement.

Après le signalement: utiliser ICE pour gérer les NAT et les pare-feu

Pour la signalisation des métadonnées, les applications WebRTC utilisent un serveur intermédiaire. Cependant, pour le streaming réel des contenus multimédias et des données une fois une session établie, RTCPeerConnection tente de connecter les clients directement ou peer-to-peer.

Dans un monde plus simple, chaque point de terminaison WebRTC disposerait d'une adresse unique qu'il pourrait échanger avec d'autres pairs afin de communiquer directement.

Connexion peer-to-peer simple
Un monde sans NAT ni pare-feu

En réalité, la plupart des appareils sont situés derrière une ou plusieurs couches de NAT. Certains sont équipés d'un logiciel antivirus qui bloque certains ports et protocoles, et nombre d'entre eux se trouvent derrière des proxys et des pare-feu d'entreprise. Un pare-feu et une NAT peuvent en effet être mis en œuvre par le même appareil, comme un routeur Wi-Fi domestique.

Pairs derrière les NAT et les pare-feu
Le monde réel

Les applications WebRTC peuvent utiliser le framework ICE pour surmonter les complexités des réseaux réels. Pour ce faire, votre application doit transmettre les URL de serveur ICE à RTCPeerConnection, comme décrit dans cet article.

ICE essaie de trouver la meilleure façon de connecter les pairs. Il essaie toutes les possibilités en parallèle et choisit l'option la plus efficace. ICE tente d'abord d'établir une connexion à l'aide de l'adresse hôte obtenue à partir du système d'exploitation et de la carte réseau d'un appareil. En cas d'échec (ce qui est le cas pour les appareils protégés par des NAT), ICE obtient une adresse externe à l'aide d'un serveur STUN et, en cas d'échec, le trafic est acheminé via un serveur de relais TURN.

En d'autres termes, un serveur STUN est utilisé pour obtenir une adresse réseau externe et les serveurs TURN sont utilisés pour relayer le trafic en cas d'échec de la connexion directe (peer-to-peer).

Chaque serveur TURN prend en charge STUN. Un serveur TURN est un serveur STUN doté d'une fonctionnalité de relais intégrée supplémentaire. ICE fait également face à la complexité des configurations NAT. En réalité, la génération d'une entrée NAT nécessite plus qu'une adresse IP:port publique.

Les URL des serveurs STUN et/ou TURN sont (éventuellement) spécifiées par une application WebRTC dans l'objet de configuration iceServers, qui constitue le premier argument du constructeur RTCPeerConnection. Pour appr.tc, cette valeur se présente comme suit:

{
  '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'
    }
  ]
}

Une fois que RTCPeerConnection dispose de cette information, la magie ICE se déclenche automatiquement. RTCPeerConnection utilise le framework ICE afin de trouver le meilleur chemin entre les pairs, en travaillant avec des serveurs STUN et TURN si nécessaire.

ÉTAT

Les NAT fournissent à un appareil une adresse IP à utiliser au sein d'un réseau local privé, mais cette adresse ne peut pas être utilisée en externe. Sans adresse publique, les pairs WebRTC n'ont aucun moyen de communiquer. Pour contourner ce problème, WebRTC utilise STUN.

Les serveurs STUN résident sur l'Internet public et n'ont qu'une tâche à réaliser : vérifier l'adresse IP:port d'une requête entrante (provenant d'une application exécutée derrière une NAT) et renvoyer cette adresse en réponse. En d'autres termes, l'application utilise un serveur STUN pour découvrir son adresse IP:port d'un point de vue public. Ce processus permet à un pair WebRTC d'obtenir lui-même une adresse publiquement accessible, puis de la transmettre à un autre pair via un mécanisme de signalement afin de configurer un lien direct. (En pratique, différents NAT fonctionnent de différentes manières et il peut y avoir plusieurs couches NAT, mais le principe reste le même.)

Les serveurs STUN n'ont pas beaucoup de travail ni de mémoire à mémoriser. Par conséquent, ils sont relativement peu performants et peuvent gérer un grand nombre de requêtes.

La plupart des appels WebRTC établissent une connexion à l'aide de STUN (86% d'après Webrtcstats.com), bien que cela puisse être moins important pour les appels entre pairs derrière des pare-feu et des configurations NAT complexes.

Connexion peer-to-peer à l&#39;aide d&#39;un serveur STUN
Utiliser des serveurs STUN pour obtenir des adresses IP:port publiques

TURN

RTCPeerConnection tente de configurer une communication directe entre les pairs sur UDP. En cas d'échec, RTCPeerConnection a recours au TCP. En cas d’échec, les serveurs TURN peuvent être utilisés en remplacement, en transmettant des données entre les points de terminaison.

Pour rappel, TURN est utilisé pour relayer des flux audio, vidéo et de données entre pairs, et non pour signaler des données.

Les serveurs TURN ont des adresses publiques, de sorte qu'ils peuvent être contactés par des pairs même s'ils se trouvent derrière des pare-feu ou des proxys. Les serveurs TURN ont une tâche conceptuellement simple : relayer un flux. Toutefois, contrairement aux serveurs STUN, ils consomment intrinsèquement une grande quantité de bande passante. En d'autres termes, les serveurs TURN doivent être plus puissants.

Connexion peer-to-peer à l&#39;aide d&#39;un serveur STUN
The full Monty: STUN, TURN and Signing

Ce schéma montre TURN en action. La méthode STUN pure n'a pas abouti, et chaque pair a donc recours à un serveur TURN.

Déployer des serveurs STUN et TURN

Pour effectuer les tests, Google exécute un serveur STUN public, stun.l.google.com:19302, utilisé par appr.tc. Pour un service STUN/TURN de production, utilisez le protocole rfc5766-turn-server. Le code source des serveurs STUN et TURN est disponible sur GitHub, où vous trouverez également des liens vers plusieurs sources d'informations concernant l'installation des serveurs. Une image de VM pour Amazon Web Services est également disponible.

Il existe un autre serveur TURN, disponible en tant que code source et également pour AWS. Voici des instructions pour configurer un restund sur Compute Engine.

  1. Ouvrez le pare-feu si nécessaire pour tcp=443 et udp/tcp=3478.
  2. Créer quatre instances, une pour chaque adresse IP publique, image Ubuntu 12.06 standard.
  3. Paramétrez la configuration du pare-feu local (autoriser N'IMPORTE QUELLE entrée).
  4. Outils d'installation : shell sudo apt-get install make sudo apt-get install gcc
  5. Installez libre depuis creytiv.com/re.html.
  6. Récupérez les informations sur le restaurant à l'adresse creytiv.com/restund.html, puis décompressez-la.
  7. wget hancke.name/restund-auth.patch et appliquer avec patch -p1 < restund-auth.patch.
  8. Exécutez make et sudo make install pour "libre" et "restund".
  9. Adaptez restund.conf à vos besoins (remplacez les adresses IP et assurez-vous qu'il contient la même clé secrète partagée), puis copiez-le dans /etc.
  10. Copiez restund/etc/restund dans le répertoire /etc/init.d/.
  11. Configurez la restauration :
    1. Définissez LD_LIBRARY_PATH.
    2. Copiez restund.conf dans le répertoire /etc/restund.conf.
    3. Définissez restund.conf pour utiliser les 10 bonnes réponses. votre adresse IP.
  12. Restauration
  13. Effectuer un test à l'aide du client STund de la machine distante: ./client IP:port

Au-delà du "un à un" : WebRTC multipartite

Vous pouvez également jeter un œil à la norme IETF proposée par Justin Uberti pour une API REST pour l'accès aux services TURN.

Il est facile d'imaginer des cas d'utilisation du streaming multimédia qui vont au-delà d'un simple appel individuel. Il peut s'agir, par exemple, d'une visioconférence rassemblant un groupe de collègues ou d'un événement public avec un intervenant et des centaines, voire des millions de spectateurs.

Une application WebRTC peut utiliser plusieurs RTCPeerConnections afin que chaque point de terminaison se connecte à tous les autres points de terminaison d'une configuration maillée. C'est l'approche adoptée par les applications, comme talky.io, qui fonctionne très bien pour un petit nombre d'applications similaires. Au-delà, l'utilisation du traitement et de la bande passante devient excessive, en particulier pour les clients mobiles.

Réseau maillé: petit appel N-way
Topologie complète du réseau maillé: toute la famille connectée

Une application WebRTC peut également choisir un point de terminaison pour distribuer les flux à tous les autres dans une configuration en étoile. Il est également possible d'exécuter un point de terminaison WebRTC sur un serveur et de créer votre propre mécanisme de redistribution (un exemple d'application cliente est fourni par webrtc.org).

Depuis Chrome 31 et Opera 18, un MediaStream d'un RTCPeerConnection peut être utilisé comme entrée pour un autre. Cela peut permettre d'obtenir des architectures plus flexibles, car cela permet à une application Web de gérer le routage des appels en choisissant à quel autre pair se connecter. Pour voir concrètement en quoi consiste WebRTC, consultez les sections Exemples de connexions WebRTC et de relais de connexion de pairs et WebRTC exemples de connexions appairées multiples.

Unité de contrôle multipoint

Pour un grand nombre de points de terminaison, il est préférable d'utiliser une unité de contrôle multipoint (MCU). Il s'agit d'un serveur faisant office de passerelle pour distribuer des contenus multimédias entre un grand nombre de participants. Les MCU peuvent gérer différentes résolutions, codecs et fréquences d'images lors d'une visioconférence, gérer le transcodage, effectuer un transfert de flux sélectif, et mixer ou enregistrer des contenus audio et vidéo. Pour les appels multipartites, vous devez prendre en compte un certain nombre de questions, en particulier comment afficher plusieurs entrées vidéo et mixer l'audio provenant de plusieurs sources. Les plates-formes cloud, telles que vLine, tentent également d'optimiser le routage du trafic.

Il est possible d’acheter un pack matériel MCU complet ou de créer le vôtre.

Vue arrière du Cisco MCU5300
Arrière d'un MCU Cisco

Plusieurs options logicielles de MCU Open Source sont disponibles. Par exemple, Licode (anciennement Lynckia) produit une MCU Open Source pour WebRTC. OpenTok contient Mantis.

Au-delà des navigateurs: VoIP, téléphones et messagerie

La nature standardisée de WebRTC permet d'établir la communication entre une application WebRTC exécutée dans un navigateur et un appareil ou une plate-forme fonctionnant sur une autre plate-forme de communication, comme un téléphone ou un système de visioconférence.

SIP est un protocole de signalisation utilisé par les systèmes VoIP et de visioconférence. Pour permettre la communication entre une application Web WebRTC et un client SIP, tel qu'un système de visioconférence, WebRTC a besoin d'un serveur proxy pour arbitrer les signaux. Le signal doit passer par la passerelle, mais, une fois la communication établie, le trafic SRTP (vidéo et audio) peut circuler directement entre pairs.

Le réseau téléphonique commuté public (RTCP) est le réseau à commutation de circuits de tous les téléphones analogiques anciens. Pour les appels entre des applications Web WebRTC et des téléphones, le trafic doit passer par une passerelle RTCP. De même, les applications Web WebRTC ont besoin d'un serveur XMPP intermédiaire pour communiquer avec les points de terminaison Jingle tels que les clients de messagerie instantanée. Jingle a été développé par Google en tant qu'extension de XMPP afin d'activer la voix et la vidéo pour les services de messagerie. Les implémentations WebRTC actuelles sont basées sur la bibliothèque C++ libjingle, une implémentation de Jingle initialement développée pour Talk.

Un certain nombre d'applications, de bibliothèques et de plates-formes exploitent la capacité de WebRTC à communiquer avec le monde extérieur:

  • sipML5: client SIP Open Source JavaScript
  • jsSIP: bibliothèque SIP JavaScript
  • Phono: API JavaScript Open Source pour téléphone conçue sous la forme d'un plug-in
  • Zingaya: widget intégrable pour les téléphones.
  • Twilio: voix et messagerie
  • Uberconference: conférence

Les développeurs sipML5 ont également créé la passerelle webrtc2sip. Tethr et Tropo ont mis au point un framework pour les communications en cas de sinistre "dans une mallette" utilisant une cellule OpenBTS pour permettre les communications entre les feature phones et les ordinateurs via WebRTC. C'est une communication téléphonique sans opérateur !

En savoir plus

L'atelier de programmation WebRTC fournit des instructions détaillées pour créer une application de chat vidéo et textuel à l'aide d'un service de signalement Socket.io exécuté sur Node.

Présentation WebRTC Google I/O de 2013 avec Justin Uberti, responsable technique WebRTC

Présentation SFHTML5 de Chris Wilson : Introduction aux applications WebRTC

Le livre de 350 pages WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web (WebRTC : API et protocoles RTCWEB du Web en temps réel HTML5) fournit de nombreux détails sur les données et les chemins de signalisation. Il inclut également un certain nombre de schémas détaillés de topologie de réseau.

WebRTC et signalisation: ce que deux ans ont appris - Article de blog TokBox expliquant pourquoi il était judicieux de ne pas faire de signalement non conforme aux spécifications

L'article A Practical Guide to Building WebRTC Apps (Guide pratique pour la création d'applications WebRTC) de Ben Strong fournit de nombreuses informations sur l'infrastructure et les topologies WebRTC.

Le chapitre WebRTC du livre High Performance Browser Networking d'Ilya Grigorik explique en détail l'architecture WebRTC, les cas d'utilisation et les performances.