本文概述
- 继续之前
- 内容指南
- 1.创建或获取一些SSL证书
- 2.示范项目结构
- 3.设置测试本地服务器
- 4.设置PeerJS服务器
- 5.设置客户端代码
- 6.允许Node.js的入站连接(仅在本地工作)
- 7.运行聊天
在本文中, 你将学习如何使用自己的托管的带有Node.js的PeerJS服务器实现Videochat。
继续之前 你将需要耐心等待, 因为如果你没有正确配置所有功能, 那么初次尝试可能无法按预期进行。因此, 要坚持不懈, 请仔细阅读所有说明, 你可能会在第一次广告上获得成功。
如果你认为本教程很长, 我们建议你在Github的此存储库中克隆正式示例, 其中包含在本文中可以找到的所有示例代码, 但是没有任何解释。不过, 自己进行测试很有用。
内容指南 本教程将是无穷无尽的, 因此, 这里是你需要遵循的所有步骤的快速介绍:
- 获取一些自动签名的SSL证书进行测试。
- 创建演示项目结构
- 使用Express创建一个安全的本地服务器以提供我们的HTML, CSS和JS文件。
- 创建一个安全的PeerJS服务器来处理信息交换。
- 编写代码以处理视频聊天。
- 了解PeerJS的工作原理。
- 创建标记以创建示例聊天。
- 允许Node.js的入站连接并更新客户端主机(仅在本地测试时)
- 运行服务器并测试
另外, 你可以在此处从Github的示例存储库中下载自签名证书, 并在自己的实现中使用它们。
2.示范项目结构 要创建基本的视频聊天, 我们需要HTML项目和JavaScript的基本结构:
注意 所有文件(证书和peer.min.js除外)都应该为空, 因为稍后我们将告诉你在每个文件中写入什么内容。
YourProjectFolder├───certificates├── cert.pem└── key.pem├───public├── index.html├── website-server.js├── source│└── js|├── peer.min.js│└── scripts.js└── package.json├───server├── peer-server.js└── package.json
在测试文件夹中, 你将需要3个文件夹, 即证书, 公共和服务器。在证书文件上, 你将需要存储必需的文件, 以使服务器在HTTPS中运行(请参阅步骤1)。在公用文件夹上, 你将找到索引文件, 该文件允许用户与其他人聊天并执行视频通话, 除了源代码内的脚本是客户端peer.js的源代码以及将要编写的scripts.js在第5步。
请记住, 结构不必相同, 仅是示例, 但是代码中文件的路径将遵循此模式, 因此, 如果你更改结构, 请注意也要在代码中进行更改。
3.设置测试本地服务器 对于我们的示例, 我们将使https:// localhost:8443上的简单html文件(index.html)可访问。要创建我们的服务器, 我们将使用express模块??, 因此打开一个终端, 切换到project / public目录, 并至少使用以下数据修改package.json文件, 请注意, 你可以在以下位置更改项目的名称版本, 主要要点是你需要创建一个有效文件:
{"name": "peerjs-videochat-application-client", "version": "1.0.0"}
一旦package.json文件有效, 继续执行以下步骤安装Express模块??:
npm install express
【如何使用PeerJS和Node.js与WebRTC创建视频聊天】安装此模块后, 你将能够轻松设置本地服务器。现在转到项目的公共文件夹, 并使用以下代码修改website-server.js文件:
注意 服务器使用第一步中提到的证书文件, 因此, 如果你决定更改示例项目的结构, 请确保也更改证书文件的路径。
// project/public/website-server.js/** * This script starts a https server accessible at https://localhost:8443 * to test the chat * * @author Carlos Delgado (Our Code World) */var fs= require('fs');
var http= require('http');
var https= require('https');
var path= require("path");
var os= require('os');
var ifaces = os.networkInterfaces();
// Public Self-Signed Certificates for HTTPS connectionvar privateKey= fs.readFileSync('./../certificates/key.pem', 'utf8');
var certificate = fs.readFileSync('./../certificates/cert.pem', 'utf8');
var credentials = {key: privateKey, cert: certificate};
var express = require('express');
var app = express();
var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);
/** *Show in the console the URL access for other devices in the network */Object.keys(ifaces).forEach(function (ifname) {var alias = 0;
ifaces[ifname].forEach(function (iface) {if ('IPv4' !== iface.family || iface.internal !== false) {// skip over internal (i.e. 127.0.0.1) and non-ipv4 addressesreturn;
}console.log("");
console.log("Welcome to the Chat Sandbox");
console.log("");
console.log("Test the chat interface from this device at : ", "https://localhost:8443");
console.log("");
console.log("And access the chat sandbox from another device through LAN using any of the IPS:");
console.log("Important: Node.js needs to accept inbound connections through the Host Firewall");
console.log("");
if (alias >
= 1) {console.log("Multiple ipv4 addreses were found ... ");
// this single interface has multiple ipv4 addressesconsole.log(ifname + ':' + alias, "https://"+ iface.address + ":8443");
} else {// this interface has only one ipv4 adressconsole.log(ifname, "https://"+ iface.address + ":8443");
}++alias;
});
});
// Allow access from all the devices of the network (as long as connections are allowed by the firewall)var LANAccess = "0.0.0.0";
// For httphttpServer.listen(8080, LANAccess);
// For httpshttpsServer.listen(8443, LANAccess);
// Serve the index.html file as content of the / routeapp.get('/', function (req, res) {res.sendFile(path.join(__dirname+'/index.html'));
});
// Expose the js resources as "resources"app.use('/resources', express.static('./source'));
这段代码设置了一个非常基本的Express服务器, 执行时可以在浏览器的本地端口8443(https)上访问它。除此之外, 它将列出(一旦在控制台中执行)可以从LAN中的其他设备访问它的地址(请参阅步骤6), 或者, 如果将其部署在生产服务器上, 则可以将其删除。
将更改保存在文件上, 然后转到下一步。
4.设置PeerJS服务器 PeerServer帮助PeerJS客户端之间的代理连接, 并且数据不通过服务器代理。要安装PeerJS的服务器端模块, 请打开在项目/服务器上创建的package.json文件, 并至少添加必需的参数以创建有效文件:
{"name": "peerjs-videochat-application-server", "version": "1.0.0"}
创建后, 在同一目录中运行以下命令来安装服务器
npm install peer
继续使用以下内容修改项目服务器文件夹(项目/服务器)中的peer-server.js文件:
// project/server/peer-server.jsvar fs = require('fs');
var PeerServer = require('peer').PeerServer;
var server = PeerServer({port: 9000, path: '/peerjs', ssl: {key: fs.readFileSync('./../certificates/key.pem', 'utf8'), cert: fs.readFileSync('./../certificates/cert.pem', 'utf8')}});
如你所见, PeerJS的服务器端配置非常简单, 你无需在服务器端执行任何其他操作。你可以添加一些事件侦听器, 但这不是必需的, 因为Peer Server将自动处理所有必需的逻辑。该服务器将在执行时在端口9000上的服务器上运行。
5.设置客户端代码 客户端可以非常简单。可以将其想象为另一个无聊的网页, 但这确实很棒。你为项目提供的样式取决于你自己, 例如, 我们使用Bootstrap框架使用Bootswatch中的Cerulean Theme创建漂亮的布局。
我们将在示例中使用的标记(project / public / index.html)如下所示:
<
!DOCTYPE html>
<
html lang="en">
<
head>
<
meta charset="UTF-8">
<
title>
Video Chat with PeerJS<
/title>
<
!-- Using some styles Bootswatch CSS from cdn -->
<
link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/cerulean/bootstrap.min.css">
<
/head>
<
body>
<
div class="container">
<
div class="row">
<
div class="col-md-6 col-lg-6">
<
!-- Display video of the current userNote: mute your own video, otherwise you'll hear yourself ...-->
<
div class="text-center">
<
video id="my-camera"width="300" height="300" autoplay="autoplay" muted="true" class="mx-auto d-block">
<
/video>
<
span class="label label-info">
You<
/span>
<
/div>
<
/div>
<
div class="col-md-6 col-lg-6">
<
!-- Display video of the connected peer -->
<
div class="text-center">
<
video id="peer-camera" width="300" height="300" autoplay="autoplay" class="mx-auto d-block">
<
/video>
<
span class="label label-info" id="connected_peer">
<
/span>
<
/div>
<
/div>
<
/div>
<
div class="row">
<
h1 class="text-center">
Videochat Example<
br>
<
small>
Share the following ID with the pal that wants to talk with you<
/small>
<
/h1>
<
!-- The ID of your current session -->
<
h4 class="text-center">
<
span id="peer-id-label">
<
/span>
<
/h4>
<
div class="col-md-12 col-lg-12">
<
div class="form-horizontal" id="connection-form">
<
fieldset>
<
legend>
Connection Form<
/legend>
<
div class="form-group">
<
label for="name" class="col-lg-2 control-label">
Username<
/label>
<
div class="col-lg-10">
<
input type="text" class="form-control" name="name" id="name" placeholder="Your random username">
<
/div>
<
/div>
<
div class="form-group">
<
label for="peer_id" class="col-lg-2 control-label">
Peer ID (id of your pal)<
/label>
<
div class="col-lg-10">
<
input type="text" class="form-control" name="peer_id" id="peer_id" placeholder="Peer ID" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
<
!-- Show message if someone connected to the client -->
<
div id="connected_peer_container" class="hidden">
An user is already connected to your session. Just provide a name to connect !<
/div>
<
/div>
<
/div>
<
div class="form-group">
<
div class="col-lg-10 col-lg-offset-2">
<
button id="connect-to-peer-btn" class="btn btn-primary">
Connect to Peer<
/button>
<
/div>
<
/div>
<
/fieldset>
<
/div>
<
/div>
<
div class="col-md-12 col-lg-12">
<
div id="chat" class="hidden">
<
div id="messages-container">
<
div class="list-group" id="messages">
<
/div>
<
/div>
<
div id="message-container">
<
div class="form-group">
<
label class="control-label">
Live chat<
/label>
<
div class="input-group">
<
span class="input-group-btn">
<
button id="call" class="btn btn-info">
Call<
/button>
<
/span>
<
input type="text" class="form-control" name="message" id="message" placeholder="Your messag here ...">
<
span class="input-group-btn">
<
button id="send-message" class="btn btn-success">
Send Message<
/button>
<
/span>
<
/div>
<
/div>
<
/div>
<
/div>
<
/div>
<
/div>
<
/div>
<
!-- Include the Client Side version of peer.js using a script tag !-->
<
script src="http://www.srcmini.com/resources/js/peer.min.js">
<
/script>
<
!-- Include the scripts that will handle the chat -->
<
script src="http://www.srcmini.com/resources/js/script.js">
<
/script>
<
/body>
<
/html>
标记结构上重要的一点是, 你遵循要提供的ID来制作以下JavaScript。请注意, 第一个视频标签(将显示你自己的视频的标签)需要将静音属性设置为true, 否则, 一旦开始传输, 你将听到自己的声音。还需要包括Peer.js的客户端版本, 此文件可以从此处的官方存储库或任何免费的CDN中获得。关键是peer.min.js文件必须位于project / public / js中。
现在对于project / public / js / scripts.js文件, 我们将编写处理该代码的方法, 首先编写一个DOMContentLoaded事件侦听器:
// When the DOM is readydocument.addEventListener("DOMContentLoaded", function(event) {// All the code of scripts.js here ...}, false);
我们现在将解释的所有代码都必须位于上一个回调中。首先, 需要确定PeerJS客户端的初始化方式并创建一些全局变量(仅适用于scripts.js文件):
var peer_id;
var username;
var conn;
/** * Important: the host needs to be changed according to your requirements. * e.g if you want to access the Peer server from another device, the * host would be the IP of your host namely 192.xxx.xxx.xx instead * of localhost. * * The iceServers on this example are public and can be used for your project. */var peer = new Peer({host: "localhost", port: 9000, path: '/peerjs', debug: 3, config: {'iceServers': [{ url: 'stun:stun1.l.google.com:19302' }, {url: 'turn:numb.viagenie.ca', credential: 'muazkh', username: 'webrtc@live.com'}]}});
在这一步中, WebRTC知识起着重要的作用, 因此, 如果你对此一无所知, 建议你在此处的HTML5 Rocks这篇写得很好的文章中阅读有关ice服务器的更多信息。本示例使用免费的Ice Server使其正常工作, 但是它们可能永远无法运行或永远处于活动状态, 因此建议你在经营企业时购买并拥有自己的STUN或TURN服务器。因此, 你将拥有部署生产级WebRTC应用程序所需的所有基础结构。
另一方面, 我们使用localhost作为主机, 通常足以让生产使其工作。如果你要进行测试, 则知道你不能使用同一台计算机来测试视频聊天, 因为2个浏览器无法同时访问摄像机, 因此你可能会将本地服务器暴露给LAN(解释)在下一步中), 方法是将主机更改为计算机的IP。
现在, 向对等方添加一些事件侦听器, 当对等方最重要的事件如视频通话等发生时, 你将允许你执行一些操作:
// Once the initialization succeeds:// Show the ID that allows other user to connect to your session.peer.on('open', function () {document.getElementById("peer-id-label").innerHTML = peer.id;
});
// When someone connects to your session:// // 1. Hide the peer_id field of the connection form and set automatically its value// as the peer of the user that requested the connection.// 2. Update global variables with received valuespeer.on('connection', function (connection) {conn = connection;
peer_id = connection.peer;
// Use the handleMessage to callback when a message comes inconn.on('data', handleMessage);
// Hide peer_id field and set the incoming peer id as valuedocument.getElementById("peer_id").className += " hidden";
document.getElementById("peer_id").value = http://www.srcmini.com/peer_id;
document.getElementById("connected_peer").innerHTML = connection.metadata.username;
});
peer.on('error', function(err){alert("An error ocurred with peer: " + err);
console.error(err);
});
/** * Handle the on receive call event */peer.on('call', function (call) {var acceptsCall = confirm("Videocall incoming, do you want to accept it ?");
if(acceptsCall){// Answer the call with your own video/audio streamcall.answer(window.localStream);
// Receive datacall.on('stream', function (stream) {// Store a global reference of the other user streamwindow.peer_stream = stream;
// Display the stream of the other user in the peer-camera video element !onReceiveStream(stream, 'peer-camera');
});
// Handle when the call finishescall.on('close', function(){alert("The videocall has finished");
});
// use call.close() to finish a call}else{console.log("Call denied !");
}});
现在添加一些辅助方法, 以在列表视图中显示已接收和已发送的数据, 并在浏览器上请求视频/音频:
/** * Starts the request of the camera and microphone * * @param {Object} callbacks */function requestLocalVideo(callbacks) {// Monkeypatch for crossbrowser geusermedianavigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// Request audio an videonavigator.getUserMedia({ audio: true, video: true }, callbacks.success , callbacks.error);
}/** * Handle the providen stream (video and audio) to the desired video element * * @param {*} stream * @param {*} element_id */function onReceiveStream(stream, element_id) {// Retrieve the video element according to the desiredvar video = document.getElementById(element_id);
// Set the given stream as the video source video.src = http://www.srcmini.com/window.URL.createObjectURL(stream);
// Store a global reference of the streamwindow.peer_stream = stream;
}/** * Appends the received and sent message to the listview * * @param {Object} data */function handleMessage(data) {var orientation ="text-left";
// If the message is yours, set text to right !if(data.from == username){orientation = "text-right"}var messageHTML ='<
a href="javascript:void(0);
" class="list-group-item' + orientation + '">
';
messageHTML += '<
h4 class="list-group-item-heading">
'+ data.from +'<
/h4>
';
messageHTML += '<
p class="list-group-item-text">
'+ data.text +'<
/p>
';
messageHTML += '<
/a>
';
document.getElementById("messages").innerHTML += messageHTML;
}
接下来, 将对用户界面中的每个动作做出反应的事件侦听器定义为登录事件, 开始调用等:
/** * Handle the send message button */document.getElementById("send-message").addEventListener("click", function(){// Get the text to sendvar text = document.getElementById("message").value;
// Prepare the data to sendvar data = http://www.srcmini.com/{from: username, text: text };
// Send the message with Peerconn.send(data);
// Handle the message on the UIhandleMessage(data);
document.getElementById("message").valuehttp://www.srcmini.com/= "";
}, false);
/** *Request a videocall the other user */document.getElementById("call").addEventListener("click", function(){console.log('Calling to ' + peer_id);
console.log(peer);
var call = peer.call(peer_id, window.localStream);
call.on('stream', function (stream) {window.peer_stream = stream;
onReceiveStream(stream, 'peer-camera');
});
}, false);
/** * On click the connect button, initialize connection with peer */document.getElementById("connect-to-peer-btn").addEventListener("click", function(){username = document.getElementById("name").value;
peer_id = document.getElementById("peer_id").value;
if (peer_id) {conn = peer.connect(peer_id, {metadata: {'username': username}});
conn.on('data', handleMessage);
}else{alert("You need to provide a peer to connect with !");
return false;
}document.getElementById("chat").className = "";
document.getElementById("connection-form").className += " hidden";
}, false);
作为最后一步(不需要立即执行), 你可以调用requestLocalVideo方法以启动自己的流(该流将用于发送给其他用户):
/** * Initialize application by requesting your own video to test ! */requestLocalVideo({success: function(stream){window.localStream = stream;
onReceiveStream(stream, 'my-camera');
}, error: function(err){alert("Cannot get access to your camera and video !");
console.error(err);
}});
6.允许Node.js的入站连接(仅在本地工作) 如果你尝试通过移动设备(Android设备)或局域网中的其他设备使用计算机的IP地址(而不是localhost)访问计算机中提到的地址(localhost:8443), 以进行视频聊天测试(因为你可以在同一台计算机上测试视频聊天), 并且Node.js被防火墙的某些规则阻止, 它(可能)不会简单地工作:
文章图片
如果你确定服务器在计算机上运行, ??则问题可能是由防火墙限制引起的, 要使其正常运行, 你将需要允许与计算机中Node.js应用程序的所有入站连接。例如, 在Windows中, 你只需打开防火墙, 导航到” 入站规则” , 然后在列表中搜索Node.js:
文章图片
右键单击Node.js的选定项, 然后从上下文菜单中选择” 属性” 。在此菜单中, 导航到” 常规” 选项卡, 然后在” 操作” 区域中, 选择” 允许连接” 单选按钮:
文章图片
这应该立即生效, 但是可以肯定的是, 重新启动打开了Node的终端, 然后再次启动它。
7.运行聊天 如果一切都按预期进行, 你现在就可以自己测试视频聊天了。你需要做的就是使用Node运行每个目录(公共目录和服务器目录)的服务器文件, 并使它们在后台运行。
打开一个新终端并切换到project / public目录, 然后运行以下命令:
node website-server.js
这将为你的网站启动服务器以测试视频聊天。然后打开另一个终端, 切换到项目/服务器目录并运行以下命令:
node peer-server.js
这将启动与Peer的聊天服务器。让2终端处于活动状态, 并使用浏览器访问https:// localhost:8443网址, 你将看到Videochat模板。在此示例中, 我们将使用2个用户, 即Huskee先生(第一个用户)和Doge先生(第二个用户):
文章图片
在这种情况下, Huskee先生的摄像头将按照定义的行为自动启动, 可以根据需要进行明显更改。此时的界面要求某人使用屏幕中间的ID进行连接, 这意味着, 如果你想与某人开始视频聊天, 则只需将ID提供给其他用户即可。如果你不是在等待某人连接, 而是想与某人连接, 则需要其他用户的ID。 Doge希望使用另一台计算机或此示例中的移动设备与Huskee先生开始聊天, 因此我们需要以我们的形式和姓名输入Huskee先生的ID(在本例中为8n9hrtc80tzhvlb6):
文章图片
一旦Doge先生拥有表单的基本数据并单击Connect to Peer, Huskee先生的屏幕将自动更新, 并显示消息, 表明有人已连接到该会话, 即Doge先生, 他只需要提供用户名:
文章图片
现在, Huskee先生已登录并可以轻松与Doge先生聊天, 因此, 由于他已经建立了连接, 因此他无法提供Peer ID来连接到其他人。此刻的聊天没有视频聊天, 只有文本聊天:
文章图片
因此, 有人需要单击” 呼叫” 按钮, 在这种情况下, 将是移动设备上的Doge先生。然后, 如果他想开始通话, Huskee先生将在浏览器中收到提示:
文章图片
如果被接受, 视频聊天将毫无问题地开始, 他们可以像使用Skype这样的应用程序进行对话和编写内容:
文章图片
如本文开头所述, 你可以在Github的官方存储库中找到此示例的源代码。
编码愉快!
推荐阅读
- 如何使用Node.js连接到MySQL数据库
- 营销中的机器学习-强大的应用程序可以尝试
- 与你合作的软件开发团队
- 使API文档工作所需的7个基本要素
- AI和机器学习如何重塑员工敬业度()
- 为什么共享办公空间吸引开发人员
- 如果你想在2020年取得成功,则需要关注的技术趋势
- 如何创建在线课程网站(原因和结果)
- 腾讯云服务器如何挂载云硬盘(Linux版本)()