构建WebRTC应用程序所需的后端服务——STUN, TURN, and signaling

开篇导读,这篇是从 https://www.html5rocks.com/en/tutorials/webrtc/infrastructure/ 搬运翻译过来的,属于WebRTC理论入门,感觉属于把webrtc说得比较通透清楚的一篇文章。往后再学习基于操作系统移植的SDK就更轻松了。

WebRTC支持对等通信,但是它仍然需要服务器,以便客户端可以交换元数据以通过称为信令的过程协调通信,并应对网络地址转换器(NAT)和防火墙。本文向您展示如何构建信令服务,以及如何处理与STUN和TURN服务器的真实连接的问题。它还说明了WebRTC应用程序如何处理多方通话并与VoIP和PSTN(也称为电话)之类的服务进行交互。如果您不熟悉WebRTC的基础知识,请在阅读本文之前参阅 我翻译的WebRTC入门 / 原英文链接 Get started with WebRTC

什么是信令?

信令是协调通信的过程。为了使WebRTC应用程序能够建立呼叫,其客户需要交换以下信息:

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

该信令传递过程需要一种方便客户端之间来回传递消息的方式。 WebRTC API未实现该机制。您需要自己构建它。在本文的后面,您将学习构建信令服务的方法。但首先,您需要一些上下文作为前提条件。

为什么WebRTC没有定义信令?

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

WebRTC呼叫设置背后的想法是完全指定和控制媒体平面,但将信令平面尽可能地留给应用程序。理由是,不同的应用可能更喜欢使用不同的协议,例如现有的SIP或Jingle呼叫信令协议,或为特定应用定制的某种东西,可能是针对新颖的用例。在这种方法中,需要交换的关键信息是多媒体会话描述,它指定了建立媒体平面所需的必要传输和媒体配置信息。

JSEP的体系结构还避免了浏览器必须保存状态(即充当信令状态机)。如果,例如每次重新加载页面时信号数据丢失,这将是有问题的。相反,可以将信令状态保存在服务器上。

JSEP要求在 offer要约 answer答案 的同级之间交换,即上面提到的媒体元数据。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 gobbledygook实际意味着什么?看一下 Internet Engineering Task Force (IETF) examples. Internet工程任务组(IETF)的示例。

请记住,WebRTC经过精心设计,因此可以通过编辑SDP文本中的值来调整要约或答案,然后再将其设置为本地或远程描述。例如,appr.tc中的 preferredAudioCodec 函数可用于设置默认编解码器和比特率。JavaScript解析使用SDP是有点痛苦,并且正在讨论将来的WebRTC版本是否应该使用JSON,但是坚持使用SDP有一些自身 优点 。

RTCPeerConnection API 和 信令signaling: Offer, answer, 和 candidate

RTCPeerConnection是WebRTC应用程序使用的API,用于在对等方之间创建连接并进行音频和视频通信。要初始化此过程,RTCPeerConnection有两个任务:

  • 确定本地媒体条件,例如分辨率和编解码器功能。这是用于 offer-and-answer 机制的元数据。
  • 获取应用程序主机的潜在网络地址,称为候选地址。

一旦确定了该本地数据,就必须通过信令机制与远程对等方交换该本地数据。想象一下 Alice 尝试給 Eve打电话 。这是完整的报价/解答机制的所有细节:

  1. Alice 创建 RTCPeerConnection 对象。
  2. Alice 使用RTCPeerConnection createOffer方法创建 offer (SDP会话描述) 。
  3. Alice 通过她的 offer 呼叫setLocalDescription。
  4. Alice 对 offer 进行字符串化处理,并使用信令机制将其发送给 Eve.

  5. Eve 调用 setRemoteDescription() 设置Alice的offer, 以便Eve她自己的RTCPeerConnection知道Alice的设置。
  6. Eve 调用 createAnswer() 并且此操作的成功回调传递给本地会话描述——Eve的answer。
  7. Eve 通过调用 setLocalDescription()将answer设置为本地描述。
  8. 然后Eve 使用信令机制将她的已回答答案发送给爱丽丝。
  9. Alice 使用setRemoteDescription()将Eve 的offer设置为远程会话描述。

