什么是信号?
信号是协调通信的过程。为了让 WebRTC 应用设置通话,其客户端需要交换以下信息:
- 用于打开或关闭通信的会话控制消息
- 错误消息
- 媒体元数据,例如编解码器、编解码器设置、带宽和媒体类型
- 用于建立安全连接的关键数据
- 网络数据,例如外界看到的主机 IP 地址和端口
此信号传递过程需要一种方法来让客户端来回传递消息。WebRTC API 未实现该机制。您需要自行构建。在本文的后面部分,您将了解构建信号服务的方法。不过,首先需要了解一些背景信息。
为什么 WebRTC 未定义信令?
为避免冗余并最大限度地与成熟技术兼容,WebRTC 标准未指定信令方法和协议。JavaScript 会话建立协议 (JSEP) 概述了这种方法:
JSEP 的架构还可避免浏览器必须保存状态,即充当信号状态机。例如,如果每次重新加载页面时信号数据都会丢失,就会出现问题。而是可以将信号状态保存在服务器上。
JSEP 要求对等方之间交换offer 和 answer(上述媒体元数据)。报价和答案以会话描述协议 (SDP) 格式传达,格式如下所示:
v=0
o=- 7614219274584779017 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 1 RTP/SAVPF 111 103 104 0 8 107 106 105 13 126
c=IN IP4 0.0.0.0
a=rtcp:1 IN IP4 0.0.0.0
a=ice-ufrag:W2TGCZw2NZHuwlnf
a=ice-pwd:xdQEccP40E+P0L5qTyzDgfmW
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=mid:audio
a=rtcp-mux
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:9c1AHz27dZ9xPI91YNfSlI67/EMkjHHIHORiClQe
a=rtpmap:111 opus/48000/2
…
想知道所有这些 SDP 术语的实际含义?请参阅 Internet Engineering Task Force (IETF) 示例。
请注意,WebRTC 的设计方式是,您可以在修改 SDP 文本中的值之前,通过修改提供方或响应方,将其设置为本地或远程描述。例如,appr.tc 中的 preferAudioCodec()
函数可用于设置默认编解码器和比特率。使用 JavaScript 操控 SDP 有些麻烦,有人提出应该改用 JSON 来构建未来版本的 WebRTC,但坚持使用 SDP 也有一些优势。
RTCPeerConnection
API 和信号:优惠、答案和候选
RTCPeerConnection
是 WebRTC 应用用于在对等设备之间建立连接以及传输音频和视频的 API。
为了初始化此流程,RTCPeerConnection
有两个任务:
- 确定本地媒体条件,例如分辨率和编解码器功能。这是用于“提供和回答”机制的元数据。
- 获取应用主机的潜在网络地址(称为候选地址)。
确定此本地数据后,必须通过信号机制与远程对等方交换这些数据。
假设 Alice 正在尝试给 Eve 打电话。下面详细介绍了完整的提供/接听机制:
- Alice 创建了一个
RTCPeerConnection
对象。 - Alice 使用
RTCPeerConnection
createOffer()
方法创建了提议(SDP 会话描述)。 - Alice 使用其优惠调用
setLocalDescription()
。 - Alice 将优惠串联化,并使用信号机制将其发送给 Eve。
- Eve 使用 Alice 的优惠调用
setRemoteDescription()
,以便其RTCPeerConnection
了解 Alice 的设置。 - Eve 调用
createAnswer()
,并向其成功回调传递本地会话描述 - Eve 的回答。 - Eve 通过调用
setLocalDescription()
将她的回答设置为本地说明。 - 然后,Eve 使用信号机制将字符串化答案发送给 Alice。
- Alice 使用
setRemoteDescription()
将 Eve 的回答设置为远程会话描述。
Alice 和 Eve 也需要交换网络信息。“寻找候选对象”这一表达式是指使用 ICE 框架查找网络接口和端口的过程。
- Alice 使用
onicecandidate
处理程序创建RTCPeerConnection
对象。 - 当候选网络变为可用时,系统会调用该处理程序。
- 在处理程序中,Alice 通过其信号通道向 Eve 发送字符串化的候选数据。
- 当 Eve 从 Alice 收到候选消息时,她会调用
addIceCandidate()
将候选对象添加到远程对等设备描述中。
JSEP 支持 ICE 候选传送,这允许调用方在初始提供方后逐步向被调方提供候选方,并允许被调方开始处理调用并设置连接,而无需等待所有候选方到达。
编写 WebRTC 以进行信令
以下代码段是 W3C 代码示例,总结了完整的信号传递流程。该代码假定存在某种信号机制 SignalingChannel
。稍后会详细介绍信号。
// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);
// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});
// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
// send the offer to the other peer
signaling.send({desc: pc.localDescription});
} catch (err) {
console.error(err);
}
};
// After remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
// Don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
// Call start() to initiate.
async function start() {
try {
// Get local stream, show it in self-view, and add it to be sent.
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
selfView.srcObject = stream;
} catch (err) {
console.error(err);
}
}
signaling.onmessage = async ({desc, candidate}) => {
try {
if (desc) {
// If you get an offer, you need to reply with an answer.
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream =
await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) =>
pc.addTrack(track, stream));
await pc.setLocalDescription(await pc.createAnswer());
signaling.send({desc: pc.localDescription});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc);
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(candidate);
}
} catch (err) {
console.error(err);
}
};
如需查看 offer/answer 和候选人交换流程的运作方式,请参阅 simpl.info RTCPeerConnection,并查看单页面视频聊天示例的控制台日志。如需了解详情,请访问 Google Chrome 中的 about://webrtc-internals 页面或 Opera 中的 opera://webrtc-internals 页面,下载 WebRTC 信令和统计信息的完整转储。
对等发现
这是用一种花哨的方式询问“如何找到可以交谈的人?”
如需拨打电话,您可以使用电话号码和电话号码目录。对于在线视频聊天和即时通讯,您需要身份和在线状态管理系统,以及供用户发起会话的途径。WebRTC 应用需要一种方法,让客户端能够相互发送信号,表示它们想要发起或加入通话。
WebRTC 未定义对等方发现机制,因此您不必在此处了解相关选项。该流程可能非常简单,只需通过电子邮件或消息发送网址即可。对于 Talky、tawk.to 和浏览器会议等视频聊天应用,您可以通过分享自定义链接来邀请他人加入通话。开发者 Chris Ball 构建了一项有趣的 serverless-webrtc 实验,让 WebRTC 通话参与者能够通过他们喜欢的任何即时通讯服务(例如即时通讯、电子邮件或信鸽)交换元数据。
如何构建信令服务?
再次强调一下,信令协议和机制并未由 WebRTC 标准定义。无论您选择哪种方式,都需要中间服务器在客户端之间交换信令消息和应用数据。遗憾的是,Web 应用无法直接对互联网大喊“请将我与我的朋友联系起来!”
幸运的是,信号消息很小,并且通常在通话开始时交换。在使用 appr.tc 进行视频聊天会话测试时,信令服务总共处理了约 30-45 条消息,所有消息的总大小约为 10KB。
除了在带宽方面相对不苛刻之外,WebRTC 信令服务也不会占用太多处理或内存资源,因为它们只需中继消息并保留少量会话状态数据(例如哪些客户端已连接)。
从服务器向客户端推送消息
用于信号传递的消息服务需要是双向的:客户端到服务器,服务器到客户端。双向通信违反了 HTTP 客户端/服务器请求/响应模型,但多年来,人们开发了各种黑客技术(例如长轮询),以便将数据从在网络服务器上运行的服务推送到在浏览器中运行的 Web 应用。
最近,EventSource
API 已广泛实现。这会启用服务器发送的事件,即从 Web 服务器通过 HTTP 发送到浏览器客户端的数据。EventSource
专用于单向消息传递,但可以与 XHR 结合使用来构建用于交换信令消息的服务。信号服务通过 EventSource
将调用方通过 XHR 请求传送的消息推送给被调用方。
WebSocket 是一种更自然的解决方案,专为全双工客户端-服务器通信而设计,消息可以同时在两个方向流动。使用纯 WebSocket 或服务器发送事件 (EventSource
) 构建信令服务的一个优势是,这些 API 的后端可在 PHP、Python 和 Ruby 等语言的大多数 Web 托管软件包中常见的各种 Web 框架上实现。
除了 Opera Mini 之外,所有现代浏览器都支持 WebSocket;更重要的是,所有支持 WebRTC 的浏览器(桌面版和移动版)也都支持 WebSocket。应对所有连接使用 TLS,以确保消息无法以未加密形式被拦截,同时减少代理遍历问题。(如需详细了解 WebSocket 和代理遍历,请参阅 Ilya Grigorik 的高性能浏览器网络中的 WebRTC 章节。)
您还可以通过让 WebRTC 客户端通过 Ajax 反复轮询消息传递服务器来处理信号,但这会导致大量冗余的网络请求,这对移动设备来说尤其成问题。即使会话已建立,对等方也需要轮询信号消息,以防其他对等方发生更改或会话终止。WebRTC 图书应用示例采用了此选项,并对轮询频率进行了一些优化。
规模信号
虽然每个客户端的信号服务占用的带宽和 CPU 相对较少,但热门应用的信号服务器可能必须处理来自不同位置的大量消息,并具有较高的并发性。获得大量流量的 WebRTC 应用需要能够处理大量负载的信号服务器。您未详细说明,但有许多可用于实现高量高性能消息传递的选项,包括:
可扩展消息传递和状态协议 (XMPP),原名为 Jabber,是为即时通讯而开发的协议,可用于信令传递(服务器实现包括 ejabberd 和 Openfire)。JavaScript 客户端(例如 Strophe.js)使用 BOSH 来模拟双向流式传输,但出于各种原因,BOSH 的效率可能不如 WebSocket,并且出于同样的原因,BOSH 可能无法很好地扩缩。)(顺便提一下,Jingle 是一个 XMPP 扩展,用于启用语音和视频。WebRTC 项目使用 libjingle 库(Jingle 的 C++ 实现)中的网络和传输组件。
开源库,例如 ZeroMQ(TokBox 用于其Rumour 服务)和 OpenMQ(NullMQ 通过 WebSocket 将 ZeroMQ 概念应用于 Web 平台,使用 STOMP 协议)。
使用 WebSocket(但可能会回退到长轮询)的商业云消息平台,例如 Pusher、Kaazing 和 PubNub(PubNub 还有一个适用于 WebRTC 的 API)。
商业 WebRTC 平台,例如 vLine
(开发者 Phil Leggetter 的实时 Web 技术指南提供了消息传递服务和库的完整列表。)
在 Node 上使用 Socket.io 构建信令服务
以下是使用在 Node 上使用 Socket.io 构建的信令服务的简单 Web 应用的代码。Socket.io 的设计可让您轻松构建服务以交换消息,而且,由于它内置了“房间”概念,因此 Socket.io 特别适合 WebRTC 信号。此示例并非旨在作为生产级信号服务进行扩容,但对于相对较少的用户来说,它很容易理解。
Socket.io 使用 WebSocket 和后备方案:AJAX 长轮询、AJAX 多部分流式传输、永久 Iframe 和 JSONP 轮询。它已移植到各种后端,但最出名的是此示例中使用的 Node 版本。
此示例中没有 WebRTC。该示例仅用于展示如何将信号构建到 Web 应用中。请查看控制台日志,了解客户端加入聊天室并交换消息时发生的情况。此 WebRTC Codelab 提供了有关如何将其集成到完整的 WebRTC 视频聊天应用中的分步说明。
以下是客户端 index.html
:
<!DOCTYPE html>
<html>
<head>
<title>WebRTC client</title>
</head>
<body>
<script src='/socket.io/socket.io.js'></script>
<script src='js/main.js'></script>
</body>
</html>
以下是客户端中引用的 JavaScript 文件 main.js
:
const isInitiator;
room = prompt('Enter room name:');
const socket = io.connect();
if (room !== '') {
console.log('Joining room ' + room);
socket.emit('create or join', room);
}
socket.on('full', (room) => {
console.log('Room ' + room + ' is full');
});
socket.on('empty', (room) => {
isInitiator = true;
console.log('Room ' + room + ' is empty');
});
socket.on('join', (room) => {
console.log('Making request to join room ' + room);
console.log('You are the initiator!');
});
socket.on('log', (array) => {
console.log.apply(console, array);
});
下面是完整的服务器应用:
const static = require('node-static');
const http = require('http');
const file = new(static.Server)();
const app = http.createServer(function (req, res) {
file.serve(req, res);
}).listen(2013);
const io = require('socket.io').listen(app);
io.sockets.on('connection', (socket) => {
// Convenience function to log server messages to the client
function log(){
const array = ['>>> Message from server: '];
for (const i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
socket.on('message', (message) => {
log('Got message:', message);
// For a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', (room) => {
const numClients = io.sockets.clients(room).length;
log('Room ' + room + ' has ' + numClients + ' client(s)');
log('Request to create or join room ' + room);
if (numClients === 0){
socket.join(room);
socket.emit('created', room);
} else if (numClients === 1) {
io.sockets.in(room).emit('join', room);
socket.join(room);
socket.emit('joined', room);
} else { // max two clients
socket.emit('full', room);
}
socket.emit('emit(): client ' + socket.id +
' joined room ' + room);
socket.broadcast.emit('broadcast(): client ' + socket.id +
' joined room ' + room);
});
});
(您无需了解 node-static 即可完成此操作。只是在本例中使用了它。
如需在 localhost 上运行此应用,您需要安装 Node、Socket.IO 和 node-static。您可以从 Node.js 下载 Node(安装过程简单且快速)。如需安装 Socket.IO 和 node-static,请在应用目录中的终端中运行 Node Package Manager:
npm install socket.io
npm install node-static
如需启动服务器,请在应用目录中的终端中运行以下命令:
node server.js
在浏览器中,打开 localhost:2013
。在任意浏览器中打开一个新标签页或窗口,然后重新打开 localhost:2013
。如需了解具体情况,请查看控制台。在 Chrome 和 Opera 中,您可以通过 Google Chrome 开发者工具使用 Ctrl+Shift+J
(在 Mac 上,使用 Command+Option+J
)访问控制台。
无论您选择哪种信号传递方法,后端和客户端应用至少需要提供与此示例类似的服务。
信号问题
- 只有在调用
setLocalDescription()
之后,RTCPeerConnection
才会开始收集候选对象。这是 JSEP IETF 草案中的强制要求。 - 利用 Trickle ICE。候选项到达后,请立即调用
addIceCandidate()
。
现成的信令服务器
如果您不想自行构建信令服务器,可以使用多个 WebRTC 信令服务器,这些服务器与上例一样使用 Socket.IO,并与 WebRTC 客户端 JavaScript 库集成:
- webRTC.io 是 WebRTC 的首批抽象库之一。
- Signalmaster 是一个信令服务器,专为与 SimpleWebRTC JavaScript 客户端库搭配使用而创建。
如果您不想编写任何代码,可以从 vLine、OpenTok 和 Asterisk 等公司获取完整的商业 WebRTC 平台。
需要说明的是,在 WebRTC 的早期,Ericsson 构建了一个使用 PHP 在 Apache 上构建的信令服务器。此方法现在已过时,但如果您考虑使用类似的方法,则值得查看该代码。
信号安全
“安全是让不该发生的事情不发生的艺术。”
Salman Rushdie
对于所有 WebRTC 组件而言,加密是必需的。
不过,WebRTC 标准未定义信令机制,因此您需要自行确保信令安全。如果攻击者设法劫持信号,则可以停止会话、重定向连接,以及记录、修改或注入内容。
确保信号安全最重要的因素是使用安全协议(HTTPS 和 WSS,例如 TLS),以确保消息无法被未加密的拦截。此外,请注意不要以其他使用相同信令服务器的调用方可以访问的方式广播信令消息。
信号传递后:使用 ICE 来处理 NAT 和防火墙
对于元数据信令,WebRTC 应用使用中间服务器,但对于会话建立后实际的媒体和数据流式传输,RTCPeerConnection
会尝试直接或点对点连接客户端。
在更简单的世界中,每个 WebRTC 端点都有一个唯一的地址,可以与其他对等方交换,以便直接通信。
实际上,大多数设备都位于一个或多个 NAT 层后面,有些设备安装了会屏蔽某些端口和协议的杀毒软件,许多设备位于代理和企业防火墙后面。事实上,防火墙和 NAT 可以由同一设备(例如家庭 Wi-Fi 路由器)实现。
WebRTC 应用可以使用 ICE 框架来克服实际网络的复杂性。为此,您的应用必须将 ICE 服务器网址传递给 RTCPeerConnection
,如本文所述。
ICE 会尝试找到连接对等方的最佳路径。它会并行尝试所有可能的方案,并选择最有效的方案。ICE 会先尝试使用从设备的操作系统和网卡获取的主机地址建立连接。如果失败(对于 NAT 后面的设备,通常会失败),ICE 会使用 STUN 服务器获取外部地址,如果失败,流量会通过 TURN 中继服务器进行路由。
换句话说,STUN 服务器用于获取外部网络地址,TURN 服务器用于在直接(点对点)连接失败时中继流量。
每台 TURN 服务器都支持 STUN。TURN 服务器是一种具有额外内置中继功能的 STUN 服务器。ICE 还可以应对 NAT 设置的复杂性。实际上,NAT 穿透可能需要的不仅仅是公共 IP:port 地址。
STUN 和/或 TURN 服务器的网址由 WebRTC 应用在 iceServers
配置对象(即 RTCPeerConnection
构造函数的第一个参数)中指定(可选)。对于 appr.tc,该值如下所示:
{
'iceServers': [
{
'urls': 'stun:stun.l.google.com:19302'
},
{
'urls': 'turn:192.158.29.39:3478?transport=udp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
},
{
'urls': 'turn:192.158.29.39:3478?transport=tcp',
'credential': 'JZEOEt2V3Qb0y27GRntt2u2PAYA=',
'username': '28224511:1379330808'
}
]
}
RTCPeerConnection
获得这些信息后,ICE 魔力就会自动发生。RTCPeerConnection
使用 ICE 框架确定对等点之间的最佳路径,并根据需要与 STUN 和 TURN 服务器配合使用。
STUN
NAT 会为设备提供一个 IP 地址,供其在专用本地网络中使用,但此地址无法在外部使用。如果没有公共地址,WebRTC 对等方将无法通信。为了解决此问题,WebRTC 使用 STUN。
STUN 服务器位于公共互联网上,只需执行一项简单的任务:检查传入请求(来自 NAT 后面运行的应用)的 IP:port 地址,并将该地址作为响应发回。换句话说,应用使用 STUN 服务器从公共角度发现其 IP:port。通过此过程,WebRTC 对等可以为自己获取一个可公开访问的地址,然后通过信号机制将其传递给另一个对等,以便设置直接链接。(在实践中,不同的 NAT 以不同的方式工作,并且可能存在多个 NAT 层,但原理仍然相同。)
STUN 服务器无需执行太多操作或记住太多信息,因此配置相对较低的 STUN 服务器也可以处理大量请求。
根据 Webrtcstats.com,大多数 WebRTC 通话都能使用 STUN 成功建立连接(86%),但对于位于防火墙后面且具有复杂 NAT 配置的对等设备之间的通话,成功率可能会较低。
TURN
RTCPeerConnection
会尝试通过 UDP 在对等方之间建立直接通信。如果失败,RTCPeerConnection
会改用 TCP。如果失败,TURN 服务器可用作回退,在端点之间中继数据。
再次强调一下,TURN 用于在对等方之间中继音频、视频和数据流式传输,而不是用于中继信号数据!
TURN 服务器具有公共地址,因此即使对等方位于防火墙或代理后面,也能与它们联系。TURN 服务器的任务在概念上很简单,就是中继数据流。不过,与 STUN 服务器不同,它们本身会消耗大量带宽。换句话说,TURN 服务器需要更强大。
下图展示了 TURN 的运作方式。纯 STUN 未能成功,因此每个对等方都改为使用 TURN 服务器。
部署 STUN 和 TURN 服务器
为了进行测试,Google 运行了一个公共 STUN 服务器 stun.l.google.com:19302,供 appr.tc 使用。对于生产 STUN/TURN 服务,请使用 rfc5766-turn-server。您可以在 GitHub 上找到 STUN 和 TURN 服务器的源代码,还可以找到指向多个服务器安装信息来源的链接。还提供 适用于 Amazon Web Services 的虚拟机映像。
我们提供了一个替代 TURN 服务器,可作为源代码提供,也适用于 AWS。以下是有关如何在 Compute Engine 上设置退款的说明。
- 根据需要为 tcp=443、udp/tcp=3478 打开防火墙。
- 创建四个实例,每个公共 IP 地址对应一个,使用标准 Ubuntu 12.06 映像。
- 设置本地防火墙配置(允许来自任何来源的任何连接)。
- 安装工具:
shell sudo apt-get install make sudo apt-get install gcc
- 从 creytiv.com/re.html 安装 libre。
- 从 creytiv.com/restund.html 提取退款并解压缩。/
wget
hancke.name/restund-auth.patch,并使用patch -p1 < restund-auth.patch
应用。- 运行
make
、sudo make install
以获取免费和退款。 - 根据您的需求调整
restund.conf
(替换 IP 地址,并确保它包含相同的共享密钥),然后复制到/etc
。 - 将
restund/etc/restund
复制到/etc/init.d/
。 - 配置退款:
- 设置
LD_LIBRARY_PATH
。 - 将
restund.conf
复制到/etc/restund.conf
。 - 设置
restund.conf
以使用正确的 10。IP 地址。
- 设置
- 运行退款
- 从远程机器使用桩客户端进行测试:
./client IP:port
不止于一对一:多方 WebRTC
您还可以查看 Justin Uberti 提出的 IETF 标准,了解用于访问 TURN 服务的 REST API。
不难想象,媒体在线播放的用例不仅仅局限于简单的一对一通话。例如,一群同事之间的视频会议,或者一个演讲者和数百万观看者之间的公开活动。
WebRTC 应用可以使用多个 RTCPeerConnection,以便每个端点都连接到网格配置中的每个其他端点。talky.io 等应用采用的就是这种方法,对于少数对等方来说,这种方法非常有效。此外,处理和带宽消耗会过多,尤其是对于移动客户端。
或者,WebRTC 应用也可以选择一个端点,以星形配置将数据流分发给所有其他端点。您还可以在服务器上运行 WebRTC 端点并构建自己的重新分发机制(webrtc.org 提供了示例客户端应用)。
从 Chrome 31 和 Opera 18 开始,一个 RTCPeerConnection
中的 MediaStream
可以用作另一个 RTCPeerConnection
的输入。这可以实现更灵活的架构,因为它支持 Web 应用通过选择要连接到的其他对等方来处理调用路由。如需了解此操作实例,请参阅 WebRTC 示例:对等连接中继和 WebRTC 示例:多个对等连接。
多点控制单元
对于大量端点,更好的选择是使用多点控制单元 (MCU)。这是一个服务器,可充当桥梁,在大量参与者之间分发媒体内容。MCU 可以处理视频会议中的不同分辨率、编解码器和帧速率;处理转码;执行选择性流转发;混音或录制音频和视频。对于多人通话,需要考虑许多问题,尤其是如何显示多个视频输入源和混合来自多个来源的音频。云平台(例如 vLine)也会尝试优化流量路由。
您可以购买完整的 MCU 硬件包,也可以自行组装。
您可以选择使用多种开源 MCU 软件。例如,Licode(以前称为 Lynckia)为 WebRTC 生产开源 MCU。OpenTok 使用 Mantis。
除了浏览器之外:VoIP、电话和即时通讯
由于 WebRTC 的标准化特性,因此可以在浏览器中运行的 WebRTC 应用与在其他通信平台(例如电话或视频会议系统)上运行的设备或平台之间建立通信。
SIP 是 VoIP 和视频会议系统使用的信令协议。如需实现 WebRTC Web 应用与 SIP 客户端(例如视频会议系统)之间的通信,WebRTC 需要代理服务器来中介信令。信号必须通过网关传输,但在建立通信后,SRTP 流量(视频和音频)可以直接点对点传输。
公共交换电话网 (PSTN) 是所有“老式”模拟电话的电路交换网络。对于 WebRTC Web 应用和电话之间的通话,流量必须通过 PSTN 网关。同样,WebRTC Web 应用需要中间 XMPP 服务器才能与 Jingle 端点(例如即时通讯客户端)通信。Jingle 由 Google 开发,是 XMPP 的扩展,可为即时通讯服务启用语音和视频功能。目前的 WebRTC 实现基于 C++ libjingle 库,该库是最初为 Talk 开发的 Jingle 实现。
许多应用、库和平台都利用 WebRTC 与外界通信的功能:
- sipML5:一个开源 JavaScript SIP 客户端
- jsSIP:JavaScript SIP 库
- Phono:作为插件构建的开源 JavaScript 电话 API
- Zingaya:可嵌入的手机微件
- Twilio:语音和消息功能
- Uberconference:会议
sipML5 开发者还构建了 webrtc2sip 网关。Tethr 和 Tropo 演示了使用 OpenBTS 小区的灾难通信框架,该框架可通过 WebRTC 实现功能手机与计算机之间的通信。这是一种无运营商的电话通信!
了解详情
WebRTC Codelab 提供了有关如何使用在 Node 上运行的 Socket.io 信令服务构建视频和文字聊天应用的分步说明。
2013 年 Google I/O 大会上的 WebRTC 演示,演讲者是 WebRTC 技术主管 Justin Uberti
Chris Wilson 的 SFHTML5 演示文稿 - WebRTC 应用简介
350 页的《WebRTC:HTML5 实时网络的 API 和 RTCWEB 协议》一书详细介绍了数据和信令路径,并包含许多详细的网络拓扑图。
WebRTC 和信令:两年来给我们的启示 - TokBox 博文,介绍了为何将信令从规范中移除是一个好主意
Ben Strong 的《构建 WebRTC 应用的实用指南》提供了大量有关 WebRTC 拓扑和基础架构的信息。
Ilya Grigorik 的高性能浏览器网络中的 WebRTC 章节深入介绍了 WebRTC 架构、用例和性能。