GB28181学习(十三)——订阅与通知

事件订阅

要求

  • 事件订阅应使用SUBSCRIBE方法;
  • 事件源接收事件订阅时,事件源应向事件观察者发送确认消息;
  • 事件源:
    • 联网系统
    • SIP服务器
    • 报警设备
    • 移动设备
    • 被集成的卡口系统等
  • 事件观察者
    • 联网系统
    • SIP服务器
    • 客户端
  • 事件:
    • 报警事件
    • 移动设备位置通知事件
    • PTZ精准位置变化事件等

流程

GB28181学习(十三)——订阅与通知_第1张图片

协议接口

  • MESSAGE消息头Content-type头域为Content-type:Application/MANSCDP+xml
  • 报警事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
  • 移动位置上报事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
  • PTZ精准位置变化事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;

事件通知

要求

  • 事件源接受事件订阅后,在事件触发后应立即通知事件观察者,事件观察者应向事件源发送事件收到的确认消息;
  • 事件通知使用NOTIFY方法;
  • 事件源:
    • 联网系统
    • SIP服务器
    • 报警设备
    • 移动设备
    • 被集成的卡口系统等
  • 事件观察者
    • 联网系统
    • SIP服务器
    • 客户端
  • 事件
    • 报警事件
    • 移动设备位置通知事件
    • PTZ精准位置变化事件等

流程

GB28181学习(十三)——订阅与通知_第2张图片

协议接口

  • MESSAGE消息头Content-type头域为Content-type:Application/MANSCDP+xml
  • 报警事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
  • 移动位置上报事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;
  • PTZ精准位置变化事件订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;

目录订阅

要求

  • 目录订阅应使用SUBSCRIBE方法;
  • 目录拥有者接收目录订阅后,应向目录订阅者发送请求确认消息;
  • 目录拥有者
    • 联网系统
    • 有子设备的设备
    • 代理设备网关
  • 目录接收者
    • 联网系统
    • 有子设备的设备
    • 代理设备网关

流程

GB28181学习(十三)——订阅与通知_第3张图片

协议接口

  • MESSAGE消息头Content-type头域为Content-type:Application/MANSCDP+xml
  • 目录订阅订阅流程中请求命令消息体采用MANSCDP协议格式定义:请求命令消息体采用XML封装;

目录通知

要求

  • 目录拥有者接收目录订阅后,当目录发生变化时立即通知目录接收者,目录接收者应向目录拥有者发送目录收到的确认消息;
  • 目录通知应使用NOTIFY方法;
  • 目录拥有者
    • 联网系统
    • 有子设备的设备
    • 代理设备网关
  • 目录接收者
    • 联网系统
    • 有子设备的设备
    • 代理设备网关
  • 域间目录订阅通知

流程

GB28181学习(十三)——订阅与通知_第4张图片

协议接口

  • 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,
		"\n"
		"\n"
		"%s\n"
		"130\n"
		"%s\n"
		"0\n"
		"0\n"
		"0\n"
		"%s\n"
		"%s\n"
		"\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(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(subjectUrl.c_str()));
	auto hdr = pjsip_generic_string_hdr_create(m_pool, &hName, &hValue);
	pjsip_msg_add_hdr(tdata->msg, reinterpret_cast(hdr));

    // 消息发送
	status = pjsip_evsub_send_request(sub, tdata);
	if (PJ_SUCCESS != status)
		return false;

	return true;
}

抓包

  1. 报警订阅
SUBSCRIBE sip:[email protected]:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.107:5060;rport;branch=xxx
Max-Forwards: 70
From: sip:[email protected];tag=xxx
To: sip:[email protected]
Contact: <sip:[email protected]: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>
  1. 报警订阅结果
SIP/2.0 200 OK
Call-ID: xxx
Contact: <sip:[email protected]:5060>
Content-Length: 0
CSeq: 18467 SUBSCRIBE
Event: presence;id=xxx
Expires: 300
From: <sip:[email protected]7>;tag=xxx
To: <sip:[email protected]1>;tag=xxx
User-Agent: SIP UAS V.2016.xxxx
Via: SIP/2.0/UDP 192.168.0.107:5060;rport=5060;branch=xxx
  1. 报警通知
NOTIFY sip:[email protected]:5060 SIP/2.0
Call-ID: xxx
Contact: <sip:[email protected]:5060>
Content-Length: 416
Content-Type: Application/MANSCDP+xml
CSeq: 2 NOTIFY
Event: presence;id=xxx
From: <sip:[email protected]1>;tag=xxx
Max-Forwards: 70
Subscription-State: active;expires=294
To: <sip:[email protected]7>;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>
  1. 报警通知返回
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:[email protected]1>;tag=xxx
To: <sip:[email protected]7>;tag=xxx
CSeq: 2 NOTIFY
Content-Length:  0
  1. 取消订阅
SUBSCRIBE sip:[email protected]:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.107:5060;rport;branch=xxx
Max-Forwards: 70
From: sip:[email protected];tag=xxx
To: sip:[email protected]
Contact: <sip:[email protected]: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>
  1. 取消订阅返回
SIP/2.0 200 OK
Call-ID: xxx
Contact: <sip:[email protected]:5060>
Content-Length: 0
CSeq: 26500 SUBSCRIBE
Event: presence;id=xxx
Expires: 0
From: <sip:[email protected]7>;tag=xxx
To: <sip:[email protected]1>;tag=xxx
User-Agent: SIP UAS V.2016.xxxx
Via: SIP/2.0/UDP 192.168.0.107:5060;rport=5060;branch=xxx

界面展示GB28181学习(十三)——订阅与通知_第5张图片

你可能感兴趣的:(GB28181,GB28181,c++)