rv1126 GB28181报警订阅及信息上报

rv1126 GB28181报警订阅及信息上报 2026-06-26 14:32:53 708

1.下级域上级域说明

1.上级域:采用的是第三方的试用软件,livegbs。

2.下级域:运行于rv1126上的国标客户端测试程序。

2.流程及信令

2.1流程

1.报警订阅或者取消订阅:上级域发送 SUBSCRIBE 请求。

2.订阅或者取消订阅结果:下级域回复 200OK 。

3.报警事件通知:下级域发送 NOTIFY 请求。

4.通知的结果:上级域回复 200OK 。

2.2信令及代码实现

2.2.1报警(取消)订阅及结果

1.报警订阅或者取消订阅信令

  • GBT 28181-2016规范里面的示范
Via:SIP/2.0/UDP 事件观察者域名或IP地址
Max-Forwards:70
From:显示名<sip:事件观察者编码@事件观察者域名或IP地址>;tag=BK32B1U8DKDrB
To:显示名<sip:事件源编码@事件源域名或IP地址>
Call-ID:17250
CSeq:1SUBSCRIBE
Expires:90
Event:presence
Content-type:Application/MANSCDP+XML
Content-Length:消息实体的字节长度
<? xmlversion="1.0"?>
<Query>
<CmdType>Alarm </CmdType>
<SN>17430</SN>
<DeviceID>64010000001340000001</DeviceID>
<StartAlarmPriority>1</StartAlarmPriority>
<EndAlarmPriority>4</EndAlarmPriority>
<AlarmMethod>0</AlarmMethod>
<StartTime>2010-11-11T00:00:00</StartTime>
<EndTime>2010-12-11T00:00:00</EndTime>
</Query>
  • 实际抓包信令
SUBSCRIBE sip:37010200541180000001@192.168.0.104:5688 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.161:15060;rport;branch=z9hG4bK227103246
From: <sip:34020000002000000001@3402000000>;tag=716882610
To: <sip:37010200541180000001@192.168.0.104:5688>;tag=894131619
Call-ID: 573882610
CSeq: 52 SUBSCRIBE
Content-Type: Application/MANSCDP+xml
Contact: <sip:34020000002000000001@192.168.0.161:15060>
Max-Forwards: 70
User-Agent: LiveGBS v221009
Expires: 3900
Event: presence
Content-Length: 275

<?xml version="1.0" encoding="GB2312"?>
<Query>
  <CmdType>Alarm</CmdType>
  <SN>680103246</SN>
  <DeviceID>37010200541180000001</DeviceID>
  <StartAlarmPriority>0</StartAlarmPriority>
  <EndAlarmPriority>0</EndAlarmPriority>
  <AlarmMethod>0</AlarmMethod>
</Query>

说明:

上述是报警订阅的信令示范及实际抓包的数据,从上面信息中可以看到 Expires 值不为零,这时就是报警订阅。如果要取消订阅,就是 Expires 值为 0。

2.结果信令

  • GBT 28181-2016规范里面的示范
Via:SIP/2.0/UDP 事件观察者域名或IP地址
From:显示名<sip:事件观察者编码@事件观察者域名或IP地址>;tag=BK32B1U8DKDrB
To:显示名<sip:事件源编码@事件源域名或IP地址>
Call-ID:17250
CSeq:1SUBSCRIBE
Expires:90
Event:presence
Content-type:Application/MANSCDP+XML
Content-Length:消息实体的字节长度
<? xmlversion="1.0"?>
<Response>
<CmdType>Alarm </CmdType>
<SN>17430</SN>
<DeviceID>64010000001340000001</DeviceID>
<Result>OK</Result>
</Response>
  • 实际抓包信令
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.0.161:15060;rport=15060;branch=z9hG4bK227103246
From: <sip:34020000002000000001@3402000000>;tag=716882610
To: <sip:37010200541180000001@192.168.0.104:5688>;tag=894131619
Call-ID: 573882610
CSeq: 52 SUBSCRIBE
Contact: <sip:37010200541180000001@192.168.0.104:5688>
Content-Type: Application/MANSCDP+xml
Event: presence
User-Agent: eXosip/4.1.0
Expires: 3900
Content-Length:   176

<?xml version="1.0" encoding="GB2312"?>
<Response>
    <CmdType>Alarm</CmdType>
    <SN>680103246</SN>
    <DeviceID>37010200541180000001</DeviceID>
    <Result>OK</Result>
</Response>

2.2.2代码实现

下级域解析 SUBSCRIBE 及 200OK 回复的代码片段实现如下:

  • 收到 SUBSCRIBE 事件,判断命令类型是否为 Alarm。
