前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >WebRTC中的信令和内网穿透技术 STUN / TURN

WebRTC中的信令和内网穿透技术 STUN / TURN

作者头像
全栈程序员站长
发布于 2022-09-13 01:35:27
发布于 2022-09-13 01:35:27
6.2K02
代码可运行
举报
运行总次数:2
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

Translated from WebRTC in the real world: STUN, TURN and signaling. 最近刚接触到WebRTC,网上看到这篇介绍WebRTC的文章不错,仔细读了读还算有用,分享出来能帮到一些刚入门的人也挺好的,翻译不好的地方可以直接看原文。

WebRTC可以进行P2P点对点通信,但是WebRTC仍然需要服务器

  • 客户端需要服务器交换一些数据来协调通信,这称之为信令。
  • 使用服务器来应对NAT网络地址转换和防火墙

在本文中,将介绍如何构建信令服务,以及如何使用STUN和TURN服务器来处理WebRTC在实际使用过程中的连接问题。本文还将解释WebRTC应用程序如何处理多方通话,并与诸如VoIP和PSTN(AKA电话)之类的服务进行交互。 如果您不熟悉WebRTC的基本知识,我们强烈建议您在阅读本文之前先看一下如何开始使用WebRTC。

什么是信令?

信令用于协调通信,WebRTC应用开始通话之前,客户端需要交换一些信息(信令):

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

客户端之间来回传递这些消息需要实现一种信令通信方式,但是WebRTC的API并没有实现信令通信机制,所以使用者需要自己去实现。下面会介绍一些构建信令服务的方法,但是这里可以先了解一下这些背景。

WebRTC为什么不规定信令标准?

为了避免冗余并提高与已有技术的兼容性,WebRTC标准未规定信令方法和协议。JavaScript会话建立协议(JSEP)描述了一种大致的方法:

WebRTC设计思想是完全指定和控制媒体层面,把信令层面尽可能的交给应用去实现。这是因为不同的应用程序可能更喜欢使用不同的信令协议,比如已经存在的SIP或者Jingle信令协议,抑或一些针对应用定制的协议。在这种方法中,需要交换的关键信息是多媒体会话描述,它指定了建立媒体连接所必需的传输和媒体配置信息。

JSEP的体系结构使浏览器不必保存状态:也就是说,作为一个信令状态机,如果在每次重新加载页面时丢失信令数据,这将是有问题的。相反,可以在服务器上保存信令状态。

JSEP 架构

JSEP需要在 offer / 提议answer / 应答 的点与点之间交换上文提到的媒体元数据信息。交换信息的两个点之间使用SDP会话描述协议进行通信。SDP协议消息格式大概是这个样子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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官方文档,点这里 SDP for the WebRTC

WebRTC被设计成可以通过修改一些SDP文本中的值来调整会话,使用JavaScript操作SDP有点麻烦,也有讨论WebRTC的未来版本是否应该使用JSON代替SDP,但目前因为使用这个方法还有一些优点所以坚持使用SDP。

RTCPeerConnection + 信令:offer(提议)、answer(应答)和candidate(候选地址)

这几个词翻译过来也不好理解,算了不翻译了。还有那个P2P的peer就先翻译为端点吧,总不能直接说是个P。

RTCPeerConnection是WebRTC应用程序在点对点之间创建连接并传送音频和视频的API。 要想创建音视频通信连接,RTCPeerConnection有两个任务:

  • 确定本地媒体信息,例如分辨率和编解码器信息。这是用于offer和answer机制的元数据。
  • 获取应用程序主机的网络地址,称为candidate。

一旦确定了本地数据,就必须通过信令机制与远程端点的进行交换。 假如有这么一个场景,Alice尝试与Eve进行通话,下面是完整的 offer / answer 机制的细节:

  1. Alice创建了一个RTCPeerConnection对象。
  2. Alice使用RTCPeerConnectioncreateOffer()方法创建了一个offer(一个SDP会话描述文本)。
  3. Alice调用setLocalDescription()将她的offer设置为本地描述。
  4. Alice把offer转换为字符串,并使用信令机制将其发送给Eve。
  5. Eve对Alice的offer调用setRemoteDescription()函数,为了让他的RTCPeerConnection知道Alice的设置。
  6. Eve调用createAnswer()函数创建answer
  7. Eve通过调用setLocalDescription()将她的answer设置为本地描述。
  8. Eve使用信令机制把她字符串化的的answer传给Alice。
  9. Alice使用setRemoteDescription()函数将Eve的answer设置为远程会话描述。

