WebRTC 学习笔记

WebRTC 学习笔记

在这里插入图片描述

导论

笔者在写本文时在参加C4网络挑战赛的可编程网络应用创新赛项,由于指导老师在sdn方面有一定的研究,我们对SRV6,组播,P4都有一定了解, 而比赛要求基于江苏省未来网络创新研究院研发的虚拟仿真实 验平台搭建环境并开发应用,通过平台使用 OpenDaylight、Open vSwitch、Mininet 等开源软件,基于 Python、Java、P4 等语言进行编程开发,实现但不局限于智能路由选择、负载均衡网关、DDoS 防御、 流量工程等场景下的网络应用。

而为了找到这样一个场景,我们想做一个基于SRV6、组播的视频会议,因为视频会议对实时性要求很高,所以我们可以运用SRV6和组播的技术,来优化链路传输,提升会议质量。市面上大多数开源的视频会议都使用了WebRTC协议来实现,故在此对WebRTC进行学习和研究,并记录一篇笔记。

参考

相对于从我这进口“二手”知识,我更希望读者可以去看原文,故在此写出我写本文时参考的文章。

https://web.dev/webrtc-basics/

https://web.dev/webrtc-infrastructure/

WebRTC概述

通过语音和视频实现人与人之间的交流被称为实时通信或简称RTC。Google在2008年做了Gmail视频聊天,2011年引入了环聊,Google随后又开源GIPS的编解码器和回声消除技术,2011年5月爱立信第一次实现了webRTC。

WebRTC实现了三套API:

  • MediaStream
  • RTCPeerConnection
  • RTCDataChannel

WebRTC应用程序所要做的几件事:

  • 获取流音频,视频或其他数据。
  • 获取网络信息,譬如IP地址和端口,并与其他WebRTC客户端(称为对等端)进行交换以启用连接,即使通过NAT和防火墙。
  • 协调信令通信以报告错误并启动或关闭会话。
  • 交换有关媒体和客户端功能的信息,例如分辨率和编解码器。
  • 交换音频流,视频流或数据流。

因为网络层之类的我们想自己写,这里详细介绍一下前面两条:

MediaStream API

我们现在用浏览器看一下这个API具体的内容

这个Mediastream就作为我们生成的对象,他有一个输入和一个输出(传递给视频元素 or RTCPeerConnection)。getAudioTracksgetVideoTracks方法返回MediaStreamTracks的数组。而这些可以追踪来自摄像头的值。我们可以用secObject.attribute来设置绑定的视频元素。我们利用track.stop则可以关闭摄像头。

 A constraint saying that we absolutely must have a minimum resolution
   of 1024x768:

   getUserMedia({
      video: { mandatory: { minWidth: 1024, minHeight: 768 } }
   }, successCallback, errorCallback);

我们可以使用类似上面的代码来设置约束条件。

我们还可以使用 chrome.tabCapture来设置屏幕捕获。

信令

WebRTC使用RTCPeerConnection在浏览器(也称为对等设备)之间通信流数据,但还需要一种机制来协调通信并发送控制消息,此过程被称为信令。WebRTC未指定信令方法和协议。信令不是RTCPeerConnection API的一部分。

我们假设为 Alice 和 Bob 进行通信,他们会使用onicecandidate()来选取候选者。

ICE 是一种能够在两个对等实体(例如 WebRTC 客户端)之间建立连接的技术。当两个实体想要彼此通信时,它们会交换 ICE 候选者,这些候选者包含了可以连接到对方的一组网络地址和端口。在交换和选择这些候选者的过程中,WebRTC 使用了 ICE 协议。

在上面的代码中,当本地 ICE 候选项可用时,它将被发送到远程端点,以便双方能够完成 ICE 过程,建立连接。在这里,pc 表示 PeerConnection 对象,onicecandidate 是一个事件监听函数,每当有新的 ICE 候选项生成时,就会触发该函数;signaling.send 是发送 ICE 候选项的函数,通常通过 WebSocket、Socket.IO 等进行信令传输。

很显然,我们也可以自己去包装一个候选者出来,并且自己实现代码完成类似ICE的过程,但是显然,ICE是一个很成熟的方案。

选取好候选者后,Alice可以把序列号的候选数据发送给Bob(使用类似websocket之类的)。