case eXosip_event_type::EXOSIP_IN_SUBSCRIPTION_NEW:
        {
            LOG_INFO("EXOSIP_IN_SUBSCRIPTION_NEW method:%s\n", evt->request->sip_method);
            LOG_INFO("EXOSIP_IN_SUBSCRIPTION_NEW username:%s\n", evt->request->to->url->username);
            if (MSG_IS_SUBSCRIBE(evt->request))
            {
                osip_body_t *meg_body = nullptr;
                osip_message_get_body(evt->request, 0, &meg_body);
                if (meg_body != nullptr)
                {
                    LOG_INFO("subscription request: %s\n", meg_body->body);
                }

                auto cmd_sn = this->get_cmd(meg_body->body);
                string cmd = get<0>(cmd_sn);
                if ("Alarm" == cmd)
                {
                    osip_header_t *dest = nullptr;
                    osip_message_get_expires(evt->request, 0, &dest);
                    if (dest != nullptr)
                    {
                        LOG_INFO("dest->hname:%s,dest->hvalue:%s\n", dest->hname, dest->hvalue);
                    }

                    if ((meg_body != nullptr) && (dest != nullptr))
                    {
                        process_subscription_query(evt, meg_body->body, dest->hname, dest->hvalue);
                    }
                }
            }
        }
  • 解析及 200OK 回复
void Device::process_subscription_query(shared_ptr<eXosip_event_t> evt, const char *body, const char *hname, const char *hvalue)
{
    pugi::xml_document document;

    if (!document.load_string(body))
    {
        LOG_ERROR("cannot parse the xml\n");
        return;
    }

    pugi::xml_node root_node = document.first_child();

    if (!root_node)
    {
        LOG_ERROR("cannot get root node of xml\n");
        return;
    }

    auto DeviceID = root_node.child("DeviceID");

    if (!DeviceID)
    {
        LOG_ERROR("cannot get the device id\n");
        return;
    }

    string deviceID = DeviceID.child_value();

    if (root_node.child("CmdType"))
    {
        auto cmdType = root_node.child("CmdType");
        string sCmdType = cmdType.child_value();
        auto SN = root_node.child("SN");
        string sSN = SN.child_value();
        if (!sCmdType.compare("Alarm"))
        {
            LOG_INFO("Alarm\n");
            osip_message_t *msg = nullptr;
            eXosip_insubscription_build_answer(sip_context, evt->tid, 200, &msg);
            if (msg != NULL)
            {
                stringstream ss;
                ss << "<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n";
                ss << "<Response>\r\n";
                ss << "<CmdType>Alarm</CmdType>\r\n";
                ss << "<SN>" << sSN << "</SN>\r\n";
                ss << "<DeviceID>" << deviceID << "</DeviceID>\r\n";
                ss << "<Result>OK</Result>\r\n";
                ss << "</Response>\r\n";
                LOG_INFO("set subscribe msg\n");
                osip_message_set_content_type(msg, "Application/MANSCDP+xml");
                osip_message_set_body(msg, ss.str().c_str(), strlen(ss.str().c_str()));
            }

            send_response_subscribe(evt, msg);

            if (memcmp(hname, "expires", strlen("expires")) == 0)
            {
                int value = stoi(hvalue);
                LOG_INFO("expires:%d\n", value);
                if (value == 0)
                {
                    // 报警订阅取消,此时expires值为0
                    expiresAlarm = value / 60;
                    alarmOpen = false;
                }
                else
                {
                    // 报警订阅,expires值为有效时间,单位秒
                    expiresAlarm = value / 60;
                    alarmOpen = true;
                    did = evt->did;
                }
            }
        }
        else
        {
            LOG_INFO("other cmdtype:%s\n", body);
        }
    }
}

2.2.3报警事件通知及结果

1.报警事件通知

  • GBT 28181-2016规范里面的示范
Via:SIP/2.0/UDP 事件源域名或IP地址
Max-Forwards:70
From:显示名<sip:事件源编码@事件源域名或IP地址>;tag=BK32B1U8DKDrB
To:显示名<sip:事件观察者编码@事件观察者域名或IP地址>
Call-ID:17250
CSeq:1NOTIFY
Subscription-State:active;expires=90;retry-after=0
Event:presence
Content-type:Application/MANSCDP+XML
Content-Length:消息实体的字节长度
<? xmlversion="1.0"?>
<Notify>
<CmdType>Alarm</CmdType>
<SN>1</SN>
<DeviceID>64010000001340000001</DeviceID>
<AlarmPriority>4</AlarmPriority>
<AlarmMethod>2</AlarmMethod>
<AlarmTime>2009-12-04T16:23:32</AlarmTime>
<AlarmDescription>警情描述</AlarmDescription>
<Longitude>171.3</Longitude>
<Latitude>34.2</Latitude>
</Notify>
  • 实际抓包信令
