概念
为了建立并维护一个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中看到日志记录。
点滴
- 可能有哪些替代消息传递机制?使用“纯”WebSocket可能遇到什么问题?
- 扩展此应用程序可能涉及哪些问题?您是否可以开发一种方法来测试成千上万的同时房间请求?
- 此应用使用JavaScript提示获取房间名称。找出一种从URL获取房间名称的方法。 例如localhost:8080 / foo会给房间名称foo。