构建 WebRTC 应用所需的后端服务

什么是信号?

信号是协调通信的过程。为了让 WebRTC 应用设置通话,其客户端需要交换以下信息:

  • 用于打开或关闭通信的会话控制消息
  • 错误消息
  • 媒体元数据,例如编解码器、编解码器设置、带宽和媒体类型
  • 用于建立安全连接的关键数据
  • 网络数据,例如外界看到的主机 IP 地址和端口

此信令过程需要一种可让客户端来回传递消息的方式。该机制不是通过 WebRTC API 实现的。您需要自行构建。在本文的后面部分,您将了解构建信号服务的方法。不过,您首先需要了解一些背景信息。

为什么 WebRTC 未定义信号?

为避免冗余并最大程度地与既有技术的兼容性,WebRTC 标准未指定信号方法和协议。JavaScript 会话建立协议 (JSEP) 概述了此方法:

JSEP 的架构还避免了浏览器必须保存状态,也就是避免浏览器需要充当信号状态机。例如,如果每次页面重新加载时指示数据都会丢失,就会带来问题。相反,信号状态可以保存在服务器上。

JSEP 架构图
JSEP 架构

JSEP 要求在 offeranswer 的对等方(即上述媒体元数据)之间交换。邀约和回答通过会话描述协议 (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 的杂乱无章的内容到底是什么意思吗?请查看互联网工程任务组 (IETF) 示例

请注意,WebRTC 的设计宗旨是:先对优惠或答案进行调整,然后再将其设为本地说明或远程说明,只需修改 SDP 文本中的值即可。例如,appr.tc 中的 preferAudioCodec() 函数可用于设置默认编解码器和比特率。使用 JavaScript 操控 SDP 有点麻烦,并且正在讨论未来的 WebRTC 版本是否应改用 JSON,但继续使用 SDP 有一些优势

RTCPeerConnection API 和信号:邀约、回答和候选定位设置

RTCPeerConnection 是 WebRTC 应用用来在对等方之间创建连接以及通信音频和视频的 API。

为了初始化此过程,RTCPeerConnection 需要执行两项任务:

  • 确定本地媒体条件,例如分辨率和编解码器功能。这是用于“提供-应答”机制的元数据。
  • 获取应用主机(称为“候选”)的潜在网络地址。

确定此本地数据后,必须通过信令机制与远程对等方交换这些数据。

假设爱丽想要给夏娃打电话。以下是完整的邀约/解答机制的详尽细节:

  1. Alice 创建了一个 RTCPeerConnection 对象。
  2. Alice 使用 RTCPeerConnection createOffer() 方法创建优惠(SDP 会话说明)。
  3. Alice 拨打了setLocalDescription()的邀约。
  4. Alice 将优惠字符串化,并使用信号机制将其发送给 Eve。
  5. Eve 致电 setRemoteDescription() 并告知了 Alice 的邀约,以便她的 RTCPeerConnection 了解 Alice 的设置。
  6. Eve 调用 createAnswer(),并向该调用的成功回调传递了本地会话说明 - Eve 的答案。
  7. Eve 通过调用 setLocalDescription() 将答案设置为本地描述。
  8. 然后,夏娃使用信号机制将字符串化的回答发送给爱丽。
  9. Alice 使用 setRemoteDescription() 将 Eve 的回答设置为远程会话说明。

爱丽和夏娃还需要交换网络信息。表达式“查找候选对象”是指使用 ICE 框架查找网络接口和端口的过程。

  1. Alice 使用 onicecandidate 处理程序创建了一个 RTCPeerConnection 对象。
  2. 当候选网络可用时,系统会调用处理程序。
  3. 在处理程序中,Alice 通过其信号通道将字符串化的候选数据发送给 Eve。
  4. 当 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);
  }
};

如需查看优惠/应答流程和候选人交换流程的实际效果,请参阅 simpl.info RTCPeerConnection,并查看控制台日志中的单页视频聊天示例。如果您需要更多数据,请访问 Google Chrome 中的 about://webrtc-internals 页面或 Opera 中的 opera://webrtc-internals 页面,下载完整的 WebRTC 信号和统计信息转储。

同行发现

“怎样才能找到要交谈的人?”

对于电话通话,您需要提供电话号码和电话簿。对于在线视频聊天和消息功能,您需要身份和在线状态管理系统,以及用户发起会话的方式。WebRTC 应用需要通过某种方式让客户端互相发送信号以表明他们想要发起或加入通话。

