webRTC
WebRTC是“网络实时通信”(Web Real Time Communication)的缩写。它最初是为了解决浏览器上视频通话而提出的,即两个浏览器之间直接进行视频和音频的通信,不经过服务器。后来发展到除了音频和视频,还可以传输文字和其他数据。
Google是WebRTC的主要支持者和开发者,它最初在Gmail上推出了视频聊天,后来在2011年推出了Hangouts,语序在浏览器中打电话。它推动了WebRTC标准的确立。
WebRTC主要让浏览器具备三个作用。
WebRTC共分成三个API,分别对应上面三个作用。
MediaStream 对应的是 JS 里的 navigator.getUserMedia() 方法,它负责从底层平台获取音视频流。音视频流经过 WebRTC 音视频引擎的自动优化、编码和解码,就可以直接用或传输到各种目的地用。这里有个 Demo,就是用 getUserMedia 获取视频流,再把每一帧都转成 ASCII 字符播放。总之 MediaStream API 设计得很简单,使用起来也很方便。
RTCPeerConnection 用来建立和维护端到端连接,并提供高效的音视频流传输。整个 WebRTC 提供的 API 中,要数这个最复杂:
首先,要建立端到端连接,不可避免要解决 NAT 穿透问题,RTCPeerConnection 为此引入了 ICE(Interactive Connectivity Establishment)框架。ICE 致力于在端之间建立一条有效的通道,优先直连,其次用 STUN 协商,再不行只能用 TURN 转发。
STUN(Session Traversal Utilities for NAT)协议,解决了三个问题:1)获得外网 IP 和端口;2)在 NAT 中建立路由条目,绑定外网端口,使得到达外网 IP 和端口的入站分组能找到应用程序,不被丢弃;3)定义了一个简单的 keep-alive 机制,保证 NAT 路由条目不会因为超时而被删除。STUN 服务器必须架设在公网上,可以自己搭建,也可以使用第三方提供的公开服务,例如 Google 的「stun:stun.l.google.com:19302」。
TURN(Traversal Using Relays around NAT)协议,依赖外网中继设备在两端之间传递数据。简单说就是通过两端都可以访问的 TURN 服务转发消息,间接把两端连起来。TURN 还会尝试使用 TCP 建立,而不仅仅是 UDP,可靠性大大增强,带宽成本也随着大幅提升。根据 Google 的统计,UDP 服务中,有 8% 左右的情况下需要 TURN。
其次,要建立端到端的信道,还是需要借助服务端来交换和协商一些信息,这个过程被称之为 Signaling。WebRTC 并没有规则 Signaling 必须使用某种协议,而把选择权交给了应用程序。我们可以选用不同方式(XMLHttpRequest、WebSocket),采用已有的 SIP、Jingle、ISUP 等发信协议,来建立信道。
通常,在 WebRTC 应用中,建立信道这一步都是优先走 WebSocket,并支持降级为 HTTP。一来支持 WebRTC 的浏览器肯定都支持 WebSocket;二来 WebSocket 实时性更好一些。特别需要注意的是,WebSocket 只用来辅助建立端到端连接,一旦连接建立,信源在端到端之间的传输就完全不需要服务端了(当然 TURN 这种中继模式就另当别论)。
RTCDataChannel 用来支持端到端的任意应用数据交换。建立 RTCPeerConnection 连接之后,除了可以传输音视频流,还可以打开一个或多个信道用来传输任何文本或二进制内容,这就是 RTCDataChanel。DataChannel API 在使用上跟 WebSocket 非常类似,功能上都可以用来在端到端之间传输数据,但是本质上他们还是有区别的:
首先,WebRTC 端与端之间是对等的,DataChannel 可以由任何一方发起;这与 WebSocket 连接只能由客户端发起不同; 其次,WebSocket 的会话层协议 TLS 是可选的;而 WebRTC 的会话层协议 DTLS 是必须的,这表明通过 WebRTC 传输的数据一定会被加密; 再者,WebSocket 运行在 TCP 之上,每条消息天然有序并可靠;而 DataChannel 可以通过 SCTP 的交付属性选项来指定消息是有序还是乱序,是可靠还是部分可靠,部分可靠时还可以指定使用超时重传还是计数重传策略。
现阶段 DataChannel 运行在下列协议之上:
对于webrtc基础,可以参考:
https://blog.coding.net/blog/getting-started-with-webrtc
http://javascript.ruanyifeng.com/htmlapi/webrtc.html
对于peerjs的学习,我在这还需要说一个问题:stun和turn的问题(stun和turn都是穿透nat用的,但是对于对等网络,stun就够了,而stun穿透不了非对等网络,这个时候就需要turn了,但是turn是需要跑服务器流量的,也就是和你服务器的带宽等是有关系的,而stun就不需要,stun只是一个穿透作用)
peerJs 官方文档:http://peerjs.com/docs/#peeron-call
PeerJS 实现了真正的浏览器上的点对点数据通讯。PeerJS 将 WebRTC 作为 API 抽象、连接代理和二进制序列化。
PeerJS 项目的目的是实现运行在不同系统上的Web应用程序相互通讯。PeerJS完善了WebRTC,因为作为视频连接协议,WebRTC并没有说明基于WebRTC的客户端应该如何定位连接的用户。
下面是一个完整的实例,包括连接,中转,获取返回数据,和对返回数据进行分析。
客户端:
// var Bundle = {
// init : function(){
var cameraIndex = 0
var peer = new Peer({
// Set API key for cloud server (you don't need this if you're running your
// own.
key: 'retailwell',
host: 'signal.retailwell.com',
port: 80,
// Set highest debug level (log everything!).
debug: 3,
config: {
'iceServers': [
{
'url' : 'turn:43.241.232.70:3478?transport=tcp',
'credential' : 'zfwzyzxq',
'username' : 'soaringnova'
}
]
}
});
// 连接
Connect = peer.connect('a79482279e0d73199eee4b054b373fa9');
peer.on('open', function(id) {
PeerId = id;
});
// 连接失败时,打印连接失败信息
peer.on('error', function(err) {
console.log(err);
})
// 发送请求信息
Connect.on('open', function() {
console.log('已执行: open');
Connect.send({'command': 'cameraList', 'peerId': PeerId});
});
peer.on('connection', connect);
// 获取返回的数据,这里是我对返回数据的一个操作,可以使情况而定
function connect(c) {
c.on('data', function(data) {
console.log(data)
// 判断是否是摄像头信息/录像数据
if (data.data.type == 'cameraInfo') {
// 摄像头信息
CameraIndex = data.data.num
var cameraJson = data.data
var fileUrl = Utils.creatBlob(data.data.cameras.thumbnails, 'image/jpg')
cameraJson.cameras.thumbnails = fileUrl
cameraIndex += 1
cameraJson.cameras.index = cameraIndex
console.log(cameraJson)
Camera.init(cameraJson)
}
if (data.data.type == 'streaming') {
// 摄像头录像数据
var fileUrl = Utils.creatBlob(data.data.chunk.uri, 'video/mp4')
var dataJson = {uri: fileUrl}
SocketPlayer.onLive(dataJson)
}
});
}
peer.on('error', function(err) {
});
window.onunload = window.onbeforeunload = function(e) {
if (!!peer && !peer.destroyed) {
peer.destroy();
}
};
// }
// }
摄像头推数据到客户端,但是在传输过程中消耗了太多时间,导致视频卡顿
以下方法还未测试,不知是否可以解决视频推送时间过长的问题(这个方式是针对视频/音频流的)。
当您建立视频/音频流时,您可以指定一些约束条件.
var videoOptions =
(isCordova) ?
{
audio: true,
video: true
}
:
{
audio: true,
video: {
mandatory: {
maxWidth: 640,
maxHeight: 360,
// maxAspectRatio:4/3,
// maxFrameRate:1
},
quality: 7,
width: { ideal: 320 },
height: { ideal: 240 }
}
};
navigator.getUserMedia(videoOptions, function (stream) {})
在上述代码中,如果您使用的是设备(android / ios),则无法选择,但可以在浏览器中进行控制. 5的质量是视频驱动程序作者在质量和带宽之间被认为是可接受的折中的水平.限制图片的尺寸也有帮助.
有关模式详细信息,请参阅此链接: https:// developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia