Commit bb22908cf7cf698853a06d51593a22eaa64e789d

Authored by 648540858
Committed by GitHub
2 parents b05ddb20 2a273acd

Merge pull request #67 from lawrencehj/wvp-28181-2.0

增加上级平台信令功能实现,解决上级点播的一些问题
Showing 19 changed files with 391 additions and 98 deletions
README.md
@@ -60,21 +60,24 @@ https://gitee.com/18010473990/wvp-GB28181.git @@ -60,21 +60,24 @@ https://gitee.com/18010473990/wvp-GB28181.git
60 15. 支持订阅与通知方法 60 15. 支持订阅与通知方法
61 - [X] 移动位置订阅 61 - [X] 移动位置订阅
62 - [X] 移动位置通知处理 62 - [X] 移动位置通知处理
63 - - [ ] 报警事件订阅 63 + - [X] 报警事件订阅
64 - [X] 报警事件通知处理 64 - [X] 报警事件通知处理
65 - [ ] 设备目录订阅 65 - [ ] 设备目录订阅
66 - [X] 设备目录通知处理 66 - [X] 设备目录通知处理
67 16. 移动位置查询和显示,可通过配置文件设置移动位置历史是否存储 67 16. 移动位置查询和显示,可通过配置文件设置移动位置历史是否存储
68 68
69 # 2.0 支持特性 69 # 2.0 支持特性
70 -- [ ] 国标通道向上级联 70 +- [X] 国标通道向上级联
71 - [X] WEB添加上级平台 71 - [X] WEB添加上级平台
72 - [X] 注册 72 - [X] 注册
73 - [X] 心跳保活 73 - [X] 心跳保活
74 - [X] 通道选择 74 - [X] 通道选择
75 - [X] 通道推送 75 - [X] 通道推送
76 - - [ ] 点播  
77 - - [ ] 云台控制 76 + - [X] 点播
  77 + - [X] 云台控制
  78 + - [X] 平台状态查询
  79 + - [X] 平台信息查询
  80 + - [X] 平台远程启动
78 - [ ] 添加RTSP视频 81 - [ ] 添加RTSP视频
79 - [ ] 添加ONVIF探测局域网内的设备 82 - [ ] 添加ONVIF探测局域网内的设备
80 - [ ] 添加RTMP视频 83 - [ ] 添加RTMP视频
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
@@ -4,10 +4,20 @@ import java.util.logging.LogManager; @@ -4,10 +4,20 @@ import java.util.logging.LogManager;
4 4
5 import org.springframework.boot.SpringApplication; 5 import org.springframework.boot.SpringApplication;
6 import org.springframework.boot.autoconfigure.SpringBootApplication; 6 import org.springframework.boot.autoconfigure.SpringBootApplication;
  7 +import org.springframework.context.ConfigurableApplicationContext;
