之前我在《janus前端核心库源码分析》一文中已经向你详细分析了janus.js
文件的实现,但对于大多同学来说,知道如何使用它才是最重要的。那具体我们该如何使用它呢?janus中的videoroomtest.js
是一个不错的例子,今天就来分析一下videoroomtest.js
,看看它是是如何使用janus.js
的。
通过分析videoroomtest.js
文件,你会发现使用janus.js
的步骤很简单,只要下面三步即可:
- 初始化
janus.js
- 创建
Janus
对象 - attach 音视频流
下面我就按上面的顺序向你逐一介绍videoroomtest.js
是如何使用janus.js
的。
janus的初始化
我们使用janus.js
之前,第一步就是调用Janus
的类
方法init
来初始化janus.js
。方法的原型如下:
1 | Janus.init = function(options){ |
init
方法需要一个JSON
格式的输入参数,它包括两个域
: debug
和一个回调函数callback
。这样当init
执行完成后,就可以通过callback
将结果返回到应用层了。videoroomtest.js
调用Janus.init
的代码如下:
1 | ... |
上面的代码非常简单,关键的一点是我们要知道传入的参数是JSON
格式的,它有两个域debug
和callback
即可。知道如何调用了,接下来我们再来看看init
函数的实现。
janus.js
的init
方法实现了什么功能呢?我们把Janus.init
方法中的主干逻辑抽取出来,代码如下:
1 | Janus.init = function(options) { |
上面代码中的initDone
表示的是之前是否初始化过janus.js
?而options
是init
方法的输入参数,通过它可以回调应用层。通过上面的代码我们可以知道init
方法的功能其实蛮简单的,就是将initDone
置位,并回调应用层。
接下来我们看一下init
回调应用层后,在应用层又做了什么事儿。 输入参数options
的callback
方法在videoroomtest.js
中是一个匿名函数
,其主干逻辑代码如下:
1 | ... |
正如你上面看到的,callback
函数只有一行关键代码,即给start
键钮绑定了一个click
方法。当用户点击start
时执行该方法。那么应用层在start
方法中又做了哪些事儿呢?
创建Janus对象
下面的代码就是start
方法的主逻辑,从中我们可以知道start
方法中完成了使用janus.js
的第二个关键步骤,即创建Janus
对象。代码如下:
1 | ... |
在该方法中首先判断浏览器
是否支持WebRTC
,如果不支持则直接退出,否则创建Janus
对象。在创建Janus
对象时,需要给它传入了一个JSON
格式的参数,该JSON
对象包括以下几个域
:
- server,Janus服务器地址
- success,连接成功后执行的回调函数
- error,连接失败后执行的回调函数
- destroyed,连接销毁时的回调函数
在上述几个域
中,最关键的是success
回调函数。它的含义是当Janus对象创建成功后,回调该函数到应用层。但对于这个回调函的详细介绍我们先暂时
放一放,现在我们先来看看创建Janus
对象时都做了哪些事儿,然后再来分析success
回调函数。
Janus类的定义如下:
1 | function Janus(gatewayCallbacks) { |
通过上面的代码我们可以知道,在创建Janus
对象时它会调用createSession
函数。而在createSession
函数内部会通过Janus
的类
方法httpAPICall
与服务端建立HTTP
连接。连接建立成功后,会回调success
函数,也就是类中的handleEvent
方法。
handleEvent
的功能我在《janus前端核心库源码分析》一文中已经介绍过,它用于处理服务端发来的消息,并根据不同的消息类型做不同的逻辑处理。
现在我们可以总结一下创建Janus
对象所做的事儿啦,其实就两件事儿:一与janus
服务器建立连接(HTTP/WebSocket/…);二处理janus
服务器发来的各种消息。
接下来我们再来讨论一下Janus
对象创建成功后,回调success
干了些什么吧!
attach 绑定媒体流
正如上面所说,Janus
创建成功后会回调输入参数中的success
函数。这个函数特别重要
,下面我们来看看在该函数中实现了什么逻辑吧。
实际上,success
回调函数做的事儿也很简单,只是调用了 janus.attach
方法,而attach正是我们使用janus.js的第三步。代码如下:
1 | success: function() { |
同样,该方法的作用在《janus前端核心库源码分析》一文中也已经做过介绍,该方法可以让浏览器与服务端的videoroom插件
绑定,以便获取媒体流。
这里
绑定
的真实含义是建立WEBRTC连接。
在调用attach
方法时,也要传一个JSON
格式的对象。在该对像包含了很多属性,这些属性的含义如下:
- plugin,要绑定的
janus
插件,这里要绑定插件为janus.plugin.videoroom
。 - opaqueId,一个随机值,插件的唯一ID。
- success,
attach
方法执行成功后的回调函数。 - error,
attach
方法执行失败后的回调函数。 - consentDialog,
- iceState,可以通过该函数更新ICE状态。在
videoroomtest.js
中没有做任何处理。 - mediaState,可以通过该函数更新媒体状态。该方法也没有做任你可事儿。
- webrtcState,更改WebRTC状态的回调函数。
- onmessage,收到事件消自己的回调函数。
- onlocalstream,收到本地流时的回调函数。
- onremotestream,收到远端流时的回调函数。
- oncleanup,销毁时的回调函数。
在上面属性中,比较关键的是success
、webrtceState
、onmessage
、onlocalstream
和onremotestream
。这几个属性都是回调函数,在不同的情况下janus.js
会调不同的回调函数。下面我们就对这几个回调函数做一下详细分析。
success回调函数
当调用attach
方法成功与janus
服务器插件
绑定之后,janus.js
会回调success
函数。代码如下:
1 | ... |
上面代码的执行过程如下,janus.js
向janus
服务器发送attach
请求,服务器收到attach
请求后进行处理,然后根据处理结果返回success
或error
。如果浏览器收到的是服务器返回的success
响应,那么就会回调success
函数。
接下来我们看一下success
回调到应用层videoroomtest.js
后做了哪些事儿吧! 代码如下:
1 | ... |
从上面的代码中我们可以看到,应用层success
的逻辑非常简单,只是将janus.js
层创建的pluginHanle
保存起来以备后用,剩下的其它的一些代码是与界面相关的,我们这里就不介绍了。
onmessage
onmessagee
实现的是对janus
服务端返回事件的处理逻辑。我们依然还是先看看在janus.js
中是如何调用该函数的。代码如下:
1 | function handleEvent(json, skipTimeout) { |
上面就是janus.js
中的handleEvent
函数的主逻辑,当janus.js
收到janus服务端发来的event
事件后,从中取出必要的信息,然后调用pluginHandle.onmessage
方法回调应用层。
应用层的onmessage
函数非常重要
,可以说它是应用层最核心的代码
。它根据从janus服务端收到的不同消息类型做不同的逻辑处理,其主逻辑框架如下:
1 | ... |
通过上面的代码我们可以看到,消息包括以下3种:
- joined,表示作为
发布者
加入成功 - destroyed, 表示用户成功
销毁
房间 - event,子事件,
event
又有四个子事件:- publishers,发布者列表
- leaving,有用户离开了
- unpublished,用户取消发布流
- error,出错
在onmessage
函数中会对3种事件消息做处理,下面我们分别对这几个事件消息做一下分析。
joined 事件
joined
消息的含义我在《janus的videoroom插件》一文中已经向你做过介绍了,即当你作为发布者
加入到房间里时,如果成功则会收到joined
事件消息。
此时你可以从该消息中取出publishers
列表,该列表中的每一个publisher
都是会中的一个发布者
(或称为一路流)。由于发布者
也是房间的订阅者
,所以你应该订阅每个发布者
的媒体流,因此你要与列表中的每个publisher
进行一次媒体协商
,并进行attach
。这样就可以接收发布者
的媒体流啦。代码如下:
1 | ... |
从代码中我们可以看到,因为它是一个发布者
所以它首先执行publishOwnFeed(true)
创建Offer
与janus服务端作媒体协商。之后遍历publishers
列表,取出每个publisher
执行newRemoteFeed
方法,在该方法中又会调用attach
方法获取其它发布者
的媒体流。
publishers 事件
当有发布者
加入到房间后,房间内的所有订阅者
都会收到publishers
事件消息。浏览器收到该消息后,应该对消息中的每个未绑定的publisher
都进行attach
操作,这样就可以接收发布者
的媒体流了。 其主逻辑代码如下:
1 | ... |
这段代码与joined
消息的处理逻辑几乎是一样的,只不过订阅者
此时不需要与janus服务器进行媒体协商,所以它没有调用publishOwnFeed
方法,其它的逻辑都是一样的了。
leaving/unpublished 事件
当一个发布者
取消发布时,janus会向房间内的其它用户发送unpublished
消息。另外,当有用户离开房间时,janus会给房间内的其它人发送leaving
消息。另外,如果离开的用户是一个发布者
的话,它同时也会发unpublished
消息,所以这里我们将两个消息放在一起讨论。
这两个消息处理的核心逻辑如下所示:
1 | ... |
上面这段代码有点不太好理解,我这里解释一下你就清楚了。首先我们来看看循环中的固定数字6
,表示什么含义呢?实际上我在《janus的videoroom插件》一文中有解释过,在janus中一个房间内最多可以支持6
路流,这个6
表过的正是这个意思。所以当收到leaving
和unpublished
消息时,客户端会遍历全局变量feeds
(保存所有订阅的流),如果在feeds
中找到了该流,则需要与该流进行detach
操作。
现在我们再读这段代码时是不是就理解它要表达的意思了呢?
onlocalstream 消息
当收到onlocalstream
消息时,说明本地流已经准备就绪了,此时我们需要让本地流的视频在浏览器里显示出来。代码如下:
1 | ... |
这段代码的含议非常简单了,就是获取本地址,然后从HTML
中拿到一个video
标签,最后将video
与本地流绑定到一起,这样就可以看到捕获的本地视频了。
onremotestream 消息
onremotestream
消息与onlocalstream
是类似的,只不过它表示的是远端的视频流。当收到远端的视频流时,我们也同样在本地创建一个video
,然后将远端视频流与video
绑定即可。
小结
本文我向你详细介绍了janus中的videoroom
是如何使用janus.js
文件的,其总的步骤是先调用Janus.init
方法进行初始化;然后创建Janus
对象,即与janus服务器建立连接,并接收来自服务器端的消息; 最后调用attach
与业务服务器绑定,再根据消息进行推流或拉流。
总的来看,使用janus.js
库大大减轻了我们开发webrtc
应用程序的工作量,提高了工作效率。