Alice和Eve也需要去交换网络信息。“查找候选地址candidate”一词是指使用ICE框架查找网络接口和端口的过程。

  1. Alice创建RTCPeerConnection对象的时候会生成一个onicecandidate句柄。
  2. 这个句柄在网络candidate生效时会被调用。
  3. Alice通过信令通道将字符串化的candidate数据发送给Eve。
  4. 当Eve从Alice获取candidate消息时,她调用addIceCandidate(),将candidate添加到远程对等描述中。

JSEP支持ICE Candidate Trickling,它允许调用方在初始化 offer 之后递增地向被调用方提供候选地址candidate,并且允许被调用方在没有等待所有候选地址candidate到达的情况下开始进行操作并建立连接。

关于信令的WebRTC代码

下面这段代码总结了信令的完整过程,这段代码假定存在SignalingChannel信令机制。后面会详细讨论信令。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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);

// 给另外一个端点发送candidate
pc.onicecandidate = ({ 
   candidate}) => signaling.send({ 
   candidate});

// 让"negotiationneeded"事件触发生成offer
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);
  }
};

// 一旦远程媒体到达,就把它放在远程视频元素结构中
pc.ontrack = (event) => { 
   
  // don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// 调用 start() 进行初始化
async function start() { 
   
  try { 
   
    // 获取本地流,把它显示在本地视频窗口中并发送出去
    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) { 
   
      // 如果收到一个offer,就需要响应一个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/pc提供一个WebRTC视频聊天的示例程序,可以在这页面直观感受一下视频聊天的过程(电脑需要有摄像头并且允许浏览器使用)。如果你想查看视频对话的过程中offer/answercandidate的交互过程log,可以从下面的页面查看或者下载一个完整的WebRTC信令和统计表格:Chrome浏览器进入这个页面chrome://webrtc-internals,Opera浏览器进入这个页面opera://webrtc-internals。(先打开前面的视频对话的网页开启视频对话,然后打开后面的地址可以查看详细交互信息)。

Peer Discovery / 对点发现机制

这是一种奇特的说法 – 我如何找人交谈? 对于打电话,我们有电话号码或者查询号码簿。对于在线视频聊天和消息传递,我们需要身份和状态管理系统,以及用户启动会话的方法。WebRTC应用程序需要一种方法让客户向他们想要发起或加入会议的其他人发送信号。

WebRTC没有规定对点发现机制,该过程可以像通过电子邮件发送URL一样简单。视频聊天应用可以把每个会议用一个URL进行表示,参加会议的人通过点击这个URL就可以进行视频会议了。开发人员Chris Ball构建了一个有趣的无服务器WebRTC测试,使WebRTC参会者能够通过他们喜欢的任何消息服务交换元数据,例如IM,电子邮件等。

如何建立信令服务?

注意!WebRTC标准没有定义信令协议和机制。 无论您选择哪种实现方式,您都需要一个中间服务器来在客户端之间交换信令消息和应用程序数据。因为在一个网络应用程序不能简单地向互联网喊“把我连接到我的朋友”就可以连接的。(歪果仁的脑回路确实清奇) 值得庆幸的是,信令消息通常很小,并且主要在呼叫开始时进行交换。在使用appr.tc进行测试时发现,对于视频聊天会话,信令服务总共处理了大约30-45条消息,所有消息的总大小也就10kB左右。 WebRTC信令服务不仅带宽占用得少,而且使用的内存资源等也都非常少,因为他只需要中继消息并保留少量的会话状态数据(例如连接的客户端)。

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

用于信令的消息服务应该是双向的:客户端到服务器和服务器到客户端。这种双向通信违背了HTTP C/S 请求/响应模型,但是为了将数据从Web服务器推送到浏览器应用上,多年来已经开发了诸如长轮询之类的技术

最近, EventSource API已经得到广泛应用。这这个API启用了“server-sent events”:通过HTTP从Web服务器连续向浏览器客户端发送数据。EventSource是为单向消息传递而设计的,但是它可以与XHR结合使用,以构建用于交换信令消息的服务:信令服务通过将消息通过EventSource推送到被调用方,从调用方传递由XHR请求传递的消息。

WebSocket是一种更自然的解决方案,就是为了全双工的客户端-服务器通信(消息可以同时双向流动)而设计的。使用纯WebSocket或Server-Sent Events(EventSource)构建的信号服务的一个优点是,这些API的后端可以使用PHP、Python和Ruby等语言,可以在大多数常用的Web框架上实现。

目前,大约四分之三的浏览器支持WebSocket,更重要的是,无论是在桌面还是移动设备上,支持WebRTC的所有浏览器也支持WebSocket。所有的链接都应该使用TLS以确保不被拦截到未加密的消息,还可以减少代理的遍历问题。

WebRTC视频聊天应用程序 “appR.TC”的信令是通过Google App Engine Channel API实现的,该API使用Comet技术(长轮询)在App Engine后端和Web客户端之间进行推送信令。

也可以通过WebRTC客户端多次使用AJAX轮询消息服务器来处理信令,但这会导致大量冗余的网络请求,特别是对于移动设备而言更严重。即使在一个会话已经建立,节点也需要在其他节点发生变化或终止会话的情况下轮询信令消息。

扩展信令

虽然信令服务每个客户端消耗相对较少的带宽和CPU资源,但是流行应用程序的信令服务器可能必须处理来自不同位置的大量消息,并且具有高并发性。获得大量流量的WebRTC应用程序需要能够处理相当大负载的信令服务器。

这里不会详细介绍针对高容量高性能的消息传递处理方法,仅仅列出如下几种选择:

  • XMPP(可扩展消息传递和呈现协议):为即时消息传递开发的可用于信令的协议。
  • 开源库,如ZeroMQ和OpenMQ。NullMQ使用基于WebSocket的STOMP协议将ZeroMQ概念应用于Web平台。
  • 使用WebSocket的商业云消息传递平台,例如Pusher,Kaazing和PubNub。
  • 商业WebRTC平台,如vLine。

(开发者Phil Leggetter的实时Web技术指南提供了消息服务和库的综合列表。)

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

下面是一个简单的Web应用程序的代码,它使用在Node上使用Socket.io构建的信令服务。Socket.io的设计使构建交换消息的服务变得简单,而Socket.io特别适合WebRTC信令,因为它内置了“房间”的概念。此示例不是为生产级信令服务而设计的,但对于相对少量的用户来说很容易理解。

Socket.io使用带有AJAX长轮询、AJAX多部分流、Forever Iframe和JSONP轮询机制的WebSocket。它已被移植到各种后端,但可能其Node版本是最有名的,我们在下面的示例中使用它。

在这个例子中没有WebRTC:它的设计只是为了展示如何在Web应用程序中构建信令。查看控制台日志以查看客户端加入会议室并交换消息时发生了什么。我们的WebRTC代码库提供了如何将其集成到完整的WebRTC视频聊天应用程序中的详细说明。

下面是客户端index.html代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
});

完整的服务器APP

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);

  });

});

