1.WebRTC的简单介绍
需要资料的后台可以私信《资料》两字可以免费领取
资料内容包括:C/C++,Linux,golang,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,WebRTC,ffmpeg 嵌入式 等。
WebRtc是一项实时通信技术,它允许浏览器或者app之间可以不借助中间媒介的情况下,建立浏览器之间点对点的连接,实现视频流和音频流或者其他任意数据的传输。
2.WebRTC的技术实现
2.1WebRTC架构
2.2 WebRTC核心API
- MediaStream: 从客户摄像头或麦克风获取的媒体流对象。
- RTCPeerConnection: 连接对象,用于连接建立,媒体流传输。
- RTCDataChannel: 数据传输通道。
2.3 WebRTC的通信流程
两个浏览器之间通过自己的公网IP地址,使用STUN协议信息和STUN服务器建立联系
两个浏览器通过SDP提供/应答机制,使用呼叫控制信令消息交换它们已发现的公共IP地址
两个浏览器执行连接检查,确保P2P可以连接
建立连接后,实时通信
3.WebRTC的优缺点
3.1WebRTC的优点
1. 方便。对于用户来说,在WebRTC出现之前想要进行实时通信就需要安装插件和客户端,但是对于很多用户来说,插件的下载、软件的安装和更新这些操作是复杂而且容易出现问题的,现在WebRTC技术内置于浏览器中,用户不需要使用任何插件或者软件就能通过浏览器来实现实时通信。对于开发者来说,在Google将WebRTC开源之前,浏览器之间实现通信的技术是掌握在大企业手中,这项技术的开发是一个很困难的任务,现在开发者使用简单的HTML标签和JavaScript API就能够实现Web音/视频通信的功能。
2. 免费。虽然WebRTC技术已经较为成熟,其集成了最佳的音/视频引擎,十分先进的codec,但是Google对于这些技术不收取任何费用。
3. 强大的打洞能力。WebRTC技术包含了使用STUN、ICE、TURN、RTP-over-TCP的关键NAT和防火墙穿透技术,并支持代理。
3.2WebRTC的缺点
1. 缺乏服务器方案的设计和部署。
2. 传输质量难以保证。WebRTC的传输设计基于P2P,难以保障传输质量,优化手段也有限,只能做一些端到端的优化,难以应对复杂的互联网环境。比如对跨地区、跨运营商、低带宽、高丢包等场景下的传输质量基本是靠天吃饭,而这恰恰是国内互联网应用的典型场景。
2. WebRTC比较适合一对一的单聊,虽然功能上可以扩展实现群聊,但是没有针对群聊,特别是超大群聊进行任何优化。
3. 设备端适配,如回声、录音失败等问题层出不穷。这一点在安卓设备上尤为突出。由于安卓设备厂商众多,每个厂商都会在标准的安卓框架上进行定制化,导致很多可用性问题(访问麦克风失败)和质量问题(如回声、啸叫)。
4. 对Native开发支持不够。WebRTC顾名思义,主要面向Web应用,虽然也可以用于Native开发,但是由于涉及到的领域知识(音视频采集、处理、编解码、实时传输等)较多,整个框架设计比较复杂,API粒度也比较细,导致连工程项目的编译都不是一件容易的事。
WebRTC学习之一:开篇
一.无插件的实时通讯
二.快速开始
三.关于WebRTC的小故事
四.WebRTC使用现状
五.我的第一个WebRTC应用
六.MediaStream (别名getUserMedia)
MediaStream API代表媒体流的同步。比如,从摄像头和麦克风获取的媒体流具有同步视频和音频轨道。不要将这里的MediaStream轨道和<track>元素混淆,它们是完全不同的概念。
理解MediaStream最简单的方法如下:
1.在Chrome或Opera中打开例子https://webrtc.github.io/samples/src/content/getusermedia/gum
2.打开控制台
3.检查stream变量,该变量是全局的。
每个MediaStream都有输入,即navigator.getUserMedia();也有输出,被传递到video元素或RTCPeerConnection
getUserMedia()方法有三个参数:
1.一个约束对象。
2.一个成功的回调,如果成功会回传一个MediaStream。
3.一个失败的回调,如果失败会回传一个error对象。
每个MediaStream都有一个label,比如'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ',getAudioTradks()和getAudioTracks()方法会回传一个MediaStreamTracks对象的数组。
在例子https://webrtc.github.io/samples/src/content/getusermedia/gum中,stream.getAudioTracks()回传了一个空数组(因为没有音频),假设摄像头正常工作并连接,stream.getVideoTracks()回传一个MediaStreamTracks对象的数组。数组中的每个MediaStreamTracks对象包含一种媒体(‘video’或‘audio’)和一个label(比如'FaceTime HD Camera (Built-in)'),而且还代表了一个或多个音视频的数据通道。在这个例子中,只有一个视频轨道,没有音频。当然,很容易就能扩展到其他情况。
在Chrome或Opera中, URL.createObjectURL()方法将MediaStream转换成Blob URL,该Blob URL可以设置为video元素的输入(在Firefox和Opera中,视频源可以通过数据流本身设置)。版本M25开始,基于Chromium的浏览器(Chrome和Opera)允许来自getUserMedia的音频数据传递到aduio或video元素。
getUserMedia还可用作Web Audio API的输入节点。
在manifest中添加audioCapture和videoCapture权限可以在加载的时候得到(仅一次)授权,毕竟加载之后用户不会再有对摄像头或麦克风的访问请求。
最终的目的是使MediaStream适用于任何数据源,不仅限于摄像头和麦克风,还包括来自磁盘或者传感器等输入设备二进制数据。
需要注意的是getUserMedia()必须在服务器上使用,而不是本地文件中,否则的话将会抛出权限的错误PERMISSION_DENIED。
getUserMedia()通常和其他的JavaScript API及库一起使用:
Webcam Toy是一个photobooth应用,它使用WebGL来添加一些特效,让用户可以共享照片或是保存到本地。
FaceKat是一个人脸追踪的游戏,使用headtrackr.js。
ASCII Camera使用Canvas API来生成ASCII码的图片。
七.约束
八.屏幕和标签捕获
九.信令:会话控制,网络和媒体信息
WebRTC使用RTCPeerConnection在浏览器(别名peer)之间互通数据流,但是需要一种机制去协调通信或者发送控制消息,这个过程被称为信令。WebRTC没有指定信令方法和协议,信令不是RTCPeerConnection API的一部分。
因此,WebRTC应用的开发者可用选择其擅长的消息协议,比如SIP或XMPP,或者其他合适的双工通信协议。
apprtc.appspot.com这个例子使用XHR和Channel API作为信令机制。codelab是我们通过Socket.io构建,运行在Node server上的应用。
信令通常用于交互三类信息:
1.会话控制消息;初始化或者关闭通信,报告错误。
2.网络信息:对于外部而言,我的IP地址和端口是什么?
3.媒体信息:什么编码和分辨率浏览器可以处理,我的浏览器要和谁通信。
在p2p的流传输之前,必须通过信令成功的交换信息。
假如Alice想和Bob通信,这里有个简单的例子来自WebRTC W3C Working Draft,展示了实际的信令处理过程。例子中假设存在某种信令机制,该机制通过createSignalingChannel()方法创建。注意在Chrome和Opera中,RTCPeerConnection是带有前缀的。
首先,Alice和Bob交换网络信息,‘finding candidates’表示通过ICE framework查找网络接口和端口。
1.Alice创建一个RTCPeerConnection对象,该对象内置onicecandidate处理器。
2.这个处理器在网络candidate生效时开始运行。
3.Alice通过信令通道发送序列化的数据给Bob,信令通道可以是WebSocket或者其他机制。
4.当Bob收到Alice的candidate消息后,调用addIceCandidate将candidate添加到远端描述。
WebRTC客户端(别名peer,这里指Alice和Bob)需要明确并交换本地和远程音视频媒体信息,比如分辨率和编码格式。交换媒体信息的信令,是通过交换会话描述协议(SDP)来实现的。
1.Alice调用了RTCPeerConnection的createOffer()方法,它的回调参数传入的是RTCSessionDescription(Alice的本地会话描述)。
2.在回调中,Alice调用setLocalDescription()方法设置了本地会话描述,然后将该会话描述通过信令通道发送给Bob。注意,RTCPeerConnection并不会采集candidate直到setLocalDescription()被调用。
3.Bob使用setRemoteDescription()方法将Alice发送给他的会话描述设置为远程会话描述。
4.Bob调用了RTCPeerConnection的createAnswer()方法,并传入它从Alice接收到的远程会话描述,此时一个与Alice兼容的本地会话产生了。createAnswer()的回调参数传入的是RTCSessionDescription(Bob将它设置为本地会话描述并发送给Alice)。
5.当Alice收到Bob的会话描述,她使用setRemoteDescription()方法将其设置为远程会话描述。
6.Ping
RTCSessionDescription对象遵从SDP(Session Description Protocol),一个SDP对象看起来如下所示:
交换网络和媒体信息可以同时进行,但这两个过程必须在音视频流开始传输之前完成。
上述的offer/answer架构被称为JSEP(JavaScript Session Establishment Protocol),JSEP架构如下所示:
一旦信令过程成功,就可以直接进行Caller和callee之间p2p的数据流传输了。
十.RTCPeerConnection
RTCPeerConnection是WebRTC的组件,用来稳定高效的处理端对端的数据流通信。
下图是WebRTC的架构图,标明了RTCPeerConnection扮演的角色。你可能注意到了,绿色部分是相当复杂的。
从JavaScript的角度来看,理解这个图最重要的是理解RTCpeerConnection这一部分。WebRTC对编解码器和协议做了大量的工作,使实时通信成为可能,甚至在一些不可靠的网络中:
1.包补偿
2.回声消除
3.自适应带宽
4.视频抖动缓冲
5.自动增益控制
6.噪声抑制
7.图像清除
章节九中的例子从信令的角度进行了讲解,下面我们将学习两个WebRTC应用;一个简单的演示了RTCPeerConnection,另一个是功能齐全的视频聊天客户端。
十一.无服务器的RTCPeerConnection
这个例子中caller和callee在同一个网页中,能更加清晰的展示RTCPeerConnection API的工作流程,因为RTCPeerConnection对象之间可以直接交换数据和消息,不需要通过中继信道机制。
一个陷阱:RTCPeerConnection()第二个约束类型的参数是可选的,它与getUserMedia()中使用的约束类型不同。
本例中pc1表示本地端(caller),pc2表示远程端(callee)
caller
1.创建一个RTCPeerConnection,并通过getUserMedia()添加数据流。
2.创建一个offer,并将它设置为pc1的本地会话描述,设置为pc2的远程会话描述。可以直接在代码中设置,不需要使用信令,因为caller和callee在同一个网页中。
callee
1.创建pc2,接收pc1的数据流,并显示到video元素中
十二.有服务器的RTCPeerConnection
实际应用中,WebRTC需要服务器,无论多简单,下面四步是必须的:
1.用户通过交换名字之类的信息发现对方。
2.WebRTC客户端应用交换网络信息。
3.客户端交换媒体信息包括视频格式和分辨率。
4.WebRTC客户端穿透NAT网关和服务器。
换句话说,WebRTC需要四种类型的服务端功能。
1.用户发现和通信
2.信令
3.NAT/防火墙穿透
4.中继服务器,防止端到端的通信失败
以上这些不在本文讨论范围之内。可以说基于STUN和TURN协议的ICE框架,使得RTCPeerConnection处理NAT穿透和其他网络难题成为可能。
ICE框架用于端到端的连接,比如说两个视频聊天客户端。起初,ICE尝试通过UDP直接连接两端,这样可以保证低延迟。在这个过程中,STUN服务器有一个简单的任务:使NAT后边的端能找到它的公网地址和端口(谷歌有多个STUN服务器,其中一个用在了apprtc.appspot.com例子)。
如果UDP传输失败,ICE会尝试TCP:首先是HTTP,然后才会选择 HTTPS。如果直接连接失败,通常因为企业的NAT穿透和防火墙,此时ICE使用中继(Relay)服务器。换句话说,ICE首先使用STUN和UDP直接连接两端,失败之后返回中继服务器。‘finding cadidates’就是寻找网络接口和端口的过程。
WebRTC工程师Justin Uberti在幻灯片2013 Google I/O WebRTC presentation中提供了许多关于ICE、STUN和TURN的信息。
十三.一个简单的视频聊天客户端
如果你觉得这个例子比较难,你也行会喜欢上我们的WebRTC codelab。那里一步步的介绍了如何建立一个完整的视频聊天应用,包括一个运行于Node server上基于Socket.io的信令服务器。
apprtc.appspot.com是一个测试WebRTC的好地方,里面有视频聊天的例子,它实现了信令和基于STUN服务器的NAT/防火墙穿透。这个例子使用adapter.js处理不同的RTCPeerConnection和getUserMedia()实现。
下面我们详细的过一遍代码。
如何开始
这个例子从initialize()函数开始运行。
需要注意的是,变量room和openChannel()参数的值都是由Google App Engine应用自身提供的。查看一下index.html template 就知道该赋什么值了。
这段代码初始化HTML video元素的相关变量,video元素播放来自本地摄像头(localVieo)和远程摄像头(remoteVideo)的视频流。resetStatus()设置了一条状态消息。
openChannel()函数建立了WebRTC客户端间的消息通道。
关于信令,本例使用的是Google App Engine Channel API,这使得JavaScritp客户端无需轮询就能实现消息传输。
使用Channel API建立通道的流程大致如下:
1.客户端A生成一个唯一ID。
2.客户端A向Google App Engine应用请求一个通道标识(即openChannel()的参数),并将它的ID传给Google App Engine应用。
3.Google App Engine应用会调用Channel API为客户端ID分配一个通道和一个通道标识。
4.Google App Engine应用将通道标识发给客户端A。
5.客户端A打开socket并监听服务器上建立的通道。
发送消息的流程大致如下:
1.客户端B给Google App Engine应用发送了一个POST请求,要求升级程序。
2.Google App Engine应用给通道发送一个请求消息。
3.消息经通道传递给客户端A
4.客户端A的onmessage回调函数被调用。
重申一次,信令传输机制是由开发者选择的。WebRTC并没有指定信令机制。本例的Channel API能被其他的方式取代,比如WebSocket。
initialize()调用完openChannel()之后,紧接着调用getUserMedia(),这个函数可以检测出浏览器是否支持getUserMedia API。如果一切顺利,onUserMediaSuccess会被调用。
这样一来,本地摄像头就能显示在localVideo元素中了。
此时,initiator被设置成1(直到caller的会话终止),maybeStart()被调用。
该函数使用了一种巧妙的结构,可以工作于多个异步回调:maybeStart()可能被任何函数调用,但是只有当localStream被定义、channelReady为true且通信还未开始的情况下,maybeStart()才会运行。因此,当连接还未建立,本地流已经可用,且信令通道已经准备好时,连接才会创建并加载本地视频流。接着started被设置为true。所以连接不会被创建多次 。
RTCPeerConnection: 发起通话
在maybeStart()中被调用的createPeerConnection(),才是关键所在。
这段代码的目的是使用STUN服务器建立一个连接,并将onIceCandidate()作为回调函数。然后给RTCPeerConnection每个事件指定处理器(函数):当会话连接或打开,当远程流被加载或移除。在本例中,这些处理器只是记录了状态消息——除了onRemoteStreamAdded(),它给remoteVideo元素设置了数据源。
从客户端到服务器的消息外传,是通过sendMessage()方法内的XHR请求实现的。
XHR多用于从客户端发送信令消息到服务端,但是某些机制需要用来实现服务端到客户端的消息传输:本例用的是Google App Engine Channel API。来自此API的消息会传递到processSignalingMessage():
本文暂时没有评论,来添加一个吧(●'◡'●)