WebRTC是Web Real-Time Communication(网页实时通信)。WebRTC 包含有三个组件:
- 访问用户摄像头及麦克风的 getUserMedia
- 穿越 NAT 及防火墙建立视频会话的 PeerConnection
- 在浏览器之间建立点对点数据通讯的 DataChannels
分别对应三个API接口:
- Network Stream API 代表媒体数据流
- RTCPeerConnection 一个RTCPeerConnection对象允许用户在两个浏览器之间直接通讯;
- Peer-to-peer Data API 一个在两个节点之间的双向的数据通道
浏览器对 WebRTC 的支持
最新支持成都可在 caniuse.com 上查询
- pc上浏览器的支持情况[pc浏览器对WebRTC的支持情况](gtms04.alicdn.com/tps/i4/TB1w…)
- Andriod chrome浏览器从29版开始支持webRTC,但是默认关闭,如果不能正常使用webRTC,请在chrome://flags,开启webRTC[移动端的浏览器支持情况](gtms04.alicdn.com/tps/i4/TB1h…)
- iOS 还不支持,不过苹果很快会支持
WebRTC API
- MediaStream
getUserMedia()与WebRTC相关,因为它是通向这组API的门户。它提供了访问用户本地相机/麦克风媒体流的手段。在移动设备上,目前只有andriod中webview内核为36或者大于36才支持(即只有andriod L或者更高版本),ios设备暂时还不支持。 - 功能检测
各家浏览器对getUserMedia支持不同,因此在使用该API之前需要检测用户浏览器是否支持getUserMedia
function hasGetUserMedia() {
return !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
}
- 请求权限
浏览器出于安全考虑,在请求网络摄像头或麦克风时,会弹出信息栏,让用户选择授予还是拒绝对其相机/麦克风的访问权限。 - 使用方法
getUserMedia()需要传递三个参数,第一个参数用于指定你要访问的媒体类型, 第二个参数是成功获取媒体数据流后的回调函数,第三个参数为获取媒体数据流失败的处理函数,相关API文档可以参考:getUserMedia
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.moZGetUserMedia || navigator.msGetUserMedia;
var video = document.querySelector('video');
navigator.getUserMedia({
audio : true,
video : true
}, function (stream) {
video.src = window.URL.creatObjectURL(stream);
}, function (error) {
console.log(error);
});
这样就可以通过video标签成功将视频流输出到页面上。
- 截取视频截图
可以通过canvas的API: ctx.drawImage(video, 0, 0)将video的某一帧绘制到canvas上,再通过canvas的canvas.toDataURL('image/png')将canvas绘制的东西转为图片。
var video = document.querySelector('video');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
navigator.getUserMedia({
audio: true,
video: true
}, function(stream) {
video.src = window.URL.creatObjectURL(stream);
}, function(error) {
console.log(error);
});
video.addEventListener('click', function() {
ctx.drawImage(video, 0, 0);
var img = new Image();
img.src = canvas.toDataURL('image/png');
document.appendChild(img);
}, false)
- 给图片添加滤镜
canvas 可以获取每一个像素点得颜色值(包括red, green, blue, alpha四个值),通过 canvas 的 API: ctx.getImageData() 获取到的所有像素点的颜色值,修改对应的像素值之后,可以通过 ctx.putImageData() 将像素点重新绘制到 canvas 中
var imgData = ctx.getImageData();
var filter = {
// 灰度效果
grayscale: function(pixels) {
var d = pixels.data;
for (var i = 0, len = d.length; i < len; i += 4) {
var r = d[i],
g = d[i + 1],
b = d[i + 2];
d[i] = d[i + 1] = d[i + 2] = (r + g + b) / 3;
}
return pixels;
},
// 复古效果
sepia: function(pixels) {
var d = pixels.data;
for (var i = 0, len = d.length; i < len; i += 4) {
var r = d[i],
g = d[i + 1],
b = d[i + 2];
d[i] = (r * 0.393) + (g * 0.769) + (b * 0.189);
d[i + 1] = (r * 0.349) + (g * 0.686) + (b * 0.168);
d[i + 2] = (r * 0.272) + (g * 0.534) + (b * 0.131);
}
return pixels;
},
// 红色蒙版效果
red: function(pixels) {
var d = pixels.data;
for (var i = 0, len = d.length; i < len; i += 4) {
var r = d[i],
g = d[i + 1],
b = d[i + 2];
d[i] = (r + g + b) / 3;
d[i + 1] = d[i + 2] = 0;
}
return pixels;
},
// 反转效果
invert: function(pixels) {
var d = pixels.data;
for (var i = 0, len = d.length; i < len; i += 4) {
var r = d[i],
g = d[i + 1],
b = d[i + 2];
d[i] = 255 - r;
d[i + 1] = 255 - g;
d[i + 2] = 255 - b;
}
return pixels;
}
};
ctx.putImageData(filter[type](imgData));
- 音频处理
navigator.getUserMedia()可以和web Audio API相结合,用来处理音频效果
var range = document.querySelector('input');
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioCtx = new AudioContext();
navigator.getUserMedia({
audio: true
}, function(stream) {
// 创建音频流
var source = audioCtx.createMediaStreamSource(stream);
// 双二阶滤波器
var biquadFilter = audioCtx.createBiquadFilter();
biquadFilter.type = 'lowshelf';
biquadFilter.frequenc.value = 1000;
biquadFilter.gain.value = range.value;
source.connect(biquadFilter);
biquadFilter.connect(audioCtx.destination);
}, function(error) {
console.log(error);
});
RTCPeerConnection
RTCPeerConnection,用于peer跟peer之间呼叫和建立连接以便传输音视频数据流;
WebRTC是实现peer to peer的实时通信(可以两个或多个peer之间),在能够通信前peer跟peer之间必须建立连接,这是RTCPeerConnection的任务,为此需要借助一个信令服务器(signaling server)来进行,信令包括3种类型的信息:
- Session control messages: 初始化和关闭通信,及报告错误;
- Network configuration: 双方的IP地址和端口号(局域网内部IP地址需转换为外部的IP地址);
- Media capabilities: 双方的浏览器支持使用何种codecs以及多高的视频分辨率。
var PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
navigator.getUserMedia = navigator.getUserMedia ? "getUserMedia" :
navigator.mozGetUserMedia ? "mozGetUserMedia" :
navigator.webkitGetUserMedia ? "webkitGetUserMedia" : "getUserMedia";
var v = document.createElement("video");
// 创建信令
var pc = new PeerConnection();
pc.addStream(video);
pc.createOffer(function(desc) {
pc.setLocalDescription(desc, function() {
// send the offer to a server that can negotiate with a remote client
});
})
// 创建回复
var pc = new PeerConnection();
pc.setRemoteDescription(new RTCSessionDescription(offer), function() {
pc.createAnswer(function(answer) {
pc.setLocalDescription(answer, function() {
// send the answer to the remote connection
});
});
})
peer跟peer之间一旦建立连接就可以直接传输音视频数据流,并不需要借助第三方服务器中转。
具体文档可以查看:developer.mozilla.org/en-US/docs/…
RTCDataChannel
RTCDataChannel可以建立浏览器之间的点对点通讯。常用的通讯方式有webSocket, ajax和 Server Sent Events等方式,websocket虽然是双向通讯,但是无论是websocket还是ajax都是客户端和服务器之间的通讯,这就意味着你必须配置服务器才可以进行通讯。而RTCDATAChannel采用另外一种实现方式
- 它使用webRTC的另外一个API:RTCPeerConnection,RTCPeerConnection无需经过服务器就可以提供点对点之间的通讯,避免服务器这个中间件
- RTCDataChannel支持SCTP机制,SCTP实际上是一个面向连接的协议,但SCTP偶联的概念要比TCP的连接具有更广的概念,SCTP对TCP的缺陷进行了一些完善,使得信令传输具有更高的可靠性,SCTP的设计包括适当的拥塞控制、防止泛滥和伪装攻击、更优的实时性能和多归属性支持。
WebRTC并未规定使用何种信令机制和消息协议,象SIP、XMPP、XHR、WebSocket这些技术都可以用作WebRTC的信令通信。
除了信令服务器,peer跟peer建立连接还需要借助另一种服务器(称为STUN server)实现NAT/Firewall穿越,因为很多peer是处于私有局域网中,使用私有IP地址,必须转换为公有IP地址才能相互之间传输数据。这其中涉及到一些专业术语包括STUN、TURN、ICE等,其实我对这些概念也不是很理解。网上找到的WebRTC demo好象都用的是Google提供的STUN server。
参考文章:www.html5rocks.com/en/tutorial…
developer.mozilla.org/en-US/docs/…
WebRTC的目的是为了简化基于浏览器的实时数据通信的开发工作量,但实际应用编程还是有点复杂,尤其调用RTCPeerConnection必须对如何建立连接、交换信令的流程和细节有较深入的理解。因此我们可以使用已经封装好的WebRTC库,这些WebRTC库对原生的webRTC的API进行进一步的封装,包装成更简单的API接口。同时屏蔽了不同浏览器之间的差异。
目前网上主要有两种WebRTC的封装库:
- WebRTC.io github地址为:github.com/webRTC/webR…
- simpleWebRTC github地址为:github.com/HenrikJoret…
最后是用WebRTC写的一个小demo:ccforward.github.io/demos/webrt…
关于 WebRTC 的相关文章推荐:www.html5rocks.com/en/tutorial…