WebRTC学习

Webrtc官方网址:https://webrtc.org/
Webrtc老版官网地址:https://webrtc.github.io/webrtc-org/
Webrtc学习网址:https://webrtc.org.cn/
Webrtc中文文档https://github.com/RTC-Developer/WebRTC-Documentation-in-Chinese
W3C API文档:https://www.w3.org/TR/webrtc/

原理和架构

源代码主目录
1.api目录:就是webrtc的接口层。比如浏览器、我们自己写的应用程序大多数时候都是直接从webrtc提供的这些api进行调用。如果我们想增加接口或者调整接口,就需要到api目录下去找相应的文件。
2.call目录:数据流的管理层,Call代表同一个端点的所有数据的流入流出,那当有多个端进行流入流出的时候就需要有多个Call。主要是对音频流、视频流的管理,当与对端建立连接之后,同一个端的这些流的管理就是通过call进行管理的。
3.video目录:与视频相关的逻辑。当视频要进行编解码处理等,video目录是一个总的入口点,video的相关逻辑都是在这里的。
4.audio目录:与音频相关的逻辑。
5.common_audio目录:common_video目录:都是与算法相关的。
6.media目录:与多媒体相关的逻辑处理,如编解码的逻辑处理。比如什么时候进行编码,什么时候进行解码这些都是在media目录下控制的。
7.logging目录:日志相关。
8.module目录:最终要的目录-----子模块。这个模块非常大,里面有很多子模块,每个子模块都非常重要。
9.pc目录:Peer Connection,连接相关的逻辑层。Peer Connection代表的是与对端的一个连接,在上层有一个连接的概念,在连接下面就有很多的东西了,比如连接的时候有stream流,流里面又有轨track,一个流里面可以有很多轨,包括音频轨、视频轨、桌面轨等等,轨道的概念就可以理解为两个平行的线,是不相交叉,音频、视频都是单独的,这样一个概念。
通过Peer Connection拿到Stream流,流里能拿到每一个多媒体,也就是音频视频,当然还可以拿到所有的统计信息,比如媒体流的统计信息、传输的统计信息等等。
Peer Connection是一个非常重要的目录,相当于上层接口的一个统一的接口层。
10.p2p目录:端到端相关代码,stun/turn。端到端要进行传输的时候需要看p2p是不是能打通,p2p有很多类型,链接能不能打通,相应的侦测工具都是在这个p2p目录下。相应的协议有STUN协议TURN协议。
11.rtc_base目录:基础代码,如线程、锁相关的统一接口代码。由于webrtc是夸平台的,所以线程、锁这些会有所不同,特别是在Windows和Linux上使用的函数差别特别大,那怎么办呢?如果上层根据每个平台去做不同的处理的话,就需要些很多代码了。但是分层之后,对于上层逻辑来说,只需要统一调用webrtc定义的这个规范,比如线程规范、锁规范,就可以了,具体在rtc_base这个目录下再区分是Windows层的还是Linux层的还是mac层的等等。
12.rtc_tool目录:里面是一些工具,音视频分析相关的工具代码。比如对H264进行分析的话有I帧、B帧、P帧、NALL头等都可以找到相应的分析工具。(音视频相关的专门的测试工具目录)
13.tool_webrtc目录:webrtc测试相关的工具代码,各种单元测试如网络模拟器,网络的测试,音频的测试,视频的测试都是在这个目录下。(整个webrtc的测试工具目录)
14.system_wrappers目录:与具体操作系统相关的代码。如CPU特性,原子操作,锁等。各个平台分别形成一个文件,比如Windows的形成一个文件,Linux的形成一个文件等等。
15.stats目录:存放各种数据统计相关的类。比如,丢包率、抖动时长等等。
16.sdk目录:主要存放Android和iOS层代码。如音频视频的采集,渲染等。

Modules子目录下的目录结构:
Modules目录下又很多子目录,而且都比较重要。

