Videoanruf im Browser auf PeerJS. Schnellstart

Ich grüße alle Leser von Habr. In diesem Jahr hatte ich die Möglichkeit, ein Videokommunikationsmodul für ein Schulungsportal zum Telefonieren per Videokommunikation direkt auf der Website von Lehrern und Schülern zu schreiben. Es war nicht notwendig, eine so frühe Aufgabe zu lösen. Nach einer kurzen Suche stellte ich fest, dass es zwei Möglichkeiten gibt: Flash und WebRTC . WebRTC in seiner reinen Form erwies sich als kompliziert, und im Allgemeinen ist es natürlich, da die Aufgabe der Videokommunikation nicht einfach ist. Aber dann bin ich auf PeerJS gestoßen , einen Wrapper für WebRTC. In diesem Artikel werde ich Ihnen erklären, wie Sie Ihren Browser-Dialer schnell organisieren können.

Um das Beispiel zu wiederholen, ist der Zugriff auf Ihre Testseite über das https-Protokoll erforderlich (da die Seite den Zugriff auf die Kamera und das Mikrofon anfordert und der Browser ohne ein sicheres Protokoll einfach einen Fehler ausgibt).

Das Startlayout sieht folgendermaßen aus:

<!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> 

Im Kopfbereich verbinden wir PeerJS remote. Es ist auch möglich, das Skript herunterzuladen und lokal zu verbinden.

input id = otherPeerId - dient zur Eingabe des Festes desjenigen, den wir anrufen werden (Sie können es als Index oder als Telefonnummer verwenden).

Zwei Video-Tags dienen zur Anzeige Ihres eigenen Videos bzw. des Videos des Gesprächspartners.

Nun ein wenig über die WebRTC-Technologie und wie der Anruf getätigt wird. WebRTC ruft ohne Beteiligung des Servers direkt von Client zu Client an. Im ersten Schritt sollten sich also 2 Browser gegenseitig finden. Dazu benötigt ein klassisches WebRTC einen Signalserver, dh einen Server, der einem Browser die Parameter eines anderen Browsers mitteilt, und in WebRTC müssen Sie einen solchen Server selbst organisieren. PeerJS-Entwickler stellen jedoch ihren eigenen Signalserver zur Verfügung. Sie müssen lediglich die Peer-ID an den potenziellen Gesprächspartner übergeben, dh an den eindeutigen Index, der im PeerJS-System empfangen wird. In einem Arbeitsentwurf habe ich es so organisiert:

  1. Nach dem Laden der Seite wird ein Peer-Objekt erstellt
  2. Die Peer-ID wird in die MySQL-Datenbank geschrieben
  3. Wenn die Anruftaste gedrückt wird, wird die Peer-ID des Gesprächspartners aus der Datenbank gezogen und zum Herstellen einer Verbindung verwendet

Im aktuellen Testfall geben wir die Peer-ID des Gesprächspartners in das Textfeld otherPeerId ein

Beginnen wir also mit dem Schreiben von Code.

1. Erstellen Sie das Haupt-Peer-Objekt

 var peer = new Peer(); 

2. Zur Eröffnung des Festes erhalten wir die begehrte PeerID, die an den Partner übertragen werden muss, damit er uns kontaktieren kann

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

3. Um einen Anruf zu erhalten, legen wir den Handler für das Anrufereignis auf

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

Bei einem eingehenden Anruf erhalten wir ein Aufrufobjekt , das wir in der globalen Variablen peercall speichern. Außerdem werden im Informationsblock eine Benachrichtigung über einen eingehenden Anruf und zwei Schaltflächen angezeigt: Akzeptieren und Ablehnen

4. Wir schreiben eine Funktion für die Schaltfläche Akzeptieren

 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 - fordert den Zugriff auf Kamera und Mikrofon an. In den Daten des Objekts, das an diese Methode übergeben wird (Audio: true, Video: true), können Sie dementsprechend nur den Zugriff auf die Kamera oder nur auf das Mikrofon anfordern. Weitere Kommentare direkt zum Code hinzugefügt.

setTimeout wurde empirisch hinzugefügt: Das Video des Partners wurde nicht abgespielt, es funktionierte jedoch mit einer Zeitüberschreitung.

5. Die Funktion des Wählens mit der Anruftaste

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

Wie im vorherigen Absatz fordern wir Ihren Medienstrom an. Nachdem wir die Aufruffunktion des Peer-Objekts aufgerufen haben, die das Aufrufobjekt an uns zurückgibt, speichern Sie es in Peercall. Wir verarbeiten das Stream-Ereignis, um herauszufinden, was sie beantwortet haben, und fügen den eingehenden Stream in das entsprechende Videoobjekt ein

Das ist alles, aber ...

Wenn sich beide Anrufer hinter dem NATth befinden, wird der Anruf nicht durchgestellt. (Warum? Lesen Sie hier habr.com/de/company/yandex/blog/419951 )
Um dieses Hindernis zu überwinden, muss beim Erstellen des Peer-Objekts der TURN-Server angegeben werden (Die Frage, wo es erhältlich ist, war nicht die einfachste. Wir mussten unser eigenes VPS unter Ubuntu 16.04 auslösen. Installation mit dem Befehl
 apt install coturn 
)

Dann wird die Schaffung des Festes ungefähr so ​​aussehen:

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

Endlich der gesamte 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> 

Diese Lösung wurde erfolgreich unter Windows 7 und Ubuntu 18.04 in Chrome, Opera, Firefox getestet. Chrome funktioniert auch unter Android und MacOS, jedoch nicht unter iPhone und iPad.

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


All Articles