由于Node.js是基于事件驱动的单线程异步IO,能够提高服务器的并发性能,且一直很火的视频直播软件也层出不穷,于是跟风来填个坑,学习学习。
最开始是看了一个教程,跟着学,实现一个既有视频通话功能,又有协同编码功能的web应用,但是无奈跟着教程用peerjs框架怎么都没调出来视频通话,最终没实现成功,于是网上一番百度,最终采用了网上的SkyRTC和PeerJS结合完成的视频通话,源码已上传git(不想看我下面啰里巴嗦乱七八糟博文的请直接去看代码,虽然代码也很乱?),因为涉及的内容很多,所以写的很省略,都是简单介绍。
github连接 https://github.com/ZeoSophia/VideoCall
项目整体目录图
Socket.io框架
WebRTC信令最流行的实现之一是使用Socket.io。Socket.io是一个JavaScript库,用于支持双向基于事件通信的实时web应用程序。Socket.io虽然使用了WebSocket协议,但它不仅仅是一个简单的WebSocket包装器,它还提供了许多其他功能,比如向多个socket广播,支持对大多数WebRTC来说至关重要的“房间”的概念。
在Node.js环境下可以直接安装Socket.io资源包,安装成功之后,首先需调用HTTP模块的createServer()
方法将Socket.io与服务端的http.srver
绑定。
var app = express();
var server = require('http').createServer(app);
var socketIO = require('socket.io');
var io = socketIO(server);
建立Socket连接,用户通过相同URL(Uniform Resource Locator)进入同一聊天室之后,通过调用io.emit()
方法将消息发送给所有进入同一“房间”的用户,即可连接成功,进而实现即时通讯,实现监听连接双方的消息方式如下:
socket.on('chatMessage', function(data) {
io.to(socket.room).emit('chatMessage', data);
});
socket.on('disconnect', function() {
socket.leave(socket.room);
});
视频通话实现
首先通过调用createStream()
方法创建本地视频流,方便后期实时的视频流传递播放,同时设置video和audio的属性值,建立方法如下:
rtc.on("connected", function(socket) {
rtc.createStream({
"video": true,
"audio": true
});
});
通过接口MediaStream的调用,调用URL.createObjectURL()
方法,将生成的媒体流绑定为前端页面”<video>
”属性的src的值(实现代码如下),再通过网页对HTML代码解析,将媒体流以本地流的形式播放出来。
rtc.on("stream_created", function(stream) {//成功
document.getElementById('me').srcObject=stream;
document.getElementById('me').play();
});
rtc.on("stream_create_error", function() {//失败
alert("failed!");
});
调用RTCPeerConnection接口后,通过调用RTCPeerConnection(iceServer)方法创建一个新对象,并且通过参数创建一个对象,同时会将此对象和一个ICE(Internet Communications Engine)代理对象以及其状态相关联,并且在创建对象时同时被初始化。
var iceServer = {
"iceServers": [{
"url": "stun:stun.l.google.com:19302"
}]
};
var pc = new PeerConnection(iceServer);
WebRTC浏览器兼容问题
WebRTC API的核心是MediaStream处理API,通常称为媒体流API或流API。MediaStream接口可实现从设备摄像头或话筒获取视频、音频数据流的功能,通过调用getUserMedia()
方法获取,采用此接口的方法解决由于浏览器版本不同,导致内核版本不同的问题。
var getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
协同编程
由于Socket.io作为一个应用层不仅能够传递视频、音频等多媒体流,同时也可以传输其他类似文档型的二进制流。前端部分通过’<textarea>’
标签存放,服务段部分发现是该页面之后,先检测是否有前端页面数据传入,通过调用res.render()
的方法将数据动态渲染出来。
<textarea id="code-screen">{{content}}</textarea>
<script>
var code = $('#code-screen').val();
var cmClient;
function init(str, revision, clients, serverAdapter) {
if (!code) {
editor.setValue(str);
}
cmClient = window.cmClient = new EditorClient(revision, clients, serverAdapter, new CodeMirrorAdapter(editor))};
socket.on('doc', function(obj) {
init(obj.str,obj.revision,obj.clients,new SocketIOAdapter(socket));
});
</script>
当两用户成功建立连接时,从数据库通过查找获取代码编辑区实时的内容,前端页面并进行回显,实现用户体验感上的“协同编程”。
if (data) {
res.render('task', {
content: data.content,
roomId: data.id
});
} else {
res.render('error');
}
Task.findByIdAndUpdate(data.room,
{content: self.document}, function(err) {
if (err) return cb(false);
cb(true);
});
- 运行代码前一定要先给peer分配端口