Google is committed to advancing racial equity for Black communities. See how.
Cette page a été traduite par l'API Cloud Translation.
Switch to English

Premiers pas avec les connexions homologues

Les connexions homologues font partie des spécifications WebRTC qui traitent de la connexion de deux applications sur des ordinateurs différents pour communiquer à l'aide d'un protocole peer-to-peer. La communication entre pairs peut être vidéo, audio ou des données binaires arbitraires (pour les clients prenant en charge l'API RTCDataChannel ). Afin de découvrir comment deux pairs peuvent se connecter, les deux clients doivent fournir une configuration de serveur ICE. Il s'agit d'un serveur STUN ou TURN, et leur rôle est de fournir des candidats ICE à chaque client qui est ensuite transféré vers l'homologue distant. Ce transfert de candidats ICE est communément appelé signalisation.

Signalisation

La spécification WebRTC inclut des API pour communiquer avec un serveur ICE (Internet Connectivity Establishment), mais le composant de signalisation n'en fait pas partie. La signalisation est nécessaire pour que deux pairs puissent partager comment ils doivent se connecter. Habituellement, cela est résolu via une API Web HTTP standard (c'est-à-dire un service REST ou un autre mécanisme RPC) où les applications Web peuvent relayer les informations nécessaires avant que la connexion homologue ne soit initiée.

L'extrait de code suivant montre comment ce service de signalisation fictif peut être utilisé pour envoyer et recevoir des messages de manière asynchrone. Ceci sera utilisé dans les exemples restants de ce guide si nécessaire.

 // Set up an asynchronous communication channel that will be
// used during the peer connection setup
const signalingChannel = new SignalingChannel(remoteClientId);
signalingChannel.addEventListener('message', message => {
    // New message from remote client received
});

// Send an asynchronous message to the remote client
signalingChannel.send('Hello!');
 

La signalisation peut être implémentée de différentes manières et la spécification WebRTC ne préfère aucune solution spécifique.

Initier des connexions homologues

Chaque connexion homologue est gérée par un objet RTCPeerConnection . Le constructeur de cette classe prend un seul objet RTCConfiguration comme paramètre. Cet objet définit la configuration de la connexion homologue et doit contenir des informations sur les serveurs ICE à utiliser.

Une fois le RTCPeerConnection créé, nous devons créer une offre ou une réponse SDP, selon que nous sommes l'homologue appelant ou l'homologue récepteur. Une fois l'offre ou la réponse SDP créée, elle doit être envoyée au pair distant via un canal différent. La transmission d'objets SDP à des homologues distants est appelée signalisation et n'est pas couverte par la spécification WebRTC.

Pour lancer la configuration de la connexion homologue du côté appelant, nous créons un objet RTCPeerConnection , puis appelons createOffer() pour créer un objet RTCSessionDescription . Cette description de session est définie comme la description locale à l'aide de setLocalDescription() et est ensuite envoyée sur notre canal de signalisation vers le côté réception. Nous avons également mis en place un écouteur sur notre canal de signalisation pour le moment où une réponse à notre description de session proposée est reçue du côté récepteur.

 async function makeCall() {
    const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]}
    const peerConnection = new RTCPeerConnection(configuration);
    signalingChannel.addEventListener('message', async message => {
        if (message.answer) {
            const remoteDesc = new RTCSessionDescription(message.answer);
            await peerConnection.setRemoteDescription(remoteDesc);
        }
    });
    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);
    signalingChannel.send({'offer': offer});
}
 

Du côté de la réception, nous attendons une offre entrante avant de créer notre instance RTCPeerConnection . Une fois cela fait, nous définissons l'offre reçue à l'aide de setRemoteDescription() . Ensuite, nous appelons createAnswer() pour créer une réponse à l'offre reçue. Cette réponse est définie comme la description locale à l'aide de setLocalDescription() , puis envoyée au côté appelant via notre serveur de signalisation.

 const peerConnection = new RTCPeerConnection(configuration);
