什么是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)
RTCPeerConnection 最重要的一个类了,是个核心类
下面我来看最核心的类也就是PeerConnection, 它的调用过程如下图:
上图是从WebRTC官网截的,
熟悉了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进行传输
C++音视频开发学习资料:点击领取→音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)
首先思考的问题:
两个不同网络环境的(具备摄像头/麦克风多媒体设备的)客户端(浏览器或APP),要实现点对点的实时音视频对话,难点在哪里?哪部分问题需要我们解决,哪部分问题由Google解决?
针对上面的问题,解决这些问题需要下面四步:
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服务器呢?
STUN(Session Traversal Utilities for NAT,NAT会话穿越应用程序)是一种网络协议,它允许位于NAT(或多重NAT)后的客户端找出自己的公网地址(ip+port),查出自己位于哪种类型的NAT之后以及NAT为某一个本地端口所绑定的Internet端端口。
STUN做的事情如下:
我们先来了解一下什么是TURN服务?
中继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)
从上面1/2点我们知道了2个客户端协商媒体信息(SDP)和网络信息(candidate),那怎么去交换?是不是需要一个中间商去做交换? 这个时候我们需要一个信令服务器(Signal server)(房间服务器)转发彼此的媒体信息和网络信息。
借助信令服务器,就可以实现上面提到的SDP媒体信息及Candidate网络信息交换。
真实的开发中,信令服务器不只是交换 媒体信息sdp和网络信息candidate,比如还会处理: (1)房间管理 (2)人员进出房间
介绍完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中涉及的密钥以及期望传输的内容,建立起加密长连接。
具体连接建立的时序图,参考零声学院的一张图如下:
联系客服