Alice 和 Eve也需要交换网络信息。“finding candidates 查找候选对象” 这一描述就是指使用 ICE 框架.查找网络接口和端口的过程。

  1. Alice 创建RTCPeerConnection 对象并附带 onicecandidate 的处理回调.
  2. 当网络候选项可用时,将调用onicecandidate 处理程序。
  3. onicecandidate 的处理程序中,Alice 通过其信令通道将字符串化的候选数据发送给Eve。
  4. 当Eve从Alice那里收到候选消息时,她调用addIceCandidate 将候选者添加到远程对等项描述中。

JSEP支持ICE Candidate Trickling,这使呼叫者可以在初始化offer之后逐步向被呼叫者提供候选者,并且让被叫方开始在通话中采取行动并建立连接,而不必等待所有候选者都到达。

Code WebRTC for signaling 

以下代码段是一个W3C代码示例,概述了完整的信令过程。该代码假定存在某种信令机制 SignalingChannel。信令将在后面详细讨论。

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stuns: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的chrome:// webrtc-internals页面或Opera的Opera://webrtc-internals页面下载完整的WebRTC信号和统计信息转储。

Peer discovery 发现对端

一种奇怪的提问方式:“我如何找到要交谈的人?”

对于电话,您具有电话号码和目录。对于在线视频聊天和消息传递,您需要身份和状态管理系统,以及用户发起会话的方式。WebRTC应用程序需要一种方法,使客户端可以相互发出信号,表示他们要开始或加入呼叫。对等发现机制不是WebRTC定义的,在此不做介绍。该过程可以像通过电子邮件发送或传递URL一样简单。例如 Talkytawk.to and Browser Meeting, 您可以通过共享自定义链接邀请其他人加入通话。开发人员Chris Ball建立了一个有趣的无服务器Webrtc实验  serverless-webrtc ,该实验使WebRTC呼叫参与者可以通过他们喜欢的任何消息传递服务(例如IM,电子邮件或归巢鸽)交换元数据。

How can you build a signaling service? 如何建立信令服务?

重申一下,WebRTC标准未定义信令协议和相关机制。无论您选择什么,都需要一个中间服务器来在客户端之间交换信令消息和应用程序数据。可悲的是,一个互联网应用程序不能简单地向互联网大喊:“将我连接到我的朋友!”   值得庆幸的是,信令消息很小,并且大多在通话开始时进行交换。在使用 appr.tc 测试视频聊天会话时,信令服务处理了大约30-45条消息,所有消息的总大小约为10KB。除了带宽方面相对不那么昂贵之外,WebRTC信令服务不会消耗太多的处理或内存,因为它们仅需要中继消息并保留少量会话状态数据(例如连接了哪些客户端)。

TIPS:用于交换会话元数据的信令机制也可以用于传达应用程序数据。这只是一个消息传递服务!

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

 用于信令的消息服务必须是双向的,客户端到服务器以及服务器到客户端。双向通信违反HTTP客户端/服务器请求/响应模型,但是,为了将数据从Web服务器上运行的服务推送到浏览器中运行的Web应用程序,多年来已经开发出各种黑客手段,例如长轮询 long polling 。

最近,EventSource API 已被广泛实现。这将使得 通过HTTP服务器发送的事件/数据到浏览器客户端成为可能。EventSource专为单向消息传递而设计,但是它可以与XHR结合使用,以构建用于交换信令消息的服务。信令服务通过XHR请求传递来的消息,将其通过EventSource推送到被叫方,从而传递来自呼叫方的消息。(原文:A signaling service passes a message from a caller, delivered by XHR request, by pushing it through EventSource to the callee.)

WebSocket 是一种更自然的解决方案,专为全双工客户端与服务器之间的通信而设计的消息,这些消息可以同时在两个方向上流动。使用纯WebSocket或服务器发送的事件(EventSource)构建的信令服务的一个优势是,这些API的后端可以在大多数Web托管程序包所通用的各种Web框架上实现,这些程序包适用于PHP,Python和Ruby之类的语言。 除Opera Mini以外的所有现代浏览器均支持WebSocket,而且更重要的是,所有支持WebRTC的浏览器也都支持WebSocket,在台式机和移动设备上都可以。即使建立了会话之后,在其他对等方更改或终止会话的情况下,对等方也需要轮询信令消息。WebRTC Book 应用程序示例采用了此选项,并对轮询频率进行了一些优化。

Scale signaling 规模化信号