jaK.jaK.jaK.NOTIFY sip:34020000002000000001@192.168.0.161:15060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.104:5688;rport;branch=z9hG4bK259082348
From: <sip:37010200541180000001@192.168.0.104>;tag=618421060
To: <sip:34020000002000000001@192.168.0.161:15060>
Call-ID: 1323924525
CSeq: 20 NOTIFY
Content-Type: Application/MANSCDP+xml
Max-Forwards: 70
User-Agent: eXosip/4.1.0
Event: presence;id=1984
Subscription-State: active;retry-after=0
Expires: 3780
Content-Length:   459

<?xml version="1.0" encoding="GB2312"?>
<Notify>
    <CmdType>Alarm</CmdType>
    <SN>247</SN>
    <DeviceID>44010200491180000002</DeviceID>
    <AlarmPriority>4</AlarmPriority>
    <AlarmMethod>5</AlarmMethod>
    <AlarmTime>2022-10-13T10:36:04</AlarmTime>
    <AlarmDescription>test</AlarmDescription>
    <Info>
        <AlarmType>6</AlarmType>
        <AlarmTypeParam>
            <EventType>1</EventType>
        </AlarmTypeParam>
    </Info>
    <Longitude>171.3</Longitude>
    <Latitude>34.2</Latitude>
</Notify>

2.结果

  • GBT 28181-2016规范里面的示范
Via:SIP/2.0/UDP 事件源域名或IP地址
From:显示名<sip:事件源编码@事件源域名或IP地址>;tag=BK32B1U8DKDrB
To:显示名<sip:事件观察者编码@事件观察者域名或IP地址>
Call-ID:17250
CSeq:1NOTIFY
Content-type:Application/MANSCDP+XML
Content-Length:消息实体的字节长度
<? xmlversion="1.0"?>
<Response>
<CmdType>Alarm </CmdType>
<SN>1</SN>
<DeviceID>64010000001340000001</DeviceID>
<Result>OK</Result>
</Response>
  • 实际抓包信令
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.0.104:5688;rport=5688;received=192.168.0.104;branch=z9hG4bK259082348
From: <sip:37010200541180000001@192.168.0.104>;tag=618421060
To: <sip:34020000002000000001@192.168.0.161:15060>;tag=786220740
CSeq: 20 NOTIFY
Call-ID: 1323924525
User-Agent: LiveGBS v221009
Content-Length: 185
Content-Type: Application/MANSCDP+xml

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <CmdType>Alarm</CmdType>
    <SN>247</SN>
    <DeviceID>44010200491180000002</DeviceID>
    <Result>OK</Result>
</Response>

2.2.4代码实现

报警事件通知的代码实现:

