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 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) { if (!xmlBody ||!pGB28181Param || !pHander) { return -1; } snprintf(xmlBody, xmlBodyLen, " \r\n" " \r\n" " Alarm \r\n" /*命令类型*/ " %d \r\n" /*命令序列号*/ " %s \r\n" /*设备编码*/ " %d \r\n" /*报警等级*/ " %s \r\n" /*报警时间*/ " %d \r\n" /*报警方式*/ " %s \r\n" /*警情描述*/ " 0.000 \r\n" " 0.000 \r\n" " \r\n" " %d \r\n" /*报警类型*/ " \r\n" "\r\n" "\r\n" "\r\n", sn, pGB28181Param->userParam.iAlarmChn[pHander->alarmChn], pGB28181Param->userParam.iAlarmPriority[pHander->alarmChn], pHander->alarmTime, pHander->alarmMethod, pHander->alarmDescri, pHander->alarmType ); return 0; } 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; }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/226645.html原文链接:https://javaforall.net