尽管信令服务器上,每个客户端消耗的带宽和CPU相对较少,热门的应用程序的信令服务器可能必须以高并发级别处理来自不同位置的大量消息。流量很多的WebRTC应用程序需要能够处理大量负载的信令服务器。在这里不做详细介绍,但对于高容量高性能的消息传递服务,有很多选项,包括:

  • eXtensible Messaging and Presence Protocol (XMPP),最初称Jabber——即时消息传递而开发的协议,可用于发送信号(服务器实现包括 ejabberd and Openfire. JavaScript 客户端,例如 Strophe.js, 使用 BOSH 模拟双向流,但是由于各种原因, BOSH 可能不如WebSocket高效,出于相同的原因,可能无法很好地扩展。) (在另外一个方向上, Jingle是XMPP扩展,用于启用语音和视频。 WebRTC项目使用libjingle库(Jingle的C ++实现)中的网络和传输组件。)
  • 开源库,例如 ZeroMQ 和 OpenMQ (NullMQ 使用WebSocket上的 STOMP 协议 将ZeroMQ概念应用于Web平台)
  • 使用WebSocket的商业云消息平台 (尽管它们可能会退回长轮询机制) 例如 PusherKaazing, 和 PubNub (PubNub also has an API for WebRTC.)
  • 商业WebRTC平台,例如 vLine

(开发人员Phil Leggetter的《实时Web技术指南—Real-Time Web Technologies Guide 》提供了消息服务和库的完整列表。)

 

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

以下是一个简单的Web应用程序的代码,该应用程序使用在Node上使用Socket.io构建的信令服务。Socket.io的设计使构建服务以交换消息变得简单,并且Socket.io由于其内置的房间概念而特别适合WebRTC信令。此示例并非旨在扩展为生产级别的信令服务,但对于相对较少的用户情况而言,这是最简单易懂的了。Socket.io使用WebSocket进行备用:AJAX长轮询,AJAX多重流化,和JSONP轮询。它已被移植到各种后端,但是可能以在此示例中使用的Node版本而闻名。

此示例中没有WebRTC。它仅用于显示如何在网络应用程序中构建信号。查看控制台日志,以查看客户端加入会议室并交换消息时发生的情况。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。它仅在本示例中使用。)要在本地机器上运行此应用程序,您需要安装Node,Socket.IO和node-static。可以从  Node.js  下载Node(安装非常简单快捷)。要安装Socket.IO和节点静态,请从您应用目录中的终端运行Node Package Manager:

npm install socket.io
npm install node-static

要启动服务器,请在您的应用目录中的终端上运行以下命令:

node server.js

在您的浏览器中,打开 localhost:2013 在任何浏览器中打开新标签或窗口,然后再次打开localhost:2013。要查看发生了什么,请检查控制台。在Chrome和Opera中,您可以使用Ctrl + Shift + J(在Mac上为Command + Option + J)打开开发者工具访问控制台。无论选择哪种信令方法,后端和客户端应用程序(至少)都需要提供类似于此示例的服务。

Signaling gotchas 信号陷阱

  • 在调用setLocalDescription()之前,RTCPeerConnection不会开始收集候选对象。这是 JSEP IETF draft.草案中规定的。
  • 利用好Trickle ICE。 接收到候选者candidates之后尽快调用 addIceCandidate()。(原文 Take advantage of Trickle ICE. Call addIceCandidate as soon as candidates arrive.)

Readymade signaling servers现成的信令服务器

如果您不想自己动手,这里有几种现成的WebRTC信令服务器,它们像上例一样使用Socket.IO,并与WebRTC客户端JavaScript库集成在一起:

  • webRTC.io 是WebRTC的第一个抽象库之一。
  • Signalmaster 是创建用于SimpleWebRTC JavaScript客户端库的信令服务器。

如果您根本不想编写任何代码,可以从 vLineOpenTok, and Asterisk.等公司获得完整的商业WebRTC平台。

作为记录参考,爱立信在WebRTC的早期使用Apache在Apache上构建了一个信号服务器。现在这已经过时了,但是如果您正在考虑类似的内容,那么值得看一下代码。

After signaling: 使用ICE应对NAT和防火墙

对于元数据信令,WebRTC应用程序使用中间服务器,但是对于会话建立后的实际媒体和数据流,RTCPeerConnection尝试直接连接客户端或对等连接。在更简单的环境中,每个WebRTC端点都将具有一个唯一的地址,可以与其他对等方交换该地址以便直接进行通信。

然而在实际环境上,大多数设备都位于一层或多层NAT的后面,有些具有阻止某些端口和协议的防病毒软件,而且很多都在代理和公司防火墙后面。实际上,防火墙和NAT可以由同一设备(例如家庭WIFI路由器)实现。(如下图所示)