7 8
8 @SpringBootApplication 9 @SpringBootApplication
9 public class VManageBootstrap extends LogManager { 10 public class VManageBootstrap extends LogManager {
  11 + private static String[] args;
  12 + private static ConfigurableApplicationContext context;
10 public static void main(String[] args) { 13 public static void main(String[] args) {
11 - SpringApplication.run(VManageBootstrap.class, args); 14 + VManageBootstrap.args = args;
  15 + VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
  16 + }
  17 + // 项目重启
  18 + public static void restart() {
  19 + context.close();
  20 + VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
  21 +
12 } 22 }
13 } 23 }
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
@@ -15,6 +15,7 @@ import org.springframework.stereotype.Component; @@ -15,6 +15,7 @@ import org.springframework.stereotype.Component;
15 public class VideoStreamSessionManager { 15 public class VideoStreamSessionManager {
16 16
17 private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>(); 17 private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>();
  18 + private ConcurrentHashMap<String, String> ssrcMap = new ConcurrentHashMap<>();
18 19
19 public String createPlaySsrc(){ 20 public String createPlaySsrc(){
20 return SsrcUtil.getPlaySsrc(); 21 return SsrcUtil.getPlaySsrc();
@@ -24,16 +25,18 @@ public class VideoStreamSessionManager { @@ -24,16 +25,18 @@ public class VideoStreamSessionManager {
24 return SsrcUtil.getPlayBackSsrc(); 25 return SsrcUtil.getPlayBackSsrc();
25 } 26 }
26 27
27 - public void put(String ssrc,ClientTransaction transaction){  
28 - sessionMap.put(ssrc, transaction); 28 + public void put(String streamId,String ssrc,ClientTransaction transaction){
  29 + sessionMap.put(streamId, transaction);
  30 + ssrcMap.put(streamId, ssrc);
29 } 31 }
30 32
31 - public ClientTransaction get(String ssrc){  
32 - return sessionMap.get(ssrc); 33 + public ClientTransaction get(String streamId){
  34 + return sessionMap.get(streamId);
33 } 35 }
34 36
35 - public void remove(String ssrc) {  
36 - sessionMap.remove(ssrc);  
37 - SsrcUtil.releaseSsrc(ssrc); 37 + public void remove(String streamId) {
  38 + sessionMap.remove(streamId);
  39 + SsrcUtil.releaseSsrc(ssrcMap.get(streamId));
  40 + ssrcMap.remove(streamId);
38 } 41 }
39 } 42 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
@@ -156,6 +156,7 @@ public class SIPProcessorFactory { @@ -156,6 +156,7 @@ public class SIPProcessorFactory {
156 processor.setRequestEvent(evt); 156 processor.setRequestEvent(evt);
157 processor.setRedisCatchStorage(redisCatchStorage); 157 processor.setRedisCatchStorage(redisCatchStorage);
158 processor.setZlmrtpServerFactory(zlmrtpServerFactory); 158 processor.setZlmrtpServerFactory(zlmrtpServerFactory);
  159 + processor.setSIPCommander(cmder);
159 return processor; 160 return processor;
160 } else if (Request.CANCEL.equals(method)) { 161 } else if (Request.CANCEL.equals(method)) {
161 CancelRequestProcessor processor = new CancelRequestProcessor(); 162 CancelRequestProcessor processor = new CancelRequestProcessor();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -78,6 +78,14 @@ public interface ISIPCommander { @@ -78,6 +78,14 @@ public interface ISIPCommander {
78 boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2); 78 boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2);
79 79
80 /** 80 /**
  81 + * 前端控制指令(用于转发上级指令)
  82 + * @param device 控制设备
  83 + * @param channelId 预览通道
  84 + * @param cmdString 前端控制指令串
  85 + */
  86 + boolean fronEndCmd(Device device, String channelId, String cmdString);
  87 +
  88 + /**
81 * 请求预览视频流 89 * 请求预览视频流
82 * 90 *
83 * @param device 视频设备 91 * @param device 视频设备
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
@@ -42,4 +42,23 @@ public interface ISIPCommanderForPlatform { @@ -42,4 +42,23 @@ public interface ISIPCommanderForPlatform {
42 * @return 42 * @return
43 */ 43 */
44 boolean catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size); 44 boolean catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size);
  45 +
  46 + /**
  47 + * 向上级回复DeviceInfo查询信息
  48 + * @param parentPlatform 平台信息
  49 + * @param sn
  50 + * @param fromTag
  51 + * @return
  52 + */
  53 + boolean deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag);
  54 +
  55 + /**
  56 + * 向上级回复DeviceStatus查询信息
  57 + * @param parentPlatform 平台信息
  58 + * @param sn
  59 + * @param fromTag
  60 + * @return
  61 + */
  62 + boolean deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag);
  63 +
45 } 64 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -235,7 +235,7 @@ public class SIPCommander implements ISIPCommander { @@ -235,7 +235,7 @@ public class SIPCommander implements ISIPCommander {
235 ptzXml.append("</Control>\r\n"); 235 ptzXml.append("</Control>\r\n");
236 236
237 String tm = Long.toString(System.currentTimeMillis()); 237 String tm = Long.toString(System.currentTimeMillis());
238 - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtz" + tm, null); 238 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null);
239 239
240 transmitRequest(device, request); 240 transmitRequest(device, request);
241 return true; 241 return true;
@@ -272,7 +272,7 @@ public class SIPCommander implements ISIPCommander { @@ -272,7 +272,7 @@ public class SIPCommander implements ISIPCommander {
272 ptzXml.append("</Control>\r\n"); 272 ptzXml.append("</Control>\r\n");
273 273
274 String tm = Long.toString(System.currentTimeMillis()); 274 String tm = Long.toString(System.currentTimeMillis());
275 - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtz" + tm, null); 275 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null);
276 transmitRequest(device, request); 276 transmitRequest(device, request);
277 return true; 277 return true;
278 } catch (SipException | ParseException | InvalidArgumentException e) { 278 } catch (SipException | ParseException | InvalidArgumentException e) {
@@ -282,6 +282,36 @@ public class SIPCommander implements ISIPCommander { @@ -282,6 +282,36 @@ public class SIPCommander implements ISIPCommander {
282 } 282 }
283 283
284 /** 284 /**
  285 + * 前端控制指令(用于转发上级指令)
  286 + * @param device 控制设备
  287 + * @param channelId 预览通道
  288 + * @param cmdString 前端控制指令串
  289 + */
  290 + @Override
  291 + public boolean fronEndCmd(Device device, String channelId, String cmdString) {
  292 + try {
  293 + StringBuffer ptzXml = new StringBuffer(200);
  294 + ptzXml.append("<?xml version=\"1.0\" ?>\r\n");
  295 + ptzXml.append("<Control>\r\n");
  296 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  297 + ptzXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  298 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  299 + ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");
  300 + ptzXml.append("<Info>\r\n");
  301 + ptzXml.append("</Info>\r\n");
  302 + ptzXml.append("</Control>\r\n");
  303 +
  304 + String tm = Long.toString(System.currentTimeMillis());
  305 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "z9hG4bK-ViaPtz-" + tm, "FromPtz" + tm, null);
  306 + transmitRequest(device, request);
  307 + return true;
  308 + } catch (SipException | ParseException | InvalidArgumentException e) {
  309 + e.printStackTrace();
  310 + }
  311 + return false;
  312 + }
  313 +
  314 + /**
285 * 请求预览视频流 315 * 请求预览视频流
286 * @param device 视频设备 316 * @param device 视频设备
287 * @param channelId 预览通道 317 * @param channelId 预览通道
@@ -387,9 +417,7 @@ public class SIPCommander implements ISIPCommander { @@ -387,9 +417,7 @@ public class SIPCommander implements ISIPCommander {
387 Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrc); 417 Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrc);
388 418
389 ClientTransaction transaction = transmitRequest(device, request, errorEvent); 419 ClientTransaction transaction = transmitRequest(device, request, errorEvent);
390 - streamSession.put(streamId, transaction);  
391 -  
392 - 420 + streamSession.put(streamId,ssrc, transaction);
393 421
394 } catch ( SipException | ParseException | InvalidArgumentException e) { 422 } catch ( SipException | ParseException | InvalidArgumentException e) {
395 e.printStackTrace(); 423 e.printStackTrace();
@@ -487,7 +515,7 @@ public class SIPCommander implements ISIPCommander { @@ -487,7 +515,7 @@ public class SIPCommander implements ISIPCommander {
487 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null); 515 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null);
488 516
489 ClientTransaction transaction = transmitRequest(device, request, errorEvent); 517 ClientTransaction transaction = transmitRequest(device, request, errorEvent);
490 - streamSession.put(streamId, transaction); 518 + streamSession.put(streamId, ssrc, transaction);
491 519
492 } catch ( SipException | ParseException | InvalidArgumentException e) { 520 } catch ( SipException | ParseException | InvalidArgumentException e) {
493 e.printStackTrace(); 521 e.printStackTrace();
@@ -893,7 +921,7 @@ public class SIPCommander implements ISIPCommander { @@ -893,7 +921,7 @@ public class SIPCommander implements ISIPCommander {
893 catalogXml.append("</Query>\r\n"); 921 catalogXml.append("</Query>\r\n");
894 922
895 String tm = Long.toString(System.currentTimeMillis()); 923 String tm = Long.toString(System.currentTimeMillis());
896 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "z9hG4bK-ViaDeviceInfo" + tm, "FromDev" + tm, null); 924 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "z9hG4bK-ViaDeviceInfo-" + tm, "FromDev" + tm, null);
897 925
898 transmitRequest(device, request); 926 transmitRequest(device, request);
899 927
@@ -923,7 +951,7 @@ public class SIPCommander implements ISIPCommander { @@ -923,7 +951,7 @@ public class SIPCommander implements ISIPCommander {
923 catalogXml.append("</Query>\r\n"); 951 catalogXml.append("</Query>\r\n");
924 952
925 String tm = Long.toString(System.currentTimeMillis()); 953 String tm = Long.toString(System.currentTimeMillis());
926 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "z9hG4bK-ViaCatalog" + tm, "FromCat" + tm, null); 954 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "z9hG4bK-ViaCatalog-" + tm, "FromCat" + tm, null);
927 955
928 transmitRequest(device, request, errorEvent); 956 transmitRequest(device, request, errorEvent);
929 } catch (SipException | ParseException | InvalidArgumentException e) { 957 } catch (SipException | ParseException | InvalidArgumentException e) {
@@ -958,7 +986,7 @@ public class SIPCommander implements ISIPCommander { @@ -958,7 +986,7 @@ public class SIPCommander implements ISIPCommander {
958 recordInfoXml.append("</Query>\r\n"); 986 recordInfoXml.append("</Query>\r\n");
959 987
960 String tm = Long.toString(System.currentTimeMillis()); 988 String tm = Long.toString(System.currentTimeMillis());
961 - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "fromRec" + tm, null); 989 + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "z9hG4bK-ViaRecordInfo-" + tm, "fromRec" + tm, null);
962 990
963 transmitRequest(device, request); 991 transmitRequest(device, request);
964 } catch (SipException | ParseException | InvalidArgumentException e) { 992 } catch (SipException | ParseException | InvalidArgumentException e) {
@@ -1101,7 +1129,7 @@ public class SIPCommander implements ISIPCommander { @@ -1101,7 +1129,7 @@ public class SIPCommander implements ISIPCommander {
1101 mobilePostitionXml.append("</Query>\r\n"); 1129 mobilePostitionXml.append("</Query>\r\n");
1102 1130
1103 String tm = Long.toString(System.currentTimeMillis()); 1131 String tm = Long.toString(System.currentTimeMillis());
1104 - Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), "viaTagPos" + tm, "fromTagPos" + tm, null); 1132 + Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null);
1105 1133
1106 transmitRequest(device, request, errorEvent); 1134 transmitRequest(device, request, errorEvent);
1107 1135
@@ -1134,7 +1162,7 @@ public class SIPCommander implements ISIPCommander { @@ -1134,7 +1162,7 @@ public class SIPCommander implements ISIPCommander {
1134 subscribePostitionXml.append("</Query>\r\n"); 1162 subscribePostitionXml.append("</Query>\r\n");
1135 1163
1136 String tm = Long.toString(System.currentTimeMillis()); 1164 String tm = Long.toString(System.currentTimeMillis());
1137 - Request request = headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), "viaTagPos" + tm, "fromTagPos" + tm, null, expires, "presence" ); //Position;id=" + tm.substring(tm.length() - 4)); 1165 + Request request = headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, expires, "presence" ); //Position;id=" + tm.substring(tm.length() - 4));
1138 transmitRequest(device, request); 1166 transmitRequest(device, request);
1139 1167
1140 return true; 1168 return true;
@@ -1187,7 +1215,7 @@ public class SIPCommander implements ISIPCommander { @@ -1187,7 +1215,7 @@ public class SIPCommander implements ISIPCommander {
1187 cmdXml.append("</Query>\r\n"); 1215 cmdXml.append("</Query>\r\n");
1188 1216
1189 String tm = Long.toString(System.currentTimeMillis()); 1217 String tm = Long.toString(System.currentTimeMillis());
1190 - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "viaTagPos" + tm, "fromTagPos" + tm, null, expires, "presence" ); 1218 + Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, expires, "presence" );
1191 transmitRequest(device, request); 1219 transmitRequest(device, request);
1192 1220
1193 return true; 1221 return true;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -118,7 +118,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -118,7 +118,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
118 try { 118 try {
119 119
120 StringBuffer keepaliveXml = new StringBuffer(200); 120 StringBuffer keepaliveXml = new StringBuffer(200);
121 - keepaliveXml.append("<?xml version=\"1.0\"?>\r\n");//" encoding=\"GB2312\"?>\r\n"); 121 + keepaliveXml.append("<?xml version=\"1.0\"?>\r\n");
122 keepaliveXml.append("<Notify>\r\n"); 122 keepaliveXml.append("<Notify>\r\n");
123 keepaliveXml.append("<CmdType>Keepalive</CmdType>\r\n"); 123 keepaliveXml.append("<CmdType>Keepalive</CmdType>\r\n");
124 keepaliveXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); 124 keepaliveXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
@@ -217,4 +217,72 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -217,4 +217,72 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
217 } 217 }
218 return true; 218 return true;
219 } 219 }
  220 +
  221 + /**
  222 + * 向上级回复DeviceInfo查询信息
  223 + * @param parentPlatform 平台信息
  224 + * @param sn
  225 + * @param fromTag
  226 + * @return
  227 + */
  228 + @Override
  229 + public boolean deviceInfoResponse(ParentPlatform parentPlatform, String sn, String fromTag) {
  230 + if (parentPlatform == null) {
  231 + return false;
  232 + }
  233 + try {
  234 + StringBuffer deviceInfoXml = new StringBuffer(600);
  235 + deviceInfoXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
  236 + deviceInfoXml.append("<Response>\r\n");
  237 + deviceInfoXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
  238 + deviceInfoXml.append("<SN>" +sn + "</SN>\r\n");
  239 + deviceInfoXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n");
  240 + deviceInfoXml.append("<DeviceName>GB28181 Video Platform</DeviceName>\r\n");
  241 + deviceInfoXml.append("<Manufacturer>Manufacturer</Manufacturer>\r\n");
  242 + deviceInfoXml.append("<Model>wvp-28181</Model>\r\n");
  243 + deviceInfoXml.append("<Firmware>2.0.202103</Firmware>\r\n");
  244 + deviceInfoXml.append("<Result>OK</Result>\r\n");
  245 + deviceInfoXml.append("</Response>\r\n");
  246 + Request request = headerProviderPlarformProvider.createMessageRequest(parentPlatform, deviceInfoXml.toString(), fromTag);
  247 + transmitRequest(parentPlatform, request);
  248 +
  249 + } catch (SipException | ParseException | InvalidArgumentException e) {
  250 + e.printStackTrace();
  251 + return false;
  252 + }
  253 + return true;
  254 + }
  255 +
  256 + /**
  257 + * 向上级回复DeviceStatus查询信息
  258 + * @param parentPlatform 平台信息
  259 + * @param sn
  260 + * @param fromTag
  261 + * @return
  262 + */
  263 + @Override
  264 + public boolean deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag) {
  265 + if (parentPlatform == null) {
  266 + return false;
  267 + }
  268 + try {
  269 + StringBuffer deviceStatusXml = new StringBuffer(600);
  270 + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
  271 + deviceStatusXml.append("<Response>\r\n");
  272 + deviceStatusXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
  273 + deviceStatusXml.append("<SN>" +sn + "</SN>\r\n");
  274 + deviceStatusXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n");
  275 + deviceStatusXml.append("<Result>OK</Result>\r\n");
  276 + deviceStatusXml.append("<Online>ONLINE</Online>\r\n");
  277 + deviceStatusXml.append("<Status>OK</Status>\r\n");
  278 + deviceStatusXml.append("</Response>\r\n");
  279 + Request request = headerProviderPlarformProvider.createMessageRequest(parentPlatform, deviceStatusXml.toString(), fromTag);
  280 + transmitRequest(parentPlatform, request);
  281 +
  282 + } catch (SipException | ParseException | InvalidArgumentException e) {
  283 + e.printStackTrace();
  284 + return false;
  285 + }
  286 + return true;
  287 + }
220 } 288 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
@@ -4,7 +4,10 @@ import java.util.HashMap; @@ -4,7 +4,10 @@ import java.util.HashMap;
4 import java.util.Map; 4 import java.util.Map;
5 5
6 import javax.sip.*; 6 import javax.sip.*;
7 -//import javax.sip.message.Request; 7 +import javax.sip.address.SipURI;
  8 +import javax.sip.header.FromHeader;
  9 +import javax.sip.header.HeaderAddress;
  10 +import javax.sip.header.ToHeader;
8 11
9 import com.genersoft.iot.vmp.common.StreamInfo; 12 import com.genersoft.iot.vmp.common.StreamInfo;
10 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 13 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
@@ -12,14 +15,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcesso @@ -12,14 +15,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcesso
12 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 15 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
13 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
14 17
15 -import org.springframework.stereotype.Component;  
16 -  
17 /** 18 /**
18 * @Description:ACK请求处理器 19 * @Description:ACK请求处理器
19 * @author: swwheihei 20 * @author: swwheihei
20 * @date: 2020年5月3日 下午5:31:45 21 * @date: 2020年5月3日 下午5:31:45
21 */ 22 */
22 -@Component  
23 public class AckRequestProcessor extends SIPRequestAbstractProcessor { 23 public class AckRequestProcessor extends SIPRequestAbstractProcessor {
24 24
25 private IRedisCatchStorage redisCatchStorage; 25 private IRedisCatchStorage redisCatchStorage;
@@ -38,10 +38,8 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor { @@ -38,10 +38,8 @@ public class AckRequestProcessor extends SIPRequestAbstractProcessor {
38 if (dialog == null) return; 38 if (dialog == null) return;
39 //DialogState state = dialog.getState(); 39 //DialogState state = dialog.getState();
40 if (/*request.getMethod().equals(Request.INVITE) &&*/ dialog.getState()== DialogState.CONFIRMED) { 40 if (/*request.getMethod().equals(Request.INVITE) &&*/ dialog.getState()== DialogState.CONFIRMED) {
41 - String remoteUri = dialog.getRemoteParty().getURI().toString();  
42 - String localUri = dialog.getLocalParty().getURI().toString();  
43 - String platformGbId = remoteUri.substring(remoteUri.indexOf(":") + 1, remoteUri.indexOf("@"));  
44 - String channelId = localUri.substring(remoteUri.indexOf(":") + 1, remoteUri.indexOf("@")); 41 + String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
  42 + String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
45 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); 43 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
46 String is_Udp = sendRtpItem.isTcp() ? "0" : "1"; 44 String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
47 String deviceId = sendRtpItem.getDeviceId(); 45 String deviceId = sendRtpItem.getDeviceId();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.request.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
2 2
  3 +import javax.sip.address.SipURI;
3 import javax.sip.Dialog; 4 import javax.sip.Dialog;
4 import javax.sip.DialogState; 5 import javax.sip.DialogState;
5 import javax.sip.InvalidArgumentException; 6 import javax.sip.InvalidArgumentException;
6 import javax.sip.RequestEvent; 7 import javax.sip.RequestEvent;
7 import javax.sip.SipException; 8 import javax.sip.SipException;
  9 +import javax.sip.header.FromHeader;
  10 +import javax.sip.header.HeaderAddress;
  11 +import javax.sip.header.ToHeader;
8 import javax.sip.message.Response; 12 import javax.sip.message.Response;
9 13
10 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; 14 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  15 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
11 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; 16 import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
12 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 17 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
13 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 18 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -18,12 +23,14 @@ import java.util.Map; @@ -18,12 +23,14 @@ import java.util.Map;
18 23
19 /** 24 /**
20 * @Description: BYE请求处理器 25 * @Description: BYE请求处理器
21 - * @author: swwheihei  
22 - * @date: 2020年5月3日 下午5:32:05 26 + * @author: lawrencehj
  27 + * @date: 2021年3月9日
23 */ 28 */
24 public class ByeRequestProcessor extends SIPRequestAbstractProcessor { 29 public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
25 30
26 - private IRedisCatchStorage redisCatchStorage; 31 + private ISIPCommander cmder;
  32 +
  33 + private IRedisCatchStorage redisCatchStorage;
27 34
28 private ZLMRTPServerFactory zlmrtpServerFactory; 35 private ZLMRTPServerFactory zlmrtpServerFactory;
29 36
@@ -38,10 +45,8 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor { @@ -38,10 +45,8 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
38 Dialog dialog = evt.getDialog(); 45 Dialog dialog = evt.getDialog();
39 if (dialog == null) return; 46 if (dialog == null) return;
40 if (dialog.getState().equals(DialogState.TERMINATED)) { 47 if (dialog.getState().equals(DialogState.TERMINATED)) {
41 - String remoteUri = dialog.getRemoteParty().getURI().toString();  
42 - String localUri = dialog.getLocalParty().getURI().toString();  
43 - String platformGbId = remoteUri.substring(remoteUri.indexOf(":") + 1, remoteUri.indexOf("@"));  
44 - String channelId = localUri.substring(remoteUri.indexOf(":") + 1, remoteUri.indexOf("@")); 48 + String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
  49 + String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
45 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId); 50 SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
46 String streamId = sendRtpItem.getStreamId(); 51 String streamId = sendRtpItem.getStreamId();
47 Map<String, Object> param = new HashMap<>(); 52 Map<String, Object> param = new HashMap<>();
@@ -50,6 +55,11 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor { @@ -50,6 +55,11 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
50 param.put("stream",streamId); 55 param.put("stream",streamId);
51 System.out.println("停止向上级推流:" + streamId); 56 System.out.println("停止向上级推流:" + streamId);
52 zlmrtpServerFactory.stopSendRtpStream(param); 57 zlmrtpServerFactory.stopSendRtpStream(param);
  58 + redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
  59 + if (zlmrtpServerFactory.totalReaderCount(streamId) == 0) {
  60 + System.out.println(streamId + "无其它观看者,通知设备停止推流");
  61 + cmder.streamByeCmd(streamId);
  62 + }
53 } 63 }
54 } catch (SipException e) { 64 } catch (SipException e) {
55 e.printStackTrace(); 65 e.printStackTrace();
@@ -58,8 +68,6 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor { @@ -58,8 +68,6 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
58 } catch (ParseException e) { 68 } catch (ParseException e) {
59 e.printStackTrace(); 69 e.printStackTrace();
60 } 70 }
61 - // TODO 优先级99 Bye Request消息实现,此消息一般为级联消息,上级给下级发送视频停止指令  
62 -  
63 } 71 }
64 72
65 /*** 73 /***
@@ -89,4 +97,13 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor { @@ -89,4 +97,13 @@ public class ByeRequestProcessor extends SIPRequestAbstractProcessor {
89 public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) { 97 public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
90 this.zlmrtpServerFactory = zlmrtpServerFactory; 98 this.zlmrtpServerFactory = zlmrtpServerFactory;
91 } 99 }
  100 +
  101 + public ISIPCommander getSIPCommander() {
  102 + return cmder;
  103 + }
  104 +
  105 + public void setSIPCommander(ISIPCommander cmder) {
  106 + this.cmder = cmder;
  107 + }
  108 +
92 } 109 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
@@ -75,20 +75,6 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { @@ -75,20 +75,6 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
75 SipURI sipURI = (SipURI) request.getRequestURI(); 75 SipURI sipURI = (SipURI) request.getRequestURI();
76 String channelId = sipURI.getUser(); 76 String channelId = sipURI.getUser();
77 String platformId = null; 77 String platformId = null;
78 -// SubjectHeader subjectHeader = (SubjectHeader)request.getHeader(SubjectHeader.NAME);  
79 -// // 查询通道是否存在 不存在回复404  
80 -// if (subjectHeader != null) { // 存在则从subjectHeader 获取平台信息  
81 -// String subject = subjectHeader.getSubject();  
82 -// if (subject != null) {  
83 -// String[] info1 = subject.split(",");  
84 -// if (info1 != null && info1 .length == 2) {  
85 -// String[] info2 = info1[1].split(":");  
86 -// if (info2 != null && info2.length == 2) {  
87 -// platformId = info2[0];  
88 -// }  
89 -// }  
90 -// }  
91 -// }  
92 78
93 FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); 79 FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
94 AddressImpl address = (AddressImpl) fromHeader.getAddress(); 80 AddressImpl address = (AddressImpl) fromHeader.getAddress();
@@ -224,7 +210,9 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor { @@ -224,7 +210,9 @@ public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
224 e.printStackTrace(); 210 e.printStackTrace();
225 } 211 }
226 })); 212 }));
227 - playResult.getResult(); 213 + if (logger.isDebugEnabled()) {
  214 + logger.debug(playResult.getResult().toString());
  215 + }
228 216
229 } catch (SipException | InvalidArgumentException | ParseException e) { 217 } catch (SipException | InvalidArgumentException | ParseException e) {
230 e.printStackTrace(); 218 e.printStackTrace();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -4,14 +4,22 @@ import java.io.ByteArrayInputStream; @@ -4,14 +4,22 @@ import java.io.ByteArrayInputStream;
4 import java.text.ParseException; 4 import java.text.ParseException;
5 import java.util.*; 5 import java.util.*;
6 6
  7 +import javax.sip.address.SipURI;
  8 +
7 import javax.sip.header.FromHeader; 9 import javax.sip.header.FromHeader;
  10 +import javax.sip.header.HeaderAddress;
  11 +import javax.sip.header.ToHeader;
8 import javax.sip.InvalidArgumentException; 12 import javax.sip.InvalidArgumentException;
  13 +import javax.sip.ListeningPoint;
  14 +import javax.sip.ObjectInUseException;
9 import javax.sip.RequestEvent; 15 import javax.sip.RequestEvent;
10 import javax.sip.SipException; 16 import javax.sip.SipException;
  17 +import javax.sip.SipProvider;
11 import javax.sip.message.Request; 18 import javax.sip.message.Request;
12 import javax.sip.message.Response; 19 import javax.sip.message.Response;
13 20
14 import com.alibaba.fastjson.JSONObject; 21 import com.alibaba.fastjson.JSONObject;
  22 +import com.genersoft.iot.vmp.VManageBootstrap;
15 import com.genersoft.iot.vmp.common.StreamInfo; 23 import com.genersoft.iot.vmp.common.StreamInfo;
16 import com.genersoft.iot.vmp.common.VideoManagerConstants; 24 import com.genersoft.iot.vmp.common.VideoManagerConstants;
17 import com.genersoft.iot.vmp.conf.UserSetup; 25 import com.genersoft.iot.vmp.conf.UserSetup;
@@ -34,6 +42,7 @@ import com.genersoft.iot.vmp.utils.SpringBeanFactory; @@ -34,6 +42,7 @@ import com.genersoft.iot.vmp.utils.SpringBeanFactory;
34 import com.genersoft.iot.vmp.utils.redis.RedisUtil; 42 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
35 import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; 43 import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce;
36 44
  45 +import gov.nist.javax.sip.SipStackImpl;
37 import gov.nist.javax.sip.address.AddressImpl; 46 import gov.nist.javax.sip.address.AddressImpl;
38 import gov.nist.javax.sip.address.SipUri; 47 import gov.nist.javax.sip.address.SipUri;
39 48
@@ -114,10 +123,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { @@ -114,10 +123,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
114 logger.info("接收到Catalog消息"); 123 logger.info("接收到Catalog消息");
115 processMessageCatalogList(evt); 124 processMessageCatalogList(evt);
116 } else if (MESSAGE_DEVICE_INFO.equals(cmd)) { 125 } else if (MESSAGE_DEVICE_INFO.equals(cmd)) {
117 - logger.info("接收到DeviceInfo消息"); 126 + //DeviceInfo消息处理
118 processMessageDeviceInfo(evt); 127 processMessageDeviceInfo(evt);
119 } else if (MESSAGE_DEVICE_STATUS.equals(cmd)) { 128 } else if (MESSAGE_DEVICE_STATUS.equals(cmd)) {
120 - logger.info("接收到DeviceStatus消息"); 129 + // DeviceStatus消息处理
121 processMessageDeviceStatus(evt); 130 processMessageDeviceStatus(evt);
122 } else if (MESSAGE_DEVICE_CONTROL.equals(cmd)) { 131 } else if (MESSAGE_DEVICE_CONTROL.equals(cmd)) {
123 logger.info("接收到DeviceControl消息"); 132 logger.info("接收到DeviceControl消息");
@@ -211,27 +220,48 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { @@ -211,27 +220,48 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
211 private void processMessageDeviceStatus(RequestEvent evt) { 220 private void processMessageDeviceStatus(RequestEvent evt) {
212 try { 221 try {
213 Element rootElement = getRootElement(evt); 222 Element rootElement = getRootElement(evt);
214 - String deviceId = XmlUtil.getText(rootElement, "DeviceID");  
215 - // 检查设备是否存在, 不存在则不回复  
216 - if (storager.exists(deviceId)) {  
217 - // 回复200 OK  
218 - responseAck(evt);  
219 - JSONObject json = new JSONObject();  
220 - XmlUtil.node2Json(rootElement, json);  
221 - if (logger.isDebugEnabled()) {  
222 - logger.debug(json.toJSONString());  
223 - }  
224 - RequestMessage msg = new RequestMessage();  
225 - msg.setDeviceId(deviceId);  
226 - msg.setType(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS);  
227 - msg.setData(json);  
228 - deferredResultHolder.invokeResult(msg); 223 + String name = rootElement.getName();
  224 + Element deviceIdElement = rootElement.element("DeviceID");
  225 + String deviceId = deviceIdElement.getText();
229 226
230 - if (offLineDetector.isOnline(deviceId)) {  
231 - publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); 227 + if (name.equalsIgnoreCase("Query")) { // 区分是Response——查询响应,还是Query——查询请求
  228 + logger.info("接收到DeviceStatus查询消息");
  229 + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
  230 + String platformId = ((SipUri) fromHeader.getAddress().getURI()).getUser();
  231 + if (platformId == null) {
  232 + response404Ack(evt);
  233 + return;
232 } else { 234 } else {
  235 + // 回复200 OK
  236 + responseAck(evt);
  237 + String sn = rootElement.element("SN").getText();
  238 + ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
  239 + cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag());
  240 + }
  241 + } else {
  242 + logger.info("接收到DeviceStatus应答消息");
  243 + // 检查设备是否存在, 不存在则不回复
  244 + if (storager.exists(deviceId)) {
  245 + // 回复200 OK
  246 + responseAck(evt);
  247 + JSONObject json = new JSONObject();
  248 + XmlUtil.node2Json(rootElement, json);
  249 + if (logger.isDebugEnabled()) {
  250 + logger.debug(json.toJSONString());
  251 + }
  252 + RequestMessage msg = new RequestMessage();
  253 + msg.setDeviceId(deviceId);
  254 + msg.setType(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS);
  255 + msg.setData(json);
  256 + deferredResultHolder.invokeResult(msg);
  257 +
  258 + if (offLineDetector.isOnline(deviceId)) {
  259 + publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
  260 + } else {
  261 + }
233 } 262 }
234 } 263 }
  264 +
235 } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { 265 } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
236 e.printStackTrace(); 266 e.printStackTrace();
237 } 267 }
@@ -263,6 +293,51 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { @@ -263,6 +293,51 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
263 deferredResultHolder.invokeResult(msg); 293 deferredResultHolder.invokeResult(msg);
264 } else { 294 } else {
265 // 此处是上级发出的DeviceControl指令 295 // 此处是上级发出的DeviceControl指令
  296 + String platformId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
  297 + String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
  298 + // 远程启动功能
  299 + if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement, "TeleBoot"))) {
  300 + if (deviceId.equals(targetGBId)) {
  301 + // 远程启动功能:需要在重新启动程序后先对SipStack解绑
  302 + logger.info("执行远程启动本平台命令");
  303 + ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
  304 + cmderFroPlatform.unregister(parentPlatform, null, null);
  305 +
  306 + Thread restartThread = new Thread(new Runnable() {
  307 + @Override
  308 + public void run() {
  309 + try {
  310 + Thread.sleep(3000);
  311 + SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
  312 + SipStackImpl stack = (SipStackImpl)up.getSipStack();
  313 + stack.stop();
  314 + Iterator listener = stack.getListeningPoints();
  315 + while (listener.hasNext()) {
  316 + stack.deleteListeningPoint((ListeningPoint) listener.next());
  317 + }
  318 + Iterator providers = stack.getSipProviders();
  319 + while (providers.hasNext()) {
  320 + stack.deleteSipProvider((SipProvider) providers.next());
  321 + }
  322 + VManageBootstrap.restart();
  323 + } catch (InterruptedException ignored) {
  324 + } catch (ObjectInUseException e) {
  325 + e.printStackTrace();
  326 + }
  327 + }
  328 + });
  329 +
  330 + restartThread.setDaemon(false);
  331 + restartThread.start();
  332 + } else {
  333 + // 远程启动指定设备
  334 + }
  335 + }
  336 + if (!XmlUtil.isEmpty(XmlUtil.getText(rootElement,"PTZCmd")) && !deviceId.equals(targetGBId)) {
  337 + String cmdString = XmlUtil.getText(rootElement,"PTZCmd");
  338 + Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(platformId, deviceId);
  339 + cmder.fronEndCmd(device, deviceId, cmdString);
  340 + }
266 } 341 }
267 } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { 342 } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
268 e.printStackTrace(); 343 e.printStackTrace();
@@ -374,9 +449,21 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { @@ -374,9 +449,21 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
374 Element deviceIdElement = rootElement.element("DeviceID"); 449 Element deviceIdElement = rootElement.element("DeviceID");
375 String deviceId = deviceIdElement.getTextTrim().toString(); 450 String deviceId = deviceIdElement.getTextTrim().toString();
376 if (requestName.equals("Query")) { 451 if (requestName.equals("Query")) {
377 - // 回复200 OK  
378 - responseAck(evt); 452 + logger.info("接收到DeviceInfo查询消息");
  453 + FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
  454 + String platformId = ((SipUri) fromHeader.getAddress().getURI()).getUser();
  455 + if (platformId == null) {
  456 + response404Ack(evt);
  457 + return;
  458 + } else {
  459 + // 回复200 OK
  460 + responseAck(evt);
  461 + String sn = rootElement.element("SN").getText();
  462 + ParentPlatform parentPlatform = storager.queryParentPlatById(platformId);
  463 + cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag());
  464 + }
379 } else { 465 } else {
  466 + logger.info("接收到DeviceInfo应答消息");
380 Device device = storager.queryVideoDevice(deviceId); 467 Device device = storager.queryVideoDevice(deviceId);
381 if (device == null) { 468 if (device == null) {
382 return; 469 return;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java
@@ -60,16 +60,17 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor { @@ -60,16 +60,17 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor {
60 logger.info(String.format("未找到callId: %s 的注册/注销平台id", callId )); 60 logger.info(String.format("未找到callId: %s 的注册/注销平台id", callId ));
61 return; 61 return;
62 } 62 }
63 - logger.info(String.format("收到 %s 的注册/注销%S响应", platformGBId, response.getStatusCode() ));  
64 63
65 ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(platformGBId); 64 ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(platformGBId);
66 if (parentPlatformCatch == null) { 65 if (parentPlatformCatch == null) {
67 logger.warn(String.format("收到 %s 的注册/注销%S请求, 但是平台缓存信息未查询到!!!", platformGBId, response.getStatusCode())); 66 logger.warn(String.format("收到 %s 的注册/注销%S请求, 但是平台缓存信息未查询到!!!", platformGBId, response.getStatusCode()));
68 return; 67 return;
69 } 68 }
  69 + String action = parentPlatformCatch.getParentPlatform().getExpires().equals("0") ? "注销" : "注册";
  70 + logger.info(String.format("收到 %s %s的%S响应", platformGBId, action, response.getStatusCode() ));
70 ParentPlatform parentPlatform = parentPlatformCatch.getParentPlatform(); 71 ParentPlatform parentPlatform = parentPlatformCatch.getParentPlatform();
71 if (parentPlatform == null) { 72 if (parentPlatform == null) {
72 - logger.warn(String.format("收到 %s 的注册/注销%S请求, 但是平台信息未查询到!!!", platformGBId, response.getStatusCode())); 73 + logger.warn(String.format("收到 %s %s的%S请求, 但是平台信息未查询到!!!", platformGBId, action, response.getStatusCode()));
73 return; 74 return;
74 } 75 }
75 76
@@ -77,11 +78,16 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor { @@ -77,11 +78,16 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor {
77 WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME); 78 WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME);
78 sipCommanderForPlatform.register(parentPlatform, callId, www, null, null); 79 sipCommanderForPlatform.register(parentPlatform, callId, www, null, null);
79 }else if (response.getStatusCode() == 200){ 80 }else if (response.getStatusCode() == 200){
80 - // 注册成功  
81 - logger.info(String.format("%s 注册成功", platformGBId )); 81 + // 注册/注销成功
  82 + logger.info(String.format("%s %s成功", platformGBId, action));
82 redisCatchStorage.delPlatformRegisterInfo(callId); 83 redisCatchStorage.delPlatformRegisterInfo(callId);
83 parentPlatform.setStatus(true); 84 parentPlatform.setStatus(true);
  85 + // 取回Expires设置,避免注销过程中被置为0
  86 + ParentPlatform parentPlatformTmp = storager.queryParentPlatById(platformGBId);
  87 + String expires = parentPlatformTmp.getExpires();
  88 + parentPlatform.setExpires(expires);
84 storager.updateParentPlatform(parentPlatform); 89 storager.updateParentPlatform(parentPlatform);
  90 +
85 redisCatchStorage.updatePlatformRegister(parentPlatform); 91 redisCatchStorage.updatePlatformRegister(parentPlatform);
86 92
87 redisCatchStorage.updatePlatformKeepalive(parentPlatform); 93 redisCatchStorage.updatePlatformKeepalive(parentPlatform);
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -267,20 +267,25 @@ public class ZLMHttpHookListener { @@ -267,20 +267,25 @@ public class ZLMHttpHookListener {
267 } 267 }
268 268
269 String streamId = json.getString("stream"); 269 String streamId = json.getString("stream");
270 -  
271 - cmder.streamByeCmd(streamId);  
272 StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); 270 StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
273 - if (streamInfo!=null){  
274 - redisCatchStorage.stopPlay(streamInfo);  
275 - storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 271 +
  272 + JSONObject ret = new JSONObject();
  273 + ret.put("code", 0);
  274 + ret.put("close", true);
  275 +
  276 + if (streamInfo != null) {
  277 + if (redisCatchStorage.isChannelSendingRTP(streamInfo.getChannelId())) {
  278 + ret.put("close", false);
  279 + } else {
  280 + cmder.streamByeCmd(streamId);
  281 + redisCatchStorage.stopPlay(streamInfo);
  282 + storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
  283 + }
276 }else{ 284 }else{
  285 + cmder.streamByeCmd(streamId);
277 streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); 286 streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
278 redisCatchStorage.stopPlayback(streamInfo); 287 redisCatchStorage.stopPlayback(streamInfo);
279 } 288 }
280 -  
281 - JSONObject ret = new JSONObject();  
282 - ret.put("code", 0);  
283 - ret.put("close", true);  
284 return new ResponseEntity<String>(ret.toString(),HttpStatus.OK); 289 return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
285 } 290 }
286 291
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -153,6 +153,16 @@ public class ZLMRTPServerFactory { @@ -153,6 +153,16 @@ public class ZLMRTPServerFactory {
153 } 153 }
154 154
155 /** 155 /**
  156 + * 查询转推的流是否有其它观看者
  157 + * @param streamId
  158 + * @return
  159 + */
  160 + public int totalReaderCount(String streamId) {
  161 + JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId);
  162 + return mediaInfo.getInteger("totalReaderCount");
  163 + }
  164 +
  165 + /**
156 * 调用zlm RESTful API —— stopSendRtp 166 * 调用zlm RESTful API —— stopSendRtp
157 */ 167 */
158 public Boolean stopSendRtpStream(Map<String, Object>param) { 168 public Boolean stopSendRtpStream(Map<String, Object>param) {
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -89,4 +89,17 @@ public interface IRedisCatchStorage { @@ -89,4 +89,17 @@ public interface IRedisCatchStorage {
89 */ 89 */
90 SendRtpItem querySendRTPServer(String platformGbId, String channelId); 90 SendRtpItem querySendRTPServer(String platformGbId, String channelId);
91 91
  92 + /**
  93 + * 删除RTP推送信息缓存
  94 + * @param platformGbId
  95 + * @param channelId
  96 + */
  97 + void deleteSendRTPServer(String platformGbId, String channelId);
  98 +
  99 + /**
  100 + * 查询某个通道是否存在上级点播(RTP推送)
  101 + * @param channelId
  102 + */
  103 + boolean isChannelSendingRTP(String channelId);
  104 +
92 } 105 }
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -225,4 +225,30 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -225,4 +225,30 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
225 return (SendRtpItem)redis.get(key); 225 return (SendRtpItem)redis.get(key);
226 } 226 }
227 227
  228 + /**
  229 + * 删除RTP推送信息缓存
  230 + * @param platformGbId
  231 + * @param channelId
  232 + */
  233 + @Override
  234 + public void deleteSendRTPServer(String platformGbId, String channelId) {
  235 + String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + platformGbId + "_" + channelId;
  236 + redis.del(key);
  237 + }
  238 +
  239 + /**
  240 + * 查询某个通道是否存在上级点播(RTP推送)
  241 + * @param channelId
  242 + */
  243 + @Override
  244 + public boolean isChannelSendingRTP(String channelId) {
  245 + String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + "*_" + channelId;
  246 + List<Object> RtpStreams = redis.scan(key);
  247 + if (RtpStreams.size() > 0) {
  248 + return true;
  249 + } else {
  250 + return false;
  251 + }
  252 + }
  253 +
228 } 254 }
src/main/java/com/genersoft/iot/vmp/vmanager/platform/PlatformController.java
@@ -60,7 +60,7 @@ public class PlatformController { @@ -60,7 +60,7 @@ public class PlatformController {
60 public ResponseEntity<String> savePlatform(@RequestBody ParentPlatform parentPlatform){ 60 public ResponseEntity<String> savePlatform(@RequestBody ParentPlatform parentPlatform){
61 61
62 if (logger.isDebugEnabled()) { 62 if (logger.isDebugEnabled()) {
63 - logger.debug("查询所有上级设备API调用"); 63 + logger.debug("保存上级平台信息API调用");
64 } 64 }
65 if (StringUtils.isEmpty(parentPlatform.getName()) 65 if (StringUtils.isEmpty(parentPlatform.getName())
66 ||StringUtils.isEmpty(parentPlatform.getServerGBId()) 66 ||StringUtils.isEmpty(parentPlatform.getServerGBId())
@@ -87,13 +87,13 @@ public class PlatformController { @@ -87,13 +87,13 @@ public class PlatformController {
87 if (parentPlatform.isEnable()) { 87 if (parentPlatform.isEnable()) {
88 // 只要保存就发送注册 88 // 只要保存就发送注册
89 commanderForPlatform.register(parentPlatform); 89 commanderForPlatform.register(parentPlatform);
90 - }else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()){ // 关闭启用时注销 90 + } else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()){ // 关闭启用时注销
91 commanderForPlatform.unregister(parentPlatform, null, null); 91 commanderForPlatform.unregister(parentPlatform, null, null);
92 } 92 }
93 93
94 - 94 +
95 return new ResponseEntity<>("success", HttpStatus.OK); 95 return new ResponseEntity<>("success", HttpStatus.OK);
96 - }else { 96 + } else {
97 return new ResponseEntity<>("fail", HttpStatus.OK); 97 return new ResponseEntity<>("fail", HttpStatus.OK);
98 } 98 }
99 } 99 }
@@ -103,7 +103,7 @@ public class PlatformController { @@ -103,7 +103,7 @@ public class PlatformController {
103 public ResponseEntity<String> deletePlatform(@RequestBody ParentPlatform parentPlatform){ 103 public ResponseEntity<String> deletePlatform(@RequestBody ParentPlatform parentPlatform){
104 104
105 if (logger.isDebugEnabled()) { 105 if (logger.isDebugEnabled()) {
106 - logger.debug("查询所有上级设备API调用"); 106 + logger.debug("删除上级平台API调用");
107 } 107 }
108 if (StringUtils.isEmpty(parentPlatform.getServerGBId()) 108 if (StringUtils.isEmpty(parentPlatform.getServerGBId())
109 ){ 109 ){
@@ -138,7 +138,7 @@ public class PlatformController { @@ -138,7 +138,7 @@ public class PlatformController {
138 public ResponseEntity<String> exitPlatform(@PathVariable String deviceGbId){ 138 public ResponseEntity<String> exitPlatform(@PathVariable String deviceGbId){
139 139
140 if (logger.isDebugEnabled()) { 140 if (logger.isDebugEnabled()) {
141 - logger.debug("查询所有上级设备API调用"); 141 + logger.debug("查询上级平台是否存在API调用:" + deviceGbId);
142 } 142 }
143 ParentPlatform parentPlatform = storager.queryParentPlatById(deviceGbId); 143 ParentPlatform parentPlatform = storager.queryParentPlatById(deviceGbId);
144 return new ResponseEntity<>(String.valueOf(parentPlatform != null), HttpStatus.OK); 144 return new ResponseEntity<>(String.valueOf(parentPlatform != null), HttpStatus.OK);
@@ -184,7 +184,7 @@ public class PlatformController { @@ -184,7 +184,7 @@ public class PlatformController {
184 public ResponseEntity<String> delChannelForGB(@RequestBody UpdateChannelParam param){ 184 public ResponseEntity<String> delChannelForGB(@RequestBody UpdateChannelParam param){
185 185
186 if (logger.isDebugEnabled()) { 186 if (logger.isDebugEnabled()) {
187 - logger.debug("给上级平台添加国标通道API调用"); 187 + logger.debug("给上级平台删除国标通道API调用");
188 } 188 }
189 int result = storager.delChannelForGB(param.getPlatformId(), param.getChannelReduces()); 189 int result = storager.delChannelForGB(param.getPlatformId(), param.getChannelReduces());
190 190
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
@@ -86,6 +86,9 @@ public class PlayServiceImpl implements IPlayService { @@ -86,6 +86,9 @@ public class PlayServiceImpl implements IPlayService {
86 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); 86 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
87 msg.setData(JSON.toJSONString(streamInfo)); 87 msg.setData(JSON.toJSONString(streamInfo));
88 resultHolder.invokeResult(msg); 88 resultHolder.invokeResult(msg);
  89 + if (hookEvent != null) {
  90 + hookEvent.response(JSONObject.parseObject(JSON.toJSONString(streamInfo)));
  91 + }
89 } else { 92 } else {
90 redisCatchStorage.stopPlay(streamInfo); 93 redisCatchStorage.stopPlay(streamInfo);
91 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId()); 94 storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());