要想运行这个app,你需要先安装Node、socket.io和node-static。从Node.js网站下载相应版本Node进行安装,然后使用一下命令安装另外两个库。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install socket.io
npm install node-static

运行node server.js命令来启动服务器。这时打开浏览器访问localhost:2013,然后再打开一个页面访问此地址,模拟两个独立的客户端。可以使用Command-Option-J(Mac)或Ctrl-Shift-J(Win)命令来查看浏览器此时处理过程。

无论选择何种方式发送信令,你的服务器后端和客户端应用程序至少都需要提供类似于此示例的服务。

信令陷阱

  • 在调用setLocalDescription()之前,RTCPeerConnection不会收集candidates信息。
  • 利用Trickle ICE机制(见上文):candidates到达后立即调用addIceCandidate()

现成的信令服务器

如果你不想自己动手实现信令服务器,这有几个使用了Socket.io的、与客户端JavaScript库集成WebRTC信令服务器可以使用:

如果您根本不想编写任何代码,可以从vLine,OpenTok和Asterisk等公司获得完整的商业WebRTC平台解决方案。

信令安全

所有WebRTC组件都必须加密。但是,WebRTC标准并未定义信令机制,因此你需要想办法确保信令安全。如果攻击者设法劫持信令,他们可以停止会话,重定向连接并记录,更改或注入内容。

确保信令的最重要因素是使用安全协议、HTTPS和WSS(例如TLS),确保不能被拦截到未加密的消息。也要注意,不要以相同的信令服务器访问其他信令者的方式来广播信令消息。

