官方关于JanusRESTful、WebSockets等传输模块的API说明的文档的翻译。
从Janus的V0.0.6开始就实现了REST、WebSockets、RabbitMQ、MQTT、Nanomsg及UnixSockets接口用于和janus服务器进行交互。(这些通信方式均是可选的,都需要第三方库的支持)。所有这些接口统一使用json消息进行通信。
其它接口和Rest接口在以下两处有少许差异:
《1》、访问特定session及handle时;
《2》、部分的通知处理机制;
1、REST接口
1.1、总体概括
Janus有三个层级的路径(Endpoint: 访问一个API要有一个确定的地址,这个地址即路径, 又称"终点")
《1》、服务根路径(server root):你可以使用POST方法请求该路径去创建一个Janus会话(session)。默认根路径是/janus,可以通过配置文件修改。
《2》、会话路径(session endpoint):[例如:/janus/12345678 ,后面的ID标识是步骤1返回的 。] 我们可以使用GET或POST方法。GET方法是 长连接,用于来自插件的event和message传输。POST方法用于创建插件句柄(plugin handle)或操作步骤1生成的janus 会话;
《3》、插件句柄路径(plugin handle endpoint): [例如:/janus/12345678/987654 ,既是在步骤2的session ID后添加handle ID] 仅仅可使用POST方法给插件发送消息或协商信息,或操作插件句柄。GET方法用于将和该插件相关的所有event通知给对应的session。
详细介绍看1.2-1.4部分。
你可以发送message和请求到上面提到的三种路径,所有message都含有以下三个变量,其它变量根据message不同而不同:
- janus: 请求或事件的类型,如“create”,“attach”,"message"等。
- transaction: 随机字符串,用于个客户端识别来自服务器的message(因为所有message是异步的)
- error: 错误信息,包含“code”及“reason”两部分;
例子
{
"janus" : "error",
"transaction" : "a1b2c3d4"
"error" : {
"code" : 458
"reason" : "Could not find session 12345678"
}
}
1.2、 服务器根路径(server root)
默认的根路径是/janus,可通过janus.jcf配置文件更改。该路径只用于创建新的janus 会话(session),通过将{janus:“create”}信息POST到该路径来实现创建。
原文:
例子:
1.3 、会话路径(session endpoint)
一旦创建了一个janus会话那么一个新的路径就被创建,该新路径由根路径及会话ID构成,比如:/janus/12345678。
janus会话路径可用以下两种方式使用:
《1》、使用无参数的GET请求该路径,请求后发送的是长连接,该长连接用于获取来自该会话的事件通知及信息通知;
《2》、用POST方式发送json消息用于和会话交互,如创建一个绑定到某个插件的新句柄或者销毁一个句柄。
《1.1》、长连接仅用于触发与你发送的消息相关的插件事件。(和上面矛盾说也可消息通知矛盾,弄懂后再区分)。事件通知的格式如下
janus: "event"
sender: 插件句柄的唯一数字ID,在POST方法创建插件句柄的响应信息中;
transaction:可选。要么是和你之前发送的请求有关,要么为空(此时意味着这是一个由插件自己发送的事件)
plugindata:一个json对象,包含以下信息
plugin: 插件的名字,如janus.plugin.echotest
data: 每个插件特有的一些信息
jsep: 可选,包含和客户端进行WeRTC PeerConnection协商的JSEP SDP(offer或answer)信息。
例子:
{
"janus" : "event",
"sender" : 1815153248,
"transaction" : "sBJNyUhH6Vc6",
"plugindata" : {
"plugin": "janus.plugin.echotest",
"data" : {
"echotest" : "event",
"result" : "ok"
}
},
}
长连接默认30秒超时,因此如果在30秒内没有事件通知则keep-alive信息会被发送用于保活。
{
"janus" : "keepalive",
}
长连接默认每次返回一个事件,如果你需要每次返回多个事件的话,可以通过在GET请求后面带maxev参数,例如:
GET http://host:port/janus/<sessionid>?maxev=5
返回消息结构如下
在销毁一个会话前最好先确定该会话管理的所有插件句柄已经被销毁。如果没有的话服务器会先自动进行插件句柄销毁操作,但是可能会有一些意想不到的问题发生。
如果一个会话长时间没有和客户端交互的话也会被自动销毁,这个超时时间session_timeout在janus.jcfg中进行配置,到时间后会触发time事件。如果有配置reclaim_session_timeout变量,那么我们可以在规定时间内使用claim请求来重新使用会话。
1.4、 插件句柄路径(the plugin handle endpint)
一旦使用会话路径创建了一个新的插件句柄,那么一个新的插件路径就在服务器端被创建。该路径的组成格式:
root path/session id/plugin handle id
例子:
/janus/12345678/98765432
插件句柄用于和插件通信相关的所有事情,如发送消息,协商绑定到插件的webrtc连接等等。
你需要使用POST方法发送带有{janus:“message”}变量的json消息。该json消息可能含有jsep变量,因为和webrtc协商相关的消息也是通过该路径发送的。
注意:
如果你发送的消息中带有jsep信息,则服务器会认为你是要进行PeerConnection协商,这意味着空的jsep或非法的jsep信息会导致整个消息请求失败。因此如果你不是进行协商的话就不要带上jsep变量。
例子:
静音
{
"janus" : "message",
"transaction" : "sBJNyUhH6Vc6",
"body" : {
"audio" : false
}
}
带JSEP的静音消息(offer)
{
"janus" : "message",
"transaction" : "sBJNyUhH6Vc6",
"body" : {
"audio" : false
},
"jsep" : {
"type" : "offer",
"sdp" : "v=0\r\no=[..more sdp stuff..]"
}
}
注意不论你因任何理由而想禁止trickle ICE那么你需要在json消息中添加变量{“trickle”: false}来显式告诉服务器。(推荐使用trickle ICE,janus默认使用trickle ICE)。
如果你要使用trickle方式来挑选ICE候选那么可使用专门的消息。这个专门消息janus字段值为“trickle”,可能有三种类型:
- 单独一条trickle 候选;
- 一组trickle候选;
- 空trickle候选或者"completed"值,用于标志通知结束。
一条:
{
"janus" : "trickle",
"transaction" : "hehe83hd8dw12e",
"candidate" : {
"sdpMid" : "video",
"sdpMLineIndex" : 1,
"candidate" : "..."
}
}
一组:
{
"janus" : "trickle",
"transaction" : "hehe83hd8dw12e",
"candidates" : [
{
"sdpMid" : "video",
"sdpMLineIndex" : 1,
"candidate" : "..."
},
{
"sdpMid" : "video",
"sdpMLineIndex" : 1,
"candidate" : "..."
},
[..]
]
}
结束:
{
"janus" : "trickle",
"transaction" : "hehe83hd8dw12e",
"candidate" : {
"completed" : true
}
}
当服务端收到一个异步消息时会马上回复一个{janus:ack}消息,然后等消息处理好之后再通过长连接以事件的机制通知客户端。值得注意的是,如果是进行webrtc的协商则一个回复你的OFFER信息的ANSWER信息不会像你预期的那样通过同一个transaction(传输)传回。插件根据其内部逻辑可能不会给你回复ANSWER,直到它内部的某些状态发生改变。
1.5、 WebRTC相关的事件
janus为每一个与PeerConnection有关的插件提供了向外部报告其状态的机制。包含以下几种事件。
- webrtcup: ICE和DTLS成功并且Janus已经正确的建立了和用户或应用的PeerConnection;
- media : Jauns正在通过PeerConnection接受音频或视频;
- slowlink: Janus通过PeerConnection报告发送端或接受端的链路问题;
- handup: PeerConnection被janus或客户端关闭;
例子
一个PeerConnection创建好了:
{
"janus" : "webrtcup",
session_id: <the session identifier>,
sender: <the handle identifier>
}
第一个音频包被janus接受或者音频包中断后有重新接受到
{
"janus" : "media",
session_id: <the session identifier>,
sender: <the handle identifier>,
"type" : "audio",
"receiving" : true
}
因为一些原因janus接收不到音频包
{
"janus" : "media",
"session_id" : <the session identifier>,
"sender" : <the handle identifier>
"type" : "audio",
"receiving" : false
}
Janus报告媒体发送问题(用户在上一秒发送了太多NACK包
{
"janus" : "slowlink",
"session_id" : <the session identifier>,
"sender" : <the handle identifier>
"uplink" : true, /// 从Janus的视角
"nacks" : <number of NACKs in the last second>
})
2、WebSockets接口
WebSocket为双向通信提供了更高效的方式,推荐在Janus使用这种传输方式,它能避免HTTP 并发所带来的超负荷及HTTP长连接所带来的的额外花销。
使用该方式和Janus通信是必须指定称为“janus-protocol”的子协议,例如:
var websocket = new WebSocket('ws://1.2.3.4:8188', 'janus-protocol');
WebSockets使用的概念和流程和上面介绍的HTTP的是一样的,如创建会话,绑定到插件并与之交互等等。
不同之处在于当使用WebSockets作为传输方式时,有些信息,如异步信息需要在http消息的基础上添加一些标志。
例如attach消息
HTTP方式:
{
"janus" : "attach",
"plugin" : "<the plugin's unique package name>",
"transaction" : "<random string>"
}
WebSockets方式
{
"janus" : "attach",
"session_id" : <the session identifier>, // 新添加!
"plugin" : "<the plugin's unique package name>",
"transaction" : "<random string>"
}
插件句柄消息
{
"janus" : "message",
"session_id" : <the session identifier>, // 新添!
"handle_id" : <the handle identifier>, // 新添!
"transaction" : "sBJNyUhH6Vc6",
"body" : {
"audio" : false
}
}
大概规律是与会话有关的消息多添加会话ID,和插件句柄有关的消息添加会话ID及插件句柄ID。
在使用Websocket时keep-alive信息与http方式有很大不同,WebSocket有专门的保活信息
{
"janus" : "keepalive",
"session_id" : <the session identifier>,
"transaction" : "sBJNyUhH6Vc6"
}
Websocket和HTTP的最后一点不同是事件通知推送的机制。HTTP使用长连接,这意味着你需要显式的订阅信息,然后在接收到事件后得马上从新订阅该事件。WebSocket则不需要订阅,因为一旦你创建了一个会话,这个通信通道会自动订阅与这个会话有关的事件,所有事件都通过同一个Websock被接受。
3、获取Janus服务器的信息
Janus的info路径可用于janus服务相关信息的查询。这些信息包括服务器版本号、一些可选属性是否支持(IPV6或Data Channel等)、配置了哪些插件等。GET请求路径为:[http://ip:8088/janus/info],返回信息举例如下。
4、参考
《1》、RESTful, WebSockets, RabbitMQ, MQTT, Nanomsg and UnixSockets API