signalingChannel.addEventListener('message', async message => {
    if (message.offer) {
        peerConnection.setRemoteDescription(new RTCSessionDescription(message.offer));
        const answer = await peerConnection.createAnswer();
        await peerConnection.setLocalDescription(answer);
        signalingChannel.send({'answer': answer});
    }
});
 

Une fois que les deux homologues ont défini les descriptions de session locale et distante, ils connaissent les capacités de l'homologue distant. Cela ne signifie pas que la connexion entre les pairs est prête. Pour que cela fonctionne, nous devons collecter les candidats ICE à chaque pair et les transférer (sur le canal de signalisation) vers l'autre pair.

Candidats ICE

Avant que deux pairs puissent communiquer à l'aide de WebRTC, ils doivent échanger des informations de connectivité. Étant donné que les conditions du réseau peuvent varier en fonction d'un certain nombre de facteurs, un service externe est généralement utilisé pour découvrir les candidats possibles pour la connexion à un pair. Ce service s'appelle ICE et utilise un serveur STUN ou TURN. STUN signifie Session Traversal Utilities pour NAT et est généralement utilisé indirectement dans la plupart des applications WebRTC.

TURN (Traversal Using Relay NAT) est la solution la plus avancée qui intègre les protocoles STUN et la plupart des services commerciaux basés sur WebRTC utilisent un serveur TURN pour établir des connexions entre pairs. L'API WebRTC prend en charge directement STUN et TURN, et est regroupée sous le terme plus complet d'établissement de connectivité Internet. Lors de la création d'une connexion WebRTC, nous fournissons généralement un ou plusieurs serveurs ICE dans la configuration de l'objet RTCPeerConnection .

Trickle ICE

Une fois qu'un objet RTCPeerConnection est créé, l' RTCPeerConnection sous-jacente utilise les serveurs ICE fournis pour rassembler des candidats pour l'établissement de la connectivité (candidats ICE). L'événement icegatheringstatechange sur RTCPeerConnection signale dans quel état se trouve le rassemblement ICE ( new , gathering ou complete ).

Bien qu'il soit possible pour un homologue d'attendre la fin de la collecte ICE, il est généralement beaucoup plus efficace d'utiliser une technique de "goutte à goutte" et de transmettre chaque candidat ICE à l'homologue distant au fur et à mesure qu'il est découvert. Cela réduira considérablement le temps de configuration de la connectivité des pairs et permettra à un appel vidéo de démarrer avec moins de retards.

Pour rassembler les candidats ICE, il vous suffit d'ajouter un auditeur pour l'événement icecandidate - icecandidate . Le RTCPeerConnectionIceEvent émis sur cet écouteur contiendra la propriété candidate qui représente un nouveau candidat qui doit être envoyé à l'homologue distant (voir Signalisation).

 // Listen for local ICE candidates on the local RTCPeerConnection
peerConnection.addEventListener('icecandidate', event => {
    if (event.candidate) {
        signalingChannel.send({'new-ice-candidate': event.candidate});
    }
});

// Listen for remote ICE candidates and add them to the local RTCPeerConnection
signalingChannel.addEventListener('message', async message => {
    if (message.iceCandidate) {
        try {
            await peerConnection.addIceCandidate(message.iceCandidate);
        } catch (e) {
            console.error('Error adding received ice candidate', e);
        }
    }
});
 

Connection établie

Une fois les candidats ICE reçus, nous devrions nous attendre à ce que l'état de notre connexion homologue finisse par passer à un état connecté. Pour détecter cela, nous ajoutons un écouteur à notre RTCPeerConnection où nous écoutons connectionstatechange événements connectionstatechange .

 // Listen for connectionstatechange on the local RTCPeerConnection
peerConnection.addEventListener('connectionstatechange', event => {
    if (peerConnection.connectionState === 'connected') {
        // Peers connected!
    }
});
 

Documentation de l'API RTCPeerConnection