在PeerJS的浏览器中进行视频通话。 快速上手

我向哈勃的所有读者致以问候。 今年,我有机会为一个培训门户网站编写了一个视频通信模块,以便直接在教师和学生的网站上通过视频通信进行打电话。 没有必要解决这样的早期任务。 简短搜索后,我发现有两种方法:Flash和WebRTC 。 纯粹的WebRTC变得很复杂,并且通常很自然,因为视频通信的任务并不简单。 但是后来我遇到了PeerJS ,它是WebRTC的包装。 在本文中,我将告诉您如何快速组织浏览器拨号器。

为了重复该示例,将需要通过https协议访问您的测试页面(因为该页面将请求访问摄像头和麦克风,并且在没有安全协议的情况下,浏览器只会给出错误)

起始布局将如下所示:

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

在头部,我们远程连接PeerJS。 也可以下载脚本并将其本地连接。

输入id = otherPeerId-旨在输入我们将要呼叫的宴会(您可以将其作为索引或电话号码)。

两个视频标签分别用于显示您自己的视频和对话者的视频。

现在介绍一下WebRTC技术以及如何进行呼叫。 WebRTC直接在客户端之间进行呼叫,而无需服务器参与,因此第一步中,浏览器应该彼此找到对方。 为此,传统的WebRTC需要一个信号服务器,即,一个服务器告诉一个浏览器另一浏览器的参数,而在WebRTC中,您必须自己组织这样的服务器。 但是,PeerJS开发人员提供了自己的信号服务器。 您需要做的就是将peerID传递给潜在的对话者,即在PeerJS系统中接收到的唯一索引。 在工作草案中,我这样组织它:

  1. 加载页面后,将创建一个Peer对象
  2. 它的peerID写入mysql数据库
  3. 当按下“呼叫”按钮时,对话者的peerID被从数据库中拉出并用于建立连接

在当前测试用例中,我们将在otherPeerId文本字段中输入对话者的peerID

因此,让我们开始编写代码。

1.创建主要的对等对象

 var peer = new Peer(); 

2.在宴会开始时,我们将收到令人垂涎的peerID,必须将其转移给合作伙伴,以便他可以与我们联系

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

3.为了接听电话,我们挂断了电话事件的处理程序

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

有了来电,我们得到一个通话对象,该对象保存在peercall全局变量中。 此外,在信息栏中,还会显示有关来电的通知,并显示两个按钮:接受和拒绝

4.我们为“ 接受”按钮编写一个函数

 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-请求访问摄像头和麦克风。 因此,在传递给此方法的对象的数据中{audio:true,video:true},您可以仅请求访问摄像机或麦克风。 进一步的注释直接添加到代码中。

setTimeout是根据经验添加的:合作伙伴的视频未开始播放,但是可以超时。

5.按通话键拨号的功能

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

与上一段一样,我们要求您提供媒体流。 在调用对等对象的调用函数之后,它将调用对象返回给我们,并将其保存在peercall中。 我们处理流事件以找出答案,并将传入流放入相应的视频对象中

仅此而已...

如果两个呼叫者都位于NATth后面,则呼叫不会通过。 (为什么?请在此处阅读habr.com/en/company/yandex/blog/419951
为了克服这一障碍,在创建对等对象时必须指定TURN服务器(在何处获取它不是最简单的问题。我们必须提出自己的问题:在Ubuntu 16.04上使用VPS。使用命令安装
 apt install coturn 


然后,宴会的创建将如下所示:

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

最后,整个代码:

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

此解决方案已在Windows7和Ubuntu 18.04的Chrome,Opera,Firefox中成功测试。 Chrome也可以在Android和MacOS上运行,但不能在iPhone和iPad上运行。

Source: https://habr.com/ru/post/zh-CN468705/


All Articles