Publié le 4 novembre 2013
WebRTC permet la communication peer-to-peer. Il nécessite des serveurs pour que les clients puissent échanger des métadonnées et coordonner la communication via un processus appelé signalisation. Les serveurs aident également les clients à gérer les traducteurs d'adresse réseau (NAT) et les pare-feu.
Ici, vous allez apprendre à créer un service de signalisation et à gérer les particularités de la connectivité réelle avec les serveurs STUN et TURN. Vous découvrirez également comment les applications WebRTC peuvent gérer les appels multipartites et interagir avec des services tels que la VoIP et le RTC (également appelés téléphones).
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, telles qu'elles sont vues par le monde extérieur
Ce processus de signalisation nécessite un moyen pour les clients de s'échanger des messages. Ce mécanisme n'est pas implémenté par les API WebRTC. Vous devez donc le créer vous-même.
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 par le protocole JSEP (JavaScript Session Establishment Protocol) :
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 actualisation de la page. À la place, l'état de signalisation peut être enregistré sur un serveur.
JSEP nécessite l'échange entre pairs de l'offre et de la réponse, les métadonnées multimédias. 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 signifie tout ce jargon SDP ? Consultez les exemples de l'IETF (Internet Engineering Task Force).
N'oubliez pas que WebRTC est conçu de manière à ce 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 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. Le SDP est quelque peu difficile à manipuler avec JavaScript, et des discussions sont en cours pour déterminer si les futures versions de WebRTC devraient plutôt utiliser JSON. Toutefois, l'utilisation du SDP présente certains avantages.
RTCPeerConnection API et signalisation : offre, réponse et candidat
RTCPeerConnection est l'API utilisée par les applications WebRTC pour créer une connexion entre pairs, et communiquer du contenu audio et vidéo.
Pour initialiser ce processus, RTCPeerConnection doit effectuer deux tâches :
- Déterminez les conditions multimédias locales, telles que les capacités de résolution et de codec. Il s'agit des métadonnées utilisées pour le mécanisme d'offre et de réponse.
- Obtenir les adresses réseau potentielles de l'hôte de l'application, appelées candidates.
Une fois ces données locales déterminées, elles doivent être échangées avec le pair distant via un mécanisme de signalisation.
Imaginez qu'Alice essaie d'appeler Eve. Voici le mécanisme de réponse complet 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
RTCPeerConnectioncreateOffer(). - Alice appelle
setLocalDescription()avec son offre. - Alice convertit l'offre en chaîne et utilise un mécanisme de signalement pour l'envoyer à Eve.
- Eve appelle
setRemoteDescription()avec l'offre d'Alice, afin que sonRTCPeerConnectionconnaisse la configuration d'Alice. - Eve appelle
createAnswer(), et le rappel de réussite de cette opération 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'Eve comme description de session distante à l'aide de
setRemoteDescription().
Alice et Eve doivent également échanger des informations réseau. L'expression "recherche de candidats" fait référence au processus de recherche d'interfaces réseau et de ports à l'aide du framework ICE.
- Alice crée un objet
RTCPeerConnectionavec un gestionnaireonicecandidate. - Le gestionnaire est appelé lorsque des candidats réseau deviennent disponibles.
- Dans le gestionnaire, Alice envoie les données de candidat converties en chaîne à Eve via leur canal de signalement.
- Quand Eve 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 fournir progressivement des candidats à l'appelé après l'offre initiale, et à l'appelé de commencer à agir sur l'appel et d'é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 signalement. Le code suppose l'existence d'un mécanisme de signalement, SignalingChannel. La signalisation est abordée plus en détail plus loin.
// 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'offre-réponse et d'échange de candidats en action, consultez simpl.info RTCPeerConnection et examinez le journal de la console pour un exemple de chat vidéo sur une seule page. Vous pouvez télécharger un dump complet de la signalisation et des statistiques WebRTC à partir de la page about://webrtc-internals dans Google Chrome ou de la page opera://webrtc-internals dans Opera.
Découverte de pairs
C'est 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 le chat vidéo et la messagerie en ligne, vous avez besoin de systèmes de gestion des identités et de la présence, ainsi que d'un moyen permettant aux utilisateurs de lancer des sessions. Les applications WebRTC ont besoin d'un moyen pour que les clients puissent se signaler mutuellement qu'ils souhaitent démarrer ou rejoindre un appel.
Les mécanismes de découverte de pairs ne sont pas définis par WebRTC, et nous n'aborderons pas les options ici. Le processus peut être aussi simple que l'envoi d'une URL par e-mail ou par message. 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 d'un appel WebRTC d'échanger des métadonnées via n'importe quel service de messagerie de leur choix, comme la messagerie instantanée, l'e-mail ou un 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. Quelle que soit l'option choisie, 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 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 des tests avec appr.tc pour une session de chat vidéo, le service de signalisation a traité un total d'environ 30 à 45 messages, pour une taille totale d'environ 10 Ko.
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 ou 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, telles que les clients connectés.
Envoyer des messages du serveur au client
Un service de messagerie pour la signalisation doit être bidirectionnel : client-serveur et serveur-client. La communication bidirectionnelle va à l'encontre du modèle de requête/réponse client/serveur HTTP, mais diverses solutions telles que l'interrogation longue 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.
L'API EventSource active les événements envoyés par le serveur, c'est-à-dire les 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 signalement transmet un message d'un appelant, envoyé par une requête XHR, en le transmettant via EventSource au destinataire.
WebSocket est conçu pour la communication client-serveur en duplex intégral, ce qui signifie que les messages peuvent circuler dans les deux sens en même temps. L'un des avantages d'un service de signalement créé avec des événements WebSocket purs 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 compatibles avec WebRTC sont également compatibles avec WebSocket. 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 de 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 de l'ouvrage High Performance Browser Networking d'Ilya Grigorik.
Vous pouvez 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 d'arrêt de la session par d'autres pairs. L'exemple d'application WebRTC Book utilise cette option avec certaines optimisations de la fréquence d'interrogation.
Signalement de scaling
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 emplacements avec des niveaux de simultanéité élevés. Les applications WebRTC qui reçoivent beaucoup de trafic ont besoin de serveurs de signalisation capables de gérer une charge considérable. Nous n'entrerons pas dans les détails ici, mais il existe un certain nombre d'options pour la messagerie à volume élevé et hautes performances, y compris les suivantes :
eXtensible Messaging and Presence Protocol (XMPP) 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 BOSH peut être inefficace et difficilement évolutif par rapport à WebSocket.
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).
Les plates-formes commerciales de messagerie cloud qui utilisent WebSocket (bien qu'elles puissent revenir à l'interrogation longue), telles que Pusher et Kaazing.
Plates-formes WebRTC commerciales, telles que vLine
Créer un service de signalisation avec Socket.io sur Node
Voici le code d'une application Web 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 intégré de salons. Cet exemple est conçu pour un nombre relativement restreint d'utilisateurs, plutôt que pour une utilisation en production.
Socket.io utilise WebSocket avec des solutions de remplacement : interrogation longue AJAX, streaming multipart AJAX, Forever Iframe et interrogation JSONP. Il a été porté sur différents backends, mais il est peut-être plus connu pour sa version Node utilisée dans cet exemple.
Il n'y a pas de WebRTC dans cet exemple. Il est conçu 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 fournit des instructions détaillées pour 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 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);
});
});
Pour exécuter cette application sur localhost, vous devez disposer de Node.js, de Socket.IO et de node-static. Pour installer Socket.IO et node-static, exécutez npm depuis 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 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 la signalisation, votre backend et votre application cliente doivent fournir des services similaires à ceux de cet exemple.
Points de vigilance concernant les signaux
RTCPeerConnectionne commencera pas à collecter des candidats tant quesetLocalDescription()n'aura pas été appelé. Cette exigence est définie dans le projet de norme JSEP de l'IETF.- 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 le vôtre, plusieurs serveurs de signalisation 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, des plates-formes WebRTC commerciales complètes sont disponibles auprès d'entreprises telles que vLine, OpenTok et Asterisk.
Pour mémoire, Ericsson a créé un serveur de signalisation utilisant PHP sur Apache au début de WebRTC. Cette solution est désormais quelque peu obsolète, mais il est utile d'examiner le code si vous envisagez une approche similaire.
Sécurité du signal
Le chiffrement est obligatoire pour tous les composants WebRTC.
Toutefois, les mécanismes de signalisation ne sont pas définis par les normes WebRTC. Il vous appartient donc de sécuriser la signalisation. 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, tels que TLS. Cela permet de s'assurer que les messages ne peuvent pas être interceptés sans chiffrement. Veillez également à ne pas diffuser les messages de signalisation de manière à ce que d'autres appelants puissent y accéder en utilisant le même serveur de signalisation.
Gérer les NAT et les pare-feu
Pour la signalisation des métadonnées, les applications WebRTC utilisent un serveur intermédiaire. En revanche, pour le streaming de contenus multimédias et de données une fois qu'une session est é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 un 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 de la mise en réseau réelle. Pour ce faire, votre application doit transmettre les URL du serveur ICE à RTCPeerConnection.
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 qui fonctionne. ICE tente d'abord d'établir une connexion à l'aide de l'adresse de l'hôte obtenue à partir du système d'exploitation et de la carte réseau d'un appareil. En cas d'échec (ce qui se produit pour les appareils derrière 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 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 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 les complexités 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 TURN sont (éventuellement) 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 d'ICE opère automatiquement. RTCPeerConnection utilise le framework ICE pour déterminer le meilleur chemin entre les pairs, en utilisant des serveurs STUN et TURN si nécessaire.
STUN
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 ne peuvent pas communiquer. Pour contourner ce problème, WebRTC utilise STUN.
Les serveurs STUN se trouvent sur l'Internet public et n'ont qu'une seule tâche : 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 publiquement, puis de la transmettre à un autre pair via un mécanisme de signalement afin de configurer un lien direct.
Les serveurs STUN n'ont pas besoin d'effectuer beaucoup d'opérations ni de mémoriser beaucoup d'informations. Par conséquent, des serveurs STUN aux spécifications relativement faibles peuvent gérer un grand nombre de requêtes.
La plupart des appels WebRTC établissent une connexion à l'aide de STUN, bien que cela puisse être moins fréquent pour les appels entre pairs derrière des pare-feu et des configurations NAT complexes.
TURN
RTCPeerConnection tente d'établir une communication directe entre pairs via UDP.
Si cela échoue, 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 les flux audio, vidéo et de données entre pairs, et non les données de signalisation.
Les serveurs TURN ont des adresses publiques. Ils peuvent donc être contactés par des pairs, même si ceux-ci se trouvent derrière des pare-feu ou des proxys. Les serveurs TURN n'ont qu'une seule tâche : relayer un flux. Contrairement aux serveurs STUN, ils consomment intrinsèquement beaucoup de bande passante.
Ce schéma montre le fonctionnement de TURN. Le protocole STUN pur n'a pas fonctionné. Chaque pair utilise donc 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.
Le serveur TURN restund est une alternative. Il est disponible sous forme de code source et également pour AWS. Vous pouvez configurer un serveur restund sur Compute :
- 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 sur creytiv.com/restund.html et décompressez-le.
wgethancke.name/restund-auth.patch et appliquez-le avecpatch -p1 < restund-auth.patch.- Exécutez
make,sudo make installpour libre et restund. - Adaptez
restund.confà vos besoins (remplacez les adresses IP et assurez-vous qu'il contient le même secret partagé), puis copiez-le dans/etc. - Copiez
restund/etc/restunddans le répertoire/etc/init.d/. - Configurez restund :
- Définissez
LD_LIBRARY_PATH. - Copiez
restund.confdans le répertoire/etc/restund.conf. - Définissez
restund.confsur "right 10". avec une adresse IP externe.
- Définissez
- Exécuter restund
- Testez à l'aide du client stund depuis une machine distante :
./client IP:port
WebRTC multipartite
Vous pouvez également consulter la norme IETF proposée par Justin Uberti pour une API REST permettant d'accéder aux services TURN.
Il existe de nombreux cas d'utilisation du streaming multimédia qui vont au-delà d'un appel individuel. Par exemple, une visioconférence entre un groupe de collègues ou un événement public avec un intervenant 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 de pairs. Au-delà, la consommation de bande passante et de traitement devient excessive, en particulier pour les clients mobiles.
Une application WebRTC peut également choisir un point de terminaison pour distribuer des 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).
Un MediaStream d'un RTCPeerConnection peut être utilisé comme entrée pour un autre. Cela permet d'obtenir des architectures plus flexibles, car une application Web peut gérer le routage des appels en choisissant l'autre pair auquel se connecter. Pour voir cela en action, consultez Exemples WebRTC : relais de connexion pair à pair et Exemples WebRTC : connexions pair à pair 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 qui sert de pont 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 dans une visioconférence, gérer le transcodage, effectuer un transfert de flux sélectif, et mixer ou enregistrer l'audio et la vidéo. Pour les appels multipartites, plusieurs problèmes doivent être pris en compte, en particulier l'affichage de plusieurs entrées vidéo et le mixage 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 de logiciels MCU Open Source sont disponibles. Par exemple, Licode (anciennement Lynckia) produit un MCU Open Source pour WebRTC. OpenTok dispose de 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ée sur une autre plate-forme de communication, telle qu'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 passer par la passerelle, mais une fois la communication établie, le trafic SRTP (vidéo et audio) peut circuler en peer-to-peer.
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 les applications Web WebRTC et les téléphones, le trafic doit passer 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 permettre la transmission de la voix et de 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. Exemple :
- jsSIP : bibliothèque SIP JavaScript
- Phono : API de téléphonie JavaScript Open Source conçue comme un plug-in
- Twilio : voix et messagerie
En savoir plus
- Consultez la documentation de l'API WebRTC.
- 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 SFHTML5 de Chris Wilson : Introduction to WebRTC Apps (Introduction aux applications WebRTC)
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 diagrammes détaillés de topologie de réseau.