Qu'est-ce que la signalisation ?
La signalisation 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, telles que les codecs, les paramètres de codec, la bande passante et les types de contenus multimédias
- 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 tels qu'ils sont visibles de l'extérieur
Ce processus de signalisation nécessite un moyen pour les clients d'échanger des messages. 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 signalisation. Mais avant cela, vous avez besoin d'un peu de contexte.
Pourquoi la signalisation n'est-elle pas définie par WebRTC ?
Pour éviter la redondance et maximiser la compatibilité avec les technologies établies, les méthodes et protocoles de signalisation ne sont pas spécifiés par les normes WebRTC. Cette approche est décrite dans le JavaScript Session Establishment Protocol (JSEP) :
L'architecture de JSEP évite également au navigateur d'avoir à enregistrer l'état, c'est-à-dire de fonctionner comme une machine d'état de signalisation. Cela poserait problème si, par exemple, les données de signalisation étaient perdues à chaque fois qu'une page était rechargée. L'état de signalisation peut en revanche être enregistré sur un serveur.

JSEP nécessite l'échange entre pairs d'une offre et d'une réponse, ainsi que des 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 ressemble à ceci :
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 signifie réellement tout ce jargon lié au SDP ? Consultez les exemples de l'Internet Engineering Task Force (IETF).
N'oubliez pas que WebRTC est conçu de manière à ce que l'offre ou la réponse puissent être modifiées avant d'être définies comme description locale ou distante en modifiant les valeurs dans le texte 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. Il est assez difficile de manipuler le SDP avec JavaScript. On se demande si les futures versions de WebRTC devraient plutôt utiliser JSON, mais il y a certains avantages à s'en tenir au SDP.
API RTCPeerConnection
et signalisation : offre, réponse et candidat
RTCPeerConnection
est l'API utilisée par les applications WebRTC pour créer une connexion entre les pairs et communiquer de l'audio et de la vidéo.
Pour initialiser ce processus, RTCPeerConnection
doit effectuer deux tâches :
- Déterminez les conditions média locales, 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 établies, elles doivent être échangées avec le pair distant via un mécanisme de signalisation.
Imaginons qu'Alice essaie d'appeler Ève. Voici le mécanisme complet d'offre/réponse dans tous ses détails :
- Alice crée un objet
RTCPeerConnection
. - Alice crée une offre (une description de session SDP) avec la méthode
RTCPeerConnection
createOffer()
. - Alice appelle
setLocalDescription()
pour lui faire son offre. - Alice sérialise l'offre et utilise un mécanisme de signalisation pour l'envoyer à Ève.
- Eve appelle
setRemoteDescription()
avec l'offre d'Alice, afin que sonRTCPeerConnection
soit au courant de la configuration d'Alice. - Eve appelle
createAnswer()
et le rappel de réussite pour cela reçoit une description de session locale : la réponse d'Eve. - Eve définit sa réponse comme description locale en appelant
setLocalDescription()
. - Eve utilise ensuite le mécanisme de signalisation pour envoyer sa réponse sous forme de chaîne à Alice.
- Alice définit la réponse d'Ève comme description de la session à distance à l'aide de
setRemoteDescription()
.
Alice et Ève doivent également échanger des informations sur le réseau. L'expression "recherche de candidats" fait référence au processus de recherche d'interfaces et de ports réseau à l'aide du framework ICE.
- Alice crée un objet
RTCPeerConnection
avec un gestionnaireonicecandidate
. - Le gestionnaire est appelé lorsque des candidats réseau deviennent disponibles.
- Dans le gestionnaire, Alice envoie les données du candidat sous forme de chaîne à Eve via leur canal de signalisation.
- Lorsqu'Eve reçoit un message 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 fournir progressivement des candidats à l'appelé après l'offre initiale, et à l'appelé de commencer à agir sur l'appel et à établir une connexion sans attendre l'arrivée de tous les candidats.
Coder WebRTC pour la signalisation
L'extrait de code suivant est un exemple de code W3C qui résume l'ensemble du processus de signalisation. Le code suppose l'existence d'un mécanisme de signalisation, SignalingChannel
. La signalisation sera abordée 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 les processus d'échange d'offres/réponses et de candidats en action, consultez simpl.info RTCPeerConnection et examinez le journal de la console pour obtenir un exemple de chat vidéo sur une seule page. Si vous souhaitez en savoir plus, téléchargez un dump complet des statistiques et de la signalisation WebRTC à partir de la page about://webrtc-internals dans Google Chrome ou de la page opera://webrtc-internals dans Opera.
Découverte de pairs
Il s'agit d'une façon élégante de 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 les discussions vidéo et les messages en ligne, vous avez besoin de systèmes de gestion de l'identité et de la présence, ainsi que d'un moyen pour les utilisateurs de lancer des sessions. Les applications WebRTC ont besoin d'un moyen pour les clients de se signaler mutuellement qu'ils souhaitent démarrer ou rejoindre un appel.
Les mécanismes de découverte des pairs ne sont pas définis par WebRTC. Nous n'aborderons pas les options ici. Il peut s'agir d'un simple e-mail ou message contenant une URL. Pour les applications de chat vidéo, telles que Talky, tawk.to et Browser Meeting, vous invitez des personnes à un appel en partageant un lien personnalisé. Le développeur Chris Ball a créé une expérience serverless-webrtc intrigante qui permet aux participants aux appels WebRTC d'échanger des métadonnées par le biais du service de messagerie de leur choix, comme la messagerie instantanée, l'e-mail ou le pigeon voyageur.
Comment créer un service de signalisation ?
Pour rappel, les protocoles et mécanismes de signalisation ne sont pas définis par les normes WebRTC. Quel que soit votre choix, vous avez besoin d'un serveur intermédiaire pour échanger des messages de signalisation et des données d'application entre les clients. Malheureusement, une application Web ne peut pas simplement crier sur Internet : "Connecte-moi à mon ami !"
Heureusement, les messages de signalisation sont petits et sont principalement échangés au début d'un appel. Lors de tests avec appr.tc pour une session de chat vidéo, un total d'environ 30 à 45 messages ont été traités par le service de signalisation, avec une taille totale d'environ 10 Ko pour tous les messages.
En plus d'être relativement peu exigeants en termes de bande passante, les services de signalisation WebRTC ne consomment pas beaucoup de ressources de traitement ni de mémoire, car ils n'ont besoin que de relayer les messages et de conserver une petite quantité de données d'état de session, comme les clients connectés.
Envoyer des messages push du serveur au client
Un service de messagerie pour la signalisation doit être bidirectionnel : du client au serveur et du serveur au client. La communication bidirectionnelle va à l'encontre du modèle requête/réponse client/serveur HTTP. Toutefois, diverses astuces telles que le long polling ont été développées au fil des ans pour transférer des 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 permet d'envoyer des événements (données envoyées d'un serveur Web à un client de navigateur via HTTP). EventSource
est conçu pour la messagerie unidirectionnelle, mais il peut être utilisé en combinaison avec XHR pour créer un service d'échange de messages de signalisation. Un service de signalisation transmet un message d'un appelant, envoyé par une requête XHR, en le transmettant via EventSource
au destinataire.
WebSocket est une solution plus naturelle, conçue pour la communication client-serveur en duplex intégral (messages pouvant circuler dans les deux sens en même temps). L'un des avantages d'un service de signalisation conçu avec des événements WebSocket ou envoyés par le serveur (EventSource
) est que le backend de ces API peut être implémenté sur une variété de frameworks Web courants dans la plupart des packages d'hébergement Web pour des langages tels que PHP, Python et Ruby.
Tous les navigateurs modernes, à l'exception d'Opera Mini, sont compatibles avec WebSocket. Plus important encore, tous les navigateurs compatibles avec WebRTC le sont également avec WebSocket, à la fois sur ordinateur et sur mobile. Le protocole TLS doit être utilisé pour toutes les connexions afin de s'assurer que les messages ne peuvent pas être interceptés sans chiffrement et pour réduire les problèmes liés à la traversée de proxy. (Pour en savoir plus sur WebSocket et le parcours de proxy, consultez le chapitre sur WebRTC dans 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 manière répétée via Ajax, mais cela entraîne de nombreuses requêtes réseau redondantes, ce qui est particulièrement problématique pour les appareils mobiles. Même après l'établissement d'une session, les pairs doivent interroger les messages de signalisation en cas de modifications ou de fin 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 l'échelle
Bien qu'un service de signalisation consomme relativement peu de bande passante et de processeur par client, les serveurs de signalisation d'une application populaire peuvent avoir à gérer de nombreux messages provenant de différents endroits avec des niveaux de concurrence élevés. Les applications WebRTC qui génèrent beaucoup de trafic ont besoin de serveurs de signalisation capables de gérer une charge considérable. Vous n'avez pas besoin d'entrer dans les détails ici, mais il existe plusieurs options pour la messagerie à haut volume et à hautes performances, y compris les suivantes :
Le protocole XMPP (eXtensible Messaging and Presence Protocol), initialement connu sous le nom de Jabber, est un protocole développé pour la messagerie instantanée qui peut être utilisé pour la signalisation (les implémentations de serveur incluent ejabberd et Openfire). Les clients JavaScript, tels que Strophe.js, utilisent BOSH pour émuler le streaming bidirectionnel, mais pour diverses raisons, BOSH peut ne pas être aussi efficace que WebSocket et, pour les mêmes raisons, peut ne pas évoluer correctement.) (Pour information, Jingle est une extension XMPP qui permet d'activer l'audio et la vidéo.) Le projet WebRTC utilise des composants réseau et de transport de la bibliothèque libjingle (une implémentation C++ de Jingle).
Bibliothèques Open Source, telles que ZeroMQ (utilisée par TokBox pour son service Rumour) et OpenMQ (NullMQ applique les concepts ZeroMQ aux plates-formes Web à l'aide du protocole STOMP sur WebSocket).
Plates-formes commerciales de messagerie cloud qui utilisent WebSocket (bien qu'elles puissent revenir à l'interrogation longue), 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 services et bibliothèques de messagerie.)
Créer un service de signalisation avec Socket.io sur Node
Vous trouverez ci-dessous le code d'une application Web simple qui utilise un service de signalisation créé avec Socket.io sur Node. La conception de Socket.io facilite la création d'un service d'échange de messages. Socket.io est particulièrement adapté à la signalisation WebRTC en raison de son concept de salles intégré. Cet exemple n'est pas conçu pour évoluer en tant que service de signalisation de qualité production, mais il est simple à comprendre pour un nombre relativement restreint d'utilisateurs.
Socket.io utilise WebSocket avec des solutions de secours : AJAX long polling, AJAX multipart streaming, Forever Iframe et JSONP polling. Il a été porté sur différents backends, mais il est peut-être mieux connu pour sa version Node utilisée dans cet exemple.
Cet exemple ne comporte pas de WebRTC. Il est conçu uniquement pour montrer comment intégrer la signalisation dans une application Web. Consultez le journal de la console pour voir ce qui se passe lorsque les clients rejoignent une salle et échangent des messages. Cet atelier de programmation WebRTC vous explique en détail comment intégrer cette fonctionnalité dans une application de chat vidéo WebRTC complète.
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 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 node-static pour cela. (mais elle est utilisée dans cet exemple).
Pour exécuter cette application sur localhost, vous devez avoir installé Node, Socket.IO et node-static. Node peut être téléchargé depuis Node.js (l'installation est simple et rapide). Pour installer Socket.IO et node-static, exécutez Node Package Manager à partir d'un terminal dans le 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 n'importe quel navigateur, puis ouvrez à nouveau localhost:2013
. Pour voir ce qui se passe, consultez la console. Dans Chrome et Opera, vous pouvez accéder à la console via les outils de développement Google Chrome avec Ctrl+Shift+J
(ou Command+Option+J
sur Mac).
Quelle que soit l'approche que vous choisissez pour la signalisation, votre backend et votre application cliente doivent au minimum fournir des services semblables à cet exemple.
Pièges liés à la signalisation
RTCPeerConnection
ne commencera à collecter des candidats que lorsquesetLocalDescription()
sera appelé. Cette opération est obligatoire dans le brouillon IETF JSEP.- Profitez de Trickle ICE. Appelez
addIceCandidate()
dès que les candidats arrivent.
Serveurs de signalisation prêts à l'emploi
Si vous ne souhaitez pas créer votre propre serveur de signalisation, plusieurs serveurs WebRTC sont disponibles. Ils utilisent Socket.IO comme dans l'exemple précédent et sont intégrés aux bibliothèques JavaScript du client WebRTC :
- webRTC.io est l'une des premières bibliothèques d'abstraction pour WebRTC.
- Signalmaster est un serveur de signalisation créé pour être utilisé avec la bibliothèque cliente JavaScript SimpleWebRTC.
Si vous ne souhaitez pas écrire de code, des plates-formes WebRTC commerciales complètes sont disponibles auprès d'entreprises telles que vLine, OpenTok et Asterisk.
Pour information, Ericsson a créé un serveur de signalisation à l'aide de PHP sur Apache au début de WebRTC. Ce code est désormais quelque peu obsolète, mais il vaut la peine de l'examiner si vous envisagez de faire quelque chose de similaire.
Sécurité de la signalisation
"La sécurité est l'art de ne rien laisser se produire."
Salman Rushdie
Le chiffrement est obligatoire pour tous les composants WebRTC.
Toutefois, les mécanismes de signalisation ne sont pas définis par les normes WebRTC. Vous devez donc sécuriser la signalisation vous-même. Si un pirate informatique parvient à détourner la signalisation, il peut arrêter des sessions, rediriger des connexions, et enregistrer, modifier ou injecter du contenu.
Le facteur le plus important pour sécuriser la signalisation est d'utiliser des protocoles sécurisés (HTTPS et WSS, par exemple TLS), qui garantissent que les messages ne peuvent pas être interceptés sans chiffrement. Veillez également à ne pas diffuser de messages de signalisation de manière à ce qu'ils soient accessibles par d'autres appelants utilisant le même serveur de signalisation.
Après la signalisation : utiliser ICE pour faire face aux NAT et aux pare-feu
Pour la signalisation des métadonnées, les applications WebRTC utilisent un serveur intermédiaire. Toutefois, pour le streaming de données et de contenus multimédias une fois la session établie, RTCPeerConnection
tente de connecter les clients directement ou en peer-to-peer.
Dans un monde plus simple, chaque point de terminaison WebRTC aurait une adresse unique qu'il pourrait échanger avec d'autres pairs pour communiquer directement.

En réalité, la plupart des appareils se trouvent derrière une ou plusieurs couches de NAT, certains disposent d'un logiciel antivirus qui bloque certains ports et protocoles, et beaucoup se trouvent derrière des proxys et des pare-feu d'entreprise. Un pare-feu et une passerelle NAT peuvent en fait être implémentés par le même appareil, comme un routeur Wi-Fi domestique.

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 du serveur ICE à RTCPeerConnection
, comme décrit dans cet article.
ICE essaie de trouver le meilleur chemin pour 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. Si cela échoue (ce qui sera le cas pour les appareils derrière des NAT), ICE obtient une adresse externe à l'aide d'un serveur STUN. Si cela échoue également, le trafic est acheminé via un serveur 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 si la connexion directe (peer-to-peer) échoue.
Chaque serveur TURN est compatible avec STUN. Un serveur TURN est un serveur STUN doté d'une fonctionnalité de relais intégrée supplémentaire. ICE gère également la complexité des configurations NAT. En réalité, le NAT hole-punching peut nécessiter plus qu'une simple adresse IP:port publique.
Les URL des serveurs STUN et/ou TURN sont (facultativement) spécifiées par une application WebRTC dans l'objet de configuration iceServers
, qui est 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 ces informations, la magie ICE opère automatiquement. RTCPeerConnection
utilise le framework ICE pour déterminer le meilleur chemin entre les pairs, en fonctionnant avec les serveurs STUN et TURN si nécessaire.
STUN
Les NAT fournissent à un appareil une adresse IP à utiliser dans un réseau local privé, mais cette adresse ne peut pas être utilisée en externe. Sans adresse publique, les pairs WebRTC ne peuvent pas communiquer. Pour contourner ce problème, WebRTC utilise STUN.
Les serveurs STUN sont hébergés sur Internet et ont une tâche simple : vérifier l'adresse IP:port d'une requête entrante (provenant d'une application exécutée derrière un NAT) et renvoyer cette adresse en réponse. En d'autres termes, l'application utilise un serveur STUN pour découvrir son adresse IP et son port d'un point de vue public. Ce processus permet à un pair WebRTC d'obtenir une adresse accessible au public et de la transmettre à un autre pair via un mécanisme de signalisation afin d'établir un lien direct. (En pratique, les différents NAT fonctionnent différemment et il peut y avoir plusieurs couches NAT, mais le principe reste le même.)
Les serveurs STUN n'ont pas besoin de faire beaucoup de choses ni de se souvenir de beaucoup d'informations. Des serveurs STUN relativement peu performants peuvent donc gérer un grand nombre de requêtes.
La plupart des appels WebRTC établissent une connexion à l'aide de STUN (86 % selon Webrtcstats.com), mais ce pourcentage peut être inférieur pour les appels entre pairs situés derrière des pare-feu et des configurations NAT complexes.

TURN
RTCPeerConnection
tente d'établir une communication directe entre les pairs via UDP. En cas d'échec, RTCPeerConnection
utilise TCP. En cas d'échec, les serveurs TURN peuvent être utilisés comme solution de secours, en relayant les données entre les points de terminaison.
Pour rappel, TURN est utilisé pour relayer le streaming audio, vidéo et de données entre pairs, et non les données de signalisation.
Les serveurs TURN disposent d'adresses publiques. Les pairs peuvent donc les contacter 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 beaucoup de bande passante. En d'autres termes, les serveurs TURN doivent être plus robustes.

Ce schéma montre TURN en action. Le STUN pur n'a pas fonctionné, donc chaque pair a recours à un serveur TURN.
Déployer des serveurs STUN et TURN
Pour les tests, Google exécute un serveur STUN public, stun.l.google.com:19302, tel qu'utilisé par appr.tc. Pour un service STUN/TURN de production, utilisez 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 sur l'installation des serveurs. Une image de VM pour Amazon Web Services est également disponible.
Un autre serveur TURN est restund, disponible en code source et également pour AWS. Voici comment configurer restund sur Compute Engine.
- Ouvrez le pare-feu si nécessaire pour tcp=443, udp/tcp=3478.
- Créez quatre instances, une pour chaque adresse IP publique, avec l'image Ubuntu 12.06 standard.
- Configurez le pare-feu local (autorisez TOUT depuis TOUT).
- Installez les outils :
shell sudo apt-get install make sudo apt-get install gcc
- Installez libre depuis creytiv.com/re.html.
- Récupérez restund depuis creytiv.com/restund.html et décompressez-le.
wget
hancke.name/restund-auth.patch et appliquez-le avecpatch -p1 < restund-auth.patch
.- Exécutez
make
,sudo make install
pour libre et restund. - 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
. - Copiez
restund/etc/restund
dans le répertoire/etc/init.d/
. - Configurer restund :
- Définissez
LD_LIBRARY_PATH
. - Copiez
restund.conf
dans le répertoire/etc/restund.conf
. - Définissez
restund.conf
sur 10 pour utiliser la bonne valeur. Adresse IP.
- Définissez
- Exécuter restund
- Testez à l'aide du client stund à partir d'une machine distante :
./client IP:port
Au-delà du face-à-face : WebRTC multiparty
Vous pouvez également consulter la norme IETF proposée par Justin Uberti pour une API REST permettant d'accéder aux services TURN.
Il est facile d'imaginer des cas d'utilisation pour le streaming multimédia qui vont au-delà d'un simple appel en tête-à-tête. Par exemple, une visioconférence entre un groupe de collègues ou un événement public avec un orateur et des centaines ou 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 dans une configuration maillée. C'est l'approche adoptée par des applications telles que talky.io, qui fonctionne remarquablement bien pour un petit nombre d'homologues. Au-delà, le traitement et la consommation de bande passante deviennent excessifs, en particulier pour les clients mobiles.

Une application WebRTC peut également choisir un point de terminaison pour distribuer les flux à tous les autres dans une configuration en étoile. Il serait également possible d'exécuter un point de terminaison WebRTC sur un serveur et de créer votre propre mécanisme de redistribution (une application cliente exemple est fournie par webrtc.org).
Depuis Chrome 31 et Opera 18, un MediaStream
provenant d'un RTCPeerConnection
peut être utilisé comme entrée pour un autre. Cela peut permettre des architectures plus flexibles, car une application Web peut gérer le routage des appels en choisissant à quel autre pair se connecter. Pour voir cela en action, consultez les exemples WebRTC : relais de connexion peer-to-peer et exemples WebRTC : connexions peer-to-peer multiples.
Multipoint Control Unit
Pour un grand nombre de points de terminaison, il est préférable d'utiliser une unité de contrôle multipoint (MCU, Multipoint Control Unit). Il s'agit d'un serveur qui sert de pont pour distribuer des contenus multimédias à un grand nombre de participants. Les MCU peuvent gérer différentes résolutions, différents codecs et différentes fréquences d'images lors d'une visioconférence. Ils peuvent également gérer le transcodage, le transfert sélectif de flux, et le mixage ou l'enregistrement audio et vidéo. Pour les appels à plusieurs participants, vous devez tenir compte de plusieurs problèmes, en particulier de la façon d'afficher plusieurs flux vidéo et de mixer l'audio de plusieurs sources. Les plates-formes cloud, telles que vLine, tentent également d'optimiser le routage du trafic.
Vous pouvez acheter un package matériel MCU complet ou créer le vôtre.

Plusieurs options logicielles MCU Open Source sont disponibles. Par exemple, Licode (anciennement Lynckia) produit une MCU Open Source pour WebRTC. OpenTok utilise Mantis.
Au-delà des navigateurs : VoIP, téléphones et messagerie
La nature standardisée de WebRTC permet d'établir une communication entre une application WebRTC exécutée dans un navigateur et un appareil ou une plate-forme exécutés 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 assurer la médiation de la signalisation. La signalisation doit transiter par la passerelle, mais une fois la communication établie, le trafic SRTP (vidéo et audio) peut transiter directement de pair à pair.
Le réseau téléphonique commuté public (RTCP) est le réseau à commutation de circuits de tous les téléphones analogiques "classiques". Pour les appels entre des applications Web WebRTC et des téléphones, le trafic doit transiter par une passerelle PSTN. 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 pour 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 utilisent la capacité de WebRTC à communiquer avec le monde extérieur :
- sipML5 : client SIP JavaScript Open Source
- jsSIP : bibliothèque JavaScript SIP
- Phono : API téléphonique JavaScript Open Source conçue comme un plug-in
- Zingaya : widget téléphonique intégrable
- Twilio : voix et messagerie
- Uberconference : visioconférence
Les développeurs sipML5 ont également créé la passerelle webrtc2sip. Tethr et Tropo ont présenté un framework de communication en cas de catastrophe "dans une mallette" à l'aide d'une cellule OpenBTS pour permettre la communication entre les téléphones classiques et les ordinateurs via WebRTC. Il s'agit d'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 signalisation Socket.io exécuté sur Node.
Présentation Google I/O WebRTC de 2013 avec Justin Uberti, responsable technique WebRTC
Présentation de Chris Wilson sur SFHTML5 : Introduction to WebRTC Apps
Le livre de 350 pages WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web fournit de nombreux détails sur les chemins de données et de signalisation, et inclut un certain nombre de schémas détaillés de topologie réseau.
WebRTC et la signalisation : ce que nous avons appris en deux ans, article de blog TokBox expliquant pourquoi il était judicieux de ne pas inclure la signalisation dans la spécification
A Practical Guide to Building WebRTC Apps de Ben Strong fournit de nombreuses informations sur les topologies et l'infrastructure WebRTC.
Le chapitre sur WebRTC dans High Performance Browser Networking d'Ilya Grigorik aborde en détail l'architecture, les cas d'utilisation et les performances de WebRTC.