1.audio_coding目录:音频编解码器相关代码。在上面的media目录也说到了编解码,media是编解码逻辑相关的,就是什么时候用编解码。这里的audio_coding目录下是编解码器,有opus编解码器,AAC编解码器等等,都是放在这个audio_coding目录下的。
2.audio_device目录:音频采集与音频播放相关的代码。在老版本的webrtc里,所有的设备都放在audio_devices这个目录里,但是新的webrtc把Android和iOS的设备相关代码都放在了sdk目录下,单独摘到了sdk下面了。但是其他的平台比如Windows的,mac的,linux的都是在audio_devices目录下。
3.audio_mixer目录:混音相关的代码。什么是混音呢?就是说同时又多人实时互动,好几个人同时在说话,就需要把声音混在一起,这样在传输的时候就比较方便,减少了音频流。
4.audio_processing目录:音频前后处理的相关代码。对音频的前处理,后处理;比如回音消除,降噪,增益等等,都是在这个目录中,但是这个目录中又有很多的子目录。
5.bitrate_controller目录:码率控制的相关代码。控制码流是500K,1M,还是2M,这个码流的控制就是在这个目录下。想改变码流,想看码流相关的控制,就进入这个目录下即可。
6.congestion_controller目录:流量控制相关代码,拥塞控制。当检测到网络流量比较高的时候,需要做一些网络流量控制,防止网络包把带宽打死,具体怎么控制就是在这里设置的,想要看流控相关的代码就在这个目录中查看。
7.desktop_capture目录:桌面采集相关。
8.pacing目录:码率探测及平滑处理相关的代码。首先需要检测到音频视频的码率是多少,检测到后做一个平滑的处理,就是不是让数据一下发送出去,需要做平滑处理,比如有时候是10K,有时候是500K,给做一个平均,不能一会儿高一会儿低,而是给做一个平滑处理。
9.remote_bitrate_estimator目录:远端码率估算相关代码。评估远端能接收的带宽是多少,不是我本地的发送的带宽,是远程接收端的估算带宽。不仅仅需要知道发送端单位时间能发送多少,还需要知道对方端单位时间能收多少,所以需要一个远端码率的评估。评估的代码就在这个目录下。
10.rtp_rtcp目录:rtp/rtcp协议相关代码。
11.video_capture目录:视频采集相关的代码。捕获视频相关的代码。
12.video_coding目录:视频编解码器相关的代码。视频的编码器VP8/VP9等等,编码器都是放在这里的。
13.video_processing目录:视频前处理、后处理相关的代码。视频帧的增强,检测,还有如果增加人脸识别就可以放在这个目录下。

 

一、首先看两个概念:轨与流。
1.轨:Track。比如一路音频就是一路轨,一路视频也是一路轨,这里的轨就是采取了轨道的概念,两条轨道是永远不相交的,音频与视频是不相交的,单独存放。两路音频其实也是两路轨,也是不相交的。
2.媒体流MediaStream。借鉴了传统的媒体流的概念,在传统的媒体流里也包括了音频轨、视频轨、字母轨。这里主要有一个层级的概念。在媒体流里包含了很多轨,这样形成一个层级的概念之后,后续的知识就比较好理解了。

二、Webrtc重要类:
1.MediaStream类,媒体流
2.RTCPeerConnection类,是整个webrtc里最终要的一个类,因为这个类是一个大而全的一个类,里面包含了很多的功能。那么这样设计有什么好处呢?对于应用层来说就特别的方便,在应用层只需要创建了一个RTCPeerConnection,也就是创建这一个连接,将MediaStream流塞到这个连接里去就不用管其他的了,其他所有的底层传输、寻路等等,全都会由RTCPeerConnection内部去执行了。所以对于应用层来说非常方便,当然在底层它肯定做了很多的工作。我们知道Webrtc主要采用的是P2P的传输,包括p2p的类型、检测、p2p是否能够打通、是否能够穿透成功,如果穿透不成功还需要通过TURN服务器去进行中转,等等这一系列的操作都是在RTCPeerConnection类里面做完了。所以,这就是为什么去看webrtc源码的时候发现非常复杂,而在应用层去使用的时候反而非常容易非常方便的原因。
所以在后续看webrtc源码的时候,或者局部逻辑的时候,可以首先从RTCPeerConnection这个类着手进行不断的深入。
3.RTCDataChannel类。这个类是非音视频数据都通过这个RTCDataChannel类进行传输,实际上RTCDataChannel是通过RTCPeerConnection获取的,所以他们之间是有关系的。像文本、二进制文件、二进制数据都可以通过RTCDataChannel进行传输,所以只需要拿到RTCDataChannel这个对象,将数据塞给RTCDataChannel对象,对于上层应用来说已经完成了。RTCDataChannel它在底层又走了很多的逻辑,对于上层应用来说是无需关心的。

所以,总结来说:RTCPeerConnection类是核心,MediaStream类里包含了很多轨,将这些轨添加到这个MediaStream类对象之后,将MediaStream类对象添加到RTCPeerConnection类对象之中去,底层就不用管了,它就会自动的传递到对端去了。
对于普通数据来说,比如传输二进制数据。首先通过RTCPeerConnection类对象获取RTCDataChannel类对象,然后其他也就不用管了,通过这个RTCDataChannel类就可以把非音视频数据的二进制数据传递到对端去了。
最核心的,RTCPeerConnection的调用过程

