怎样用WebRTC和Node.js 开发实时视频app程序

0_BUEGq1Yx3JWXlMS7_%E5%89%AF%E6%9C%AC
照片由加布里埃尔BENOIS在上Unsplash提供

时间就是金钱,所以我直接讲重点。本文中,我将向你展示如何编写视频聊天应用程序,该应用程序允许在两个连接的用户之间共享视频和音频。这很简单,并且很适合用JavaScript语言进行培训,更准确地说是用WebRTC技术和Node.js。

什么是WebRTC?

Web实时通信WebRTC是一种HTML5规范,它允许你直接在浏览器之间进行实时通信,而无需任何第三方插件。WebRTC可以用于多个任务(甚至是文件共享),但显然实时对等音频和视频通信是主要功能,在本文中我们将重点介绍这些功能。

WebRTC的作用是允许访问设备,你可以使用麦克风、摄像头在WebRTC的帮助下共享屏幕,实时进行所有操作。

WebRTC JavaScript API

WebRTC是一个涉及很多技术的复杂主题。但是,建立连接、通信和传输数据是通过一组JS API实现的。主要的API包括:

  • RTCPeerConnection-创建并导航对等连接,
  • RTCSessionDescription-描述连接(或潜在连接)的一端以及它的配置方式,
  • navigator.getUserMedia-捕获音频和视频。

为什么选择Node.js?

要在两个或更多设备之间建立远程连接,你需要一台服务器,在这种情况下,你需要的是一台处理实时通信的服务器。Node.js是为实时可伸缩应用程序构建的,要想开发具有免费数据交换的双向连接apps,你可能会用到WebSockets,该WebSockets允许打开客户端和服务器之间的通信会话。而来自客户端的请求被处理为一个循环,更确切地说是事件循环,这使Node.js成为一个不错的选择,因为它采用“非阻塞”方法来处理请求,从而在整个过程中实现了低延迟和高吞吐量。

我们将在Demo中创建什么?

我们将创建一个非常简单的应用程序,该应用程序允许我们流式传输音频和视频到已连接的设备的一个基本视频聊天应用程序中。我们将使用:

  • 用于提供静态文件的Express库,例如代表UI的HTML文件。
  • socket.io库用于使用WebSocket在两个设备之间建立连接。
  • WebRTC,允许媒体设备在连接的设备之间流式传输音频和视频。


Afif Kusuma在Unsplash上拍摄的照片

视频聊天实施

我们要做的第一件事是提供一个HTML文件,该文件将用作我们应用程序的UI。
让我们通过运行以下命令初始化一个新的node.js项目:

npm init

之后,我们需要通过运行以下命令安装一些dev依赖项:

npm i -D typescript ts-node nodemon @types/express @types/socket.io

我们通过运行以下命令添加生产依赖性:

npm i express socket.io

现在我们可以定义脚本以在package.json文件中运行我们的项目:

{ 
 “scripts”: {
 “start”: “ts-node src/index.ts”, 
 “dev”: “nodemon — watch ‘src/**/*.ts’ — exec ‘ts-node’ src/index.ts” 
},
“devDependencies”: { 
“@types/express”: “⁴.17.2”, 
“@types/socket.io”: “².1.4”, 
“nodemon”: “¹.19.4”, 
“ts-node”: “⁸.4.1”, 
“typescript”: “³.7.2” 
},    
“dependencies”: {
 “express”: “⁴.17.1”,
 “socket.io”: “².3.0” 
 }
}

当我们运行npm run dev命令时,nodemon将查看每个以.ts扩展名结尾的文件在src文件夹中的所有更改。现在,我们将创建一个src文件夹,并在此文件夹中创建两个打字稿文件:index.ts和server.ts。

在server.ts内部,我们将创建服务器类,并将其与express和socket.io一起使用:

import express, { Application } from "express";
import socketIO, { Server as SocketIOServer } from "socket.io";
import { createServer, Server as HTTPServer } from "http";
export class Server {
 private httpServer: HTTPServer; 
 private app: Application; 
 private io: SocketIOServer; 
 
 private readonly DEFAULT_PORT = 5000;  
 
