通过WebRTC进行实时通信-建立信令服务交换数据

2020-04-02 18:42:13 浏览数 (1)

概念

为了建立并维护一个WebRTC呼叫,WebRTC端点需要交换 metadata:

  • 候选者(网络)信息
  • **Off****Answer**提供了关于媒体的信息,如分辨率和解码器。

换句话说,交换metadata需要在点对点传输音频、视频或数据之前。这个过程称之为信令。

在前一步,发送者与接收者的 RTCPeerConnection对象在同一个页面上,信令在两个对象间传递metadata是一件简单的事情。

在真实世界的应用程序中,在web页面上的发送者与接收者的 RTCPeerConnection对象运行在不同的设备上,所以你说需要给他们提供一种通讯metadata的方法。

为了这一点,我们使用信令服务:一种能在WebRTC端点之间传递消息的服务。真实的消息是明文的:字符化的 javascript 对象。

前提条件:安装Node.js

为了下一步的试验(step-04 到 step-06),你需要使用 Node.js在本地运行一个服务。

你可以从这个链接下载并安装 Node.js 或 通过你喜欢的 包管理。

安装好后,你能引入下一步需要的依赖(运行 npm install),以及运行一个小的本地服务进行这个实验(运行 node index.js)。这些命令在后面说明我们需要的时候再说明。

关于 App

WebRTC使用客户端的 JavaScript API, 但在直实世界里也使用信令(消息)服务器,以及 STUN 和 TURN服务。你能在[这里] here 找到更多信息。

在这一步,你将构建一个简单的 Node.js信令服务,使用 Node.js Socket.IO 模块和 JavaScript 库。Node.js和 Socket.IO的经验是有用的,但不是关键的; 消息组件非常简单。

选择正确的信令服务 这个实验使用 Socket.IO作为信令服务。 Socket.IO设计成使它直接构建一个交换消息的服务, 并且 Socket.IO适合用于学习 WebRTC信令,因为它内部有放房间的概念。 然而,对一个产品服务,有更好的选择。看 How to Select a Signaling Protocol for Your Next WebRTC Project.

在这个例子中,服务(Node.js应用)在index.js中实现。而运行在它上边的客户端(web应用)在index.html中实现。

在本步骤中的 Node.js应用有两上作务 首先,它充当消息中继:

代码语言:javascript复制
socket.on('message', function (message) {
  log('Got message: ', message);
  socket.broadcast.emit('message', message);
});

其次,它管理WebRTC视频聊天'房间':

代码语言:javascript复制
if (numClients === 0) {
  socket.join(room);
  socket.emit('created', room, socket.id);
} else if (numClients === 1) {
  socket.join(room);
  socket.emit('joined', room, socket.id);
  io.sockets.in(room).emit('ready');
} else { // max two clients
  socket.emit('full', room);
}

我们的简单 WebRTC应用允许最多两上人在房间里。

HTML & JavaScript

更新 index.html,它看看起来像下面这样:

代码语言:javascript复制
<!DOCTYPE html>
<html>

<head>

  <title>Realtime communication with WebRTC</title>

  <link rel="stylesheet" href="css/main.css" />

</head>

<body>

  <h1>Realtime communication with WebRTC</h1>

  <script src="/socket.io/socket.io.js"></script>
  <script src="js/main.js"></script>
  
</body>

</html>

在此步骤中,您不会在页面上看到任何内容:所有日志记录都在浏览器控制台上完成。 (要在Chrome中查看控制台,请按Ctrl-Shift-J或Command-Option-J,如果您使用的是Mac。)

用以下内容替换js / main.js:

代码语言:javascript复制
'use strict';

var isInitiator;

window.room = prompt("Enter room name:");

var socket = io.connect();

if (room !== "") {
  console.log('Message from client: Asking to join room '   room);
  socket.emit('create or join', room);
}

socket.on('created', function(room, clientId) {
  isInitiator = true;
});

