GB28181协议--报警

1、简介

根据《GBT 28181-2016 公共安全视频监控联网系统信息传输、交换、控制技术要求》9.4节的《报警事件通知和分发基本要求》描述:

发生报警事件时, 源设备应将报警信息发送给 SIP 服务器;SIP 服务器接收到报警事件后, 将报警信息分发给目标设备。 报警事件通知和分发使用IETF RFC 3428 中定义的方法 Message 传送报警信息。源设备包括SIP 设备、 网关、SIP 客户端、 联网系统或者综合接处警系统以及卡口系统等, 目标设备包括具有接警功能的SIP 客户端、 联网系统或者综合接处警系统以及卡口系统等。

2、流程

报警事件通知和分发流程见下图:
在这里插入图片描述
命令流程描述如下:

  • (1): 报警事件产生后, 源设备向SIP 服务器发送报警通知命令, 报警通知命令采用 Message 方法携带;
  • (2): SIP 服务器收到命令后返回200 OK;
  • (3):SIP 服务器接收到报警事件后, 向源设备发送报警事件通知响应命令, 报警通知响应命令采用 Message 方法携带;
  • (4): 源设备收到命令后返回200 OK;
  • (5):SIP 服务器接收到报警事件后, 确定需要转发的目标设备,SIP 服务器向目标设备发送报警事件通知命令, 报警通知命令采用 Message 方法携带;
  • (6): 目标设备收到命令后返回200 OK;
  • (7): 目标设备接收到报警事件后, 向SIP 服务器发送报警事件通知响应命令, 报警通知响应命令采用 Message 方法携带;
  • (8):SIP 服务器收到命令后返回200 OK

3、协议接口

  • (1)请求命令消息体
    消息头 Content-type 字段为 Content-type: Application/ MANSCDP+xml。
    报警事件通知和分发流程中的请求命令采用 MANSCDP 协议格式定义, 详细描述见 A.2.5 报警通知。
    源设备向SIP 服务器通知报警、SIP 服务器向目标设备发送报警的通知命令均采用 Message 方法的消息体携 带。 报 警 事 件 通 知 命 令 应 包 括 命 令 类 型 (CmdType) 、 命 令 序 列 号 (SN) 、 设 备 编 码(DeviceID) 、 报警级别(AlarmPriority) 等。 可选项: 报警时间(AlarmTime) 、 报警方式(AlarmMethod) 、经度(Longitude) 、 纬度(Latitude) 、 扩展报警类型(AlarmType) 、 报警类型参数(AlarmTypeParam) 。相关设备在收到 Message 消息后, 应立即返回200 OK 应答,200 OK 应答均无消息体。

  • (2)应答命令消息体
    消息头 Content-type 字段为 Content-type: Application/ MANSCDP+xml。
    报警事件通知和分发流程中的应答命令采用 MANSCDP 协议格式定义, 详细描述见 A.2.6 报警通知应答。SIP 服务器向源设备、 目标设备向SIP 服务器发送报警通知应答命令均采用 Message方法的消息体携带。报警事件通知应答命令应包括命令类型(CmdType) 、 命令序列号(SN) 、 设备编码(DeviceID) 、执行结果(Result) 。
    相关设备在收到 Message 消息后, 应立即返回200 OK 应答,200 OK 应答均无消息体。

4、软件代码

报警发送接口:
int SipSendAlarm(GB28181Param_t *pGB28181Param, AlarmHander_t *pHander, int sn);