WebRTC应用程序可以使用ICE框架来克服现实世界中网络的复杂性。为了做到这一点,如本文所述,您的应用必须将ICE服务器URL传递给RTCPeerConnection。ICE试图找到连接对等方的最佳路径。它并行尝试所有可能性,并选择最有效的选择。ICE首先尝试使用从设备的操作系统和网卡获得的主机地址进行连接。如果失败(就是那些在NAT之后的设备),则使用STUN服务器获取外部地址,如果失败,则将流量通过TURN中继服务器进行路由。换句话说,如果直接(对等)连接失败,则将STUN服务器用于获取外部网络地址,并使用TURN服务器来中继转发流量。

每个TURN服务器都支持STUN。TURN服务器可以理解为是具有附加内置转发功能的STUN服务器。ICE还可以应对NAT设置的复杂性。实际上,NAT打孔可能不仅仅需要一个公共IP:端口地址。(还需要以下所说的stun服务器配置信息)

STUN和/或TURN服务器的URL由(可选)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'
    }
  ]
}

注意:TURN凭证示例是有时间限制的,并且已于2013年9月到期。TURN服务器的运行成本很高,您需要购买自己的服务器或寻找服务提供商。要测试凭据,您可以使用候选者收集样本 candidate gathering sample 并检查您是否获得了类型为Relay的候选者。

一旦RTCPeerConnection获得了该信息,ICE框架就会自动启动魔术。 RTCPeerConnection使用ICE框架找出对等点之间的最佳路径,并在必要时使用STUN和TURN服务器。

STUN

NAT为设备提供IP地址,以供在专用局域网中使用,但是此地址不能在外部使用。没有公共地址,WebRTC对等方将无法通信。为解决此问题,WebRTC使用STUN服务器。

STUN服务器位于公共互联网上,并且有一个简单的任务——检查传入请求的IP:端口地址(从运行在NAT后面的应用程序)并发回该地址作为回应。换句话说,该应用程序使用STUN服务器从公共角度发现其IP:端口。通过此过程,WebRTC对等方可以获得自己的公共可访问地址,然后通过信令机制将其传递给另一个对等方,以建立直接链接。(实际上,不同的NAT以不同的方式工作,并且可能有多个NAT层,但是原理仍然相同)。STUN服务器不必做很多事情或记住很多事情,因此规格较低的STUN服务器也可以处理大量请求。

TURN

RTCPeerConnection尝试通过UDP建立对等方之间的直接通信。如果失败,则RTCPeerConnection求助于TCP。如果失败,则可以将TURN服务器用作后备,在端点之间中继数据。这里申明一下,TURN用于中继对等方之间的音频,视频和数据流,而不是发送信令数据!

TURN服务器具有公共地址,因此即使对等点位于防火墙或代理之后,对等点也可以与它们联系。TURN服务器在概念上很简单—中继流。但是,与STUN服务器不同,它们固有地消耗大量带宽。换句话说,TURN服务器需要更强大的网络资源。

该图显示了TURN的作用。纯STUN未能成功,因此每个对等方都使用TURN服务器。

部署STUN和TURN服务器

为了进行测试,Google运行了一个由 appr.tc 使用的公共STUN服务器stun.l.google.com:19302。对于生产环境的STUN / TURN服务,请使用 rfc5766-turn-server。 GitHub 上提供了STUN和TURN服务器的源代码,您还可以在其中找到指向有关服务器安装信息的多个信息源的链接。 VM image for Amazon Web Services is also available。

备用的TURN服务器称为restund,可以作为 source code 使用,也可以用于AWS。以下是有关如何在计算引擎上设置Restund的说明。

  1. 根据需要为tcp = 443,udp / tcp = 3478打开防火墙。
  2. 创建四个实例,每个公共IP一个实例,标准Ubuntu 12.06映像。
  3. 设置本地防火墙配置(从ANY进允许ANY出)。
  4. 安装工具:
    sudo apt-get install make
    sudo apt-get install gcc
  5. 从 creytiv.com/re.html. 安装 libre
  6. 从 creytiv.com/restund.html 获取restund并解压缩。
  7. wget hancke.name/restund-auth.patch 然后申请打补丁 patch -p1 < restund-auth.patch.
  8. 运行 makesudo make install for libre and restund.
  9. 使restund.conf适应您的需要(替换IP地址并确保它包含相同的共享机密)并复制到/ etc。
  10. 复制 restund/etc/restund 到 /etc/init.d/.
  11. 配置 restund:
    a. Set LD_LIBRARY_PATH.
    b. Copy restund.conf to /etc/restund.conf.
    c. Set restund.conf to use the right 10. IP address.
  12. 运行restund
  13. 使用远程计算机上的stund客户端进行测试: ./client IP:port

