HowTo文档

如何在 XSwitch 中对接 GB28181 协议的摄像头

随着视频监控应用的发展,涌现了大量的监控平台提供商,它们的接入协议各不相同,对不同厂商设备集中调阅的复杂度越来越高。在这样的产业背景下,GB/T28181 应运而生。

GB28181 定义了基于 SIP(会话初始协议)、SDP(会话描述协议)等协议的互联规范,安全注册、实时视音频点播等应用基于 SIP REGISTER、INVITE 等请求和响应方法。

配置 XSwitch 分机

进入【呼叫】⇨【分机】,新建一个分机,根据协议统一编码规则,应创建 20 位十进制数字字符号码,比如:34020000001320000005。

点击新创建的分机,进入分机详情页,修改类型海康摄像头,这样在呼叫该监控时,XSwitch 会自动添加Subject 消息头域以及正确的 SDP 信息。

需要说明一下,GB28181 设备或者平台一般不认域名,创建分机时需要单独配置一下域,一般取分机号码前 10 位即可。

监控摄像头配置

以海康摄像头为例,进入【配置】⇨【网络】⇨【高级配置】⇨【平台接入】,选择平台接入方式为28181,同时配置 SIP 服务器地址端口、用户名、ID、密码,启用并保存配置即可。

如果注册状态显示为在线则表示注册成功,如下图:

这里需要记住该处配置的SIP 服务器 ID,呼叫摄像头进行实时点播时会用到。

实时音视频点播

点播场景可以获取到设备的音视频,注意,设备是sendonly。如果想获取到设备的音频,设备需要选择复合流,否则 PS 流中只有视频。

路由配置

进入【呼叫】⇨【路由】,新建一条路由:

  • 名称:hk,也可以随意
  • 被叫字冠:340,根据上文提到的编码规则
  • 呼叫源:default
  • 最大长度:20
  • 目的地类型:本地分机

同时需要在号码变换中修改主叫号码变换为34020000001320000001

注意:

此处的主叫号码应该设置为上文中提及的SIP 服务器 ID,否则呼叫时,可能会收到415 Unsupported Media Type.

呼叫测试

使用xTalk或者 SIP 视频电话直接呼叫监控分机即可。

如果你想在终端fs_cli发起呼叫,可以直接:

bgapi originate {origination_caller_id_number=34020000001320000001}user/34020000001320000005 &conference(3000)

上述命令只有在分机类型选择为海康摄像头时才好用。

其实完整的命令应该是这样的

bgapi originate {origination_caller_id_number=34020000001320000001,sip_h_Subject=34020000001320000005:0\,34020000001320000001:0,absolute_codec_string=PS}user/34020000001320000005 &conference(3000)

Subject各字段含义分别为媒体流发送者设备编码:发送端媒体流序列号,媒体流接收者设备编码:接收端媒体流序列号

其中,媒体流发送者指的是摄像头,接收端指的是 XSwitch

另外,我们看到这里设置的absolute_codec_stringPS,因此你需要检查一下 XSwitch 中是否已经成功加载mod_ps

如果对协商过程感兴趣,可以在终端fs_cli开启sofia global siptrace on或者参考 GB28181-2016 附录部分

广播

广播场景下可以对设备喊话,注意,设备是recvonly

呼叫测试

广播发起方需要首先发送MESSAGE消息 Notify 设备,设备回复MESSAGE Response 后,会主动发送INVITE,所以需要配置对应的路由。

进入【呼叫】⇨【路由】新建一条路由,其中被叫号码为前文提及的SIP 服务器 ID,如果对接的是平台,真正的主叫设备 ID 在INVITE头部Subject字段中,from 则为平台注册到 XSwitch 的号码,平台会管理很多设备。

MESSAGE 参考:

MESSAGE sip:34020000001320000005@192.168.3.98:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.3.200;rport;branch=z9hG4bK1ap14K9Bmvrcg
Route: <sip:34020000001320000005@192.168.3.98:5060>
Max-Forwards: 70
From: "34020000001320000001" <sip:34020000001320000001@140.143.134.19:10160>;tag=1pN12ray0F6Ha
To: <sip:34020000001320000005@192.168.3.98:5060>
Call-ID: 6dcee39e-820d-4204-b890-8500b838188d
CSeq: 59825685 MESSAGE
User-Agent: FreeSWITCH-mod_sofia/1.10.8-dev+git~20221102T021101Z~fcab6ea333~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
Content-Type: Application/MANSCDP+xml
Content-Length: 185
X-FS-Sending-Message: 63e5e877-2fb6-4467-98ac-33de4cdd890a