int SipSendAlarm(GB28181Param_t *pGB28181Param, AlarmHander_t *pHander, int sn)
{
    
    
	int ret = 0;
	char from[128] = {
    
    0,};  
	char proxy[128] = {
    
    0,}; 
	char xmlBody[1024] = {
    
    0,};
	osip_message_t *rqt_msg = NULL;


	// sip还未注册,那么不发送数据
	if (!SipGetRegStatus() || !pGB28181Param || !pHander)
	{
    
    
		return -1;
	}

	if (!IS_ALARM_CHN_VALID(pHander->alarmChn))
	{
    
    
		return -1;
	}

	snprintf(from, sizeof(from), "sip:%s@%s:%s", 
			pGB28181Param->userParam.devSipID, 
			pGB28181Param->userParam.devSipIP,
			pGB28181Param->userParam.devSipPort);

	snprintf(proxy, sizeof(proxy), "sip:%s@%s:%s", 
			pGB28181Param->userParam.sipServerID, 
			pGB28181Param->userParam.sipServerIP,
			pGB28181Param->userParam.sipServerPort);

	/* 构建"MESSAGE"请求 */
	if (eXosip_message_build_request(&rqt_msg, "MESSAGE", proxy, from, NULL)!=OSIP_SUCCESS)
	{
    
    
		return -1;
	}

	if (MakeAlarmBody(xmlBody, sizeof(xmlBody), sn, pGB28181Param, pHander))
	{
    
    
		return -1;
	}
	
	if (osip_message_set_content_type(rqt_msg, "Application/MANSCDP+xml")!=OSIP_SUCCESS)
	{
    
    
		osip_message_free(rqt_msg);
		return -1;
	}

	if (osip_message_set_body(rqt_msg, xmlBody, strlen(xmlBody))!=OSIP_SUCCESS)
	{
    
    
		osip_message_free(rqt_msg);
		return -1;
	}

	/* 发送消息 */
	eXosip_lock();
	ret = eXosip_message_send_request(rqt_msg);
	eXosip_unlock();
	
	return (ret==OSIP_SUCCESS)?0:-1;
}

报警消息构建接口:
static int MakeAlarmBody(char *xmlBody, int xmlBodyLen, int sn, GB28181Param_t *pGB28181Param, AlarmHander_t *pHander);

static int MakeAlarmBody(char *xmlBody, int xmlBodyLen, int sn, GB28181Param_t *pGB28181Param, AlarmHander_t *pHander)
{
    
    
	if (!xmlBody ||!pGB28181Param || !pHander)
	{
    
    
		return -1;
	}
	
	snprintf(xmlBody, xmlBodyLen, "<?xml version=\"1.0\"?>\r\n"
		"<Notify>\r\n"
		"<CmdType>Alarm</CmdType>\r\n"					/*命令类型*/
		"<SN>%d</SN>\r\n"								/*命令序列号*/
		"<DeviceID>%s</DeviceID>\r\n"					/*设备编码*/
		"<AlarmPriority>%d</AlarmPriority>\r\n"  		/*报警等级*/
		"<AlarmTime>%s</AlarmTime>\r\n"  				/*报警时间*/
		"<AlarmMethod>%d</AlarmMethod>\r\n"  			/*报警方式*/
		"<AlarmDescription>%s</AlarmDescription>\r\n" 	/*警情描述*/
		"<Longitude>0.000</Longitude>\r\n"
		"<Latitude>0.000</Latitude>\r\n"
		"<Info>\r\n"
		"<AlarmType>%d</AlarmType>\r\n"  				/*报警类型*/
		"<AlarmTypeParam>\r\n"
		"</AlarmTypeParam>\r\n"
		"</Info>\r\n"
		"</Notify>\r\n",
		sn, 
		pGB28181Param->userParam.iAlarmChn[pHander->alarmChn],
		pGB28181Param->userParam.iAlarmPriority[pHander->alarmChn],
		pHander->alarmTime,
		pHander->alarmMethod,
		pHander->alarmDescri,
		pHander->alarmType
	);


	return 0;
}

报警应答解析:
接收sip数据接口:
int SipEventProcess(GB28181Param_t *pGB28181Param)

int SipEventProcess(GB28181Param_t *pGB28181Param)
{
    
    
	int ret = 0;
	int len = 0;
	char *msg = NULL;
	osip_header_t *dest = NULL;
	eXosip_event_t *sipEvent = NULL;


	sipEvent = eXosip_event_wait( 0, 100);
	if (!sipEvent)
	{
    
    
		eXosip_lock();
		eXosip_execute();
		eXosip_automatic_action();
		eXosip_unlock();
		return -1;
	}
	eXosip_lock();
	eXosip_execute();
	eXosip_automatic_action();
	eXosip_unlock();

	switch(sipEvent->type)
	{
    
    
		case EXOSIP_MESSAGE_ANSWERED:
		{
    
    
			// 更新保活时间
			pthread_mutex_lock(&g_SipState.mutex);
			g_SipState.keepliveAckTime = GetSysSec();
			pthread_mutex_unlock(&g_SipState.mutex);
			if(MSG_IS_MESSAGE(sipEvent->response))
			{
    
    
				ret = SipResponsMsgProcess(pGB28181Param, sipEvent);
			}
		}
			break;
			
		default:
			GB_PrintWarn("error Event,  Event type: %d\n", sipEvent->type);
			break;
	}

	eXosip_event_free(sipEvent);

	return ret;
}

