在正式讲解之前还是先提供项目下载地址:
https://url25.ctfile.com/f/34512525-576982564-42a010?p=7054 (访问密码:7054)
什么是 SimpleWebRTC在我们继续之前,重要的是我们了解我们将使用的主要工具。SimpleWebRTC是一个 JavaScript 库,可简化 WebRTC 点对点数据、视频和音频调用。
SimpleWebRTC 充当浏览器的 WebRTC 实现的包装器。您可能已经知道,浏览器供应商并不完全同意实现不同功能的单一方式,这意味着对于每个浏览器,WebRTC 都有不同的实现。作为开发人员,您必须为计划支持的每个浏览器编写不同的代码。SimpleWebRT 充当该代码的包装器。它公开的 API 易于使用和理解,这使其成为实现跨浏览器 WebRTC 的绝佳候选者。
构建 WebRTC 视频聊天应用现在是时候通过构建应用程序来弄脏我们的手了。我们将构建一个运行在 Express 服务器之上的单页应用程序。
要运行它,或者在家里跟随它,你需要安装 Node 和 npm。如果您不熟悉这些,或者需要一些帮助来安装它们,请查看我们之前的教程:
- 使用 nvm 安装多个版本的 Node.js
- npm 初学者指南 — 节点包管理器
您还需要一台带有网络摄像头的 PC 或笔记本电脑。如果没有,您需要为自己准备一个可以连接到显示器顶部的 USB 网络摄像头。您可能需要朋友或第二台设备来测试远程连接。
依赖项我们将使用以下依赖项来构建我们的项目:
- SimpleWebRTC — WebRTC 库
- Semantic UI CSS — 一个优雅的 CSS 框架
- jQuery — 用于选择页面上的元素和事件处理。
- Handlebars — 一个 JavaScript 模板库,我们将使用它为消息生成 HTML
- Express — NodeJS 服务器。
转到您的工作区并创建一个文件夹simplewebrtc-messenger。在 VSCode 或您喜欢的编辑器中打开文件夹并创建以下文件和文件夹结构:
simplewebrtc-messenger
├── public
│ ├── images
│ │ └── image.png
│ ├── index.html
│ └── js
│ └── app.js
├── README.md
└── server.js
或者,如果您愿意,也可以通过命令行执行相同操作:
mkdir -p simplewebrtc-messenger/public/{images,js}
cd simplewebrtc-messenger
touch public/js/app.js public/index.html .gitignore README.md server.js
打开README.md并复制以下内容:
# Simple WebRTC Messenger
A tutorial on building a WebRTC video chat app using SimpleWebRTC.
如果您打算使用 git 存储库,请将该行添加node_modules到文件中。使用以下命令.gitignore生成文件:package.json
npm init -y
您应该得到以下输出:
{
"name": "simplewebrtc-messenger",
"version": "1.0.0",
"description": "A tutorial on building a WebRTC video chat app using SimpleWebRTC.",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
现在让我们安装我们的依赖项:
npm install express handlebars jquery semantic-ui-css simplewebrtc
随着安装的进行,将此代码复制到server.js:
const express = require('express');
const app = express();
const port = 3000;
// Set public folder as root
app.use(express.static('public'));
// Provide access to node_modules folder from the client-side
app.use('/scripts', express.static(`${__dirname}/node_modules/`));
// Redirect all traffic to index.html
app.use((req, res) => res.sendFile(`${__dirname}/public/index.html`));
app.listen(port, () => {
console.info('listening on %d', port);
});
服务器代码非常标准。只需阅读评论以了解发生了什么。
接下来,让我们设置我们的public/index.html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="scripts/semantic-ui-css/semantic.min.css">
<title>SimpleWebRTC Demo</title>
<style>
html { margin-top: 20px; }
#chat-content { height: 180px; overflow-y: scroll; }
</style>
</head>
<body>
<!-- Main Content -->
<div class="ui container">
<h1 class="ui header">Simple WebRTC Messenger</h1>
<hr>
</div>
<!-- Scripts -->
<script src="scripts/jquery/dist/jquery.min.js"></script>
<script src="scripts/semantic-ui-css/semantic.min.js"></script>
<script src="scripts/handlebars/dist/handlebars.min.js "></script>
<script src="scripts/simplewebrtc/out/simplewebrtc-with-adapter.bundle.js"></script>
<script src="js/app.js"></script>
</body>
</html>
接下来,让我们设置我们的基本客户端 JavaScript 代码。将此代码复制到public/js/app.js:
window.addEventListener('load', () => {
// Put all client-side code here
});
最后,从我们的 GitHub 存储库下载此图像并将其保存在public/images文件夹中。
现在我们可以运行我们的应用程序了:
npm start
在浏览器中打开 URL localhost:3000,您应该会看到以下内容:
标记
现在让我们继续public/index.html。为了简单起见(特别是如果您已经熟悉 Handlebars),您可以从我们的GitHub 存储库中复制整个标记代码。否则,让我们一步一步来。首先,复制此代码并将其放在div中的<hr>标记之后:ui container
<div class="ui two column stackable grid">
<!-- Chat Section -->
<div class="ui ten wide column">
<div class="ui segment">
<!-- Chat Room Form -->
<div class="ui form">
<div class="fields">
<div class="field">
<label>User Name</label>
<input type="text" placeholder="Enter user name" id="username" name="username">
</div>
<div class="field">
<label>Room</label>
<input type="text" placeholder="Enter room name" id="roomName" name="roomName">
</div>
</div>
<br>
<div class="ui buttons">
<div id="create-btn" class="ui submit orange button">Create Room</div>
<div class="or"></div>
<div id="join-btn" class="ui submit green button">Join Room</div>
</div>
</div>
<!-- Chat Room Messages -->
<div id="chat"></div>
</div>
</div>
<!-- End of Chat Section -->
<!-- Local Camera -->
<div class="ui six wide column">
<h4 class="ui center aligned header" style="margin:0;">
Local Camera
</h4>
<img id="local-image" class="ui large image" src="images/image.png">
<video id="local-video" class="ui large image hidden" autoplay></video>
</div>
</div>
<!-- Remote Cameras -->
<h3 class="ui center aligned header">Remote Cameras</h3>
<div id="remote-videos" class="ui stackable grid">
<div class="four wide column">
<img class="ui centered medium image" src="images/image.png">
</div>
<div class="four wide column">
<img class="ui centered medium image" src="images/image.png">
</div>
<div class="four wide column">
<img class="ui centered medium image" src="images/image.png">
</div>
<div class="four wide column">
<img class="ui centered medium image" src="images/image.png">
</div>
</div>
浏览标记代码并阅读注释以了解每个部分的用途。如果您不熟悉 CSS 库,还可以查看Semantic UI文档。刷新您的浏览器。您应该有以下视图:
我们使用空白图像作为占位符来指示相机位置将流到网页上的哪个位置。请注意,只要您的互联网带宽可以处理,此应用程序将能够支持多个远程连接。
模板现在让我们添加三个 Handlebar 模板,这将使我们的网页具有交互性。
在 div 之后放置以下标记ui container(尽管位置并不重要)。我们将从聊天容器开始,它由以下部分组成:
- 房间号
- 空聊天消息容器(稍后通过 JavaScript 填充)
- 用于发布消息的输入。
<!-- Chat Template -->
<script id="chat-template" type="text/x-handlebars-template">
<h3 class="ui orange header">Room ID -> <strong>{{ room }}</strong></h3>
<hr>
<div id="chat-content" class="ui feed"> </div>
<hr>
<div class="ui form">
<div class="ui field">
<label>Post Message</label>
<textarea id="post-message" name="post-message" rows="1"></textarea>
</div>
<div id="post-btn" class="ui primary submit button">Send</div>
</div>
</script>
接下来,添加以下模板,该模板将用于显示用户聊天消息:
<!-- Chat Content Template -->
<script id="chat-content-template" type="text/x-handlebars-template">
{{#each messages}}
<div class="event">
<div class="label">
<i class="icon blue user"></i>
</div>
<div class="content">
<div class="summary">
<a href="#"> {{ username }}</a> posted on
<div class="date">
{{ postedOn }}
</div>
</div>
<div class="extra text">
{{ message }}
</div>
</div>
</div>
{{/each}}
</script>
最后,添加以下模板,该模板将用于显示来自远程摄像机的流:
<!-- Remote Video Template -->
<script id="remote-video-template" type="text/x-handlebars-template">
<div id="{{ id }}" class="four wide column"></div>
</script>
标记代码希望是不言自明的,所以让我们继续为我们的应用程序编写客户端 JavaScript 代码。
主应用脚本打开文件public/js/app.js并添加以下代码:
// Chat platform
const chatTemplate = Handlebars.compile($('#chat-template').html());
const chatContentTemplate = Handlebars.compile($('#chat-content-template').html());
const chatEl = $('#chat');
const formEl = $('.form');
const messages = [];
let username;
// Local Video
const localImageEl = $('#local-image');
const localVideoEl = $('#local-video');
// Remote Videos
const remoteVideoTemplate = Handlebars.compile($('#remote-video-template').html());
const remoteVideosEl = $('#remote-videos');
let remoteVideosCount = 0;
// Add validation rules to Create/Join Room Form
formEl.form({
fields: {
roomName: 'empty',
username: 'empty',
},
});
在这里,我们正在初始化我们计划操作的几个元素。我们还在表单中添加了验证规则,以便用户不能将任何一个字段留空。
接下来,让我们初始化我们的 WebRTC 代码:
// create our WebRTC connection
const webrtc = new SimpleWebRTC({
// the id/element dom element that will hold "our" video
localVideoEl: 'local-video',
// the id/element dom element that will hold remote videos
remoteVideosEl: 'remote-videos',
// immediately ask for camera access
autoRequestMedia: true,
});
// We got access to local camera
webrtc.on('localStream', () => {
localImageEl.hide();
localVideoEl.show();
});
现在你知道为什么它被称为 SimpleWebRTC。这就是我们初始化 WebRTC 代码所需要做的一切。请注意,我们甚至没有指定任何 ICE 服务器或 STUN 服务器。它只是工作。但是,您可以使用其他 TURN 服务,例如Xirsys。您需要设置一个本地SignalMaster服务器来处理 WebRTC 信号。
让我们快速刷新一下网页以确认新代码正在运行
该页面应请求访问您的相机和麦克风。只需单击接受,您应该会得到上面的视图。
聊天室脚本现在让我们使表单功能化。我们需要编写创建和加入房间的逻辑。此外,我们需要编写额外的逻辑来显示聊天室。我们将chat-room-template为此使用 。让我们首先将点击处理程序附加到表单的按钮:
$('.submit').on('click', (event) => {
if (!formEl.form('is valid')) {
return false;
}
username = $('#username').val();
const roomName = $('#roomName').val().toLowerCase();
if (event.target.id === 'create-btn') {
createRoom(roomName);
} else {
joinRoom(roomName);
}
return false;
});
接下来,我们需要声明createRoomandjoinRoom函数。将以下代码放在点击处理程序代码之前:
// Register new Chat Room
const createRoom = (roomName) => {
console.info(`Creating new room: ${roomName}`);
webrtc.createRoom(roomName, (err, name) => {
showChatRoom(name);
postMessage(`${username} created chatroom`);
});
};
// Join existing Chat Room
const joinRoom = (roomName) => {
console.log(`Joining Room: ${roomName}`);
webrtc.joinRoom(roomName);
showChatRoom(roomName);
postMessage(`${username} joined chatroom`);
};
创建或加入房间就这么简单:只需使用SimpleWebRTC 的 createRoom 和 joinRoom 方法。
您可能还注意到我们还有尚未定义的功能showChatroom。postMessage现在让我们通过在调用代码之前插入以下代码来做到这一点:
// Post Local Message
const postMessage = (message) => {
const chatMessage = {
username,
message,
postedOn: new Date().toLocaleString('en-GB'),
};
// Send to all peers
webrtc.sendToAll('chat', chatMessage);
// Update messages locally
messages.push(chatMessage);
$('#post-message').val('');
updateChatMessages();
};
// Display Chat Interface
const showChatRoom = (room) => {
// Hide form
formEl.hide();
const html = chatTemplate({ room });
chatEl.html(html);
const postForm = $('form');
// Post Message Validation Rules
postForm.form({
message: 'empty',
});
$('#post-btn').on('click', () => {
const message = $('#post-message').val();
postMessage(message);
});
$('#post-message').on('keyup', (event) => {
if (event.keyCode === 13) {
const message = $('#post-message').val();
postMessage(message);
}
});
};
花一些时间浏览代码以了解逻辑。你很快就会遇到另一个我们没有声明的函数,updateChatMessages. 现在让我们添加它:
// Update Chat Messages
const updateChatMessages = () => {
const html = chatContentTemplate({ messages });
const chatContentEl = $('#chat-content');
chatContentEl.html(html);
// automatically scroll downwards
const scrollHeight = chatContentEl.prop('scrollHeight');
chatContentEl.animate({ scrollTop: scrollHeight }, 'slow');
};
此功能的目的只是用新消息更新聊天 UI。我们还需要一个接收来自远程用户的消息的函数。将以下函数添加到app.js:
// Receive message from remote user
webrtc.connection.on('message', (data) => {
if (data.type === 'chat') {
const message = data.payload;
messages.push(message);
updateChatMessages();
}
});
这就是我们让聊天室正常工作所需的所有逻辑。刷新页面并登录
点击创建房间按钮。你会被带到这个视图。发布一些消息以确认聊天室正在运行。
确认它工作正常后,继续下一个任务。
远程摄像机如前所述,SimpleWebRTC 支持多个对等点。以下是新用户加入房间时添加远程视频流的代码:
// Remote video was added
webrtc.on('videoAdded', (video, peer) => {
const id = webrtc.getDomId(peer);
const html = remoteVideoTemplate({ id });
if (remoteVideosCount === 0) {
remoteVideosEl.html(html);
} else {
remoteVideosEl.append(html);
}
$(`#${id}`).html(video);
$(`#${id} video`).addClass('ui image medium'); // Make video element responsive
remoteVideosCount = 1;
});
就是这样。如果您期待更复杂的事情,我很抱歉。我们所做的只是简单地为 增加一个事件监听器videoAdded,它的回调接收一个video可以直接添加到 DOM 的元素。它还接收一个peer对象,其中包含有关我们的对等连接的有用信息,但在这种情况下,我们只对 DOM 元素的 ID 感兴趣。
不幸的是,如果不在 HTTPS 服务器上运行,就无法测试这段代码。理论上,您可以为您的 Express 服务器生成一个自签名证书,以便在您的内部网络中运行该应用程序。但坏消息是,如果证书不是来自受信任的机构,浏览器将不允许您访问网络摄像头。
测试上述代码最简单的解决方案是将其部署到支持 HTTPS 协议的公共服务器上。
部署我们将要执行的这种方法是部署 NodeJS 应用程序的最简单方法之一。我们所要做的就是首先在now.sh注册一个帐户。
只需选择免费计划。您需要提供您的电子邮件地址。您还需要验证您的电子邮件地址以激活您的帐户。接下来,now在您的系统上安装 CLI 工具:
npm install -g now
安装完成后,就可以部署应用了。只需在项目文件夹的根目录执行以下命令:
now --public
如果这是您第一次运行该命令,系统会要求您输入您的电子邮件地址。然后,您将收到一封电子邮件,您需要使用该电子邮件来验证您的登录信息。验证完成后,您需要now --public再次执行该命令。几秒钟后,您的应用程序将在指定的 URL 启动并运行,该 URL 将在终端上打印出来。
如果您使用的是 VSCode 集成终端,只需按下ALT并单击即可在浏览器中打开 URL。
您需要允许该页面访问您的摄像头和麦克风。接下来像以前一样创建一个房间。登录后,您需要访问另一台设备,例如另一台带前置摄像头的笔记本电脑或智能手机。您也可以请有互联网连接的朋友来帮助您。只需访问相同的 URL,然后输入新的用户名和相同的房间名称。远程用户必须点击加入房间按钮。在几秒钟内,两个设备都应该连接到聊天室。如果设备没有摄像头,没关系,因为聊天功能仍然可以使用。
结论在本教程中,您了解了 SimpleWebRTC 以及如何使用它来创建实时应用程序。具体来说,我们创建了一个消息应用程序,允许用户向远程对等方发送文本和进行视频通话。SimpleWebRTC 是一个非常棒的跨浏览器库,用于在 Web 应用程序中轻松实现 WebRTC。
,