对等发现机制并非由 WebRTC 定义,因此您无需考虑此方法。此过程可能非常简单,只需向网址发送电子邮件或发送消息即可。对于 Talkytawk.to浏览器会议等视频聊天应用,您可以通过分享自定义链接来邀请他人加入通话。开发者 Chris Ball 构建了一个有趣的 serverless-webrtc 实验,可让 WebRTC 通话参与者通过他们喜欢的任何消息传递服务(例如即时通讯、电子邮件或 homing pigeon)交换元数据。

如何构建信号服务?

重申一下,WebRTC 标准并未定义信令协议和机制。无论您如何选择,都需要通过中间服务器在客户端之间交换信令消息和应用数据。遗憾的是,Web 应用不能简单地对着互联网大声喊出“帮我联系我的朋友!”

幸运的是,信号消息很小,大多在通话开始时进行交换。在使用 appr.tc 对视频聊天会话进行测试时,信号服务总共处理了大约 30-45 条消息,所有消息的总大小约为 10KB。

WebRTC 信令服务对带宽的要求相对较低,且不会占用太多处理量或内存,因为它们只需要中继消息并保留少量会话状态数据,例如连接了哪些客户端。

将消息从服务器推送到客户端

用于信令的消息服务必须是双向的:客户端到服务器和服务器到客户端。双向通信违背了 HTTP 客户端/服务器请求/响应模型,但为了将数据从网络服务器上运行的服务推送到在浏览器中运行的 Web 应用,我们多年来开发了各种黑客手段(例如长轮询)。

最近,EventSource API广泛实现。这支持服务器发送的事件,即通过 HTTP 从网络服务器发送到浏览器客户端的数据。EventSource 专为单向消息传递而设计,但可与 XHR 结合使用来构建用于交换信令消息的服务。信号服务通过 EventSource 将消息推送给被调用方,传递调用方的消息(通过 XHR 请求传递)。

WebSocket 是一种更自然的解决方案,专为全双工客户端-服务器通信而设计,这种消息可以同时在两个方向上流动。使用纯 WebSocket 或服务器发送的事件 (EventSource) 构建的信号服务的一个优势是,这些 API 的后端可以在大多数语言(如 PHP、Python 和 Ruby)的网络托管包通用的各种 Web 框架上实现。

除 Opera Mini 以外,所有新型浏览器均支持 WebSocket,更重要的是,所有支持 WebRTC 的浏览器也都支持 WebSocket,包括桌面设备和移动设备。您应对所有连接使用 TLS,以确保邮件在未加密的情况下不会被拦截,同时可以减少代理遍历问题。(如需详细了解 WebSocket 和代理遍历,请参阅 Ilya Grigorik 的《High Performance Browser Networking》(高性能浏览器网络)中的 WebRTC 章节。)

也可以通过让 WebRTC 客户端通过 Ajax 反复轮询消息传递服务器来处理信号,但这样会产生大量冗余网络请求,这对移动设备来说尤其如此。即使已建立会话,对等方也需要在发生变化或会话被其他对等方终止时,轮询信号消息。WebRTC Book 应用示例采用此选项,并对轮询频率进行了一些优化。

规模信号

尽管信号服务在每个客户端消耗的带宽和 CPU 相对较少,但热门应用的信号服务器可能必须以高并发级别处理来自不同位置的大量消息。获得大量流量的 WebRTC 应用需要向能够处理相当负载的服务器发送信号。在这里,我不会详细介绍,但有许多方法可让您发送大量高效消息,其中包括:

(开发者 Phil Leggetter 的实时网络技术指南提供了全面的消息传递服务和库列表)。

在 Node 上使用 Socket.io 构建信号服务

下面是一个简单 Web 应用的代码,该应用使用在 Node 上使用 Socket.io 构建的信号服务。Socket.io 的设计让构建交换消息的服务变得轻松,而 Socket.io 因其内置的房间概念而特别适合 WebRTC 信号。此示例并非设计为作为生产级信号服务进行扩展,但对于相对少数的用户来说简单易懂。

Socket.io 将 WebSocket 用于以下回退方式:AJAX 长轮询、AJAX 多部分流式传输、Forever 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 库集成:

如果您根本不想编写任何代码,则可以使用 vLineOpenTokAsterisk 等公司提供的全部商业 WebRTC 平台。

记录一下,在 WebRTC 的早期,爱立信在 Apache 上使用 PHP 构建了一个信号服务器。这现在有点过时了,但如果您正在考虑类似内容,则有必要查看一下代码。

信号安全性

