使用SimpleWebRTC构建WebRTC视频聊天应用程序

本文在我们的《 6个JavaScript项目》 一书中有介绍 构建使您对现代JavaScript开发非常熟悉的项目。

随着WebRTC的出现以及浏览器实时处理对等通信的能力的增强,构建实时应用程序比以往任何时候都更加容易。 在本教程中,我们将介绍SimpleWebRTC以及如何在实现WebRTC时使我们的生活更轻松。 在整篇文章中,我们将构建一个具有消息传递功能的WebRTC视频聊天应用程序。

如果您需要一些有关WebRTC和对等通信的背景知识,我建议阅读WebRTC的曙光getUserMedia API简介

什么是SimpleWebRTC

在继续之前,了解我们将要使用的主要工具很重要。 SimpleWebRTC是一个JavaScript库,可简化WebRTC对等数据,视频和音频呼叫。

SimpleWebRTC充当浏览器WebRTC实现的包装。 您可能已经知道,浏览器供应商并不完全同意采用一种实现不同功能的方式,这意味着对于每种浏览器,WebRTC都有不同的实现。 作为开发人员,您必须为计划支持的每种浏览器编写不同的代码。 SimpleWebRT充当该代码的包装器。 它公开的API易于使用和理解,这使其成为实现跨浏览器WebRTC的绝佳选择。

构建WebRTC视频聊天应用

现在是时候通过构建应用程序来使我们动手了。 我们将构建一个在Express服务器之上运行的单页应用程序。

请注意,您可以从我们的GitHub存储库下载本教程的代码。 要运行它或在家中跟随,您需要安装Node和npm。 如果您不熟悉这些内容,或者想获得安装它们的帮助,请查看我们以前的教程:

您还需要一台具有网络摄像头的PC或笔记本电脑。 如果没有,则需要为自己准备一个USB网络摄像头,该摄像头可以连接到显示器的顶部。 您可能需要一个朋友或另一台设备来测试远程连接。

依存关系

我们将使用以下依赖项来构建我们的项目:

  • SimpleWebRTC — WebRTC库
  • 语义UI CSS —一个优雅的CSS框架
  • jQuery —用于选择页面上的元素和事件处理。
  • 把手 -一个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存储库中复制整个标记代码。 否则,让我们逐步进行操作。 首先,复制此代码并将其放在ui container div中的<hr>标记之后:

<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模板,这些模板将使我们的网页具有交互性。

ui container div之后放置以下标记(尽管位置并不重要)。 我们将从聊天容器开始,该容器由以下部分组成:

  • 房间编号
  • 空的聊天消息容器(稍后将通过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;
});

接下来,我们需要声明createRoomjoinRoom函数。 将以下代码放在点击处理程序代码之前:

// 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方法

您可能还已经注意到,我们具有尚未定义的showChatroompostMessage函数。 现在,通过在调用代码之前插入以下代码来做到这一点:

// 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添加事件侦听videoAdded ,该事件侦听器的回调接收可以直接添加到DOM的video元素。 它还会收到一个peer对象,该对象包含有关我们的对等连接的有用信息,但是在这种情况下,我们只对DOM元素的ID感兴趣。

不幸的是,如果不在HTTPS服务器上运行,就无法测试这部分代码。 从理论上讲,您可以为Express服务器生成一个自签名证书,以便在内部网络中运行该应用程序。 但坏消息是,如果证书不是来自受信任的机构,浏览器将不允许您访问网络摄像头。

测试上述代码的最简单解决方案是将其部署到支持HTTPS协议的公共服务器上。

部署方式

我们将要执行的此方法是部署NodeJS应用的最简单方法之一。 我们要做的就是首先在now.sh中注册一个帐户。

只需选择免费计划。 您需要提供您的电子邮件地址。 您还需要验证电子邮件地址才能激活帐户。 接下来, now在系统上安装CLI工具:

npm install -g now

安装完成后,您可以部署应用程序。 只需在项目文件夹的根目录下执行以下命令:

now --public

如果这是您第一次运行该命令,系统将要求您输入电子邮件地址。 然后,您会收到一封电子邮件,您需要该电子邮件来验证您的登录信息。 验证完成后,您now --public再次执行命令now --public 。 几秒钟后,您的应用将在指定的URL上启动并运行,该URL将在终端上打印出来。

如果您使用的是VSCode集成终端,只需按ALT ,然后单击以在浏览器中打开URL。

部署允许摄像头

您需要允许该页面访问您的相机和麦克风。 接下来,像以前一样创建一个房间。 登录后,您需要访问另一台设备,例如另一台带有前置摄像头的笔记本电脑或智能手机。 您也可以要求有Internet连接的朋友帮助您。 只需访问相同的URL,然后输入新的用户名和相同的房间名称。 远程用户将必须点击“ 加入会议室”按钮。 在几秒钟内,两个设备都应连接到聊天室。 如果设备没有摄像头,那就可以了,因为聊天功能仍然可以使用。

遥控相机

结论

在本教程中,您了解了SimpleWebRTC以及如何使用它来创建实时应用程序。 具体来说,我们创建了一个消息传递应用程序,允许用户发送文本并与远程对等方进行视频通话。 SimpleWebRTC是一个非常出色的跨浏览器库,用于在Web应用程序中轻松实现WebRTC。

别忘了本教程中使用的代码在GitHub上可用 。 克隆它,制作一些有趣的东西,然后玩得开心!

From: https://www.sitepoint.com/webrtc-video-chat-application-simplewebrtc/

网页视频开发 webrtc ;(function () { var logger = { log: function (){}, warn: function (){}, error: function (){} }; // normalize environment var RTCPeerConnection = null, getUserMedia = null, attachMediaStream = null, reattachMediaStream = null, browser = null, webRTCSupport = true; if (navigator.mozGetUserMedia) { logger.log("This appears to be Firefox"); browser = "firefox"; // The RTCPeerConnection object. RTCPeerConnection = mozRTCPeerConnection; // The RTCSessionDescription object. RTCSessionDescription = mozRTCSessionDescription; // The RTCIceCandidate object. RTCIceCandidate = mozRTCIceCandidate; // Get UserMedia (only difference is the prefix). // Code from Adam Barth. getUserMedia = navigator.mozGetUserMedia.bind(navigator); // Attach a media stream to an element. attachMediaStream = function(element, stream) { element.mozSrcObject = stream; element.play(); }; reattachMediaStream = function(to, from) { to.mozSrcObject = from.mozSrcObject; to.play(); }; // Fake get{Video,Audio}Tracks MediaStream.prototype.getVideoTracks = function() { return []; }; MediaStream.prototype.getAudioTracks = function() { return []; }; } else if (navigator.webkitGetUserMedia) { browser = "chrome"; // The RTCPeerConnection object. RTCPeerConnection = webkitRTCPeerConnection; // Get UserMedia (only difference is the prefix). // Code from Adam Barth. getUserMedia = navigator.webkitGetUserMedia.bind(navigator); // Attach a media stream to an element. attachMediaStream = function(element, stream) { element.autoplay = true; element.src = webkitURL.createObjectURL(stream); }; reattachMediaStream = function(to, from) { to.src = from.src; }; // The representation of tracks in a stream is changed in M26. // Unify them for e
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值