优秀的编程知识分享平台

网站首页 > 技术文章 正文

WebRTC运行机制(webrtc stun)

nanyue 2024-07-26 16:01:59 技术文章 5 ℃

1. 轨与流

  • Track
  • MediaStream

什么是Track?

Track又称作为轨道。比如一路音频就是一路轨,一路视频也是一路轨,这里的轨就是采取了轨道的概念,两条轨道是永远不相交的,音频与视频是不相交的,单独存放。两路音频其实也是两路轨,也是不相交的。

什么是MediaStream?

MediaStream又叫做媒体流,借鉴了以前传统的媒体流的概念,在传统的媒体流里面也包括了音频轨、视频轨还有字幕轨,所以这里主要有个层级的概念,在媒体流里面包含了很多轨,这样形成一个层级的概念之后,我们再往下看的时候就比较好理解了。

我们再来看一下几个重要的类,第一个和我们刚看到的是同一个名字,也就是MediaStream,就是把它在WebRTC里面单独写了一个类,这里我们就不过多介绍了。

第二个是RTCPeerConnection,RTCPeerConnection是整个WebRTC里面最为重要的一个类,因为这个类是一个大而全的一个类,它里面包含了很多的功能,这样设计有什么好处呢?对于应用层来说,就特别的方面,在应用层我只要创建了一个PeerConnection,也就是创建了一个连接,我们将MediaStream也就是流设置到连接里去,那他所有底层的传输和寻路都由PeerConnection自己在内部执行了,其实对应用层来说,是一个非常好的消息。但是它在底层它做了很多工作,因为我们知道WebRTC主要采用的是P2P的传输,那包括你P2P的类型和检测,P2P是否能够打通,是否能穿透成功,如果穿透不成功,我门还需要通过turn服务器进行中转,这一系列的操作都是在PeerConnection的下面完成了。

所以我们在看WebRTC内部的代码的时候,其实非常的复杂,对于应用层的开发者来说,利用WebRTC去开发,其实会方便很多。

我们只要知道这个重要的一个类,还有一个我们自己的一个重要方法,就能完成我们自己的一个应用程序,所以PeerConnection是我们要重点要掌握的一个类,对应用层来说我们要知道它都有哪些功能。我们可以用哪些方法去增加我们应用的功能。

对于我们后面学习WebRTC底层代码的时候,我们也要重点关注这个PeerConnection,因为他是一个总的点,要去分析每一块的逻辑的时候都可以通过这个点一步一步的往下深入,当我遇到困难的时候,我们可以在回来在重新往下屡。

第三个是RTCDataChannel,DataChannel就是我们非音视频的数据,都通过DataChannel,进行传输,实际上DataChannel,是通过PeerConnection获取的,所以他们之间是有关系的,那像我们的文本、文件、二进制数据,都可以通过DataChannel进行传输,所以当我们拿到DataChannel这个对象之后,将数据塞给他,上层应用就算完成了。实际上在底层,它也走了很多的逻辑。

那么通过这个三个类,我们知道PeerConnection是核心,MediaStream包含了很多轨,将这些轨添加到一些Stream之后, 再将它添加到PeerConnection当中去,那么底层的就不用管了,他就自动传输到对应端去了,对于普通的数据来说 也是一样,我将二进制数据,首先我通过PeerConnection获取这个DataChannel,再把二进制数据塞到DataChannel中去,那么我们的非媒体数据非音视频数据也能正常的传输出去,传送到对端。

接下来我们需要熟悉WebRTC中几个非常重要的类,这里的详细介绍一下:

C++音视频开发学习资料点击领取音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

2. WebRTC重要的类

2.1 MediaStream

  • MediaStream — MediaStream用来表示一个媒体数据流(通过getUserMedia接口获取),允许你访问输入设备,如麦克风和 Web摄像机,该 API 允许从其中任意一个获取媒体流。

2.2 RTCPeerConnection

RTCPeerConnection 最重要的一个类了,是个核心类

  • RTCPeerConnection:一个RTCPeerConnection对象允许用户在两个浏览器之间直接通讯。
  • SDP: 用来描述当前连接者想要传输的内容,支持的协议类型,支持的编解码类型等。
  • RTCIceCandidate:表示一个ICE协议的候选者,简单的说,就是目标节点的IP以及端口。
  • RTCIceServer:表示一个ICE Server,其主要用于当前主机的IP发现,通过和ICE Server通讯,我们会得到一组可供连接使用的IP:Port候选值,双方通过交换ICE候选值来建立起连接。

2.2.1 RTCPeerConnection 调用过程

下面我来看最核心的类也就是PeerConnection, 它的调用过程如下图:

上图是从WebRTC官网截的,

  1. 首先的是Stream流,也就是Media Stream,它包括了很多轨,包括了视频、音频……,当然也可以只有一路音频或者一路视频;
  2. 接下来就是PeerConnection, Connection内部是有两个线程: 一个 是Worker线程,另一个是Signaling线程, 就是通过PeerConnectionFactoryInterface来创建两个线程,PeerConnectionFactory实际上就是个连接工厂了,它可以创造很多的PeerConnection, 它不仅可以创建PeerConnection;还可以创建MediaStream;也可以创建LocalVideoTrack或LocalAudioTrack。创建之后首先是创建一个一个的轨,然后通过AddTrack将他们添加到MediaStream媒体流中去。
  3. 那么可能有多个媒体流,最终都通过AddStream添加到PeerConnection中去,它们复用的是同一个连接Connection,当然在底层的话有可能是不同的路,那么在这里要注意的是什么是多个Stream。
  4. 我们都清楚在我本机有可能有音频和视频,当我们塞到一个Stream里面去,那这个就是为什么一路会有多路Stream,那就是有可能是与多方通讯,每一方实际就是一个Stream,仔细想想在一个音视频会议中,能有三方进行视频通讯,那么每一方就是一个Stream。

2.2.2 RTCPeerConnection 调用时序图

熟悉了PeerConnection的关系后,我们再来看看这几个方法的调用关系,如下图是RTCPeerConnection 调用时序图:

首先是应用层会触发CreatePeerConnectionFactory,这样就创造出了PeerConnectionFactory这个工厂,那么这个工厂呢又触发了CreatePeerConnection,

然后创建了一个PeerConnection连接,这个工厂还会创建CreateLocalMediaStream、CreateLocalVideoTrack、CreateLocalAudioTrack这些轨,之后再通过AddTrack将这些 轨添加到Stream中去,添加完了之后在调用这个AddStream将这个流添加到PeerConnection连接中去,流提交好了之后会提交这个流的变化CommitStreamChanges。当这个流触发变化的时候,就会触发这个事件创建一个offer 的SDP的描述信息。

有了这个描述 信息之后呢,通过应用层通过信令发送到远端,在这一端 收到这个offer SDP,SDP里面包括的信息有包括哪些视频哪些音频以及音频格式是什么视频格式是什么?你的传输地址是什么?这些信息实际就度过来了。然后根据这些信息远端会回一个answer给这个信令,信令与 我们媒体流的信息实际上是两条路,并不是通过TCP传输的,它是通过UDP传输的,当这个信令收到这个answer之后,就会传给这个connection,然后个连接就拿到了对方这个媒体流信息以及它的传输端口、传输地址。这样他们之间就打通这个通道了,可以相互的传这个媒体数据了。当远端的数据来了之后,这个Connection还会将远端的这个流,添加到这个APP中去,APP它本身也是一个ConnectionObserver,这其实是一个观察者,要知道这个连接发生了哪些事件。

通过上面这样一个清晰的时序图,我们很容易就可以了解整个api的一个调用过程。以上就是我们整个webRTC的一个运行机制。后续文章还会详细讲解SDP信令这块的知识。


2.3 RTCDataChannel

非音视频数据都是通过RTCDataChannel进行传输

  • DataChannel:数据通道( DataChannel)接口表示一个在两个节点之间的双向的数据通道,该通道可以设置成可靠传输或非可靠传输 。

3. WebRTC 一些基本概念

C++音视频开发学习资料点击领取音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

4. WebRTC 通话原理

首先思考的问题:

两个不同网络环境的(具备摄像头/麦克风多媒体设备的)客户端(浏览器或APP),要实现点对点的实时音视频对话,难点在哪里?哪部分问题需要我们解决,哪部分问题由Google解决?

  1. 音视频编解码能力沟通
  2. 网络传输数据
  3. 如何发现对方

针对上面的问题,解决这些问题需要下面四步:

  1. 媒体协商
  2. 网络协商(每个客户端是有多个 映射地址)
  3. 媒体协商+网络协商数据的交换通道
  4. 信令服务器的开发:SDP/Candidate的交互,房间维护。


4.1 媒体协商

要实现P2P通信,首先需要了解彼此是否都支持相同的媒体能力,WebRTC默认使用V8编解码器,如果要连接的对方不支持V8解码,如果没有媒体协商过程。那么即使连接成功,把视频数据发给对方,对方也无法播放。

比如:Peer-A端可支持VP8、H264多种编码格式,而Peer-B端支持VP9、H264,要保证二端都正确的编解码,最简单的办法就是取它们的交集H264

注:有一个专门的协议 ,称为Session Description Protocol (SDP),可用于描述上述这类信息,在WebRTC中,参与视频通讯的双方必须先交换SDP信息,这样双方才能知根知底,而交换SDP的过程,也称为"媒体协商"。


4.2 网络协商

在了解了彼此的媒体能力后,接下来需要确认的是双方的网络通信能力。只有彼此要了解对方的网络情况,这样才有可能找到一条相互通讯的链路。

理想的网络情况是每个浏览器的电脑都是私有公网IP,可以直接进行点对点连接。事实上,真实的网络环境非常复杂,特别是在国内很多企业都有多级网络,有的网络甚至禁止发送UDP包,这样在对称的NAT网络下,打洞是打不通的,必须借助TURN服务器转发。

如下图,实际情况是:我们的电脑和电脑之前或大或小都是在某个局域网中,需要NAT。(Network Address Translation,网络地址转换)