“安全是让一切不发生任何事情的艺术。”

Salman Rushdie

所有 WebRTC 组件都必须加密。

不过,WebRTC 标准并未定义信号机制,因此能否确保信号的安全性由您自行负责。如果攻击者设法劫持信号,则可以停止会话、重定向连接以及记录、更改或注入内容。

确保信令安全的最重要的因素是使用安全协议(HTTPS 和 WSS,例如 TLS),可确保消息在未加密的情况下不会被拦截。另外,请注意不要在广播信令消息时可被使用同一信令服务器的其他调用方访问。

收到信号后:使用 ICE 应对 NAT 和防火墙

对于元数据信号,WebRTC 应用会使用中间服务器,但对于实际的媒体和数据传输,一旦建立会话,RTCPeerConnection 会尝试直接连接客户端或点对点连接。

在更简单的情况下,每个 WebRTC 端点都有一个唯一的地址,它可以与其他对等方交换该地址,以直接通信。

简单的点对点连接
没有 NAT 和防火墙的环境

实际上,大多数设备都位于一层或多层 NAT 后,有些设备安装的杀毒软件会阻止某些端口和协议,还有很多设备都受代理和公司防火墙保护。实际上,防火墙和 NAT 可能由同一设备实现,例如家用 Wi-Fi 路由器。

NAT 和防火墙后的对等方
现实世界

WebRTC 应用可以使用 ICE 框架来解决实际网络的复杂性。为了实现这一点,您的应用必须将 ICE 服务器网址传递给 RTCPeerConnection,如本文所述。

ICE 会尝试找到连接对等设备的最佳路径。它会并行尝试所有可能性,并选择最有效的有效方案。ICE 首先会尝试使用从设备的操作系统和网卡获取的主机地址建立连接。如果连接失败(对于 NAT 后面的设备会出现这种情况),ICE 会使用 STUN 服务器获取一个外部地址,如果失败,流量会通过 TURN 中继服务器进行路由。

换言之,STUN 服务器用于获取外部网络地址,TURN 服务器用于在直接(点对点)连接失败时中继流量。

每个 TURN 服务器都支持 STUN。TURN 服务器是具有额外内置中继功能的 STUN 服务器。ICE 还可以应对 NAT 设置的复杂性。实际上,NAT 穿孔可能不仅仅需要公共 IP:端口地址。

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 服务器。

眩晕

NAT 为设备提供在专用本地网络内使用的 IP 地址,但不能在外部使用该地址。如果没有公开地址,WebRTC 对等方就无法进行通信。为了解决此问题,WebRTC 使用了 STUN

STUN 服务器位于公共互联网上,并且有一项简单的任务:检查传入请求(来自在 NAT 后面运行的应用)的 IP:端口地址,然后将其作为响应发回。换句话说,应用使用 STUN 服务器从公共角度发现其 IP:端口。此过程使 WebRTC 对等方能够为自身获取可公开访问的地址,然后通过信令机制将该地址传递给其他对等方,以设置直接链路。(实际上,不同的 NAT 以不同的方式工作,并且可能有多个 NAT 层,但原则仍然相同。)

STUN 服务器不必执行太多操作或记住很多,因此规格相对较低的 STUN 服务器可以处理大量请求。

大多数 WebRTC 调用成功使用 STUN 建立连接,根据 Webrtcstats.com 的数据显示,此调用的成功率为 86%,但对于位于防火墙和复杂 NAT 配置的对等方之间的调用而言,这一结果可能会低于此百分比。

使用 STUN 服务器的点对点连接
使用 STUN 服务器获取公共 IP:端口地址

TURN

RTCPeerConnection 尝试通过 UDP 在对等方之间建立直接通信。如果失败,RTCPeerConnection 会求助于 TCP。如果失败,可将 TURN 服务器用作后备,在端点之间中继数据。

重申一下,TURN 用于在对等设备之间中继音频、视频和数据流,而不是发送数据!

TURN 服务器具有公共地址,因此,即使对等方设有防火墙或代理,对等方也可以与之通信。TURN 服务器有一个概念上简单的任务:中继流。但是,与 STUN 服务器不同,它们本身就占用大量带宽。换言之,TURN 服务器需要更强大。

使用 STUN 服务器的点对点连接
完整的 Monty:STUN、TURN 和 Signaling