void Device::alarmNotify(string DeviceId, int iAlarmPriority, int iAlarmMethod, int iAlarmType)
{
    osip_message_t *requestAlarm = nullptr;

    auto status = eXosip_message_build_request(sip_context, &requestAlarm, "NOTIFY", to_sip.c_str(), from_sip.c_str(), nullptr);
    if (OSIP_SUCCESS != status)
    {
        LOG_ERROR("build requestAlarm failed: %d\n", status);
    }

    // osip_message_set_header(requestAlarm, "Event", "id=1984");
    osip_message_set_header(requestAlarm, "Event", "presence;id=1984");
    osip_message_set_header(requestAlarm, "Subscription-State", "active;retry-after=0");

    char buf[5] = {0};
    int timeAlarm = 0;
    timeAlarm = expiresAlarm * 60;
    sprintf(buf, "%d", timeAlarm);
    osip_message_set_header(requestAlarm, "Expires", buf);
    if (requestAlarm != NULL)
    {
        struct timeval curTime;
        gettimeofday(&curTime, NULL);

        char buffer[80] = {0};
        struct tm nowTime;
        localtime_r(&curTime.tv_sec, &nowTime);

        strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%S", &nowTime);
        string alarmTime = buffer;
        LOG_INFO("alarmTime:%s\n", alarmTime.c_str());

        stringstream ssAlarm;
        ssAlarm << "<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n";
        ssAlarm << "<Notify>\r\n";
        ssAlarm << "<CmdType>Alarm</CmdType>\r\n";                                /*命令类型(必选):报警通知*/
        ssAlarm << "<SN>" << get_sn() << "</SN>\r\n";                             /*命令序列号(必选)*/
        ssAlarm << "<DeviceID>" << DeviceId << "</DeviceID>\r\n";                 /*设备编码(必选):如果是NVR,就是通道编码*/
        ssAlarm << "<AlarmPriority>" << iAlarmPriority << "</AlarmPriority>\r\n"; /*报警级别(必选):1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情*/
        ssAlarm << "<AlarmMethod>" << iAlarmMethod << "</AlarmMethod>\r\n";       /*报警方式(必选):1为电话报警, 2为设备报警, 3为短信报警, 4为GPS报警, 5为视频报警, 6为设备故障报警, 7其他报警*/
        ssAlarm << "<AlarmTime>" << alarmTime << "</AlarmTime>\r\n";              /*报警时间(必选)*/
        ssAlarm << "<AlarmDescription>test</AlarmDescription>\r\n";               /*警情描述(可选)*/
        ssAlarm << "<Info>\r\n";                                                  /*扩展Info项(可选):携带报警类型、报警类型参数字段*/
        ssAlarm << "<AlarmType>" << iAlarmType << "</AlarmType>\r\n";             /*报警类型(可选):依赖报警方式,有三种情况。*/
        if (iAlarmType == 6)
        {
            int iEventType = 1;
            ssAlarm << "<AlarmTypeParam>\r\n";                            /*报警类型扩展参数(可选):在入侵检测报警时可携带<EventType>节点。*/
            ssAlarm << "<EventType>" << iEventType << "</EventType>\r\n"; /*事件类型(可选): 1-进入区域; 2-离开区域*/
            ssAlarm << "</AlarmTypeParam>\r\n";
        }
        ssAlarm << "</Info>\r\n";
        ssAlarm << "<Longitude>171.3</Longitude>\r\n"; /*经度信息(可选)*/
        ssAlarm << "<Latitude>34.2</Latitude>\r\n";    /*纬度信息(可选)*/
        ssAlarm << "</Notify>\r\n";

        osip_message_set_content_type(requestAlarm, "Application/MANSCDP+xml");
        osip_message_set_body(requestAlarm, ssAlarm.str().c_str(), strlen(ssAlarm.str().c_str()));
        send_request(requestAlarm);
    }
}

报警事件通知各个字段的含义见 附录。

3.附录

3.1报警通知各个字段的含义

1.Notify消息体:

字段名 字段值 是否必选 含义
CmdType Alarm 必选 命令类型:报警通知
SN 十进制整数 必选 命令序列号
DeviceID 20位十进制字符串 必选 设备编号
AlarmPriority 字符串 必选 报警级别:
1:一级警情,
2:二级警情,
3:三级警情,
4:四级警情
AlarmMethod 字符串 必选 报警方式:
1:电话报警,
2:设备报警,
3:短信报警,
4:GPS报警,
5:视频报警,
6:设备故障报警,
7:其他报警
AlarmTime 2009-12-04T16:23:32 必选 报警时间
AlarmDescription 字符串 可选 报警内容描述
Longitude double 可选 经度信息
Latitude double 可选 纬度信息
Info XML节点 可选 扩展Info项携带报警类型、
报警类型参数字段

2.Notify的扩展信息Info消息体:

二级XML节点 三级XML节点 字段值 是否必选 含义
AlarmType 整数 可选 报警类型,依赖报警方式,
有三种情况。
AlarmTypeParam XML节点 可选 报警类型扩展参数,
在入侵检测报警时
可携带节点。
EventType 整数 可选 事件类型:
1:进入区域
2:离开区域

关于AlarmType字段的含义解释:

  • 报警方式(AlarmMethod)为 2 时
    1.不携带AlarmType为默认的报警设备报警;
    2.携带AlarmType取值及对应报警类型:1-视频丢失报警; 2-设备防拆报警; 3-存储设备磁盘满报警; 4-设 备高温报警; 5-设备低温报警。
  • 报警方式(AlarmMethod)为 5 时
    取值如下:1-人工视频报警; 2-运动目标检测报警; 3-遗留物检测报警; 4-物体移除检测报警; 5-绊线检测报警;6-入侵检测报警; 7-逆行检测报警; 8-徘徊检测报警; 9-流量统计报警; 10-密度检测报警; 11-视频异常检测报警; 12-快速移动报警。
  • 报警方式(AlarmMethod)为 6 时
    取值如下: 1-存储设备磁盘故障报警; 2-存储设备风扇故障报警。
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区