跳到主要内容

CometD推送

概述

科达视讯平台支持通过ComedD推送技术,实时地将视频会议过程中的各种状态变化推送给调用方。

CometD仅支持Java和JavaScript客户端。

基本概念

Comet:一种用于web的推送技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求。

CometD:实现了Comet技术,可以运行在HTTP或WebScocket协议,使用Bayeux协议在客户端和服务器之间交换信息。

通道:CometD中的核心概念,发布者发布消息到通道中,订阅者订阅通道来接收消息。详细见通道说明

推送消息流程

cometd-flow

传输层

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的登录逻辑,先通过AppKeyAppSecret获取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/**

注意:通配符仅能在通道的最后一段中使用。

使用场景分析:

  1. 订阅某个会议的所有信息:

    subscribe /userdomains/{domain_id}/confs/001112/**

  2. 订阅会议列表更新信息:

    subscribe /userdomains/{domain_id}/confs/*

  3. 订阅本级终端列表:

    subscribe /userdomains/{domain_id}/confs/0001112/cascades/0/mts/*

  4. 订阅所有会议信息:

    subscribe /userdomains/{domain_id}/confs/**

订阅通配符通道时,服务器推送过来的消息内容中的通道是不带有通配符的具体通道。