解析应答接口:

static int SipResponsMsgProcess(GB28181Param_t *pGB28181Param, eXosip_event_t *sipEvent)
{
    
    
	char xmlSN[32] = {
    
    0,};
	char deviceID[32] = {
    
    0,};
	char cmdType[32] = {
    
    0,};
	char rspXmlBody[2048] = {
    
    0,};
	osip_body_t *rspBody = NULL;
	mxml_node_t *xml = NULL;
	mxml_node_t *node = NULL;
	osip_message_t *rsqMsg = NULL;
	

	if (!pGB28181Param || !sipEvent)
	{
    
    
		return -1;
	}
	eXosip_lock();
	/*获取接收到请求的XML消息体*/
	int ret = osip_message_get_body(sipEvent->response, 0, &rspBody);
	if((NULL == rspBody) || (NULL == rspBody->body))
	{
    
    
		eXosip_unlock();
		return -1;
	}
	eXosip_unlock();
	xml = mxmlLoadString(NULL,rspBody->body, MXML_TEXT_CALLBACK);
	if (!xml)
	{
    
    
		return -1;
	}

	// 查找CmdType
	node = mxmlFindElement(xml, xml, "CmdType", NULL, NULL, MXML_DESCEND);
	if (!node)
	{
    
    
		return -1;
	}
	strncpy(cmdType, mxmlGetText(node, NULL), sizeof(cmdType));
	if (strlen(cmdType) <=0 )
	{
    
    
		return -1;
	}
	
	node = mxmlFindElement(xml, xml, "DeviceID", NULL, NULL, MXML_DESCEND);
	if (!node)
	{
    
    
		return -1;
	}
	strncpy(deviceID, mxmlGetText(node, NULL), sizeof(deviceID));
	if (strlen(deviceID) <=0)
	{
    
    
		return -1;
	}

	// 对这个SN需要做一下防重复处理,后面再考虑这个功能
	node = mxmlFindElement(xml, xml, "SN", NULL, NULL, MXML_DESCEND);
	if (!node)
	{
    
    
		return -1;
	}
	// 应答时,需要使用设备发过来的SN
	strcpy(xmlSN, mxmlGetText(node, NULL));
	if (strlen(xmlSN) <=0 )
	{
    
    
		return -1;
	}
	
	eXosip_lock();
	if ((ret = eXosip_message_build_answer( sipEvent->tid, 200, &rsqMsg)) != OSIP_SUCCESS)
	{
    
    
		eXosip_unlock();
		return -1;
	}
	
	if ((ret = eXosip_message_send_answer( sipEvent->tid, 200, rsqMsg)) != OSIP_SUCCESS)
	{
    
    
		eXosip_unlock();
		return -1;
	}
	eXosip_unlock();


	 if (!strcmp(cmdType, "Alarm"))
	{
    
    
		AlarmMsgParase(xml, rspXmlBody, sizeof(rspXmlBody), xmlSN, deviceID, pGB28181Param);
	}
	else
	{
    
    
		mxmlDelete(xml);
		return -1;
	}

	mxmlDelete(xml);
	

	return 0;
}

解析应答命令:

static int AlarmMsgParase(mxml_node_t *xml, char *msg, int msgLen, char *sn, char *devID, GB28181Param_t *pGB28181Param)
{
    
    
	char result[32] = {
    
    0,};
	
	if ( !pGB28181Param || !msg || msgLen<= 0 || !xml )
	{
    
    
		return -1;
	}

	memset(msg, 0, msgLen);
	uint8_t iChn = GetChannelID(devID, pGB28181Param, GET_ALARM_TYPE);
	if (!IS_ALARM_CHN_VALID(iChn))
	{
    
    
		return -1;
	}

	// 查找CmdType
	mxml_node_t *node = mxmlFindElement(xml, xml, "Result", NULL, NULL, MXML_DESCEND);
	if (!node)
	{
    
    
		return -1;
	}
	strncpy(result, mxmlGetText(node, NULL), sizeof(result));

	if (!strcmp(result, "OK"))
	{
    
    
	}

	return 0;
}

建议阅读:
GB28181协议–设备注册和注销

参考资料:
《GBT 28181-2016 公共安全视频监控联网系统信息传输、交换、控制技术要求》

猜你喜欢

转载自blog.csdn.net/jisuanji111111/article/details/123131207