//使用Google的stun服务器 var iceServer = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] }; //兼容浏览器的getUserMedia写法 var getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); //兼容浏览器的PeerConnection写法 var PeerConnection = (window.PeerConnection || window.webkitPeerConnection00 || window.webkitRTCPeerConnection || window.mozRTCPeerConnection); //与后台服务器的WebSocket链接 var socket = __createWebSocketChannel(); //建立PeerConnection实例 var pc = new PeerConnection(iceServer); //发送ICE候选到其余客户端 pc.onicecandidate = function(event){ socket.send(JSON.stringify({ "event": "__ice_candidate", "data": { "candidate": event.candidate } })); }; //若是检测到媒体流链接到本地,将其绑定到一个video标签上输出 pc.onaddstream = function(event){ someVideoElement.src = URL.createObjectURL(event.stream); }; //获取本地的媒体流,并绑定到一个video标签上输出,而且发送这个媒体流给其余客户端 getUserMedia.call(navigator, { "audio": true, "video": true }, function(stream){ //发送offer和answer的函数,发送本地session描述 var sendOfferFn = function(desc){ pc.setLocalDescription(desc); socket.send(JSON.stringify({ "event": "__offer", "data": { "sdp": desc } })); }, sendAnswerFn = function(desc){ pc.setLocalDescription(desc); socket.send(JSON.stringify({ "event": "__answer", "data": { "sdp": desc } })); }; //绑定本地媒体流到video标签用于输出 myselfVideoElement.src = URL.createObjectURL(stream); //向PeerConnection中加入须要发送的流 pc.addStream(stream); //若是是发送方则发送一个offer信令,不然发送一个answer信令 if(isCaller){ pc.createOffer(sendOfferFn); } else { pc.createAnswer(sendAnswerFn); } }, function(error){ //处理媒体流建立失败错误 }); //处理到来的信令 socket.onmessage = function(event){ var json = JSON.parse(event.data); //若是是一个ICE的候选,则将其加入到PeerConnection中,不然设定对方的session描述为传递过来的描述 if( json.event === "__ice_candidate" ){ pc.addIceCandidate(new RTCIceCandidate(json.data.candidate)); } else { pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp)); } };
实例
因为涉及较为复杂灵活的信令传输,故这里不作简短的实例,能够直接移步到最后
RTCDataChannel
既然能创建点对点的信道来传递实时的视频、音频数据流,为何不能用这个信道传一点其余数据呢?RTCDataChannel API就是用来干这个的,基于它咱们能够在浏览器之间传输任意数据。DataChannel是创建在PeerConnection上的,不能单独使用
使用DataChannel
咱们可使用channel = pc.createDataCHannel("someLabel");
来在PeerConnection的实例上建立Data Channel,并给与它一个标签
DataChannel使用方式几乎和WebSocket同样,有几个事件:
* onopen
* onclose
* onmessage
* onerror
同时它有几个状态,能够经过readyState
获取:
* connecting: 浏览器之间正在试图创建channel
* open:创建成功,可使用send
方法发送数据了
* closing:浏览器正在关闭channel
* closed:channel已经被关闭了
两个暴露的方法:
* close(): 用于关闭channel
* send():用于经过channel向对方发送数据
经过Data Channel发送文件大体思路
JavaScript已经提供了File API从input[type='file']
的元素中提取文件,并经过FileReader来将文件的转换成DataURL,这也意味着咱们能够将DataURL分红多个碎片来经过Channel来进行文件传输
一个综合的Demo
SkyRTC-demo,这是我写的一个Demo。创建一个视频聊天室,并可以广播文件,固然也支持单对单文件传输,写得还很粗糙,后期会继续完善
使用方式
- 下载解压并cd到目录下
- 运行
npm install
安装依赖的库(express, ws, node-uuid) - 运行
node server.js
,访问localhost:3000
,容许摄像头访问 - 打开另外一台电脑,在浏览器(Chrome和Opera,还未兼容Firefox)打开
{server所在IP}:3000
,容许摄像头和话筒访问 - 广播文件:在左下角选定一个文件,点击“发送文件”按钮
- 广播信息:左下角input框输入信息,点击发送
- 可能会出错,注意F12对话框,通常F5能解决
功能
视频音频聊天(链接了摄像头和话筒,至少要有摄像头),广播文件(可单独传播,提供API,广播就是基于单独传播实现的,可同时传播多个,小文件还好说,大文件坐等内存吃光),广播聊天信息