什么是WebRtc
从百度百科摘抄了这么一段话。
WebRTC实现了基于网页的视频会议,标准是WHATWG 协议,目的是通过浏览器提供简单的javascript就可以达到实时通讯(Real-Time Communications (RTC))能力。
WebRTC(Web Real-Time Communication)项目的最终目的主要是让Web开发者能够基于浏览器(Chrome\FireFox\...)轻易快捷开发出丰富的实时多媒体应用,而无需下载安装任何插件,Web开发者也无需关注多媒体的数字信号处理过程,只需编写简单的Javascript程序即可实现,W3C等组织正在制定Javascript 标准API,目前是WebRTC 1.0版本,Draft状态;另外WebRTC还希望能够建立一个多互联网浏览器间健壮的实时通信的平台,形成开发者与浏览器厂商良好的生态环境。同时,Google也希望和致力于让WebRTC的技术成为HTML5标准之一,可见Google布局之深远。
WebRTC提供了视频会议的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:windows,linux,mac,android。
什么是Licode
从Licode官网地址了解到它是一个开源的WebRtc通信平台,因此我们可以从GitHub上下载它的源码链接地址。
它是一个基于webRTC技术之上的开源项目,通过更便捷(easy,fast and scalable)的接口你可以快速搭建出基于webRTC技术的网络视频会议系统,或者与此类似的系统。
那么什么地方会用到它呢?
Licode允许您在网络上创建视频会议室。 但是您也可以实现流媒体录制和您想要的任何其他实时多媒体功能!
Licode包含了客户端和服务端的完整实现。
Licode模块
- Erizo 它是WebRTC Multipoint Control Unit (MCU),使用C++编写,并且100%兼容WebRtc标准和协议。
- Erizo Api 它是Erizo的Node.js插件包装器。可以从Node.js 层面去管理和配置Erizo的各项功能。
- Erizo Controller 核心服务。 向用户提供会议室以进行多方会议。 它还提供了足够的安全性机制和附加功能:数据,用户列表,事件等。
- Nuve 提供了视频会议室管理的API,用户对第三方应用程序的访问控制和服务注册。 它还为服务提供了云可扩展性。
Licode框架
摘自:https://zhuanlan.zhihu.com/p/40462946
Server端分析
erizoController:erizo_controller\erizoController\erizoController.js
erizoController主要实现的对会议房间的管理。
getOrCreateRoom(myId, token.room, token.p2p) | 根据token.room(roomId)获取房间,如果当前不存在这个房间,则新创建一个房间。 myId是当前erizoController的id, 可以开启多个erizoController |
getUsersInRoom(roomId,callback) | 从一个给定的房间(roomId)中获取用户列表 |
deleteRoom (roomId, callback) | 删除一个给定的 房间(roomId) |
deleteUser(user, roomId, callback) | 从一个给定的房间(roomId)中删除一个用户(user) |
在代码的开始部分,erizoController.js中还包含了当前的erizoController配置,
iceServers的URL配置,limit_n_rooms限制最大可创建的房间数,maxErizosUsedByRoom 每个房间可以使用的最大 Erizo的数量,当前erizoController的服务器IP/PORT。
roomController:erizo_controller\erizoController\roomController.js
roomController实现的是对一个房间的控制,在erizo_controller\erizoController\models\Room.js中,Room的constructor中可以看到,如果当前房间不是P2P模式,那么就会为该房间创建一个roomController。
addExternalInput(clientId, publisherId, url, label, callback) | 增加一个ExternalInput,ExternalInput是一个外部输入,也是我们输入的音频视频 |
addExternalOutput (publisherId, url, options, callback) | 增加一个ExternalOutput,ExternalOutput是一个外部输出,主要是对audio和video数据进行打包成Rtp数据包输出。 |
removeExternalOutput (publisherId, url, callback) | 移除一个ExternalOutput |
processConnectionMessageFromClient (erizoId, clientId, connectionId, msg, callback) | 处理来自客户端的链接消息 |
processStreamMessageFromClient (erizoId, clientId, streamId, msg) | 处理来自客户端的流消息 |
addPublisher(clientId, streamId, options, callback, retries) | 添加一个发布者到房间,这时会创建新的OneToManyProcessor 和新的 WebRtcConnection.而WebRtcConnection会成为OneToManyProcessor的发布者。OneToManyProcessor是一个一对多的发布订阅管理器。 具体的实现是:为streamId获取或创建一个ErizoJS,为了在本地跟踪发布者流信息,更新本地的流状态,即这个流所使用的erizoId。每个ErizoJS都有一个id,这个id就是erizoId。真正的addPublisher是在ErizoJS中进行,而ErizoJS可以在一个远程机器上,因此我们我们要在这里去调用ErizoJS中的addPublisher需要进行RPC,Licode 是通过RabbitMQ实现的RPC。调用成功或者失败都会重新更新流的状态。
|
addSubscriber (clientId, streamId, options, callback, retries) | 添加一个订阅者到房间,创建新的 WebRtcConnection.而这个WebRtcConnection会成为添加到OneToManyProcessor的的订阅者列表 |
addMultipleSubscribers(clientId, streamIds, options, callback, retries) | 同时订阅多个流,每个流id存在于streamIds |
removePublisher(clientId, streamId, callback) | 移除一个发布者,会将与该发布者关联的OneToManyProcessor一同删除。 |
removeSubscriber (subscriberId, streamId, callback = () => {}) | 移除一个订阅者,会从该订阅者关联的OneToManyProcessor一同删除。 |
getStreamStats (streamId, callback) | 获取某个流的状态 |
removeMultipleSubscribers (subscriberId, streamIds, callback) | 同时取消订阅多个流,每个流id存在于streamIds |
removeClient (clientId) | 删除一个客户端 |
getErizoJS (callback, previousPosition = undefined) |
maxErizosUsedByRoom | 一个房间最大可以使用的Erizo的数量,每个Erizo都是一个进程。 |
erizos | 是一个ErizoList,记录当前房间使用的Erizo,初始的是空的。 |
amqper | 使用的消息队列,用作RPC,Licode使用RabbitMQ实现RPC, |
erizoControllerId | 所属的erizoController的ID |
streamManager | 记录当前房间的stream,通过stream_id标识。 |
Room:erizo_controller\erizoController\models\Room.js
在非P2P模式下(服务器模式),通过roomController对房间的行为进行管理。
可以想到,发出各种操作行为的都是Client,因此房间里的实体是Client。一个房间中包含多个Client并通过client_id 标识。
Client:erizo_controller\erizoController\models\Client.js
channel | 消息通道,socket |
room | 所属房间 |
token | 标识符 |
id | uuidv4() |
socketEventListeners | 监听的事件列表 |
user | 这个Client的用户信息,{ name: token.userName, role: token.role, permissions: {} } |
permissions | 权限 |
setNewChannel | 掉线后,重新连接,设置新的通道。 |
onMultipleSubscribe(streams, options = {}) | 订阅多个流 |
onMultipleUnsubscribe(streams) | 取消订阅多个流 |
sendMessage(type, arg) | 发送消息 |
onSendDataStream(message) | 将数据流分发给每个订阅者,message中包含stream_id,通过stream_id找到stream,对每个订阅了该stream的订阅者发送这个message |
onStreamMessageP2P(message) | p2p模式下,发给对端的Client |
onConnectionMessage(message) | 处理连接消息 |
onStreamMessage(message) | 非p2p,如果不是控制消息,或者是一个控制消息并且有权限,则调用controller中的processStreamMessageFromClient对消息进行处理 |
onUpdateStreamAttributes(message) | 更新流的属性,需要通知给每个订阅改流的Client |
_publishExternalInput(id, options, sdp, callback) | 新建一个PublishedStream,通过RoomController中的 addPublishedStream加入到当前房间的streammanager中,添加一个ExternalInput。 |
_publishErizo(id, options, sdp, callback) | 新建一个PublishedStream,通过RoomController中的 addPublishedStream加入到当前房间的streammanager中,添加一个Publisher。 |
_publishP2P(id, options, sdp, callback) | |
onSubscribe(options, sdp, callback) | 订阅 |
onPublish(options, sdp, callback) | 发布,包括发布_publishExternalInput、_publishErizo、_publishP2P |
onStartRecorder(options, callback) | 录制开始 |
onStopRecorder(options, callback) | 录制结束 |
onUnpublish(streamId, callback) | 取消发布 |
onUnsubscribe(streamId, callback) | 取消订阅 |
onAutoSubscribe(data, callback) | 自动订阅 |
onDisconnect() |