一对一之外:多方WebRTC Multiparty WebRTC

您可能还想看看Justin Uberti提出的用于REST API的IETF标准,以访问TURN服务,REST API for access to TURN Services.  。可以轻松想象出 一对多调用的媒体流用例。例如,一组同事之间的视频会议或一个发言人与数以百万计的观众之间的公共活动。

WebRTC应用程序可以使用多个RTCPeerConnections,以便每个端点都可以连接到网格配置中的每个其他端点。这是诸如talky.io之类的应用所采用的方法,对于少数同时期应用来说效果非常好。除此之外,处理和带宽消耗变得过多,尤其是对于移动客户端。或者,WebRTC应用程序可以选择一个端点以星型配置将流分发给所有其他端点。也可以在服务器上运行WebRTC端点并构建自己的重新分配机制(webrtc.org提供了一个客户端应用程序示例  sample client app )。

从Chrome 31和Opera 18开始,来自另外一端的RTCPeerConnection的MediaStream可以用作一个新的输入。这可以启用更灵活的体系结构,因为它使Web应用程序可以通过选择要连接到的其他对等方来处理呼叫路由。要查看实际效果,可以查阅 WebRTC samples Peer connection relay and WebRTC samples Multiple peer connections.

多点控制单元 Multipoint Control Unit

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

您可以购买完整的MCU硬件套件或自行构建。提供了几种开源MCU软件选项。例如,Licode(以前称为Lynckia)为WebRTC生产一个开源MCU。 

浏览器之外:VoIP,电话和消息传递

WebRTC的标准化性质使在浏览器中运行的WebRTC应用程序与在另一个通信平台(例如电话或视频会议系统)上运行的设备或平台之间建立通信成为可能。SIP 是VoIP和视频会议系统使用的信令协议。为了启用WebRTC Web应用程序和SIP客户端(例如视频会议系统)之间的通信,WebRTC需要代理服务器来中介信令。信令必须流经网关,但是一旦建立了通信,SRTP流量(视频和音频)就可以直接对等流动。

公共交换电话网 Public Switched Telephone Network (PSTN) 是所有老旧的台式模拟电话的电路交换网。对于WebRTC Web应用程序与电话之间的通话,流量必须通过PSTN网关。同样,WebRTC Web应用程序需要一个中间XMPP服务器才能与 Jingle  端点(例如IM客户端)进行通信。Jingle由Google开发,是XMPP的扩展,可为消息传递服务启用语音和视频。当前的WebRTC实现基于C ++ libjingle 库,它是最初为Talk开发的Jingle的实现。

许多应用程序,库和平台都利用WebRTC与外界进行通信的能力:

sipML5开发人员还构建了 webrtc2sip 网关。Tethr和Tropo已经展示了一个“在公文包里”(原文 "in a briefcase",应该是指很老的台式机上) 使用OpenBTS cell 进行灾难通信的框架 a framework for disaster communications,以使功能电话和计算机之间可以通过WebRTC进行通信。那是没有承运人的电话通讯!

Find out more

The WebRTC codelab provides step-by-step instructions for how to build a video and text chat app using a Socket.io signaling service running on Node.

Google I/O WebRTC presentation from 2013 with WebRTC tech lead, Justin Uberti

Chris Wilson's SFHTML5 presentation—Introduction to WebRTC Apps

The 350-page book WebRTC: APIs and RTCWEB Protocols of the HTML5 Real-Time Web provides a lot of detail about data and signaling pathways, and includes a number of detailed network topology diagrams.

WebRTC and Signaling: What Two Years Has Taught Us—TokBox blog post about why leaving signaling out of the spec was a good idea

Ben Strong's A Practical Guide to Building WebRTC Apps provides a lot of information about WebRTC topologies and infrastructure.

The WebRTC chapter in Ilya Grigorik's High Performance Browser Networking goes deep into WebRTC architecture, use cases, and performance.

猜你喜欢

转载自blog.csdn.net/a360940265a/article/details/114648590
今日推荐