 constructor() {   
  this.initialize();    
  this.handleRoutes();   
  this.handleSocketConnection(); 
 }  
 
 private initialize(): void {
  this.app = express();
  this.httpServer = createServer(this.app);
  this.io = socketIO(this.httpServer); 
 }  
 
 private handleRoutes(): void {   
  this.app.get("/", (req, res) => {     
    res.send(`<h1>Hello World</h1>`);    
  }); 
 }  
 
 private handleSocketConnection(): void {   
  this.io.on("connection", socket => {     
    console.log("Socket connected.");   
  }); 
 }  
 
 public listen(callback: (port: number) => void): void {         this.httpServer.listen(this.DEFAULT_PORT, () =>      callback(this.DEFAULT_PORT)   
  ); 
 }
}

要运行我们的服务器,我们需要创建一个新的Server类的实例并调用listen方法,将其放入index.ts文件中:

import { Server } from “./server”;
const server = new Server();
server.listen(port => { 
 console.log(`Server is listening on http://localhost:${port}`);
});

现在,当我们运行npm run dev 时,我们应该看到:

当我们打开浏览器并输入 http://localhost:5000时,我们应该注意到“ Hello World”消息:

现在,我们将在 public/index.html中创建一个新的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” /> <title>Dogeller</title> 
<link href=”https://fonts.googleapis.com/css?family=Montserrat:300,400,500,700&display=swap" rel=”stylesheet” /> <link rel=”stylesheet” href=”./styles.css” /> 
<script src=”https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script> 
</head>
<body> 
<div class=”container”> 
<header class=”header”> 
<div class=”logo-container”> 
<img src=”./img/doge.png” alt=”doge logo” class=”logo-img” /> 
<h1 class=”logo-text”> Doge<span class=”logo-highlight”>ller</span> </h1> 
</div> 
</header> 
<div class=”content-container”> 
<div class=”active-users-panel” id=”active-user-container”> 
<h3 class=”panel-title”>Active Users:</h3> 
</div> 
<div class=”video-chat-container”> 
<h2 class=”talk-info” id=”talking-with-info”> Select active user on the left menu. </h2> 
<div class=”video-container”> 
<video autoplay class=”remote-video” id=”remote-video”></video> <video autoplay muted class=”local-video” id=”local-video”></video> </div> 
</div> 
</div> 
</div> 
<script src=”./scripts/index.js”></script> 
</body>
</html>

在此文件中,我们声明了两个视频元素:一个用于远程视频连接,另一个用于本地视频。你可能已经注意到,我们也在导入本地脚本,因此让我们创建一个名为scripts的新文件夹,并在此目录中创建index.js 文件。

现在,你需要将index.html提供给浏览器。首先,你需要告诉express你要提供哪些静态文件。为了做到这一点,我们将在Server类内实施一个新方法:

private configureApp(): void { 
  this.app.use(express.static(path.join(__dirname, “../public”))); 
}

不要忘记在configureApp方法内部调用initialize方法:

private initialize(): void { 
 this.app = express(); 
 this.httpServer = createServer(this.app); 
 this.io = socketIO(this.httpServer); 
 this.configureApp(); 
 this.handleSocketConnection();
}

现在,当你输入http:// localhost:5000时,你应该会看到运行中的index.html文件:

接下来要实现访问摄像头和视频,并将其流式传输到local-video元素。为此,你需要打开public/scripts/index.js文件并使用以下方法:

navigator.getUserMedia( 
 {video: true, audio: true }, 
 stream => { 
   const localVideo = document.getElementById("local-video");   
 if (localVideo) {     
  localVideo.srcObject = stream;   
 } 
}, 
 error => {     
  console.warn(error.message); 
 }
);

当你返回浏览器时,你会注意到一个提示,要求你访问媒体设备,而在接受该提示后,你应该会看到相机在运行。
图片:

如果你需要有关操作步骤的帮助,请在评论中告诉我,我们会很高兴回复你。拜!

原文作者 Bilal Rifas
原文链接 https://medium.com/javascript-in-plain-english/how-i-developed-a-real-time-video-chat-app-c4f640686a48