事实上,为了保护WebRTC应用程序,信令使用TLS绝对是必要的。

使用ICE处理NAT和防火墙

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

简单网络结构中,每个WebRTC端点都有一个唯一的地址,可以直接与其他端点交换信息直接通信。

没有NAT和防火墙的应用场景如下图

实际上,大多数设备都处于一层或多层NAT网络结构中,有些设备具有阻止某些端口和协议的防病毒软件,而且许多设备都支持代理和企业防火墙。防火墙和NAT也可以由相同的设备实现,例如家庭wifi路由器

真实的使用场景

WebRTC应用程序可以使用ICE框架来克服现实网络的复杂性。要实现此目的,您的应用程序必须将ICE服务器URL传递给RTCPeerConnection,如下所述。

ICE会尝试遍历两个端点之间的所有路径并查找最佳路径。ICE首先尝试使用从设备的操作系统和网卡获得的主机地址建立连接。如果这个方法失败(表示此时设备处于NAT环境下),ICE使用STUN服务器获取外部地址。如果使用STUN也无法连接,则通过TURN中继服务器进行路由

换句话说:

  • STUN服务器用于获取外部网络地址。
  • 如果直连失败,TURN服务器将用于中继流量。

每个TURN服务器都支持STUN:TURN服务器是内置了中继功能的STUN服务器。ICE还可以应对复杂的NAT设置,实际上,NAT打洞可能不仅仅需要共有IP和端口。

