关注微信公众号(瓠悠笑软件部落),一起学习,一起摸鱼
本文是Google开源大会对WebRTC的讲解。自己看视频做的笔记。英文好的同学,建议直接看视频。原视频地址
如果访问不了,可以访问我的公众号。里面有视频:视频带文字版
喜欢的话,别忘了点击好看。谢谢你的支持。
WebRTC 的三种任务
- 获取音频和视频
- 传达音频和视频
- 传达任意数据
三种主要的JavaScript APIs
- MediaStream(aka getUserMedia)
- RTCPeerConnection
- RTCDataChannel
MediaStream
- 代表一种 音频 或者/和 语音流.
- 可以包含多个 “tracks”
- 通过 navigator.getUserMedia() 获取一个 MediaStream
MediaStream
aka getUserMedia
var constraints = {video: true};
function successCallback(stream) {
var video = document.querySelector("video");
video.src = window.URL.createObjectURL(stream);
}
function errorCallback(error) {
console.log("navigator.getUserMedia error:", error);
}
navigator.getUserMedia(constraints, successCallback, errorCallback);
Constraints
- Controls the contents of the MediaStream
- Media type, resolution, frame rate
video: {
mandatory: {
minWidth: 640,
minHeigh: 360
},
optional [{
minWidth: 1280,
minHeigth: 720
}]
}
getUserMedia + Web Audio
// success callback when requesting audio input stream
function gotStream(stream) {
var audioContext = new webkitAudioContext();
// create an AudioNode from the stream
var mediaStreamSource = audioContext.createMediaStreamSource(stream);
// connect it to the destination or any other node for processing!
mediaStreamSource.connect(audioContext.destination);
}
确保打开了Chrome 浏览器里面 about:flags 里面的 Web Audio Input
获取用户切图 gUM screencapture
var constraints = {
video: {
mandatory: {
chromeMediaSource: 'screen'
}
}
}
navigator.webkitGetUserMedia(constraints, gotStream);
RTCPeerConnection
audio 和 video 点到点之间的链接通信
Communicate Media Streams
RTCPeerConnection 做了很多
- 信令处理
- 解码操作
- 端到端的通信
- 安全
- 带宽控制
WebRTC 架构
RTCPeerConnection 样例
pc = new RTCPeerConnection(null);
pc.onaddstream = gotRemoteStream;
pc.addStream(localStream);
pc.createOffer(gotOffer);
function gotOffer(desc) {
pc.setLocalDescription(desc);
sendOffer(desc);
}
function getAnswer(desc) {
pc.setRemoteDescription(desc);
}
function getRemoteStream(e) {
attachMediaStream(remoteVideo, e.stream);
}
RTCDataChannel
端到端之间的任意数据的双向通信
RTCDataChannel
- Same API as WebSocket
- Ultra-low lantency 超低延迟
- Unreliable or reliable 根据应用场景选择是速度重要,还是可靠性重要。比如传文件,需要搞可靠性。而传游戏数据,数度更重要。
- Secure 保证传输的数据在接收后能够以正确的方式解码。
RTCDataChannel API
var pc = new webkitRTCPeerConnection(servers, {optional: [{RtpDataChannels: true}]};
pc.ondatachannel = function(event) {
receiveChannel = event.channel;
receiveChannel.onmessage = function(event) {
document.querySelector("div#receive").innerHTML = event.data;
};
};
sendChannel = pc.createDataChannel("sendDataChannel", {reliable: false});
document.querySelector("button#send").onclick = function() {
var data = document.querySelector("textarea#send").value;
sendChannel.send(data);
};
Servers and Protocols
Peer to Peer - 但是我们需要服务器.
Abstract Signaling
- 需要交换 ‘session description’ objects.
- 我支持什么样的格式,我想要发送什么
- 端到端之间建立链接时,需要的网络信息
- 可以使用任意 messaging mechanism,比如: web sockets, Google Cloud Messaging, XHR
- 可以使用任意 messaging protocol . 比如:JSON,或者标准的协议: SPI XMPP。
Signaling Diagram
An RTCSessionDescription
STUN and TURN
P2P in the age of firewalls and NATs
端到端之间 session 完整的路径。
在很早以前,这不是问题。人们知道对方的公网IP地址就可以直接连接进行通信。
但后来有了NAT, NAT分发所谓的私有IP地址.而私有IP地址不能用于建立链接通信。我们就无法建立真正的端到端通信。除非我们有公共地址。所以引入了STUN技术。
STUN
- 告诉我我的公网IP地址是多少. 当一个request 发送到STUN Server的时候,STUN Server查看这个请求的来源地址,并把地址放到 packet里面,然后发回去。所以现在WebRTC 知道 Peer 的公网IP地址了,之后STUN server 就不会参与到 Peer 与 Peer 之间的通信链路中去了。也就不需要转发 media。
- 一个简单的 Server,运行成本低
- Data flows peer-to-peer
通常情况下,是可以建立通信的,但不是在所有的情况下都能正常工作。所以引入了TURN 技术。
TURN
- 如果 peer-to-peer 通信失败的话,提供一个 cloud fallback.
当无法建立端到端的链接时,转而调用云服务中的 relay。请求:给我一个公共的IP地址。由于这个公共地址是在云服务上。任何人都可以和他建立链接。也就以为着这个call可以建立起来。即使你在一个受限制的网络环境中,甚至在一个网络代理后面。 - 数据是通过 server 发送的,使用 server 的带宽
缺点是,由于数据实际上是通过服务器中继的,因此会产生运营成本。但这意味着这个通话可以在几乎所有的网络环境下正常的工作。 - 确保 call 可以在绝大数网络环境下正常工作。
现在,一方面,我们有STUN,它超级便宜,但面对复杂的网络环境,会不可用。我们有TURN。他通常都可用。但会占用服务器的带宽。这两种方案,如何选择最好的方案呢?
先尝试使用STUN Server 建立链接,如果不行,我们无法穿透NATs. s所以,我们回过头来,接着我们唯一能用的是TURN,把 media 数据从我们的发起 peer, 经过NAT, 再经过 TURN server 发送给另一端的 peer. 这些都是通过 ICE 技术实现的。
ICE
- ICE: 一个用于链接 Peers 的框架。
- 尝试为每一个 call 找到最佳的通信路径。
- 绝大多数 calls 都可以使用 STUN(webrtcstats.com);
部署 STUN/TURN
- stun.l.google.com:19302
- WebRTC stunserver, turnserer 建议取名的时候,取一个长长的名字以确保唯一性。
- rfc5766-turn-server 他有 Amazon VM 镜像。你可以下载下来,部署到云服务器上去,你就可以给你的用户提供 TURN server 了。
- restund 另外一个 TURN server,我们使用过,效果很好。
WebRTC code package 里面有 STUN 和 TURN 的源代码。
安全 Security
在WebRTC开始的时候,就考虑了安全问题
- 强制加密 media 和 data . 所有传输的数据都使用标准的 AES 加密。
- Secure UI, explicit opt-in . 只有用户明确地选择了使用麦克风和摄像头,WebRTC才可以用这些功能。
- Sanboxed, no plugins. WebRTC 运行在Chrome 浏览器的 沙盒 里面。
所以即使有人试图攻击chrome里面的webRTC. 浏览器和用户都会得到完整的保护。 - WebRTC Security Architecture WebRTC 安全架构
Secure pathways 安全的传输方式
- Signaling 用HTTPS加密
- Audio/Video 使用SRTP加密
- Data 使用DTLS(Datagram TLS) 加密
Architecutres
如果有多个call,比如一个多方会议,我应该如何构建我的应用程序?
Peer to Peer: 1 对 1 的 call
Mesh(网孔):小型的多方会议.
Mesh 表示每一个peer 都会连接到另外所有的其他peer。
这样也很简单,因为他们之间的链接不涉及服务器服务器和其他东东,比如信令。但有缺点: 假设有N个Peer参与通信,每一个Peer要发送的数据,必须将数据复制N-1分,分别发送给其他N-1个Peer. 这将有对应的CPU和带宽消耗。所以这取决于你要发送的media类型。对于Audio,开销要大一些。对应Video,开销要小一些。拓扑图中参与通话的Peers数量因此会收到限制. 如果某一个Peer是手机设备。CPU和带宽吃紧。限制更明显。
为了解决这个问题,引入另外一种架构。
Star: medium N-way call 星形架构
从所有peer里面找到一个性能最强的。由它从当会话的中心角色。我们称之为 the focus for the call. foucs 实际负责接收数据,复制并转发给所有其他Peers 或者 endpoints. 但是我们要处理多方的高清视频流(HD video streams). focus 的任务就有点吃不消了。所以对于大型的多方会话,需要使用MCU。
MCU multipoint control unit. 多点控制单元
MCU 是一个为传递大量音频和视频而定制的服务器。它可以做各种事情. 它可以选择 stream 并转发. 它实际上可以混合音频或视频数据。它还能录制。如果一个Peer 掉线了,MCU不会中断整个会议,因为MCU要负责所有的Peer的会话,而不单单是某一个Peer。
Beyong browers 不仅仅限制于在浏览器中使用。
Phones and more
- 容易和非浏览器设备集成
- sipML5 开源的 JavaScript SPI client. 可以用于标准的SIP设备。
- Phono 开源的 JavaScript phone API
- Zingaya embeddable phone widget
Zingaya PSTN
创建一个 WebRTC app
chrome://webrtc-internals
在这里可以看到webRTC API 调用的日志,你可以debug.
adapter.js
让你在所有版本的浏览器里面使用同样的代码
- 移除了厂商前缀(vendor prefixes)
- 将 Chrome/Firefox 的差异做了抽象处理。
- 最大限度地减少规范流失的影响(minimizes effects of spec chrun)
实际上 webRTC 规范的更新频率非常快,对于一个特定的浏览器,这些API 不能一直匹配最新版本的规范。adapter.js可以帮助Web开发人员隔离浏览器之间的差异和版本之间的差异。因此我们确保adapter.js始终实现最新的规范,然后向下发送到版本支持的任何内容。所以新的API发布的时候,不需要更改开发人员的代码,只需要更新一下adapter.js 文件就可以了。
JavaScript frameworks
- Video chat:
- SimpleWebRTC
- easyRTC
- webRTC.io
- Peer-to-peer data:
- PeerJS
- Sharefest
SimpleWebRTC
很方便的 peer-to-peer 视频和语音
var webrtc = new WebRTC ({
localVideoEl: 'localVideo',
remoteVideosEl: 'remoteVideos',
autoRequestMedia: true
});
webrtc.on('readyToCall', function (){
webrtc.joinRoom('My room name');
});
PeerJS
方便的 peer-to-peer data
var peer = new Peer('someid', {key: 'apikey'});
peer.on('connection', function(conn) {
conn.on('data', function(data) {
// will print 'hi!'
console.log(data);
});
});
// connecting peer
var peer = new Peer('anotherid', {key: 'apikey'});
var conn = peer.connect('someid');
conn.on('open', function() {
conn.send('hi!');
});
javascript 并不用关心产品方面的服务特性,比如 信令,STUN 和 TURN 服务。幸运的是,OpenTok 和 vLine 为我们提供了这些服务。你只需要注册这些服务,获取API key, 就可以使用他们的产品功能发起 call. 触达世界的每个角落。他们还制作了可以轻松放入WebRTC应用程序的UI小部件.所以你能快速的开发和运行 WebRTC app.
Services
- 完成 video services:
- OpenTok (acuqired by Telefonica Digital)
- vLine
最新版chrome 已经支持 HD video quality 和 full-band audio quality.