分析流程图:
看到Stream流,也就是MediaStream包含了很多轨,包括音频轨、视频轨等等,当然也可以只有一路音频一路视频。
接下来看PeerConnection,它内部有两个线程,一个是Worker thread,一个是Signaling thread,通过PeerConnectionFactory会创建这两个线程,PeerConnectionFactory实际上就是一个连接工厂,可以创建出很多PeerConnection,这个工厂会创建PeerConnection,还会创建LocalMediaStream和LocalVideoTracker/LocalAudioTracker。
这些创建流程里,首先是创建一个个的轨LocalVideoTracker/LocalAudioTracker通过AddTrack将这些轨添加到LocalMediaStream类媒体流对象中,当然这里可能有多个LocalMediaStream媒体流,但是,最终都通过AddStream将这些流添加到PeerConnection连接对象中,这里如果有多个流,这些流复用的是同一个PeerConnection连接对象。
需要注意的是,什么是多个流的状况呢?1:1的通讯只有1个流,流里面包含音频轨和视频轨。那多个流呢,就是可能有与多个人在通讯,与多方通讯,每一方实际就是一个stream,就会存在多个流。比如有一个音视频会议中, 同时又3方在进行通讯,那么每一方就是一个stream。

首先是application应用层会触发CreatePeerConnectionFactory;这样就创建出一个PeerConnectionFactory工厂;这个PeerConnectionFactory工厂又触发了CreatePeerConnection,然后创建了一个PeerConnection连接;这个PeerConnectionFactory还会去调用CreateLocalMediaStream,CreateLocalVideoTrack,CreateLocalAudioTrack,然后通过AddTrack将CreateLocalVideoTrack,CreateLocalAudioTrack这些轨添加到CreateLocalMediaStream中去;添加完之后再触发AddStream将这个流添加到PeerConnection这个连接中去;流添加完之后会提交流的变化,当流发生变化的时候,会提交触发一个事件,也就是CommitStreamChanges,触发的这个事件干什么呢?会创建一个offer的SDP的描述信息;有了这个offer SDP描述信息之后,就会在应用层通过信令发送到了远端了,在对端就会收到这个offer SDP描述信息。这个描述信息都包含哪些信息呢?包含有哪些音频、有哪些视屏、音频格式是什么、视屏格式是什么、传输地址是什么,这些信息就会全部收到了。根据这些信息,远端会回复一个answer 的SDP给这个信令。信令与媒体流信息其实是两条路,一个(也就是信令)是通过TCP传输的,一个(也就是媒体流)是通过UDP传输的,这两条信路。信令收到answer之后就会传给PeerConnection连接对象;这个时候,这个PeerConnection连接就拿到了对方媒体流的信息以及它的传输端口、传输地址,这样他们之间就打通这个通道了。就可以相互的传递数据了,当远端的数据过来之后,这个PeerConnection连接会将远端的流添加到application中去,也就是OnAddStream。Application本身也是一个Connection Observer一个观察者,就是随时要知道这个Connection连接都发生了哪些事件。
通过这个时序图,就可以了解到一个api的完整调用过程。
以上就是webrtc的整个运行机制。

获取音视频设备

音视频数据采集

一般采样率是44200,采样大小是16位,2个字节

渲染

录制

 

信令服务器

相互协商过程,STP,编解码算法,信令服务器中转。。。发现对方,之后通过P2P,不行的则P2P穿透,不行的话,就要通过TURN中转。。。

需要三种:房间服务器room,信令服务器,流中转服务器。

socket.io信令服务器有房间服务器的概念。

  1. 客户端向服务器端口1发送信息,STUN服务器向客户端返回信息。如果都没有收到,那么UDP不可用。有收到,即可以拿到客户端的公网IP地址,判断
    1. 客户端的公网IP地址与客户端ip一致,就是没有NAT。客户端再次向STUN服务器端口1发送信息,STUN服务器用不同的IP和post向客户端返回信息,如果收到信息说明客户端此时是开放网络。没有收到的话,说明客户端在一个对称的防火墙后
    2. 客户端的公网IP与客户端ip1不一致,说明客户端在NAT之后。就要对NAT类型判断。客户端向STUN服务器端口1发送信息,STUN服务器用不同的IP和post向客户端返回信息
      1. 收到的话,说明是完全锥形NAT
      2. 收不到的话,客户端向STUN服务器端口2发送信息,STUN服务器用和之前相同的IP和post向客户端返回信息。
        1. 如果IP地址和之前不同,那么就是对称型NAT
        2. 如果IP地址和之前相同,可能就是地址限制或者端口限制。客户端向服务器端口1发送信息,服务器用相同的地址不同的端口返回信息,如果可以接收到那就是地址限制型NAT,如果不可以接收到那就是端口限制型NAT

     

STUN服务器打不通,找不到端口和IP,那么就要TURN中转

小端,内存使用,因为和内存增长方向相同。低地址低字节,高地址高字节

大端,网络使用,因为网络先发比较重要的高字节。低地址高字节,高地址低字节

转换n = (((n&0xff000000) >>24) | ((n&0x00ff0000) >>8) | ((n&0x0000ff00) <<8) | ((n&0x000000ff) <<24) );

send和data需要带一个32字节的头,所以用channle


SDP格式

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值