CometD推送
概述
摩云视讯平台支持通过ComedD推送技术,实时地将视频会议过程中的各种状态变化推送给调用方。
CometD仅支持Java和JavaScript客户端。
基本概念
Comet:一种用于web的推送技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求。
CometD:实现了Comet技术,可以运行在HTTP或WebScocket协议,使用Bayeux协议在客户端和服务器之间交换信息。
通道:CometD中的核心概念,发布者发布消息到通道中,订阅者订阅通道来接收消息。详细见通道说明。
推送消息流程
传输层
CometD支持长轮询、回调轮询及WebSocket传输层。
客户端可以自行指定所使用的传输层,这里推荐使用WebSocket传输层,长轮询传输层作为备选,当WebSocket传输层不可用时,CometD客户端会自动降级为长轮询传输层。
// 长轮询传输层
HttpClient httpclient = new HttpClient();
httpclient.start();
ClientTransport httptransport = new LongPollingTransport(null, httpclient);
// WebSocket传输层
WebSocketClient webSocketClient = new WebSocketClient();
webSocketClient.start();
JettyWebSocketTransport wsTransport = new JettyWebSocketTransport(null, null, webSocketClient);
bayeuxclient = new BayeuxClient(url, wsTransport, httptransport);
登录
用户使用推送服务需要先登录推送服务器,获取sso_cookie
。
这里登录复用平台业务API的登录逻辑,先通过APP ID和APP KEY获取APP TOKEN,再使用用户名及密码登录。
这里复用了平台业务API的登录逻辑,先通过AppKey
和AppSecret
获取account_token
,再使用用户名及密码登录。
详细登录步骤请参考登录认证。
握手
登录成功后,HTTP服务器会在回复HTTP客户端登录成功的消息中带Cookie,CometD客户端需携带此Cookie,调用handshake接口与CometD服务器进行握手,CometD服务器端通过校验此Cookie字段来完成认证。
握手调用如下:
bayeuxclient.putCookie(cookie); //将Login回复中携带的Cookie设置给bayeuxClient
bayeuxclient.handshake(hslistener); //握手
访问CometD服务器的URL:
http://xx.xx.xx.xx/api/v1/publish
由于握手过程是异步操作,要想确认握手是否成功,可以向handshake()接口传入回调,在回调中获取服务器发给客户端的用户域ID(domain_id)信息:
function hslistener(ClientSessionChannel channel, Message message)
{
if (message.isSuccessful())
{
Map<String, Object> map = message.getExt();
domain_id = map.get("user_domain_moid").toString();
}
}
握手成功回复的消息是json格式,如下所示:
{
"ext":{"user_domain_moid":"w8oflp85rsopfl85l1rfhet8","ack":true},
"minimumVersion":"1.0",
"clientId":"aug11o8nfq1xzpvgpdiptn6s7wje",
"supportedConnectionTypes":["websocket","long-polling","callback-polling"],
"channel":"/meta/handshake",
"id":"1",
"version":"1.0",
"successful":true
}
订阅
握手成功后才可以订阅通道,调用subscribe接口:
bayeuxclient.getChannel(subchannl).subscribe(msglistener, sublistener);
订阅的通道前要加入用户域信息,如:
subchannl = /userdomains/{domain_id}/confs/{conf_id};
domain_id
在握手成功的回复中获取。
订阅通道也是异步操作,需要传入两个回调,一个用来判断订阅是否成功并保存订阅的通道,一个用来接收订阅通道的消息内容,如:
List<String> channlList = new ArrayList<String>();
function sublistener(ClientSessionChannel channel, Message message)
{
if (message.isSuccessful())
{
//获取订阅的通道
String strChannel = message.get("subscription").toString();
//保存订阅成功的通道,便于断链后重订阅
channlList.add(strChannel);
}
}
function msglistener(ClientSessionChannel channel, Message message)
{
//通道名
String strChannel = message.getChannel();
//通道方法
Map<String, Object> data = message.getDataAsMap();
String method = data.get("method").toString();
}
服务器推送的消息是json格式,如下所示:
{
"data":{"method":"delete"},
"channel":"/userdomains/w8oflp85rsopfl85l1rfhet8/confs/7770480/cascades/0/mts/1"
}
method含义:
- update 新建资源或数据更新
- delete 删除资源
如果服务器推送过来的通道method是update,则需再次发送HTTP GET请求,来获取通道的详细数据。 如果method是delete,则无需再次发送HTTP请求,因为此时服务器端已将该通道的数据删除了。
发送HTTP GET请求的URL:
http://xx.xx.xx.xx/api/v1/vc/{channel}
心跳保护
登录成功后,客户端需每隔30min给服务器发送一条HTTP心跳消息,确保登录有效性。
心跳消息URL:
http://xx.xx.xx.xx/api/v1/system/heartbeat
断链重订阅
短暂的网络异常,服务器可以保存客户端的状态,客户端不需要重新握手;
长时间网络异常或服务器异常情况下,服务器会删除客户端的相关状态,客户端需要与服务器重新握手,握手成功后对已经订阅过的通道重新订阅,保证信息实时更新。
String subchannl = "";
for (int i = 0; i < channlList.size(); i++)
{
subchannl = channlList.get(i).toString();
bayeuxclient.getChannel(subchannl).subscribe(msglistener, sublistener);
}
通道说明
这里的通道与会议业务API中的通道相同,如下所示:
通道 | 说明 |
---|---|
/confs/{conf_id} | 会议信息 |
/confs/{conf_id}/cascades | 级联信息 |
/confs/{conf_id}/cascades/{cascade_id}/mts/{mtid} | 终端信息 |
/confs/{conf_id}/chairman | 主席 |
/confs/{conf_id}/speaker | 发言人 |
/confs/{conf_id}/dualstream | 双流源 |
/confs/{conf_id}/vad | 语音激励 |
/confs/{conf_id}/mixs/{mix_id} | 混音 |
/confs/{conf_id}/vmps/{vmp_id} | 画面合成 |
/confs/{conf_id}/poll | 会议轮询 |
/confs/{conf_id}/recorders/{rec_id} | 录像 |
/confs/{conf_id}/mtvmps/{mt_id} | 终端自主画面合成 |
/confs/{conf_id}/hduvmps/{hdu_id} | 电视墙自主画面合成 |
/confs/{conf_id}/hdus/{hdu_id} | 会议电视墙 |
/confs/{conf_id}/inspections/{mt_id}/{mode} | 终端选看 |
/confs/{conf_id}/upload | 上传终端 |
/confs/{conf_id}/monitor/{dst_ip}/{dst_port} | 监控 |
完整推送通道信息请参考推送接口概览
订阅通道时,可以仅订阅通道本身,也可以使用通配符来订阅通道的子通道。
订阅通道本身:
subscribe /channel
订阅一级子通道(如:/channel/a
, /channel/b
):
subscribe /channel/*
订阅所有层级子通道(如:/channel/a
,/channel/a/1
, /channel/b
):
subscribe /channel/**
注意:通配符仅能在通道的最后一段中使用。
使用场景分析:
订阅某个会议的所有信息:
subscribe /userdomains/{domain_id}/confs/001112/**
订阅会议列表更新信息:
subscribe /userdomains/{domain_id}/confs/*
订阅本级终端列表:
subscribe /userdomains/{domain_id}/confs/0001112/cascades/0/mts/*
订阅所有会议信息:
subscribe /userdomains/{domain_id}/confs/**
订阅通配符通道时,服务器推送过来的消息内容中的通道是不带有通配符的具体通道。