NAT是什么? 网路位址转换(Network Address Translation)可为你的装置提供公用IP位址。路由器具备公用IP位址,而连上路由器的所有装置则具备私有IP位址。接着针对请求,从装置的私有IP对应到路由器的公用IP与专属的通讯端口。如此一来,各个装置不需占用专属的公用IP,亦可在网路上被清楚识别。

我们先来看一下什么是网络地址转换,如下图:

我们要实现网络穿透,就需要做IP,端口映射,需要知道自己所在的 公网IP,这时候我们需要借助STUN服务器. 那什么是STUN服务器呢?

4.2.1 STUN

STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址(ip+port),查出自己位于哪种类型的NAT之后以及NAT为某一个本地端口所绑定的Internet端端口。

STUN做的事情如下:

  • 使用一句话说明STUN做的事情就是:告诉我你的公网IP地址+端口是什么。
  • 问题是:STUN并不是每次都能成功的为需要NAT的通话设备分配IP地址的,P2P在传输媒体流时,使用的本地带宽,在多人视频通话的过程中,通话质量的好坏往往需要根据使用者本地的带宽确定。
  • 即使透过 STUN 服务器取得了公用 IP 位址,也不一定能建立连线。因为不同的NAT类型处理传入的UDP分组的方式是不同的。
  • 四种主要类型中有三种是可以使用STUN穿透:完全圆锥型NAT受限圆锥型NAT端口受限圆锥型NAT。但大型公司网络中经常采用的对称型 NAT(又称为双向NAT)则不能使用,这类路由器会透过 NAT 布署所谓的「Symmetric NAT」限制。也就是说,路由器只会接受你之前连线过的节点所建立的连线。这类网络就需要TURN技术。
  • 那么怎么办?TURN可以很好的解决这个问题。

我们先来了解一下什么是TURN服务?

4.2.2 TURN

  • TURN的全称为Traversal Using Relays around NAT,是STUN/RFC5389的一个拓展,主要添加了Relay功能。如果终端在NAT之后, 那么在特定的情景下,有可能使得终端无法和其对等端(peer)进行直接的通信,这时就需要公网的服务器作为一个中继,对来往的数据进行转发。

中继NAT实现的穿透(Traversal Using Relays around NAT)就是透过TURN服务器开启连线并转送所有数据,进而绕过Symmetric NAT的限制。你可透过TURN服务器建立连线,再告知所有端点传送封包至该服务器,最后让服务器转送封包给你。这个方法更耗时且更占频宽,因此在没有其他替代方案时才会使用这个方法。

在STUN分配公网IP失败后,可以通过TURN服务器请求公网IP地址作为中继地址。这种方式的带宽由服务器端承担,在多人视频聊天的时候,本地带宽压力较小。以上是WebRTC中经常用到的2个协议,STUN和TURN服务器我们使用coturn开源项目来搭建。

做WebRTC开发的时候,我们经常会听到一个词ICE( Interactive Connectivity Establishment,交互式连接建立)跟STUN和TURN不一样,ICE不是一种协议,而是一个框架(Framework),它整合了STUN和TURN。coturn开源项目集成了STUN(打洞)和TURN(中继)的功能。网络信息:放在 candidate

实际上我们可以用下面一个公式: P2P= STUN + TURN + ICE

C++音视频开发学习资料点击领取音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

4.3 媒体协商+网络协商数据的交换通道

从上面1/2点我们知道了2个客户端协商媒体信息(SDP)和网络信息(candidate),那怎么去交换?是不是需要一个中间商去做交换? 这个时候我们需要一个信令服务器(Signal server)(房间服务器)转发彼此的媒体信息和网络信息。

4.4 信令服务器

  • 信令服务器架构图如下:

借助信令服务器,就可以实现上面提到的SDP媒体信息及Candidate网络信息交换。

真实的开发中,信令服务器不只是交换 媒体信息sdp和网络信息candidate,比如还会处理: (1)房间管理 (2)人员进出房间

5. WebRTC 连接建立流程

介绍完ICE框架中各个独立部分的含义之后,在让我们来看一看整个框架是如何工作的:

建立连接的过程可以总结如下:

连接双方(Peer)通过第三方服务器来交换(Signalling)各自的SessionDescription数据。 连接双方(Peer)通过STUN协议从STUN Server那里获取到自己的NAT结构,子网IP和公网IP,端口,这里的IP和端口对我们称之为ICE Candidate。 连接双方(Peer)通过第三方服务器来交换(Signalling)各自ICE Candidates,如果连接双方在同一个NAT下那他们仅通过内网Candidate就能建立起连接,反之如果他们处于非对称型NAT下,就需要STUN Server识别出的公网Candidate进行通讯。 如果仅通过STUN Server发现的公网Candidate仍然无法建立连接,换句话说就是连接双方(Peer)中至少有一方处于对称NAT下,这就需要处于对称NAT下的客户端(Peer)去寻求TURN Server提供的转发服务,然后将转发形式的Candidate共享(Signalling)给对方(Peer)。 连接双方(Peer)向目标IP端口发送报文,通过SessionDescription中涉及的密钥以及期望传输的内容,建立起加密长连接。

具体连接建立的时序图,参考零声学院的一张图如下:

最近发表
标签列表