socket.on('full', function(room) {
  console.log('Message from client: Room '   room   ' is full :^(');
});

socket.on('ipaddr', function(ipaddr) {
  console.log('Message from client: Server IP address is '   ipaddr);
});

socket.on('joined', function(room, clientId) {
  isInitiator = false;
});

socket.on('log', function(array) {
  console.log.apply(console, array);
});

建立 Socket.IO并运行在 Node.js上

在HTML文件中,您可能已经看到您正在使用Socket.IO文件:

代码语言:javascript复制
<script src="/socket.io/socket.io.js"></script>

在工作目录的顶层创建一个名为package.json的文件,其中包含以下内容:

代码语言:javascript复制
{
  "name": "webrtc-codelab",
  "version": "0.0.1",
  "description": "WebRTC codelab",
  "dependencies": {
    "node-static": "^0.7.10",
    "socket.io": "^1.2.0"
  }
}

这是一个应用程序清单,它告诉Node Package Manager(npm)要安装哪些项目依赖项。

要安装依赖项(例如/socket.io/socket.io.js),请在工作目录的命令行终端中运行以下命令:

代码语言:javascript复制
npm install

您应该看到一个安装日志,结束如下所示:

如您所见,npm已经安装了package.json中定义的依赖项。

在工作目录的顶层(而不是在js目录中)创建一个新文件index.js并添加以下代码:

代码语言:javascript复制
'use strict';

var os = require('os');
var nodeStatic = require('node-static');
var http = require('http');
var socketIO = require('socket.io');

var fileServer = new(nodeStatic.Server)();
var app = http.createServer(function(req, res) {
  fileServer.serve(req, res);
}).listen(8080);

var io = socketIO.listen(app);
io.sockets.on('connection', function(socket) {

  // convenience function to log server messages on the client
  function log() {
    var array = ['Message from server:'];
    array.push.apply(array, arguments);
    socket.emit('log', array);
  }

  socket.on('message', function(message) {
    log('Client said: ', message);
    // for a real app, would be room-only (not broadcast)
    socket.broadcast.emit('message', message);
  });

  socket.on('create or join', function(room) {
    log('Received request to create or join room '   room);

    var clientsInRoom = io.sockets.adapter.rooms[room];
    var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;

    log('Room '   room   ' now has '   numClients   ' client(s)');

    if (numClients === 0) {
      socket.join(room);
      log('Client ID '   socket.id   ' created room '   room);
      socket.emit('created', room, socket.id);

    } else if (numClients === 1) {
      log('Client ID '   socket.id   ' joined room '   room);
      io.sockets.in(room).emit('join', room);
      socket.join(room);
      socket.emit('joined', room, socket.id);
      io.sockets.in(room).emit('ready');
    } else { // max two clients
      socket.emit('full', room);
    }
  });

  socket.on('ipaddr', function() {
    var ifaces = os.networkInterfaces();
    for (var dev in ifaces) {
      ifaces[dev].forEach(function(details) {
        if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
          socket.emit('ipaddr', details.address);
        }
      });
    }
  });

});

从命令行终端,在工作目录中运行以下命令:

代码语言:javascript复制
node index.js

在浏览器中,打开localhost:8080。

每次打开此URL时,系统都会提示您输入房间名称。 要加入同一个房间,请每次选择相同的房间名称,例如“foo”。

打开一个新标签页,然后再次打开localhost:8080。 选择相同的房间名称。

在第三个选项卡或窗口中打开localhost:8080。 再次选择相同的房间名称。

检查每个选项卡中的控制台:您应该从上面的JavaScript中看到日志记录。

点滴

  1. 可能有哪些替代消息传递机制?使用“纯”WebSocket可能遇到什么问题?
  2. 扩展此应用程序可能涉及哪些问题?您是否可以开发一种方法来测试成千上万的同时房间请求?
  3. 此应用使用JavaScript提示获取房间名称。找出一种从URL获取房间名称的方法。 例如localhost:8080 / foo会给房间名称foo。

0 人点赞