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_string
为PS
,因此你需要检查一下 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