事件订阅
要求
- 事件订阅应使用SUBSCRIBE方法;
- 事件源接收事件订阅时,事件源应向事件观察者发送确认消息;
- 事件源:
- 联网系统
- SIP服务器
- 报警设备
- 移动设备
- 被集成的卡口系统等
- 事件观察者
- 事件:
- 报警事件
- 移动设备位置通知事件
- PTZ精准位置变化事件等
流程
协议接口
- MESSAGE消息头Content-type头域为Content-type:Application/MANSCDP+xml;
- 报警事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
- 移动位置上报事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
- PTZ精准位置变化事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
事件通知
要求
- 事件源接受事件订阅后,在事件触发后应立即通知事件观察者,事件观察者应向事件源发送事件收到的确认消息;
- 事件通知使用NOTIFY方法;
- 事件源:
- 联网系统
- SIP服务器
- 报警设备
- 移动设备
- 被集成的卡口系统等
- 事件观察者
- 事件
- 报警事件
- 移动设备位置通知事件
- PTZ精准位置变化事件等
流程
协议接口
- MESSAGE消息头Content-type头域为Content-type:Application/MANSCDP+xml;
- 报警事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
- 移动位置上报事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
- PTZ精准位置变化事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
目录订阅
要求
- 目录订阅应使用SUBSCRIBE方法;
- 目录拥有者接收目录订阅后,应向目录订阅者发送请求确认消息;
- 目录拥有者
- 目录接收者
流程
协议接口
- MESSAGE消息头Content-type头域为Content-type:Application/MANSCDP+xml;
- 目录订阅订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
目录通知
要求
- 目录拥有者接收目录订阅后,当目录发生变化时立即通知目录接收者,目录接收者应向目录拥有者发送目录收到的确认消息;
- 目录通知应使用NOTIFY方法;
- 目录拥有者
- 目录接收者
- 域间目录订阅通知
流程
协议接口
- MESSAGE消息头Content-type头域为Content-type:Application/MANSCDP+xml;
- 目录订阅订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
代码实现
pj_init();
pjlib_util_init();
pj_caching_pool_init(&m_cachingPool, &pj_pool_factory_default_policy, 0);
pjsip_endpt_create(&m_cachingPool.factory, nullptr, &m_endPoint);
pjsip_tsx_layer_init_module(m_endPoint);
pjsip_ua_init_module(m_endPoint, nullptr);
// 订阅相关
pjsip_evsub_init_module(m_endPoint);
pjsip_pres_init_module(m_endPoint, pjsip_evsub_instance());
std::string CMySipMedia::CreateAlarmXmlText_(const std::string& eventName, const GBSubscribeContext& subContext)
{
char szAlarmInfo[500] = { 0 };
pj_ansi_snprintf(szAlarmInfo, 500,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<Query>\n"
"<CmdType>%s</CmdType>\n"
"<SN>130</SN>\n"
"<DeviceID>%s</DeviceID>\n"
"<StartAlarmPrority>0</StartAlarmPrority>\n"
"<EndAlarmPrority>0</EndAlarmPrority>\n"
"<AlarmMethod>0</AlarmMethod>\n"
"<StartTime>%s</StartTime>\n"
"<EndTime>%s</EndTime>\n"
"</Query>\n", eventName.c_str()
, subContext.GetDeviceId().c_str()
, subContext.GetSubStartTime().c_str()
, subContext.GetSubEndTime().c_str()
);
return szAlarmInfo;
}
static pjsip_evsub_user pres_user = {
&pres_on_evsub_state,
&pres_on_evsub_tsx_state,
&pres_on_evsub_rx_refresh,
&pres_on_evsub_rx_notify,
&pres_on_evsub_client_refresh,
&pres_on_evsub_server_timeout,
};
// 接收NOTIFY消息
static void pres_on_evsub_rx_notify(pjsip_evsub* sub,
pjsip_rx_data* rdata,
int* p_st_code,
pj_str_t** p_st_text,
pjsip_hdr* res_hdr,
pjsip_msg_body** p_body)
{
}
bool CMySipContext::Subscribe(pjsip_dialog* dlg, pjsip_evsub_user* pres_user, const std::string& eventName, const std::string& xmlText, const GBSubscribeContext& subContext)
{
// 创建uac
pjsip_evsub* sub = nullptr;
static const pj_str_t STR_PRESENCE = { (char*)"presence", 8 };
pj_status_t status = pjsip_evsub_create_uac(dlg, pres_user, &STR_PRESENCE, 0, &sub);
if (PJ_SUCCESS != status)
return false;
// 初始化
pjsip_tx_data* tdata = nullptr;
status = pjsip_evsub_initiate(sub, nullptr, subContext.GetExpires(), &tdata);
if (PJ_SUCCESS != status)
return false;
// 构造Body
pjsip_media_type type;
type.type = pj_str((char*)"application");
type.subtype = pj_str((char*)"MANSCDP+xml");
auto text = pj_str(const_cast<char*>(xmlText.c_str()));
tdata->msg->body = pjsip_msg_body_create(m_pool, &type.type, &type.subtype, &text);
auto hName = pj_str((char*)"Subject");
auto subjectUrl = subContext.GetDeviceId() + ":" + SiralNum + "," + GetCode() + ":" + SiralNum;
auto hValue = pj_str(const_cast<char*>(subjectUrl.c_str()));
auto hdr = pjsip_generic_string_hdr_create(m_pool, &hName, &hValue);
pjsip_msg_add_hdr(tdata->msg, reinterpret_cast<pjsip_hdr*>(hdr));
// 消息发送
status = pjsip_evsub_send_request(sub, tdata);
if (PJ_SUCCESS != status)
return false;
return true;
}
抓包
- 报警订阅
SUBSCRIBE sip:xxx@192.168.0.111:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.107:5060;rport;branch=xxx
Max-Forwards: 70
From: sip:xxx@192.168.0.107;tag=xxx
To: sip:xxx@192.168.0.111
Contact: <sip:xxx@192.168.0.107:5060>
Call-ID: xxx
CSeq: 18467 SUBSCRIBE
Event: presence;id=xxx
Expires: 300
Supported: 100rel
Accept: application/pidf+xml, application/xpidf+xml
Allow-Events: presence
Subject: xxx:xxx,xxx:xxx
Content-Type: application/MANSCDP+xml
Content-Length: 327
<?xml version="1.0" encoding="UTF-8"?>
<Query>
<CmdType>Alarm</CmdType>
<SN>130</SN>
<DeviceID>xxx</DeviceID>
<StartAlarmPrority>0</StartAlarmPrority>
<EndAlarmPrority>0</EndAlarmPrority>
<AlarmMethod>0</AlarmMethod>
<StartTime>2023-10-24T00:00:00</StartTime>
<EndTime>2023-10-24T23:00:00</EndTime>
</Query>
- 报警订阅结果
SIP/2.0 200 OK
Call-ID: xxx
Contact: <sip:xxx@192.168.0.111:5060>
Content-Length: 0
CSeq: 18467 SUBSCRIBE
Event: presence;id=xxx
Expires: 300
From: <sip:xxx@192.168.0.107>;tag=xxx
To: <sip:xxx@192.168.0.111>;tag=xxx
User-Agent: SIP UAS V.2016.xxxx
Via: SIP/2.0/UDP 192.168.0.107:5060;rport=5060;branch=xxx
- 报警通知
NOTIFY sip:xxx@192.168.0.107:5060 SIP/2.0
Call-ID: xxx
Contact: <sip:xxx@192.168.0.111:5060>
Content-Length: 416
Content-Type: Application/MANSCDP+xml
CSeq: 2 NOTIFY
Event: presence;id=xxx
From: <sip:xxx@192.168.0.111>;tag=xxx
Max-Forwards: 70
Subscription-State: active;expires=294
To: <sip:xxx@192.168.0.107>;tag=xxx
User-Agent: SIP UAS V.2016.xxxx
Via: SIP/2.0/UDP 192.168.0.111:5060;rport;branch=xxx
<?xml version="1.0" encoding="GB2312" standalone="yes" ?>
<Notify>
<CmdType>Alarm</CmdType>
<SN>29</SN>
<DeviceID>xxx</DeviceID>
<AlarmPriority>1</AlarmPriority>
<AlarmMethod>5</AlarmMethod>
<AlarmTime>2023-10-24T10:17:45</AlarmTime>
<AlarmDescription>........</AlarmDescription>
<AlarmInfo>11</AlarmInfo>
<Info>
<AlarmType>2</AlarmType>
<AlarmTypeParam>
<EventType>1</EventType>
</AlarmTypeParam>
</Info>
</Notify>
- 报警通知返回
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.0.111:5060;rport=5060;received=192.168.0.111;branch=xxx
Call-ID: xxx
From: <sip:xxx@192.168.0.111>;tag=xxx
To: <sip:xxx@192.168.0.107>;tag=xxx
CSeq: 2 NOTIFY
Content-Length: 0
- 取消订阅
SUBSCRIBE sip:xxx@192.168.0.111:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.107:5060;rport;branch=xxx
Max-Forwards: 70
From: sip:xxx@192.168.0.107;tag=xxx
To: sip:xxx@192.168.0.111
Contact: <sip:xxx@192.168.0.107:5060>
Call-ID: xxx
CSeq: 26500 SUBSCRIBE
Event: presence;id=xxx
Expires: 0
Supported: 100rel
Accept: application/pidf+xml, application/xpidf+xml
Allow-Events: presence
Subject: xxx:xx,xxx:xx
Content-Type: application/MANSCDP+xml
Content-Length: 327
<?xml version="1.0" encoding="UTF-8"?>
<Query>
<CmdType>Alarm</CmdType>
<SN>130</SN>
<DeviceID>xxx</DeviceID>
<StartAlarmPrority>0</StartAlarmPrority>
<EndAlarmPrority>0</EndAlarmPrority>
<AlarmMethod>0</AlarmMethod>
<StartTime>2023-10-24T00:00:00</StartTime>
<EndTime>2023-10-24T23:00:00</EndTime>
</Query>
- 取消订阅返回
SIP/2.0 200 OK
Call-ID: xxx
Contact: <sip:xxx@192.168.0.111:5060>
Content-Length: 0
CSeq: 26500 SUBSCRIBE
Event: presence;id=xxx
Expires: 0
From: <sip:xxx@192.168.0.107>;tag=xxx
To: <sip:xxx@192.168.0.111>;tag=xxx
User-Agent: SIP UAS V.2016.xxxx
Via: SIP/2.0/UDP 192.168.0.107:5060;rport=5060;branch=xxx
界面展示