Commit 6bab3b674059411f21dcbc18038846955e76b5cf

Authored by mk1990
Committed by GitHub
2 parents 88db5769 c395cf42

Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0

README.md
... ... @@ -109,21 +109,45 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
109 109 - [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。
110 110 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。
111 111  
112   -# docker快速体验
113   -目前作者的docker-compose因为时间有限维护不及时,这里提供第三方提供的供大家使用,维护不易,大家记得给这位小伙伴点个star。
114   -https://github.com/SaltFish001/wvp_pro_compose
115   -[https://github.com/SaltFish001/wvp_pro_compose](https://github.com/SaltFish001/wvp_pro_compose)
116   -这是作者维护的一个镜像,可能存在不及时的问题。
117   -```shell
118   -docker pull 648540858/wvp_pro
119   -
120   -docker run --env WVP_IP="你的IP" -it -p 18080:18080 -p 30000-30500:30000-30500/udp -p 30000-30500:30000-30500/tcp -p 80:80 -p 5060:5060 -p 5060:5060/udp 648540858/wvp_pro
121   -```
122   -docker使用详情查看:[https://hub.docker.com/r/648540858/wvp_pro](https://hub.docker.com/r/648540858/wvp_pro)
  112 +[//]: # (# docker快速体验)
  113 +
  114 +[//]: # (目前作者的docker-compose因为时间有限维护不及时,这里提供第三方提供的供大家使用,维护不易,大家记得给这位小伙伴点个star。 )
  115 +
  116 +[//]: # (https://github.com/SaltFish001/wvp_pro_compose)
  117 +
  118 +[//]: # ([https://github.com/SaltFish001/wvp_pro_compose](https://github.com/SaltFish001/wvp_pro_compose))
  119 +
  120 +[//]: # (这是作者维护的一个镜像,可能存在不及时的问题。)
  121 +
  122 +[//]: # (```shell)
  123 +
  124 +[//]: # (docker pull 648540858/wvp_pro)
  125 +
  126 +[//]: # ()
  127 +[//]: # (docker run --env WVP_IP="你的IP" -it -p 18080:18080 -p 30000-30500:30000-30500/udp -p 30000-30500:30000-30500/tcp -p 80:80 -p 5060:5060 -p 5060:5060/udp 648540858/wvp_pro)
  128 +
  129 +[//]: # (```)
  130 +
  131 +[//]: # (docker使用详情查看:[https://hub.docker.com/r/648540858/wvp_pro](https://hub.docker.com/r/648540858/wvp_pro))
123 132  
124 133 # gitee同步仓库
125 134 https://gitee.com/pan648540858/wvp-GB28181-pro.git
126 135  
  136 +# 遇到问题
  137 +国标最麻烦的地方在于设备的兼容性,所以需要大量的设备来测试,目前作者手里的设备有限,再加上作者水平有限,所以遇到问题在所难免;
  138 +1. 查看wiki,仔细的阅读可以帮你避免几乎所有的问题
  139 +2. 搜索issues,这里有大部分的答案
  140 +3. 加QQ群,这里有大量热心的小伙伴,但是前提新希望你已经仔细阅读了wiki和搜索了issues。
  141 +4. 你可以请作者为你解答,但是我不是免费的。
  142 +5. 你可以把遇到问题的设备寄给我,可以更容易的复现问题。
  143 +
  144 +
  145 +# 合作
  146 +目前很多打着合作的幌子来私聊的,其实大家大可不必,目前作者没有精力,你有问题可以付费找我解答,也可以提PR
  147 +,如果对代码有建议可以提ISSUE;也可以加群一起聊聊。我们欢迎所有有兴趣但遇到项目中来的人。
  148 +
  149 +
  150 +
127 151 # 使用帮助
128 152 QQ群: 901799015, ZLM使用文档[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
129 153 QQ私信一般不回, 精力有限.欢迎大家在群里讨论.觉得项目对你有帮助,欢迎star和提交pr。
... ...
... ... @@ -256,6 +256,7 @@
256 256 <plugin>
257 257 <groupId>org.springframework.boot</groupId>
258 258 <artifactId>spring-boot-maven-plugin</artifactId>
  259 + <version>2.3.5.RELEASE</version>
259 260 <configuration>
260 261 <includeSystemScope>true</includeSystemScope>
261 262 </configuration>
... ... @@ -263,6 +264,7 @@
263 264 <plugin>
264 265 <groupId>org.apache.maven.plugins</groupId>
265 266 <artifactId>maven-compiler-plugin</artifactId>
  267 + <version>3.8.1</version>
266 268 <configuration>
267 269 <source>1.8</source>
268 270 <target>1.8</target>
... ... @@ -272,6 +274,7 @@
272 274 <plugin>
273 275 <groupId>pl.project13.maven</groupId>
274 276 <artifactId>git-commit-id-plugin</artifactId>
  277 + <version>3.0.1</version>
275 278 <configuration>
276 279 <offline>true</offline>
277 280 </configuration>
... ... @@ -280,6 +283,7 @@
280 283 <plugin>
281 284 <groupId>org.apache.maven.plugins</groupId>
282 285 <artifactId>maven-surefire-plugin</artifactId>
  286 + <version>2.22.2</version>
283 287 <configuration>
284 288 <skipTests>true</skipTests>
285 289 </configuration>
... ...
src/main/java/com/genersoft/iot/vmp/domain/req/PresetQuerySipReq.java
1 1 package com.genersoft.iot.vmp.domain.req;
2 2  
3   -import lombok.Data;
4 3  
5 4 /**
6 5 * @author chenjialing
7 6 */
8   -@Data
9 7 public class PresetQuerySipReq {
10 8  
11 9 private String presetId;
12 10  
13 11 private String presetName;
  12 +
  13 + public String getPresetId() {
  14 + return presetId;
  15 + }
  16 +
  17 + public void setPresetId(String presetId) {
  18 + this.presetId = presetId;
  19 + }
  20 +
  21 + public String getPresetName() {
  22 + return presetName;
  23 + }
  24 +
  25 + public void setPresetName(String presetName) {
  26 + this.presetName = presetName;
  27 + }
14 28 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
... ... @@ -77,6 +77,21 @@ public class SendRtpItem {
77 77 private String CallId;
78 78  
79 79 /**
  80 + * 发送时,rtp的pt(uint8_t),不传时默认为96
  81 + */
  82 + private int pt = 96;
  83 +
  84 + /**
  85 + * 发送时,rtp的负载类型。为true时,负载为ps;为false时,为es;
  86 + */
  87 + private boolean usePs = true;
  88 +
  89 + /**
  90 + * 当usePs 为false时,有效。为1时,发送音频;为0时,发送视频;不传时默认为0
  91 + */
  92 + private boolean onlyAudio = false;
  93 +
  94 + /**
80 95 * 播放类型
81 96 */
82 97 private InviteStreamType playType;
... ... @@ -221,5 +236,27 @@ public class SendRtpItem {
221 236 this.dialog = dialog;
222 237 }
223 238  
  239 + public int getPt() {
  240 + return pt;
  241 + }
224 242  
  243 + public void setPt(int pt) {
  244 + this.pt = pt;
  245 + }
  246 +
  247 + public boolean isUsePs() {
  248 + return usePs;
  249 + }
  250 +
  251 + public void setUsePs(boolean usePs) {
  252 + this.usePs = usePs;
  253 + }
  254 +
  255 + public boolean isOnlyAudio() {
  256 + return onlyAudio;
  257 + }
  258 +
  259 + public void setOnlyAudio(boolean onlyAudio) {
  260 + this.onlyAudio = onlyAudio;
  261 + }
225 262 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
... ... @@ -30,7 +30,7 @@ public class CatalogDataCatch {
30 30 CatalogData catalogData = data.get(device.getDeviceId());
31 31 if (catalogData == null || catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end)) {
32 32 catalogData = new CatalogData();
33   - catalogData.setChannelList(new ArrayList<>());
  33 + catalogData.setChannelList(Collections.synchronizedList(new ArrayList<>()));
34 34 catalogData.setDevice(device);
35 35 catalogData.setSn(sn);
36 36 catalogData.setStatus(CatalogData.CatalogDataStatus.ready);
... ... @@ -46,7 +46,7 @@ public class CatalogDataCatch {
46 46 catalogData.setSn(sn);
47 47 catalogData.setTotal(total);
48 48 catalogData.setDevice(device);
49   - catalogData.setChannelList(new ArrayList<>());
  49 + catalogData.setChannelList(Collections.synchronizedList(new ArrayList<>()));
50 50 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng);
51 51 catalogData.setLastTime(new Date(System.currentTimeMillis()));
52 52 data.put(deviceId, catalogData);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
... ... @@ -4,8 +4,12 @@ import com.alibaba.fastjson.JSON;
4 4 import com.alibaba.fastjson.JSONObject;
5 5 import com.genersoft.iot.vmp.common.StreamInfo;
6 6 import com.genersoft.iot.vmp.conf.DynamicTask;
  7 +import com.genersoft.iot.vmp.gb28181.bean.InviteStreamType;
  8 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7 9 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
8 10 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
  11 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
  12 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
9 13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
10 14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
11 15 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
... ... @@ -13,6 +17,8 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
13 17 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
14 18 import com.genersoft.iot.vmp.service.IMediaServerService;
15 19 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  20 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  21 +import org.ehcache.shadow.org.terracotta.offheapstore.storage.IntegerStorageEngine;
16 22 import org.slf4j.Logger;
17 23 import org.slf4j.LoggerFactory;
18 24 import org.springframework.beans.factory.InitializingBean;
... ... @@ -51,6 +57,9 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
51 57 private IRedisCatchStorage redisCatchStorage;
52 58  
53 59 @Autowired
  60 + private IVideoManagerStorage storager;
  61 +
  62 + @Autowired
54 63 private ZLMRTPServerFactory zlmrtpServerFactory;
55 64  
56 65 @Autowired
... ... @@ -62,6 +71,12 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
62 71 @Autowired
63 72 private DynamicTask dynamicTask;
64 73  
  74 + @Autowired
  75 + private ISIPCommander cmder;
  76 +
  77 + @Autowired
  78 + private ISIPCommanderForPlatform commanderForPlatform;
  79 +
65 80  
66 81 /**
67 82 * 处理 ACK请求
... ... @@ -78,6 +93,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
78 93 if (dialog.getState()== DialogState.CONFIRMED) {
79 94 String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
80 95 logger.info("ACK请求: platformGbId->{}", platformGbId);
  96 + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformGbId);
81 97 // 取消设置的超时任务
82 98 dynamicTask.stop(callIdHeader.getCallId());
83 99 String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
... ... @@ -94,8 +110,23 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
94 110 param.put("dst_port", sendRtpItem.getPort());
95 111 param.put("is_udp", is_Udp);
96 112 param.put("src_port", sendRtpItem.getLocalPort());
97   - zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
98   -
  113 + param.put("pt", sendRtpItem.getPt());
  114 + param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
  115 + param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
  116 + JSONObject jsonObject = zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
  117 + if (jsonObject == null) {
  118 + logger.error("RTP推流失败: 请检查ZLM服务");
  119 + } else if (jsonObject.getInteger("code") == 0) {
  120 + logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
  121 + } else {
  122 + logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"),JSONObject.toJSON(param));
  123 + if (sendRtpItem.isOnlyAudio()) {
  124 + // TODO 可能是语音对讲
  125 + }else {
  126 + // 向上级平台
  127 + commanderForPlatform.streamByeCmd(parentPlatform, callIdHeader.getCallId());
  128 + }
  129 + }
99 130  
100 131  
101 132 // if (streamInfo == null) { // 流还没上来,对方就回复ack
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
2 2  
3   -import com.genersoft.iot.vmp.conf.SipConfig;
4   -import com.genersoft.iot.vmp.conf.UserSetting;
5 3 import com.genersoft.iot.vmp.domain.req.PresetQuerySipReq;
6 4 import com.genersoft.iot.vmp.gb28181.bean.*;
7   -import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
8   -import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
9   -import com.genersoft.iot.vmp.gb28181.session.CatalogDataCatch;
10 5 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
11 6 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
12 7 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
13 8 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
14 9 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
15   -import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
16   -import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
17   -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
18   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
19   -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
20 10 import org.dom4j.DocumentException;
21 11 import org.dom4j.Element;
22 12 import org.slf4j.Logger;
... ... @@ -24,7 +14,6 @@ import org.slf4j.LoggerFactory;
24 14 import org.springframework.beans.factory.InitializingBean;
25 15 import org.springframework.beans.factory.annotation.Autowired;
26 16 import org.springframework.stereotype.Component;
27   -import org.springframework.util.StringUtils;
28 17  
29 18 import javax.sip.InvalidArgumentException;
30 19 import javax.sip.RequestEvent;
... ... @@ -35,7 +24,6 @@ import java.text.SimpleDateFormat;
35 24 import java.util.ArrayList;
36 25 import java.util.Iterator;
37 26 import java.util.List;
38   -import java.util.UUID;
39 27  
40 28 import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
41 29  
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
... ... @@ -246,17 +246,7 @@ public class ZLMRTPServerFactory {
246 246 * 调用zlm RESTFUL API —— startSendRtp
247 247 */
248 248 public JSONObject startSendRtpStream(MediaServerItem mediaServerItem, Map<String, Object>param) {
249   - Boolean result = false;
250   - JSONObject jsonObject = zlmresTfulUtils.startSendRtp(mediaServerItem, param);
251   - if (jsonObject == null) {
252   - logger.error("RTP推流失败: 请检查ZLM服务");
253   - } else if (jsonObject.getInteger("code") == 0) {
254   - result= true;
255   - logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port"));
256   - } else {
257   - logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"),JSONObject.toJSON(param));
258   - }
259   - return jsonObject;
  249 + return zlmresTfulUtils.startSendRtp(mediaServerItem, param);
260 250 }
261 251  
262 252 /**
... ...