WebRTC ( Web Real-Time Communications 网页即时通讯) 是一项网页实时通信技术,(以目前所熟知的大多数直播软件,或是远程会议,视频通话类软件,都是借助于特定的客户端作视频数据的推流工做,客户端进行拉流播放)WebRTC创建浏览器之间点对点(Peer-to-Peer,P2P) 链接,实现视频流和(或)音频流或者其余任意数据的传输。WebRTC包含的这些标准使用户在无需安装任何插件或者第三方的软件的状况下,建立点对点(Peer-to-Peer)的数据分享和电话会议成为可能。而且于 2011年6月1日开源,并在Google、Mozilla、Opera的支持下被归入万维网联盟的W3C推荐标准,它经过简单的API为浏览器和移动应用程序提供实时通讯(RTC)的功能。javascript
WebRTC项目的原则是API开源、免费、标准化、浏览器内置,比现有的技术更高效。WebRTC虽然冠以“Web”之名,但并不受限于传统互联网应用或浏览器的终端运行环境。实际上,不管终端运行环境是浏览器、桌面应用、移动设备(Android或iOS)仍是IoT设备,只要IP链接可到达且符合WebRTC规范就能够互通。这一点释放了大量智能终端(或运行在智能终端上的App)的实时通讯能力,打开了许多对于实时交互性要求较高的应用场景的想象空间,音视频会议·在线教育·照相机·音乐播放器·共享远程桌面·录制·即时通讯工具·P2P网络加速·文件传输工具·游戏·实时人脸识别,都是其合适的应用领域,java
Web应用:Web开发者能够基于Web API开发基于视频、音频的实时通讯应用,如视频会议、远程教育、视频通话、视频直播、游戏直播、远程协做、互动游戏、实时人脸识别等git
MediaStream:媒体数据流,如音频流、视频流等。
RTCPeerConnection:该类很重要,提供了应用层的调用接口。
RTCDataChannel:传输非音视频数据,如文字、图片等
复制代码
C++ API 层 有C++语言编写,使浏览器厂商容易实现WebRTC标准的Web API,抽象地对数字信号过程进行处理。如 RTCPeerConnection
API是每一个浏览器之间点对点链接的核心,RTCPeerConnection
是WebRTC组件,用于处理点对点间流数据的稳定和有效通讯。github
Session Management 是一个抽象的会话层,提供会话创建和管理功能。该层协议留给应用开发者自定义实现。对于Web应用,建议使用WebSocket技术来管理信令Session, 信令主要用来转发会话双方的媒体信息和网络信息。也是后端开发者须要关注的一层web
Transport 为WebRTC的传输层,涉及音视频的数据发送、接收、网络打洞等内容,能够经过STUN和ICE组件来创建不一样类型的网络间的呼叫链接 关注与 P2P 这里算法
VideoEngine是WebRTC视频处理引擎, 包含一系列视频处理的总体框架,从摄像头采集视频到视频信息网络传输再到视频显示,是一个完整过程的解决方案后端
VoiceEngine(音频引擎)是包含一系列音频多媒体处理的框架,包括从音频采集到网络传输端等整个解决方案。VoiceEngine是WebRTC极具价值的技术之一,是Google收购GIPS公司后开源的,目前在VoIP技术上处于业界领先地位浏览器
通话的大体能够分为三个步骤 (假定通话的双方为Alice和Bob。双方要创建起通话,主要步骤以下所示)服务器
one: 媒体协商Alice 与 Bob 经过信令服务器进行媒体协商,如双方使用的音视频编码格式。双方交换的媒体数据由SDP(Session Description Protocol,会话描述协议)描述
two: 网络协商Alice 与 Bob 经过STUN服务器获取到各自的网络信息,如IP和端口。而后经过信令服务器转发,互相交换各类网络信息。这样双方就知道对方的IP和端口了,即P2P打洞成功创建直连。这个过程涉及NAT及ICE协议。
three: 创建链接Alice 与 Bob 若是没有创建起直连,则经过TURN中转服务器转发音视频数据,最终完成音视频通话
媒体协商就是双方在创建链接以前 必须告诉对方 用什么样的媒体格式 ,了解对方支持的媒体格式 才能保证后续正确的编解码 Alice 端可支持VP八、H264多种编码格式,而 Bob 端支持VP九、H264 经过媒体协商 取他们的交集H264来编解码视频。
描述媒体链接内容的协议叫(Session Description Protocol) 简称 (SDP) 内容 例如分辨率,格式,编码,加密算法等。因此在数据传输时两端都可以理解彼此的数据。SDP并非一个真正的协议,而是一种数据格式,用于描述在设备之间共享媒体的链接的元数据。 那SDP 信息从哪里来呢?通常来讲,在创建链接以前,链接双方须要先经过 RTCPeerConnection
API来指定本身要传输什么数据(如Audio、Video、DataChannel) 而后经过 CreateOffer()
,CreateAnswer()
方法建立 SDP 信息
SDP 信息的交换 要借助于 信令服务器 能够用来交换双方的SDP信息,通常是经过建立Socket链接进行交互处理。可使用Node.js、Golang或其余技术,只要能交换双方的SDP数据便可。
贴一个SDP数据 -- 就下面这玩意
v=0
o=- 7524998691693353763 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=msid-semantic: WMS kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:hwkT
a=ice-pwd:tXV1yDOgQpS9bBHqY5w+/oGf
a=ice-options:trickle
a=fingerprint:sha-256 54:9D:F1:8C:46:89:61:24:FC:B1:5C:F6:6E:BF:18:AF:22:CD:A0:37:37:64:37:61:D6:FF:4F:0D:C2:70:7B:A4
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ 6426930d-bb60-4633-b8b5-bb91d19d8430
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
a=ssrc:5150036 cname:+RCf3A8Ya1BflCDM
a=ssrc:5150036 msid:kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ 6426930d-bb60-4633-b8b5-bb91d19d8430
a=ssrc:5150036 mslabel:kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ
a=ssrc:5150036 label:6426930d-bb60-4633-b8b5-bb91d19d8430
m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 121 127 120 125 107 108 109 124 119 123 118 114 115 116
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:hwkT
a=ice-pwd:tXV1yDOgQpS9bBHqY5w+/oGf
a=ice-options:trickle
a=fingerprint:sha-256 54:9D:F1:8C:46:89:61:24:FC:B1:5C:F6:6E:BF:18:AF:22:CD:A0:37:37:64:37:61:D6:FF:4F:0D:C2:70:7B:A4
a=setup:actpass
a=mid:1
a=extmap:14 urn:ietf:params:rtp-hdrext:toffset
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:13 urn:3gpp:video-orientation
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id
a=sendrecv
a=msid:kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ 1cfb3b88-4ed0-4267-9c1e-c861e2a323cb
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 profile-id=0
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 VP9/90000
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=fmtp:100 profile-id=2
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:102 H264/90000
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 transport-cc
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:121 rtx/90000
a=fmtp:121 apt=102
a=rtpmap:127 H264/90000
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 transport-cc
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtpmap:120 rtx/90000
a=fmtp:120 apt=127
a=rtpmap:125 H264/90000
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 transport-cc
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtpmap:108 H264/90000
a=rtcp-fb:108 goog-remb
a=rtcp-fb:108 transport-cc
a=rtcp-fb:108 ccm fir
a=rtcp-fb:108 nack
a=rtcp-fb:108 nack pli
a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtpmap:124 H264/90000
a=rtcp-fb:124 goog-remb
a=rtcp-fb:124 transport-cc
a=rtcp-fb:124 ccm fir
a=rtcp-fb:124 nack
a=rtcp-fb:124 nack pli
a=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f
a=rtpmap:119 rtx/90000
a=fmtp:119 apt=124
a=rtpmap:123 H264/90000
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 transport-cc
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f
a=rtpmap:118 rtx/90000
a=fmtp:118 apt=123
a=rtpmap:114 red/90000
a=rtpmap:115 rtx/90000
a=fmtp:115 apt=114
a=rtpmap:116 ulpfec/90000
a=ssrc-group:FID 3517908871 1250619161
a=ssrc:3517908871 cname:+RCf3A8Ya1BflCDM
a=ssrc:3517908871 msid:kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ 1cfb3b88-4ed0-4267-9c1e-c861e2a323cb
a=ssrc:3517908871 mslabel:kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ
a=ssrc:3517908871 label:1cfb3b88-4ed0-4267-9c1e-c861e2a323cb
a=ssrc:1250619161 cname:+RCf3A8Ya1BflCDM
a=ssrc:1250619161 msid:kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ 1cfb3b88-4ed0-4267-9c1e-c861e2a323cb
a=ssrc:1250619161 mslabel:kFj1r3NdWzKanYt530Rbg0QQk8DbMwv2eXuJ
a=ssrc:1250619161 label:1cfb3b88-4ed0-4267-9c1e-c861e2a323cb
复制代码
媒体协商须要通讯双方彼此要了解对方的网络状况 。这样才有可能找到一条通讯链路。须要作如下两个处理
理想的网络状况是每一个浏览器所在的计算机IP都是公网IP,能够直接进行点对点链接 ,可是 理想很丰满 现实很骨感 实际状况是咱们的计算机都是在某个局域网中而且有防火墙,须要进行网络地址转换(Network Address Translation,NAT)在解决WebRTC使用过程当中的上述问题时,咱们须要用到NAT、STUN和TURN等概念,下面分别介绍。
NAT 简单来讲,NAT是为了解决IPv4下的IP地址匮乏而出现的一种技术。例如,一般咱们处在一个路由器之下 路由器的WAN口有一个公网IP,而全部链接路由器LAN口的设备会分配一个私有的的地址一般为 192.168.1.一、192.168.1.2,若是有n个设备,可能分配到192.168.1.n,而这个IP地址显然只是一个内网的IP地址,这样一个路由器的公网地址对应了n个内网的地址,这种使用少许的公有IP地址表明较多的私有IP地址的方式,将有助于减缓IP地址空间的枯竭, NAT技术会保护内网地址的安全性,因此这就会引起一个问题,就是当咱们采用P2P中的链接方式时,NAT会阻止外网地址的访问,这时咱们就得采用NAT穿透技术了
能够借助一个公网IP服务器,Alice与Bob都往公网IP-PORT 发包,公网服务器就能够获知 Alice 与 Bob 的IP/PORT,又因为Alice与Bob主动给公网IP服务器发包,因此公网服务器能够穿透NAT- Alice 与 NAT-Bob,并发送包给Alice与Bob。因此只要公网IP将Bob的IP/PORT 发给Alice,将Alice的IP/PORT发给Bob,这样下次Alice与Bob互相发送消息时,就不会被NAT阻拦了 , WebRTC的防火墙穿透技术就是基于上述思路来实现的。在WebRTC中采用ICE
框架来保证RTCPeerConnection
能实现NAT穿透。
交互式链接设施Interactive Connectivity Establishment (ICE) 是一个容许你的浏览器和对端浏览器创建链接的协议框架,ICE经过使用如下几种技术完成上述工做
STUN是一种网络协议,即简单的用UDP穿透NAT, 它容许位于 NAT(或多重NAT)后的客户端 [处于局域网中的计算机] 找出本身的公网地址,查出本身位于哪一种类型的NAT以后以及NAT为某一个本地端口所绑定的Internet端口。这些信息被用来在两个同时处于NAT路由器以后的主机之间建立UDP通讯 可是 But 经过STUN服务器取得了公网IP位址,也不必定能创建链接。 这是 由于不一样的NAT类型处理传入的UDP分组的方式是不一样的,四种主要类型中有三种可使用STUN穿透:彻底圆锥型NAT、受限圆锥型NAT和端口受限圆锥型NAT。但大型公司网络中常常采用的对称型NAT(又称为双向NAT)则不能使用,这类路由器会透过NAT部署所谓的“Symmetric NAT限制”,也就是说,路由器只会接受你以前连线过的节点所创建的连线,这类网络就须要用到TURN技术。
彻底锥形NAT,全部从同一个内网IP和端口号发送过来的请求都会被映射成同一个外网IP和端口号,而且任何一个外网主机均可以经过这个映射的外网IP和端口号向这台内网主机发送包。
限制锥形NAT,它也是全部从同一个内网IP和端口号发送过来的请求都会被映射成同一个外网IP和端口号。与彻底锥形不一样的是,外网主机只可以向先前已经向它发送过数据包的内网主机发送包。
端口限制锥形NAT,与限制锥形NAT很类似,只不过它包括端口号。也就是说,一台IP地址X和端口P的外网主机想给内网主机发送包,必须是这台内网主机先前已经给这个IP地址X和端口P发送过数据包。
对称NAT,全部从同一个内网IP和端口号发送到一个特定的目的IP和端口号的请求,都会被映射到同一个IP和端口号。若是同一台主机使用相同的源地址和端口号发送包,可是发往不一样的目的地,NAT将会使用不一样的映射。此外,只有收到数据的外网主机才能够反过来向内网主机发送包
TURN是指使用中继穿透NAT ,主要添加了中继功能。若是终端在进行NAT以后,在特定的情景下有可能使得终端没法和其余终端进行直接的通讯,这时就须要将公网的服务器做为一个中继,对来往的数据进行转发。这个转发采用的协议就是TURN
STUN服务器和TURN服务器咱们使用coturn开源项目来搭建,地址为github.com/coturn/cotu…。也可使用以Golang技术开发的服务器来搭建,地址为github.com/pion/turn
信令服务器不仅是交换SDP和Candidate,还有其余功能,好比房间管理、用户列表、用户进入、用户退出等IM功能
1)链接双方(Peer)经过第三方服务器来交换(signaling)各自的SDP数据。
2)链接双方经过STUN协议从STUN服务器那里获取到本身的NAT结构、子网IP和公网IP、端口,即Candidate信息。
3)链接双方经过第三方服务器来交换各自的Candidate,若是链接双方在同一个NAT下,那它们仅经过内网 Candidate就能创建起链接;若是它们处于不一样NAT下,就须要经过STUN服务器识别出的公网Candidate进行通讯。
4)若是仅经过STUN服务器发现的公网Candidate仍然没法创建链接,这就须要寻求TURN服务器提供的转发服务,而后将转发形式的Candidate共享给对方。
5)链接双方向目标IP端口发送报文,经过SDP数据中涉及的密钥以及指望传输的内容创建起加密长链接。
标注的场景是Alice向Bob发起对聊请求
一、Alice 首先建立PeerConnection
对象,而后打开本地音视频设备,将音视频数据封装成MediaStream
添加到PeerConnection中
二、Alice 调用PeerConnection
的CreateOffer
方法建立一个用于offer的SDP对象,SDP对象中保存当前音视频的相关参数。
三、Alice 经过PeerConnection
的SetLocalDescription
方法将该SDP对象保存起来,并经过信令服务器发送给 Bob
四、Bob接收到Alice发送过的offer SDP 对象,经过PeerConnection
的SetRemoteDescription
方法将其保存起来、
五、而且Bob调用PeerConnection
的CreateAnswer
方法建立一个应答的SDP对象,经过PeerConnection
的SetLocalDescription
的方法保存该应答SDP对象
六、而且Bob须要将建立的应答的SDP对象经过信令服务器发送给Alice
七、Alice 接收到 Bob 发送过来的应答SDP对象,将其经过PeerConnection
的SetRemoteDescription
方法保存起来
八、在SDP信息的 offer/answer流程中,Alice和Bob已经根据SDP信息建立好相应的音频l和视频,而且经过NAT穿透获取了Candidate数据,Candidate数据 包含了彼此的IP地址信息(本地IP地址、公网IP地址)和端口信息
九、当Alice收集到Candidate信息后,PeerConnection
会经过OnIceCandidate
接口给Alice发送通知,Alice将收到的Candidate信息经过信令服务器发送给Bob,Bob经过PeerConnection
的AddIceCandidate
方法保存起来
十、一样的操做Blice对Alice再来一次。
十一、这样Alice和Bob就已经创建了音视频传输的P2P通道,Bob接收到Alice传送过来的音视频流,会经过PeerConnection
的OnAddStream
回调接口返回一个标识Alice端音视频流的MediaStream对象,在Bob端渲染出来便可 -- A、B收到对方的媒体流并播放