【wvp-pro-gb28181】新建CallIdHeader失败的原因解析记录
写在前面
最后一直在研究wvp-pro gb28181 发现其项目非常完善,只需要优化一点部署细节即可最近由于国标级连上下级,我搭建了多个服务器,在用一个物理服务器的时候发现级连上级失败了一直处于离线状态,上级日志一看根本就没有收到,说明根本就没有开始发,根据报错信息 我们快速找到源码所在
[新建CallIdHeader失败], ip={}, transport={}
我加上了打印方便分析问题
分析过程
经过日志排查发现传进来的是公网ip,作为key 去取udpSipProviderMap,而udpSipProviderMap中是内网ip,这个问题在只有一个内网ip的时候是不会发生的因为只要size为1就取的first,以下代码我加了兼容方案就是最后为空的时候还是取first,那么如何从本质上解决这个问题呢,继续往下看
SIPSender
public CallIdHeader getNewCallIdHeader(String ip, String transport) {log.info("getNewCallIdHeader:ip "+ip + " transport " + transport + "sipLayer:" + sipLayer.getUdpSipProvider());if (ObjectUtils.isEmpty(transport)) {return sipLayer.getUdpSipProvider().getNewCallId();}SipProviderImpl sipProvider;if (ObjectUtils.isEmpty(ip)) {sipProvider = transport.equalsIgnoreCase("TCP") ? sipLayer.getTcpSipProvider(): sipLayer.getUdpSipProvider();log.info("getNewCallIdHeader ip null " + sipProvider);} else {sipProvider = transport.equalsIgnoreCase("TCP") ? sipLayer.getTcpSipProvider(ip): sipLayer.getUdpSipProvider(ip);log.info("getNewCallIdHeader ip notnull " + sipProvider);}if (sipProvider == null) {sipProvider = sipLayer.getUdpSipProvider();log.info("getNewCallIdHeader 最后获取" + sipProvider);}if (sipProvider != null) {return sipProvider.getNewCallId();} else {log.warn("[新建CallIdHeader失败], ip={}, transport={}", ip, transport);return null;}}
SipLayer
public SipProviderImpl getUdpSipProvider(String ip) {log.info("getUdpSipProvider udpSipProviderMap.size() " + udpSipProviderMap.size());log.info("getUdpSipProvider udpSipProviderMap.keySet() " + udpSipProviderMap.keySet());if (udpSipProviderMap.size() == 1) {return udpSipProviderMap.values().stream().findFirst().get();}if (ObjectUtils.isEmpty(ip)) {return null;}SipProviderImpl udpSipProvider = udpSipProviderMap.get(ip);if (udpSipProvider == null){return udpSipProviderMap.values().stream().findFirst().get();}return udpSipProvider;}
既然是级连 ip问题就离不开也就是离不开配置项
我们回到zlm配置 WVP-PRO文档 文档原文如下
#zlm 默认服务器配置
media:id: zlmediakit-local# [必须修改] zlm服务器的内网IPip: 172.19.128.50# [可选] 有公网IP就配置公网IP, 不可用域名wan_ip:# [必须修改] zlm服务器的http.porthttp-port: 9092# [可选] zlm服务器访问WVP所使用的IP, 默认使用127.0.0.1,zlm和wvp没有部署在同一台服务器时必须配置hook-ip: 172.19.128.50# [必选选] zlm服务器的hook.admin_params=secretsecret: TWSYFgYJOQWB4ftgeYut8DW4wbs7pQnj# 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试rtp:# [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输enable: true# [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功port-range: 30000,35000 # 端口范围# [可选] 国标级联在此范围内选择端口发送媒体流,send-port-range: 40000,40300 # 端口范围
这里恰好没有写关键的sdp 和stream ip
在一开始的时候按照文档写ip为内网ip 结果发现怎么都播放不了 反而改为公网ip后 才能正常播放
那是因为播放拉流相关的地址 默认继承的ip,所以才导致ip设为公网可用 设为内网反而不可用了
这里困惑了很长一段时间,再加上https域名部署后,就能查到了ip不设置域名那必然有新的地方
ip:公网ip
stream-ip: 域名 # 客户端拉流地址
sdp-ip: 域名 # SIP 设备协商地址
此时如果不纠结ip本身 就能达到了 播放地址是域名的效果了,那么作者为什么会标注ip一定得是内网ip呢 继续往下看
当我们有两个ip的时候,原来的代码就会有进来的ip去取,进来的ip对应刚才的设置,那么key就对不上,就会返回为空 导致请求失败
那么有人可能又问了 这个172.18.0.1是哪里来的 ,这个可能是虚拟化环境中(如Docker 导致的 ,也可能是网络本身 或者网卡设置的,这个原因根据实际情况,我这边是同事装了Docker
所以最终心得是
最终配置
ip:内网ip
stream-ip: 域名/公网ip # 客户端拉流地址
sdp-ip: 域名/公网ip # SIP 设备协商地址
证书问题
其他配套文档中没有提清楚的
# 合并
cat custom.crt custom.key > default.pem
# 检查合并后的PEM格式
openssl x509 -in default.pem -text -noout # 直接查看完整证书内容
https 生成证书后替换此处
https播放链接修改端口 如hls
以上便能同时解决
1.域名访问网站
2.ip级连上级平台
3.https域名播放
等有空了发了个部署全过程