WebRTC应用的 RTCPeerConnection 构造函数的第一个参数 iceServers 中会指定STUN或TURN服务器的URL。对于appr.tc,该值看起来像这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{ 
   
  '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月到期。要测试凭据,您可以使用candidate采集示例程序并检查您是否获得了中继类型的candidate。

一旦RTCPeerConnection具有该信息,RTCPeerConnection就可以使用ICE框架计算出端点之间的最佳路径,必要时会使用STUN和TURN服务器。

STUN

NAT为设备提供内网IP地址,以便在专用本地网络中使用,但是这个地址不能在外部使用。对于WebRTC而言,没有公共地址,点与点之间就无法直接进行通信。为了解决这个问题,WebRTC采用STUN技术。

STUN服务器位于公网上并且有一个简单的任务:检查传入请求的IP和端口地址(来自在NAT网络中运行的应用程序)并将该地址作为响应发回。换句话说,应用程序使用STUN服务器查询其位于公网上的IP和端口。此过程使WebRTC端点能够查询到自己公开访问的地址,然后通过信令机制将其传递给另一个端点,以便建立直接链接。(事实上,不同的NAT以不同的方式工作,并且可能存在多个NAT层,但原理仍然是相同的)。

大白话的说就是,很多内网的设备可以给公网地址发送数据,并不知道公网是用什么的地址来识别自己的,STUN服务器在收到查询请求的时候会告诉这个设备它的公网地址是啥样子的。设备拿到这个地址把这个地址发送给需要建立直接联系的其他设备

STUN服务器对计算性能和存储要求都不太高,因此相对低规格的STUN服务器可以处理大量请求。

根据webrtcstats.com的统计,有86%的WebRTC应用使用STUN成功建立连接,在内网端点之间的呼叫可能会更少,因为不用考虑防火墙和NAT地址转换。

使用STUN服务器去获取本设备公共的地址

TURN

RTCPeerConnection尝试通过UDP建立点与点之间的直接通信。如果失败,RTCPeerConnection将转向TCP。如果TCP连接失败,可以将TURN服务器用作回退,在端点之间中继数据。

注意:TURN用于在端点之间中继音频/视频/数据流,而不是信令数据!

TURN服务器具有公共地址,因此即使端点位于防火墙或代理之后,也可以与其他端点进行通信。TURN服务器虽然只有这么一个简单的任务 —— 中继流, 但与STUN服务器不同,它们本身就消耗了大量带宽。换句话说,TURN服务器需要更强大。

完整的交互过程: STUN, TURN 和信令图

此图显示TURN正在运行:单纯使用STUN未成功连接,因此每个端点都使用TURN服务器进行中继。

部署STUN和TURN服务器

为了进行测试,Google运行appr.tc使用的是公共STUN服务器stun.l.google.com:19302。对于生产STUN / TURN服务,我们建议使用rfc5766-turn-server。

可以从code.google.com/p/rfc5766-turn-server获取STUN和TURN服务器的源代码,该代码还提供了有关服务器安装的多个信息源的链接。还提供Amazon Web Services的VM映像。

restund是一个可替代的TURN服务器,这个代码也是开源的,也可用于AWS。以下是如何在Google Compute Engine上设置restund的介绍:

  1. 根据需要打开防火墙相应端口,tcp=443,udp/tcp=3478。
  2. 创建具有公网IP的四个实例,标准Ubuntu 12.04映像。
  3. 设置本地防火墙配置 (allow ANY from ANY)。
  4. 安装必要的工具makegcc
  5. 安装库creytiv.com/re.html.
  6. 下载restund并解压, creytiv.com/restund.html
  7. 执行wget hancke.name/restund-auth.patchpatch -p1 < restund-auth.patch
  8. 执行 make, sudo make install安装libre和restund。
  9. 根据需要调整restund.conf(替换IP地址并确保它包含相同的共享密钥)并复制到/etc
  10. restund/etc/restund复制到/etc/init.d/
  11. 配置restund:
    • Set LD_LIBRARY_PATH
    • Copy restund.conf to /etc/restund.conf
    • Set restund.conf to use the right 10. IP address
  12. 运行restund。
  13. 从远程机器测试这个stund: ./client IP:port

具有多个端点的WebRTC

上面讨论的都是一对一的呼叫,很容易想象,媒体流的用例不仅仅是简单的一对一呼叫。比如一群同事一起组织一个会议或者需要众多人观看的会议都是多个端点同时在线的。

WebRTC应用程序可以使用多个RTCPeerConnections,以便每个端点连接到网状配置中的每个其他端点。这是talky.io等应用程序采用的方法,这种每个端点都直接连接的方式对于少数几个参会者系统来说的话效果非常好。但是这种方式处理和带宽消耗变得过大,尤其是对于移动客户端。

Mesh拓扑结构: 每个端点都直接连接

除此之外,WebRTC应用程序可以选择一个端点,以星形网络配置将流分发给所有其他端点。也可以直接在服务器上运行一个WebRTC端点(虚拟参会者)并构建自己的重新分发机制。

从Chrome 31和Opera 18开始,一个RTCPeerConnectionMediaStream可以作为另一个RTCPeerConnection的输入。这样可以实现更灵活的架构,因为它允许Web应用程序通过选择要连接的其他端点来处理呼叫路由。

MCU / 多点控制单元

对于拥有大量端点而言,更好的选择是使用多点控制单元(MCU),这是一个可以作为在大量参与者之间分发媒体数据的类似于桥梁的服务器。MCU可以调整视频会议不同分辨率,编解码器和帧速率,处理转码,进行选择性流转发以及混合或记录音频和视频。对于多方通话,需要考虑许多问题:特别是如何显示多个视频输入并混合来自多个来源的音频。vLine等云平台也会尝试优化流量路由。

可以购买完整的MCU硬件,也可以自己构建。 有几种开源MCU软件可供选择。例如,Licode为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库的,这是最初为Google Talk开发的Jingle实现版本。

许多应用程序、库和平台利用WebRTC特性,比如:

  • sipML5: 一个开源的JavaScript SIP客户端。
  • jsSIP: JavaScript SIP库
  • Phono: 作为插件存在的开源的JavaScript phone API。
  • Zingaya: 一个可嵌入的手机小部件。
  • Twilio: 语音和消息通信。
  • Uberconference: 会议。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/160563.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【教程】如何使用Javascript构建WebRTC视频直播?
WebRTC是一个免费的开源项目,它通过简单的API为浏览器和移动应用程序提供实时通信功能。本文将向你展示WebRTC的基本概念和功能,并指导你使用Node.js构建自己的WebRTC视频直播。
TSINGSEE青犀视频
2021/04/12
4.5K0
零基础入门:基于开源WebRTC,从0到1实现实时音视频聊天功能
本文由微医云技术团队前端工程师张宇航分享,原题“从0到1打造一个 WebRTC 应用”,有修订和改动。
JackJiang
2021/08/24
3.9K0
WebRTC实现p2p视频通话
简介 目的 帮助自己了解webrtc 实现端对端通信 # 使用流程 git clone https://gitee.com/wjj0720/webrtc.git cd ./webRTC npm i npm run dev # 访问 127.0.0.1:3003/test-1.html 演示h5媒体流捕获 # 访问 127.0.0.1:3003/local.html 演示rtc 本地传输 # 访问 127.0.0.1:3003/p2p.html 演示局域网端对端视屏
random_wang
2019/10/22
7K0
WebRTC实现p2p视频通话
仿照AirDrop(隔空投送)优雅地在局域网中传输文件
在前一段时间,我想在手机上向电脑发送文件,因为要发送的文件比较多,所以我想直接通过USB连到电脑上传输,等我将手机连到电脑上之后,我发现手机竟然无法被电脑识别,能够充电但是并不能传文件,因为我的电脑是Mac而手机是Android,所以无法识别设备这件事就变得合理了起来。那么接着我想用WeChat去传文件,但是一想到传文件之后我还需要手动将文件删掉否则会占用我两份手机存储并且传输还很慢,我就又开始在网上寻找其他软件,这时候我突然想起来了AirDrop也就是隔空投送,就想着有没有类似的软件可以用,然后我就找到了Snapdrop这个项目,我觉得这个项目很神奇,不需要登录就可以在局域网内发现设备并且传输文件,于是在好奇心的驱使下我也学习了一下,并且基于WebRTC/WebSocket实现了类似的文件传输方案,并且在实现的过程中解决了如下问题:
WindRunnerMax
2024/01/02
6980
Web前端WebRTC攻略(一) 基础介绍
随着互联网高速发展,以及即将到来的5G时代,WebRTC作为前端互动直播和实时音视频的利器,也是将前端开发者们不可错过的学习领域。如果你现在只是听过而已,那你可能要好好学习一番。 01  什么是WebRTC? WebRTC 全称是(Web browsers with Real-Time Communications (RTC) 大概2011年,谷歌收购了 GIPS,它是一个为 RTC 开发出许多组件的公司,例如编解码和回声消除技术。Google 开源了 GIPS 开发的技术,并希望将其打造为行业标准。 收
用户1097444
2022/06/29
2.7K0
Web前端WebRTC攻略(一) 基础介绍
结合 AppRTC 源码分析 WebRTC 建立连接的过程
这两年来,WebRTC 越来越多地出现在人们的视野,在在线教育,在线医疗等领域的应用也越来越多。大家研究 WebRTC 的热情也越来越高涨,不过 WebRTC 的入门门槛个人觉得稍微有些高,特别是各种概念,比如 NAT 穿越,ICE,STUN,TURN,Signaling server等等,刚开始可能会觉得比较繁杂,不易理解。然后建立连接的整个过程,异步调用比较多,很容易搞混。那么这篇文章里我们会根据 WebRTC 的官方 demo AppRTC 的 iOS 版本来分析一下 WebRTC 从进入房间到建立音视频连接的过程,为了便于了解,我们本次的讨论不涉及到底层的具体实现。
JoeyBlue
2021/09/07
1.8K0
WebRTC介绍及简单应用
WebRTC介绍及简单应用 WebRTC,即Web Real-Time Communication,web实时通信技术。简单地说就是在web浏览器里面引入实时通信,包括音视频通话等。 WebRTC
用户1141560
2017/12/25
6.2K0
【OpenIM原创】简单轻松入门 一文讲解WebRTC实现1对1音视频通信原理
WebRTC(Web Real-Time Communication)是 Google于2010以6829万美元从 Global IP Solutions 公司购买,并于2011年将其开源,旨在建立一个互联网浏览器间的实时通信的平台,让 WebRTC技术成为 H5标准之一。我们看官网(https://webrtc.org)的介绍
OpenIM
2021/08/12
1.7K0
iOS下WebRTC音视频通话(一)WebRTC介绍WebRTC 过程
在iOS下做IM功能时,难免都会涉及到音频通话和视频通话。QQ中的QQ电话和视频通话效果就非常好,但是如果你没有非常深厚的技术,也没有那么大的团队,很难做到QQ那么快速和稳定的通话效果。 但是利用WebRTC技术,即使一个人也能够实现效果不错的音视频通话。本篇介绍WebRTC的基础概念。
Haley_Wong
2018/08/22
3.9K0
WebRTC 入门指南
WebRTC (Web Real-Time Communications) 是由谷歌开源并推进纳入 W3C 标准的一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC 包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。
ihoey
2020/07/27
1.5K0
通过WebRTC进行实时通信-通过RTCPeerConnection传输视频
RTCPeerConnection 是调用WebRTC传输音视频和交换数据的API。这个例子是在同一个页面中两个RTCPeerConnection对象之间建立连接。没有什么实际价值,但却能很好的证明RTCPeerConnection是如何工作的。
音视频_李超
2020/04/02
5.7K0
iOS 端实现1对1音视频实时通话
之前,我已经写过 Android 端实现1对1音视频实时通话 的文章。在那篇文章中,我向大家介绍了在 Android 端是如何使用 WebRTC 进行音视频通话的。今天,我们再来看看 iOS 端1对1音视频实时通话的具体实现。
音视频_李超
2020/04/01
4.4K0
iOS 端实现1对1音视频实时通话
实时音视频入门学习:开源工程WebRTC的技术原理和使用浅析
本文由ELab技术团队分享,原题“浅谈WebRTC技术原理与应用”,有修订和改动。
JackJiang
2022/01/10
1.8K0
实时音视频入门学习:开源工程WebRTC的技术原理和使用浅析
iOS下WebRTC音视频通话(三)-音视频通话过程的分析补充
前两篇文章记录了音视频通话的一些概念和一些流程,以及一个局域网内音视频通话的示例。 今天以一个伪真实网络间的音视频通话示例,来分析WebRTC音视频通话的过程。 上一篇因为是在相同路由内,所以不需要穿墙,两个客户端是可以直接传输多媒体流数据。用XMPP作为信令传输的通道也非常的简单。 本篇会添加上STUN服务器和TURN服务器,让ICE框架的功能发挥出来,实现完整的音视频通话。但是因为两个客户端所处网络环境不同,需要将这两个客户端加入到同一个虚拟的网络中(即房间服务器),所以需要服务器端的支持,关于服务器端的开发,这里就不做描述了。
Haley_Wong
2018/08/22
4.2K0
iOS下WebRTC音视频通话(三)-音视频通话过程的分析补充
抛弃websocket,前端直接打通信道,webRTC搭建音视频聊天
什么是WebRTC? 众所周知,浏览器本身不支持相互之间直接建立信道进行通信,都是通过服务器进行中转。比如现在有两个客户端,甲和乙,他们俩想要通信,首先需要甲和服务器、乙和服务器之间建立信道。甲给乙发送消息时,甲先将消息发送到服务器上,服务器对甲的消息进行中转,发送到乙处,反过来也是一样。这样甲与乙之间的一次消息要通过两段信道,通信的效率同时受制于这两段信道的带宽。同时这样的信道并不适合数据流的传输,如何建立浏览器之间的点对点传输,一直困扰着开发者。WebRTC应运而生 WebRTC是一个开源项目,旨在
李海彬
2018/03/27
7.5K0
抛弃websocket,前端直接打通信道,webRTC搭建音视频聊天
WebRTC 前端实时通信技术
江天德
2017/09/21
4.7K1
WebRTC 前端实时通信技术
WebRTC 点对点直播
作者:villainthr WebRTC 全称为:Web Real-Time Communication。它是为了解决 Web 端无法捕获音视频的能力,并且提供了 peer-to-peer(就是浏览器
腾讯IVWEB团队
2017/03/13
10.4K0
JavaScript 是如何工作的:WebRTC 和对等网络的机制!
WebRTC,名称源自网页即时通信(英语:Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的API。
前端小智@大迁世界
2019/03/15
2.5K0
JavaScript 是如何工作的:WebRTC 和对等网络的机制!
WebRTC 教程(1)
WebRTC: Web Real Time Communication 是一系列为提供端到端实时通信连接的协议和 API。Google 于 2011 年发布了基于浏览器的 WebRTC 项目,且这个技术可以使很多不同的应用,如视频会议、文件传输、聊天和桌面共享等都不需要额外的插件。
用户1324186
2022/04/11
2.2K0
WebRTC 教程(1)
WebRTC学习笔记——建立连接
1.WebRTC简介 WebRTC是一个开源的项目,可以提供浏览器,手机应用之间实时通信能力。 同时,这一功能已经内置于现代浏览器中,所以它可以做到无须借助第三方软件或插件便可以在开发网络中传输高质量
IMWeb前端团队
2017/12/29
2.1K0
WebRTC学习笔记——建立连接
推荐阅读
相关推荐
【教程】如何使用Javascript构建WebRTC视频直播?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验