<?xml version="1.0"?>
<Notify>
<CmdType>Broadcast</CmdType>
<SN>111</SN>
<SourceID>34020000001320000001</SourceID>
<TargetID>34020000001320000005</TargetID>
</Notify>

INVITE 参考:

INVITE sip:34020000001320000001@192.168.3.200:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.3.98:5060;rport;branch=z9hG4bK621100893
From: <sip:34020000001320000005@192.168.3.98:5060>;tag=1324899375
To: <sip:34020000001320000001@192.168.3.200:5060>
Call-ID: 1063016033
CSeq: 20 INVITE
Contact: <sip:34020000001320000005@192.168.3.98:5060>
Content-Type: application/sdp
Max-Forwards: 70
User-Agent: IP Camera
Subject: 34020000001320000001:1,34020000001320000005:2
Content-Length:   214

v=0
o=34020000001320000005 2260 2260 IN IP4 192.168.3.98
s=Play
c=IN IP4 192.168.3.98
t=0 0
m=audio 15062 RTP/AVP 8 96
a=recvonly
a=rtpmap:8 PCMA/8000
a=rtpmap:96 PS/90000
y=0200000017
f=v/////a/1/8/1

发送MESSAGE lua 脚本参考 broadcast.lua:

local body = ''
local sn = '111'
local source_id = '34020000001320000001'    -- 服务器编码 ID
local device_id = '34020000001320000005'    -- 设备编码 ID
local to = '34020000001320000005'           -- 平台注册到 FS 的号码(对接平台时为下级平台编码)或者跟 device_id 相同(直接对接设备)

local api = freeswitch.API()
local domain = api:execute("global_getvar", "domain")

body = '<?xml version="1.0" encoding="GB2312"?>\n' ..
        '<Notify>\n<CmdType>Broadcast</CmdType>\n<SN>'.. sn ..'</SN>\n<SourceID>' .. source_id ..'</SourceID>\n<TargetID>' .. device_id .. '</TargetID>\n' ..
        '</Notify>\n'

local event = freeswitch.Event("Custom", "SMS::SEND_MESSAGE");
event:addHeader('type', 'Application/MANSCDP+xml')
-- 对接平台时,平台可能不认 from 中的 domain
-- event:addHeader('from', source_id .. '@local_sip_ip:local_sip_port')
event:addHeader('from', source_id .. '@' .. domain)
event:addHeader('to', to .. '@' .. domain)
event:addHeader('sip_profile', 'default')
event:addHeader('dest_proto', 'sip')
event:addBody(body)
event:fire();

对讲

GB28181 对讲是基于点播和广播实现的,也就是说,对同一设备对讲需要两路呼叫来实现。

对讲测试

由于对讲基于点播和广播两路呼叫来实现,我们可以通过conference来实现。

首先,点播设备:

conference 3000 bgdial {origination_caller_id_number=34020000001320000001,sip_h_Subject=34020100001320000005:0\,34020000001320000001:0,absolute_codec_string=PS,conference_member_flags=mute}user/34020000001320000005

发起广播,需要将广播来话路由到同一个 conference 中:

lua broadcast.lua

呼叫普通 SIP 终端:

conference 3000 bgdial user/1009

由于点播+广播是两路呼叫,设备在 conference 中存在两个成员,这样点播到的音频会再次广播给设备,设备会啸叫。需要单独处理一下,点播设备时设置conference_member_flags=mute,这样谁也听不到设备的声音,然后:

conference 3000 relate id1 id2 nohear
conference 3000 unmute all

其中:id1对应广播成员,id2对应点播成员。

至此,对讲完成。

对讲说明

点播时正常,对讲时听不到设备的声音,这是由于部分设备默认工作模式不是双工的,设备说话时需要按键,或者可以修改设备为双工模式。

参考

https://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=469659DC56B9B8187671FF08748CEC89

XSwitch对接鼎信通达网关