然后Bob要调用addicecandidate(同样我们也可以封装出一个我们自己的)将候选信息存到添加到自身RTCPeerConnection对象中远程对等描述中。

当然,对于传输的视频文件,我们还要做编解码和解析度等信息,我们可以通过会话描述协议完成,这些函数封装在 RTCPeerConnection里面。

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);
  }
};

执行类似上面的语句,Alice执行 RTCPeerConnection createOffer() 方法。 方法返回的对象传递给RTCSessionDescription(Alice的本地会话描述)。

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);
  }
};

在回调中,Alice使用setLocalDescription设置本地描述,然后通过其信令通道将此会话描述发送给Bob。

Bob 使用setRemoteDescription将爱丽丝Alice发送给他的描述设置为远程描述。

Bob 执行 RTCPeerConnection createAnswer() 方法,将他从 Alice 那里得到的远程描述传递给它(RTCPeerConnection),以便可以生成与她兼容的本地会话。createAnswer() 的回调会回传 RTCSessionDescription对象,Bob 将其设置为本地描述,并将其发送给 Alice。

以上的过程称为 JavaScript 会话建立协议(JSEP)。

RTCPeerConnection

WebRTC的解编码器和协议做了很多工作,优化了在较差网络条件下的 RTC:

  • 隐藏丢包
  • 回声消除
  • 带宽适应性
  • 动态抖动缓冲
  • 自动增益控制
  • 降噪抑制
  • 影像清理

这里我们重点关注RTCPeerConnection API plus servers,服务器功能可以归纳成这四个:

  • 用户发现和交流
  • 发信号
  • NAT / 防火墙的穿透
  • 对等通信失败时,失败尝试的中继服务器和转发服务器

WebRTC自带的ICE框架用于连接对等方(例如两个视频聊天客户端)的框架。最初,ICE尝试通过UDP以尽可能短的延迟直接连接对等方。在此过程中,STUN服务器只有一个任务:使NAT后面的对等方能够找到其公共地址和端口,这些应该是服务端做的事情,我会在下面详细讨论这些问题。

WebRTC所需要的后端服务

Peer discovery(发现对端)

我们需要完成可以找到我们需要对话的人,那么我们就需要设计一个身份和状态管理系统,并且给与用户发起对话的方法。

消息推送

用于信令的消息服务必须是双向的,客户端到服务器以及服务器到客户端。

我们可以使用多种手段实现双向通信,比如长轮询和EventSource API

但是最佳实践应该是websocket,当然建立了会话之后,由于其他对等方会更改或终止会话,对等方也需要轮询信令消息。(个人理解成保活,类似于心跳)

Scale signaling (规模化信号)

作为信令服务器,当客户端较多时,应该支持高并发级别处理大量消息,因此我们应该实现一个高容量高性能的消息传递服务。

下面是一些可能的实现方案:

  • XMPP
  • ZeroMQ
  • Pusher等商业云消息平台

Readymade signaling servers(现成的信令服务器)

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

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

After signaling(应对NAT和防火墙)

在实际环境上,大多数设备都位于一层或多层NAT的后面,当我们将ICE服务器的url传给RTCPeerConnection以后,ICE会试图找到最佳的路径,首先直接进行连接,如果失败了,那么我们先用STUN协议获得外部网络地址,然后用TURN来中继转发流量。

STUN

NAT为设备提供了IP地址,让其可以在公共局域网里面使用,没有公共地址,我们就没办法实现WebRTC通信,那么我们就可以使用STUN服务器来实现该问题的解决。

STUN的任务很简单,检查传入请求的ip:port,然后传回ip:port即可,通过这个过程就可以找到公共可访问地址了。

TURN

RTCPeerConnection尝试通过UDP建立对等方之间的直接通信。如果失败,则RTCPeerConnection求助于TCP。如果失败,则可以将TURN服务器用作后备,在端点之间中继数据,也就相当于一个传话筒。做一个简单的比喻,你想找我,发微信打电话都找不到我,你就选择打电话给我的室友,让他来找我并且传话。

总结

这篇文章参考官方的文档和一些函数的说明写成,可以在短时间内对WebRTC建立起基本的认识。其中,由于ICE框架的功能我们可以通过一些sdn的知识来完成修改,所以着重关注了相关知识,其他方面缺漏较多可以阅读我参考的两篇文章作为补充。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值