此图显示了 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 上设置 RESTund 的说明。

  1. 根据需要为 tcp=443、udp/tcp=3478 打开防火墙。
  2. 创建四个实例,每个实例对应一个公共 IP 标准 Ubuntu 12.06 映像。
  3. 设置本地防火墙配置(允许任意一项)。
  4. 安装工具: shell sudo apt-get install make sudo apt-get install gcc
  5. 访问 creytiv.com/re.html 安装 libre。
  6. creytiv.com/restund.html 获取其余内容并解压缩。/
  7. wget hancke.name/restund-auth.patch 并使用 patch -p1 < restund-auth.patch 应用。
  8. 针对 libre 和 RESTund 运行 makesudo make install
  9. 根据您的需求调整 restund.conf(替换 IP 地址并确保其包含相同的共享密钥),并将其复制到 /etc
  10. restund/etc/restund 复制到 /etc/init.d/
  11. 配置 RESTund:
    1. 设置 LD_LIBRARY_PATH
    2. restund.conf 复制到 /etc/restund.conf
    3. restund.conf 设置为使用正确的 10。IP 地址。
  12. 运行休息
  13. 使用远程计算机中的 Stund 客户端进行测试:./client IP:port

超越一对一:多方 WebRTC

您可能还想了解一下 Justin Uberti 为用于访问 TURN 服务的 REST API 提议的 IETF 标准。

可以简单想象一下媒体流式传输的使用场景,而不只是简单的一对一呼叫。例如,一群同事召开的视频会议,或有一位发言者与数百或数百万观看者进行的公开活动。

WebRTC 应用可以使用多个 RTCPeerConnection,以便每个端点都连接到网格配置中的每一个其他端点。这是 talky.io 等应用所采用的方法,对少数类似应用来说效果非常好。除此之外,处理和带宽消耗也会变得过高,移动客户端更是如此。

网状网:小 N 向通话
全网状拓扑:所有人都能连接到所有人

或者,WebRTC 应用也可选择一个端点,以星形配置将视频流分发到所有其他端点。您还可以在服务器上运行 WebRTC 端点并构建您自己的重新分发机制(webrtc.org 提供了一个示例客户端应用)。

自 Chrome 31 和 Opera 18 起,一个 RTCPeerConnection 中的 MediaStream 可用作另一个 RTCPeerConnection 的输入。这样可以实现更灵活的架构,因为它使 Web 应用能够通过选择要连接到哪个其他对等网络来处理调用路由。如需查看实际运作方式,请参阅对等连接中继示例 WebRTC多个对等连接示例

多点控制单元

对于大量端点,较好的选择是使用多点控制单元 (MCU)。此服务器充当在大量参与者之间分发媒体的桥梁。MCU 可以适应视频会议中的不同分辨率、编解码器和帧速率;处理转码;执行选择性流转发;以及混音或录制音频和视频。对于多方通话,需要考虑许多问题,特别是如何显示多个视频输入以及混合来自多个来源的音频。云平台(如 vLine)也会尝试优化流量路由。

您可以购买完整的 MCU 硬件软件包,也可以自行组装。

Cisco MCU5300 的后视图
Cisco 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 端点(例如 IM 客户端)进行通信。Jingle 由 Google 开发,是对 XMPP 的扩展,可为消息传递服务启用语音和视频功能。当前的 WebRTC 实现是以 C++ libjingle 库为基础,该库是最初为 Talk 开发的 Jingle 实现。

许多应用、库和平台都利用 WebRTC 与外界通信的功能:

sipML5 开发者还构建了 webrtc2sip 网关。Tethr 和 Tropo 使用 OpenBTS 手机“在公文包中”演示了灾难通信框架,该框架支持功能手机和计算机之间的通过 WebRTC 通信。这就是没有运营商的电话通信!

了解详情

WebRTC Codelab 提供了有关如何使用在 Node 上运行的 Socket.io 信号服务构建视频和文本聊天应用的分步说明。

2013 年 Google I/O 大会 WebRTC 演讲,WebRTC 技术主管 Justin Uberti

Chris Wilson 的 SFHTML5 演示文稿 - WebRTC 应用简介

WebRTC:HTML5 实时 Web 的 API 和 RTCWEB 协议一书共 350 页,其中详细介绍了数据和信号路径,并提供了一些详细的网络拓扑图。

WebRTC 和信号:2 年的经验教训 - TokBox 博文,介绍了为什么不遵循规范是个好主意

Ben Strong 的 《构建 WebRTC 应用的实用指南》提供了大量有关 WebRTC 拓扑和基础架构的信息。

Ilya Grigorik 的 《高性能浏览器网络》中的 WebRTC 章节深入介绍了 WebRTC 架构、用例和性能。