Appel vidéo dans le navigateur sur PeerJS. Démarrage rapide

Je salue tous les lecteurs de Habr. Cette annĂ©e, j’ai eu l’occasion d’écrire un module de communication vidĂ©o pour un portail de formation pour tĂ©lĂ©phoner via la communication vidĂ©o directement sur le site Web de l’enseignant et de l’élĂšve. Il n'Ă©tait pas nĂ©cessaire de rĂ©soudre une tĂąche aussi prĂ©coce. AprĂšs une courte recherche, j'ai dĂ©couvert qu'il y avait 2 façons: Flash et WebRTC . Le WebRTC dans sa forme pure s'est avĂ©rĂ© compliquĂ©, et en gĂ©nĂ©ral, il est naturel, car la tĂąche de la communication vidĂ©o n'est pas simple. Mais ensuite, je suis tombĂ© sur PeerJS , qui est un wrapper pour WebRTC. Dans cet article, je vais vous expliquer comment organiser rapidement votre numĂ©roteur de navigateur.

Afin de répéter l'exemple, l'accÚs à votre page de test via le protocole https sera nécessaire (puisque la page demandera l'accÚs à la caméra et au microphone, et sans protocole sécurisé le navigateur donnera simplement une erreur)

La disposition de départ ressemblera à ceci:

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Peer</title> <script src="https://unpkg.com/peerjs@1.0.0/dist/peerjs.min.js"></script> </head> <body> <p><h3> ID: </h3><span id=myid ></span></p> <input id=otherPeerId type=text placeholder="otherPeerId" > <button onclick="callToNode(document.getElementById('otherPeerId').value)"></button> <br> <video id=myVideo muted="muted" width="400px" height="auto" ></video> <div id=callinfo ></div> <video id=remVideo width="400px" height="auto" ></video> </body> 

Dans la section tĂȘte, nous connectons PeerJS Ă  distance. Il est Ă©galement possible de tĂ©lĂ©charger le script et de le connecter localement.

input id = otherPeerId - conçu pour entrer dans la fĂȘte de celui que nous appellerons (vous pouvez le prendre comme index ou comme numĂ©ro de tĂ©lĂ©phone).

Deux balises vidéo sont conçues pour afficher votre propre vidéo et pour la vidéo de l'interlocuteur, respectivement.

Maintenant, un peu sur la technologie WebRTC et la façon dont l'appel est effectuĂ©. WebRTC effectue un appel de client Ă  client directement, sans implication du serveur, donc dans la premiĂšre Ă©tape 2 les navigateurs devraient se trouver. Pour ce faire, un WebRTC classique nĂ©cessite un serveur de signaux, c'est-Ă -dire un serveur qui indique Ă  un navigateur les paramĂštres d'un autre navigateur, et dans WebRTC, vous devez organiser vous-mĂȘme un tel serveur. Cependant, les dĂ©veloppeurs PeerJS fournissent leur propre serveur de signaux. Tout ce que vous devez faire est de passer le peerID Ă  l'interlocuteur potentiel, c'est-Ă -dire l'index unique reçu dans le systĂšme PeerJS. Dans un projet de travail, je l'ai organisĂ© comme ceci:

  1. AprÚs le chargement de la page, un objet Peer est créé
  2. Son peerID est écrit dans la base de données mysql
  3. Lorsque le bouton d'appel est enfoncé, l'ID pair de l'interlocuteur est retiré de la base de données et utilisé pour établir une connexion

Dans le cas de test actuel, nous entrerons le peerID de l'interlocuteur dans le champ de texte otherPeerId

Commençons donc à écrire du code.

1. Créez l'objet homologue principal

 var peer = new Peer(); 

2. A l'ouverture de la fĂȘte, nous recevrons le peerID convoitĂ©, qui devra ĂȘtre transfĂ©rĂ© au partenaire afin qu'il puisse nous contacter

 peer.on('open', function(peerID) { document.getElementById('myid').innerHTML=peerID; }); 

3. Pour recevoir un appel, nous raccrochons le gestionnaire de l'événement d'appel

 var peercall; peer.on('call', function(call) { // Answer the call, providing our mediaStream peercall=call; document.getElementById('callinfo').innerHTML="  <button onclick='callanswer()' ></button><button onclick='callcancel()' ></button>"; }); 

Avec un appel entrant, nous obtenons un objet d' appel , que nous enregistrons dans la variable globale peercall . Toujours dans le bloc d'informations, une notification concernant un appel entrant et 2 boutons seront affichés: Accepter et rejeter

4. Nous Ă©crivons une fonction pour le bouton Accepter

 function callanswer() { navigator.mediaDevices.getUserMedia ({ audio: true, video: true }).then(function(mediaStream) { var video = document.getElementById('myVideo'); peercall.answer(mediaStream); //         //peercall.on ('close', onCallClose); //  -  video.srcObject = mediaStream; //      (  ) document.getElementById('callinfo').innerHTML=" ... <button onclick='callclose()' > </button>"; //,   ,     video.onloadedmetadata = function(e) {// ,    video.play(); }; setTimeout(function() { //        document.getElementById('remVideo').srcObject = peercall.remoteStream; document.getElementById('remVideo').onloadedmetadata= function(e) { //       document.getElementById('remVideo').play(); }; },1500); }).catch(function(err) { console.log(err.name + ": " + err.message); }); } 

navigator.mediaDevices.getUserMedia - demande l'accÚs à la caméra et au microphone. Dans les données de l'objet transmis à cette méthode {audio: true, video: true}, vous pouvez donc demander l'accÚs uniquement à la caméra ou uniquement au microphone. D'autres commentaires ont été ajoutés directement au code.

setTimeout a été ajouté de maniÚre empirique: la vidéo du partenaire n'a pas commencé à jouer, mais cela a fonctionné avec un timeout.

5. La fonction de numérotation par le bouton d' appel

 function callToNode(peerId) { // navigator.mediaDevices.getUserMedia ({ audio: true, video: true }).then(function(mediaStream) { var video = document.getElementById('myVideo'); peercall = peer.call(peerId,mediaStream); //,  peerId-    mediaStream peercall.on('stream', function (stream) { // ,   setTimeout(function() { document.getElementById('remVideo').srcObject = peercall.remoteStream; document.getElementById('remVideo').onloadedmetadata= function(e) { document.getElementById('remVideo').play(); }; },1500); }); // peercall.on('close', onCallClose); video.srcObject = mediaStream; video.onloadedmetadata = function(e) { video.play(); }; }).catch(function(err) { console.log(err.name + ": " + err.message); }); } 

Comme dans le paragraphe précédent, nous demandons votre flux multimédia. AprÚs avoir appelé la fonction d'appel de l'objet homologue, qui nous renverra l'objet d'appel, enregistrez-le dans peercall. Nous traitons l'événement de flux pour savoir ce qu'ils ont répondu et mettons le flux entrant dans l'objet vidéo correspondant

C'est tout, mais ...

Si les deux appelants sont derriĂšre l'appel NAT ne passera pas. (Pourquoi? Lisez ici habr.com/en/company/yandex/blog/419951 )
Afin de surmonter cet obstacle, il est nĂ©cessaire de spĂ©cifier le serveur TURN lors de la crĂ©ation de l'objet homologue (La question de savoir oĂč l'obtenir n'Ă©tait pas la plus simple. Nous avons dĂ» Ă©lever notre propre: VPS sur Ubuntu 16.04. Installation avec la commande
 apt install coturn 
)

Ensuite, la crĂ©ation de la fĂȘte ressemblera Ă  ceci:

 var callOptions={'iceServers': [ {url: 'stun:95.xxx.xx.x9:3479', username: "user", credential: "xxxxxxxxxx"}, { url: "turn:95.xxx.xx.x9:3478", username: "user", credential: "xxxxxxxx"}] }; peer= new Peer({config: callOptions}); 

Enfin, tout le code:

 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Peer</title> <script src="https://unpkg.com/peerjs@1.0.0/dist/peerjs.min.js"></script> </head> <body> <p><h3> ID: </h3><span id=myid ></span></p> <input id=otherPeerId type=text placeholder="otherPeerId" > <button onclick="callToNode(document.getElementById('otherPeerId').value)"></button> <br> <video id=myVideo muted="muted" width="400px" height="auto" ></video> <div id=callinfo ></div> <video id=remVideo width="400px" height="auto" ></video> <script> var callOptions={'iceServers': [ {url: 'stun:95.xxx.xx.x9:3479', username: "user", credential: "xxxxxxxxxx"}, { url: "turn:95.xxx.xx.x9:3478", username: "user", credential: "xxxxxxxx"}] }; peer= new Peer({config: callOptions}); peer.on('open', function(peerID) { document.getElementById('myid').innerHTML=peerID; }); var peercall; peer.on('call', function(call) { // Answer the call, providing our mediaStream peercall=call; document.getElementById('callinfo').innerHTML="  <button onclick='callanswer()' ></button><button onclick='callcancel()' ></button>"; }); function callanswer() { navigator.mediaDevices.getUserMedia ({ audio: true, video: true }).then(function(mediaStream) { var video = document.getElementById('myVideo'); peercall.answer(mediaStream); //         //peercall.on ('close', onCallClose); //  -  video.srcObject = mediaStream; //      (  ) document.getElementById('callinfo').innerHTML=" ... <button onclick='callclose()' > </button>"; //,   ,     video.onloadedmetadata = function(e) {// ,    video.play(); }; setTimeout(function() { //        document.getElementById('remVideo').srcObject = peercall.remoteStream; document.getElementById('remVideo').onloadedmetadata= function(e) { //       document.getElementById('remVideo').play(); }; },1500); }).catch(function(err) { console.log(err.name + ": " + err.message); }); } function callToNode(peerId) { // navigator.mediaDevices.getUserMedia ({ audio: true, video: true }).then(function(mediaStream) { var video = document.getElementById('myVideo'); peercall = peer.call(peerId,mediaStream); peercall.on('stream', function (stream) { // ,   setTimeout(function() { document.getElementById('remVideo').srcObject = peercall.remoteStream; document.getElementById('remVideo').onloadedmetadata= function(e) { document.getElementById('remVideo').play(); }; },1500); }); // peercall.on('close', onCallClose); video.srcObject = mediaStream; video.onloadedmetadata = function(e) { video.play(); }; }).catch(function(err) { console.log(err.name + ": " + err.message); }); } </script> </body> 

Cette solution a été testée avec succÚs sous Windows7 et Ubuntu 18.04 dans Chrome, Opera, Firefox. Chrome fonctionne également sur Android et MacOS, mais il ne fonctionne pas sur iPhone et iPad.

Source: https://habr.com/ru/post/fr468705/


All Articles