WebRTC是为了解决实时音视频传输问题,致力于提供免安装、免插件、免专利费,人人可用的高效便捷的实时流媒体传输。javascript
目前实时流媒体主流有三种实现方式:WebRTC、HLS、RTMP,当你看直播网站的时候会发现不少采用了HLS(HTTP Live Streaming,http直播),它是一种把流媒体拆分红多个独立小文件的技术,按照播放时间请求不一样文件,把hls的文件进行解复用以后取出音视频数据而后丢给video去播放(Safari和安卓版的Chrome能直接播放hls)。它的优势是:使用了传统http协议,因此兼容性和稳定都很是好,服务端能够把hls文件上传到cdn,进而可以应对百万级别观众的直播,缺点是延时比较大,一般在10s以上,适合观众和主播没有什么交互的场景。由于一个hls文件时间长度一般在10s以上,再加上生成文件的时间就致使延迟很大。html
它是苹果推出的一种标准,而另外一种RTMP是Adobe推出的,使用长链接,是一套完整的流媒体传输协议,使用flv视频容器,原生浏览器不支持(flash插件支持),不过可使用websocket + MSE的方式,相关的类库比较少,在Android/IOS客户端上的直播应该用得比较多一点。相对于HLS请求分片的形式,RTMP因为使用长链接,接收不间断的数据流,它的延迟要比HLS小不少,一般是1~3秒,因此若是观众和主播之间有通话或者视频交互,这种方式的延迟是能够接受的。前端
第3种WebRTC(Web Real Time Communication)是谷歌在2012年推出的,到如今已经有6年的发展。今年2018年3月份WebRTC 1.0正式定稿,并获得了Safari在内的全部主流浏览器的支持(Edge弄了一个ORTC),WebRTC致力于高效的实时音视频通讯,作到比RTMP提供更低的延迟和更小的缓冲率。而且官方还提供了配套的native的Andorid/IOS的库,不过实际的实现多是套一个webview,由webview启动webrtc,再把数据给native层渲染。vue
先介绍下WebRTC的组成。java
WebRTC由三大块组成,以下图所示:git
(1)getUserMedia是负责获取用户本地的多媒体数据,如调起摄像头录像等。github
(2)RTCPeerConnection是负责创建P2P链接以及传输多媒体数据。web
(3)RTCDataChannel是提供的一个信令通道,在游戏里面信令是实现互动的重要元素。算法
getUserMedia负责获取用户本地的多媒体数据,包括调起麦克风录音、摄像头捕获的视频和屏幕录制这三种,我已经在《如何实现前端录音功能》用到了这个API——借助WebRTC的getUserMedia实现录音。调摄像头录制视频也是相似,方法很简单,以下代码所示:vuex
window.navigator.mediaDevices
.getUserMedia({video: true})
.then(mediaStream => {
// 画到一个video元素上面
$('video')[0].srcObject = mediaStream;
});复制代码
若是想实现录屏(屏幕共享)的话,就把获取媒体的参数改一下,以下代码把参数由默认的摄像头改为屏幕:
navigator.mediaDevices
.getUserMedia({video: {mediaSource: 'screen'}})
.then(stream => {
videoElement.srcObject = stream;
});复制代码
而后就会弹一个框询问要录制的应用窗口,以下图所示:
例如能够选PPT应用,就能够开始演讲了。这个目前只有firefox支持,Edge有一个相似叫getDisplayMedia,Chrome还在开发之中,可是能够装一个官方提供的浏览器插件。可见这个demo。
经过getUserMedia调起以后拿到流对象mediaStream,这个流能够在本地渲染,同时经过RTCPeerConnection能够传给对方。
为了实现客户端的点到点链接(数据不需通过服务器转发),RTCPeerConnection作了不少工做。首先须要解决的问题是局域网穿透。
要创建一个链接须要知道对方的IP地址和端口号,在局域网里面一台路由器可能会链接着不少台设备,例如家庭路由器接入宽带的时候宽带服务商会分配一个公网的IP地址,全部连到这个路由器的设备都共用这个公网IP地址。若是两台设备都用了同一个端口号建立套接字去链接服务,这个时候就会冲突,由于对外的IP是同样的。所以路由器须要重写IP地址/端口号进行区分,以下图所示:
有两台设备分别用了相同的端口号创建链接,被路由器转换成不一样的端口,对外网表现为相同IP地址不一样端口号,当服务器给这两个端口号发送数据的时候,路由器再根据地址转换映射表把数据转发给相应的主机。
因此当你在本地监听端口号为55020,可是对外的端口号并非这个,对方用55020这个端口号是连不到你的。这个时候有两种解决方法,第一种是在路由器设置一下端口映射,以下图所示:
上图的配置是把全部发往8123端口的数据包到转到192.168.123.20这台设备上。
可是咱们不能要求每一个用户都这么配他们的路由器,所以就有了穿墙打洞,基本方法是先由服务器与其中一方(Peer)创建链接,这个时候路由器就会创建一个端口号内网和外网的映射关系并保存起来,如上面的外网1091就能够打到电脑的55020的应用上,这样就打了一个洞,这个时候服务器把1091端口加上IP地址告诉另外一方(Peer),让它用这个打好洞的地址进行链接。这就是创建P2P链接穿墙打洞的原理,最先起源于网络游戏,由于打网络游戏常常要组网,WebRTC对NAT打洞进行了标准化。
这个的有效性受制于用户的网络拓扑结构,由于若是路由器的映射关系既取决于内网的IP + 端口号,也取决于服务器的IP加端口号,这个时候就打不了洞了,由于服务器打的那个洞不能给另一个外网的应用程序使用(会创建不一样的映射关系)。相反若是地址映射表只取决于内网机器的IP和端口号那么是可行的。打不了洞的状况下WebRTC也提供了解决方法,即用一个服务器转发多媒体数据。
这套打洞的机制叫ICE(Interactive Connectivity Establishment),帮忙打洞的服务器叫TURN服务,转发多媒体数据的服务器叫STUN服务。谷歌提供了一个turn server,在我家的网络下只能拿到局域网的地址:
为此笔者写了一个demo,可打开这个连接尝试P2P聊天(能够用两个tab或者两台电脑),效果以下图所示:
除了默认提供的TURN服务打洞以外,还须要有一个websocket服务交换互连双方的信息。因此须要写一个websocket服务,我用Node.js简单写了一个,代码已经传到github:webrtc-server-client-demo,包括浏览器端的代码。
这个过程以下图所示:
首先打开摄像头获取到本地的mediaStream,并把它添加到RTCPeerConnection的对象里面,而后建立一个本地的offer,这个offer主要是描述本机的一些网络和媒体信息,采用SDP( Session Description Protocol)格式,以下所示:
v=0
o=- 4809135116782128887 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS 6ReMVBFmnh4JhjzqjNO2AVBc26Ktg0R5jCFB
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
...复制代码
而后把这个offer经过websocket服务发送给要链接的对方,对方收到后建立一个answer,格式、做用和offer同样,发送给呼叫方告知被呼叫方的一些信息。当任意一方收到对方的sdp信息后就会调setRemoteDescription记录起来。而当收到默认的ice server发来的打洞信息candidate以后,把candidate发送给对方(在setRemoteDesc以后),让对方发起链接,成功的话就会触发onaddstream事件,把事件里的event.stream画到video上面便可获得对方的影像。
这就是整一个链接过程。
若是链接成功就开始传输多媒体数据,这里面WebRTC作了不少工做。
WebRTC总体的架构以下图所示(可见官网):
主要的工做包括:
(1)音视频的编解码(VP8/VP9/AV1)
(2)抗丢包和拥塞控制
(3)回声和噪音消除
WebRTC一个很大的做用就体如今这里了——提供可靠的传输、优质的编解码以及回声问题消除,笔者曾经还用了一个叫h323 plus的包作了一个项目,也是P2P链接。而如今这种实时多媒体传输功能直接内嵌到浏览器里面,对于开发人员来讲无疑大大地提升了开发效率。
在实际的线上项目里面,因为P2P连通率和稳定性并非特别乐观,因此更多地是采用P2SP的架构,S表明Server,以下图所示:
一方面可以提升稳定性,另外一方面可以解决一对多和多对多视频聊天的问题。由于WebRTC比较适用于一对一的,在一对多场景让一个用户的流推给几个用户不论是性能仍是上传带宽均可能会有问题。
能够作一个兼容方案,当P2P不行的时候就切到P2SP.
关于RTCDataChannel这里不展开讨论,实际场景仍是使用WebSocket比较多。
WebRTC已经被W3C发布了1.0标准,可是暂未成为RFC标准。WebRTC也在逐渐地发展,包括:
(1)Chrome 69使用了新的回声消除算法AEC3
(2)VP9编码提高了35%的质量,新的AV1编码能够在Chrome里面使用
(3)包括RTCRtpSender等更加丰富的操纵API
将来的RTC将会提供更多功能:
(1)直接操做媒体流数据的能力(如今得经过CaptureStream间接操做)
(2)自定义编解码参数的能力RTCRtpEncodeingParameters(Chrome 70)
等等。
相信WebRTC的将来是很是光明的。
【人人网招聘中高级前端】
1. 项目背景: 咱们在作一个企业级海外的SAAS CRM(客户管理系统)产品, 前端的技术挑战很大, 好比在咱们的网站让客户直接打网络电话(直接打手机那种), 发email, 自动根据用户场景处理业务等。
2. 技术栈背景: 也是采用比较流行的vue, vuex等框架, 通信是WebRTC, 消息分发系统用Google的FCM和苹果的APN。服务部署在亚马逊或谷歌云上。服务全球客户。
3. 另外由于产品是一个企业级用户产品因此个方面要求比较高(好比性能,安全,多任务处理等)。因此对候选人技术要求比较高,若是您对技术特别在乎,那么咱们的空缺提供了很好的才能发挥空间和锻炼成长的机会。