Commit 82fd369ce554467f794c9aa66e453adecefc73a9

Authored by 648540858
2 parents 6a2ff995 7918f037

Merge branch 'wvp-28181-2.0'

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
Showing 31 changed files with 498 additions and 357 deletions
sql/mysql.sql
@@ -277,7 +277,6 @@ CREATE TABLE `media_server` ( @@ -277,7 +277,6 @@ CREATE TABLE `media_server` (
277 `rtspSSLPort` int NOT NULL, 277 `rtspSSLPort` int NOT NULL,
278 `autoConfig` int NOT NULL, 278 `autoConfig` int NOT NULL,
279 `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 279 `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
280 - `streamNoneReaderDelayMS` int NOT NULL,  
281 `rtpEnable` int NOT NULL, 280 `rtpEnable` int NOT NULL,
282 `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 281 `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
283 `sendRtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 282 `sendRtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
sql/update.sql
  1 +alter table wvp.media_server
  2 + drop column streamNoneReaderDelayMS;
  3 +
  4 +alter table stream_proxy
  5 + add enable_disable_none_reader bit(1) default null;
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
1 package com.genersoft.iot.vmp.common; 1 package com.genersoft.iot.vmp.common;
2 2
  3 +import io.swagger.v3.oas.annotations.media.Schema;
3 4
  5 +@Schema(description = "流信息")
4 public class StreamInfo { 6 public class StreamInfo {
5 7
  8 + @Schema(description = "应用名")
6 private String app; 9 private String app;
  10 + @Schema(description = "流ID")
7 private String stream; 11 private String stream;
  12 + @Schema(description = "设备编号")
8 private String deviceID; 13 private String deviceID;
  14 + @Schema(description = "通道编号")
9 private String channelId; 15 private String channelId;
  16 + @Schema(description = "HTTP-FLV流地址")
10 private String flv; 17 private String flv;
11 18
  19 + @Schema(description = "IP")
12 private String ip; 20 private String ip;
13 - 21 + @Schema(description = "HTTPS-FLV流地址")
14 private String https_flv; 22 private String https_flv;
  23 + @Schema(description = "Websocket-FLV流地址")
15 private String ws_flv; 24 private String ws_flv;
  25 + @Schema(description = "Websockets-FLV流地址")
16 private String wss_flv; 26 private String wss_flv;
  27 + @Schema(description = "HTTP-FMP4流地址")
17 private String fmp4; 28 private String fmp4;
  29 + @Schema(description = "HTTPS-FMP4流地址")
18 private String https_fmp4; 30 private String https_fmp4;
  31 + @Schema(description = "Websocket-FMP4流地址")
19 private String ws_fmp4; 32 private String ws_fmp4;
  33 + @Schema(description = "Websockets-FMP4流地址")
20 private String wss_fmp4; 34 private String wss_fmp4;
  35 + @Schema(description = "HLS流地址")
21 private String hls; 36 private String hls;
  37 + @Schema(description = "HTTPS-HLS流地址")
22 private String https_hls; 38 private String https_hls;
  39 + @Schema(description = "Websocket-HLS流地址")
23 private String ws_hls; 40 private String ws_hls;
  41 + @Schema(description = "Websockets-HLS流地址")
24 private String wss_hls; 42 private String wss_hls;
  43 + @Schema(description = "HTTP-TS流地址")
25 private String ts; 44 private String ts;
  45 + @Schema(description = "HTTPS-TS流地址")
26 private String https_ts; 46 private String https_ts;
  47 + @Schema(description = "Websocket-TS流地址")
27 private String ws_ts; 48 private String ws_ts;
  49 + @Schema(description = "Websockets-TS流地址")
28 private String wss_ts; 50 private String wss_ts;
  51 + @Schema(description = "RTMP流地址")
29 private String rtmp; 52 private String rtmp;
  53 + @Schema(description = "RTMPS流地址")
30 private String rtmps; 54 private String rtmps;
  55 + @Schema(description = "RTSP流地址")
31 private String rtsp; 56 private String rtsp;
  57 + @Schema(description = "RTSPS流地址")
32 private String rtsps; 58 private String rtsps;
  59 + @Schema(description = "RTC流地址")
33 private String rtc; 60 private String rtc;
34 61
  62 + @Schema(description = "RTCS流地址")
35 private String rtcs; 63 private String rtcs;
  64 + @Schema(description = "流媒体ID")
36 private String mediaServerId; 65 private String mediaServerId;
  66 + @Schema(description = "流编码信息")
37 private Object tracks; 67 private Object tracks;
  68 + @Schema(description = "开始时间")
38 private String startTime; 69 private String startTime;
  70 + @Schema(description = "结束时间")
39 private String endTime; 71 private String endTime;
  72 + @Schema(description = "进度(录像下载使用)")
40 private double progress; 73 private double progress;
41 74
  75 + @Schema(description = "是否暂停(录像回放使用)")
42 private boolean pause; 76 private boolean pause;
43 77
44 public static class TransactionInfo{ 78 public static class TransactionInfo{
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
@@ -69,9 +69,6 @@ public class MediaConfig{ @@ -69,9 +69,6 @@ public class MediaConfig{
69 @Value("${media.secret}") 69 @Value("${media.secret}")
70 private String secret; 70 private String secret;
71 71
72 - @Value("${media.stream-none-reader-delay-ms:15000}")  
73 - private int streamNoneReaderDelayMS = 15000;  
74 -  
75 @Value("${media.rtp.enable}") 72 @Value("${media.rtp.enable}")
76 private boolean rtpEnable; 73 private boolean rtpEnable;
77 74
@@ -151,10 +148,6 @@ public class MediaConfig{ @@ -151,10 +148,6 @@ public class MediaConfig{
151 return secret; 148 return secret;
152 } 149 }
153 150
154 - public int getStreamNoneReaderDelayMS() {  
155 - return streamNoneReaderDelayMS;  
156 - }  
157 -  
158 public boolean isRtpEnable() { 151 public boolean isRtpEnable() {
159 return rtpEnable; 152 return rtpEnable;
160 } 153 }
@@ -219,7 +212,6 @@ public class MediaConfig{ @@ -219,7 +212,6 @@ public class MediaConfig{
219 mediaServerItem.setRtspSSLPort(rtspSSLPort); 212 mediaServerItem.setRtspSSLPort(rtspSSLPort);
220 mediaServerItem.setAutoConfig(autoConfig); 213 mediaServerItem.setAutoConfig(autoConfig);
221 mediaServerItem.setSecret(secret); 214 mediaServerItem.setSecret(secret);
222 - mediaServerItem.setStreamNoneReaderDelayMS(streamNoneReaderDelayMS);  
223 mediaServerItem.setRtpEnable(rtpEnable); 215 mediaServerItem.setRtpEnable(rtpEnable);
224 mediaServerItem.setRtpPortRange(rtpPortRange); 216 mediaServerItem.setRtpPortRange(rtpPortRange);
225 mediaServerItem.setSendRtpPortRange(sendRtpPortRange); 217 mediaServerItem.setSendRtpPortRange(sendRtpPortRange);
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -33,6 +33,8 @@ public class UserSetting { @@ -33,6 +33,8 @@ public class UserSetting {
33 33
34 private Boolean usePushingAsStatus = Boolean.TRUE; 34 private Boolean usePushingAsStatus = Boolean.TRUE;
35 35
  36 + private Boolean streamOnDemand = Boolean.TRUE;
  37 +
36 private String serverId = "000000"; 38 private String serverId = "000000";
37 39
38 private String thirdPartyGBIdReg = "[\\s\\S]*"; 40 private String thirdPartyGBIdReg = "[\\s\\S]*";
@@ -146,4 +148,12 @@ public class UserSetting { @@ -146,4 +148,12 @@ public class UserSetting {
146 public void setUsePushingAsStatus(Boolean usePushingAsStatus) { 148 public void setUsePushingAsStatus(Boolean usePushingAsStatus) {
147 this.usePushingAsStatus = usePushingAsStatus; 149 this.usePushingAsStatus = usePushingAsStatus;
148 } 150 }
  151 +
  152 + public Boolean getStreamOnDemand() {
  153 + return streamOnDemand;
  154 + }
  155 +
  156 + public void setStreamOnDemand(Boolean streamOnDemand) {
  157 + this.streamOnDemand = streamOnDemand;
  158 + }
149 } 159 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -162,7 +162,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -162,7 +162,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
162 if (requesterId == null) { 162 if (requesterId == null) {
163 logger.info("无法从FromHeader的Address中获取到平台/设备id,返回400"); 163 logger.info("无法从FromHeader的Address中获取到平台/设备id,返回400");
164 // 参数不全, 发400,请求错误 164 // 参数不全, 发400,请求错误
165 - responseAck(serverTransaction, Response.BAD_REQUEST); 165 + try {
  166 + responseAck(serverTransaction, Response.BAD_REQUEST);
  167 + } catch (SipException | InvalidArgumentException | ParseException e) {
  168 + logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage());
  169 + }
166 return; 170 return;
167 } 171 }
168 String ssrc = null; 172 String ssrc = null;
@@ -209,7 +213,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -209,7 +213,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
209 // return; 213 // return;
210 // } 214 // }
211 // 通道存在,发100,TRYING 215 // 通道存在,发100,TRYING
212 - responseAck(serverTransaction, Response.TRYING); 216 + try {
  217 + responseAck(serverTransaction, Response.TRYING);
  218 + } catch (SipException | InvalidArgumentException | ParseException e) {
  219 + logger.error("[命令发送失败] invite TRYING: {}", e.getMessage());
  220 + }
213 } else if (channel == null && gbStream != null) { 221 } else if (channel == null && gbStream != null) {
214 222
215 String mediaServerId = gbStream.getMediaServerId(); 223 String mediaServerId = gbStream.getMediaServerId();
@@ -217,13 +225,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -217,13 +225,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
217 if (mediaServerItem == null) { 225 if (mediaServerItem == null) {
218 if ("proxy".equals(gbStream.getStreamType())) { 226 if ("proxy".equals(gbStream.getStreamType())) {
219 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId); 227 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId);
220 - responseAck(serverTransaction, Response.GONE); 228 + try {
  229 + responseAck(serverTransaction, Response.GONE);
  230 + } catch (SipException | InvalidArgumentException | ParseException e) {
  231 + logger.error("[命令发送失败] invite GONE: {}", e.getMessage());
  232 + }
221 return; 233 return;
222 } else { 234 } else {
223 streamPushItem = streamPushService.getPush(gbStream.getApp(), gbStream.getStream()); 235 streamPushItem = streamPushService.getPush(gbStream.getApp(), gbStream.getStream());
224 if (streamPushItem == null || streamPushItem.getServerId().equals(userSetting.getServerId())) { 236 if (streamPushItem == null || streamPushItem.getServerId().equals(userSetting.getServerId())) {
225 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId); 237 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId);
226 - responseAck(serverTransaction, Response.GONE); 238 + try {
  239 + responseAck(serverTransaction, Response.GONE);
  240 + } catch (SipException | InvalidArgumentException | ParseException e) {
  241 + logger.error("[命令发送失败] invite GONE: {}", e.getMessage());
  242 + }
227 return; 243 return;
228 } 244 }
229 } 245 }
@@ -232,25 +248,47 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -232,25 +248,47 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
232 streamPushItem = streamPushService.getPush(gbStream.getApp(), gbStream.getStream()); 248 streamPushItem = streamPushService.getPush(gbStream.getApp(), gbStream.getStream());
233 if (streamPushItem == null) { 249 if (streamPushItem == null) {
234 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId); 250 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId);
235 - responseAck(serverTransaction, Response.GONE); 251 + try {
  252 + responseAck(serverTransaction, Response.GONE);
  253 + } catch (SipException | InvalidArgumentException | ParseException e) {
  254 + logger.error("[命令发送失败] invite GONE: {}", e.getMessage());
  255 + }
236 return; 256 return;
237 } 257 }
238 }else if("proxy".equals(gbStream.getStreamType())){ 258 }else if("proxy".equals(gbStream.getStreamType())){
239 proxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(gbStream.getApp(), gbStream.getStream()); 259 proxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(gbStream.getApp(), gbStream.getStream());
240 if (proxyByAppAndStream == null) { 260 if (proxyByAppAndStream == null) {
241 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId); 261 logger.info("[ app={}, stream={} ]找不到zlm {},返回410", gbStream.getApp(), gbStream.getStream(), mediaServerId);
242 - responseAck(serverTransaction, Response.GONE); 262 + try {
  263 + responseAck(serverTransaction, Response.GONE);
  264 + } catch (SipException | InvalidArgumentException | ParseException e) {
  265 + logger.error("[命令发送失败] invite GONE: {}", e.getMessage());
  266 + }
243 return; 267 return;
244 } 268 }
245 } 269 }
246 } 270 }
247 - responseAck(serverTransaction, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 271 + try {
  272 + responseAck(serverTransaction, Response.CALL_IS_BEING_FORWARDED);
  273 + } catch (SipException | InvalidArgumentException | ParseException e) {
  274 + logger.error("[命令发送失败] invite CALL_IS_BEING_FORWARDED: {}", e.getMessage());
  275 + }
248 } else if (catalog != null) { 276 } else if (catalog != null) {
249 - responseAck(serverTransaction, Response.BAD_REQUEST, "catalog channel can not play"); // 目录不支持点播 277 + try {
  278 + // 目录不支持点播
  279 + responseAck(serverTransaction, Response.BAD_REQUEST, "catalog channel can not play");
  280 + } catch (SipException | InvalidArgumentException | ParseException e) {
  281 + logger.error("[命令发送失败] invite 目录不支持点播: {}", e.getMessage());
  282 + }
250 return; 283 return;
251 } else { 284 } else {
252 logger.info("通道不存在,返回404"); 285 logger.info("通道不存在,返回404");
253 - responseAck(serverTransaction, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 286 + try {
  287 + // 通道不存在,发404,资源不存在
  288 + responseAck(serverTransaction, Response.NOT_FOUND);
  289 + } catch (SipException | InvalidArgumentException | ParseException e) {
  290 + logger.error("[命令发送失败] invite 通道不存在: {}", e.getMessage());
  291 + }
254 return; 292 return;
255 } 293 }
256 if (sdp == null || ssrc == null) { 294 if (sdp == null || ssrc == null) {
@@ -320,7 +358,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -320,7 +358,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
320 if (port == -1) { 358 if (port == -1) {
321 logger.info("不支持的媒体格式,返回415"); 359 logger.info("不支持的媒体格式,返回415");
322 // 回复不支持的格式 360 // 回复不支持的格式
323 - responseAck(serverTransaction, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415 361 + try {
  362 + // 不支持的格式,发415
  363 + responseAck(serverTransaction, Response.UNSUPPORTED_MEDIA_TYPE);
  364 + } catch (SipException | InvalidArgumentException | ParseException e) {
  365 + logger.error("[命令发送失败] invite 不支持的格式: {}", e.getMessage());
  366 + }
324 return; 367 return;
325 } 368 }
326 String username = sdp.getOrigin().getUsername(); 369 String username = sdp.getOrigin().getUsername();
@@ -333,13 +376,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -333,13 +376,21 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
333 device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId); 376 device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId);
334 if (device == null) { 377 if (device == null) {
335 logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel); 378 logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel);
336 - responseAck(serverTransaction, Response.SERVER_INTERNAL_ERROR); 379 + try {
  380 + responseAck(serverTransaction, Response.SERVER_INTERNAL_ERROR);
  381 + } catch (SipException | InvalidArgumentException | ParseException e) {
  382 + logger.error("[命令发送失败] invite 未找到设备信息: {}", e.getMessage());
  383 + }
337 return; 384 return;
338 } 385 }
339 mediaServerItem = playService.getNewMediaServerItem(device); 386 mediaServerItem = playService.getNewMediaServerItem(device);
340 if (mediaServerItem == null) { 387 if (mediaServerItem == null) {
341 logger.warn("未找到可用的zlm"); 388 logger.warn("未找到可用的zlm");
342 - responseAck(serverTransaction, Response.BUSY_HERE); 389 + try {
  390 + responseAck(serverTransaction, Response.BUSY_HERE);
  391 + } catch (SipException | InvalidArgumentException | ParseException e) {
  392 + logger.error("[命令发送失败] invite BUSY_HERE: {}", e.getMessage());
  393 + }
343 return; 394 return;
344 } 395 }
345 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId, 396 SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
@@ -351,7 +402,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -351,7 +402,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
351 } 402 }
352 if (sendRtpItem == null) { 403 if (sendRtpItem == null) {
353 logger.warn("服务器端口资源不足"); 404 logger.warn("服务器端口资源不足");
354 - responseAck(serverTransaction, Response.BUSY_HERE); 405 + try {
  406 + responseAck(serverTransaction, Response.BUSY_HERE);
  407 + } catch (SipException | InvalidArgumentException | ParseException e) {
  408 + logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
  409 + }
355 return; 410 return;
356 } 411 }
357 sendRtpItem.setCallId(callIdHeader.getCallId()); 412 sendRtpItem.setCallId(callIdHeader.getCallId());
@@ -526,13 +581,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -526,13 +581,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
526 } 581 }
527 } 582 }
528 } 583 }
529 -  
530 - } catch (SipException | InvalidArgumentException | ParseException e) {  
531 - e.printStackTrace();  
532 - logger.warn("sdp解析错误");  
533 - e.printStackTrace();  
534 } catch (SdpParseException e) { 584 } catch (SdpParseException e) {
535 - e.printStackTrace(); 585 + logger.error("sdp解析错误", e);
536 } catch (SdpException e) { 586 } catch (SdpException e) {
537 e.printStackTrace(); 587 e.printStackTrace();
538 } 588 }
@@ -544,7 +594,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -544,7 +594,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
544 private void pushProxyStream(RequestEvent evt, ServerTransaction serverTransaction, GbStream gbStream, ParentPlatform platform, 594 private void pushProxyStream(RequestEvent evt, ServerTransaction serverTransaction, GbStream gbStream, ParentPlatform platform,
545 CallIdHeader callIdHeader, MediaServerItem mediaServerItem, 595 CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
546 int port, Boolean tcpActive, boolean mediaTransmissionTCP, 596 int port, Boolean tcpActive, boolean mediaTransmissionTCP,
547 - String channelId, String addressStr, String ssrc, String requesterId) throws InvalidArgumentException, ParseException, SipException { 597 + String channelId, String addressStr, String ssrc, String requesterId) {
548 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); 598 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
549 if (streamReady) { 599 if (streamReady) {
550 // 自平台内容 600 // 自平台内容
@@ -554,7 +604,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -554,7 +604,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
554 604
555 if (sendRtpItem == null) { 605 if (sendRtpItem == null) {
556 logger.warn("服务器端口资源不足"); 606 logger.warn("服务器端口资源不足");
557 - responseAck(serverTransaction, Response.BUSY_HERE); 607 + try {
  608 + responseAck(serverTransaction, Response.BUSY_HERE);
  609 + } catch (SipException | InvalidArgumentException | ParseException e) {
  610 + logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
  611 + }
558 return; 612 return;
559 } 613 }
560 if (tcpActive != null) { 614 if (tcpActive != null) {
@@ -579,7 +633,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -579,7 +633,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
579 private void pushStream(RequestEvent evt, ServerTransaction serverTransaction, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform, 633 private void pushStream(RequestEvent evt, ServerTransaction serverTransaction, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
580 CallIdHeader callIdHeader, MediaServerItem mediaServerItem, 634 CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
581 int port, Boolean tcpActive, boolean mediaTransmissionTCP, 635 int port, Boolean tcpActive, boolean mediaTransmissionTCP,
582 - String channelId, String addressStr, String ssrc, String requesterId) throws InvalidArgumentException, ParseException, SipException { 636 + String channelId, String addressStr, String ssrc, String requesterId) {
583 // 推流 637 // 推流
584 if (streamPushItem.isSelf()) { 638 if (streamPushItem.isSelf()) {
585 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream()); 639 Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
@@ -591,7 +645,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -591,7 +645,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
591 645
592 if (sendRtpItem == null) { 646 if (sendRtpItem == null) {
593 logger.warn("服务器端口资源不足"); 647 logger.warn("服务器端口资源不足");
594 - responseAck(serverTransaction, Response.BUSY_HERE); 648 + try {
  649 + responseAck(serverTransaction, Response.BUSY_HERE);
  650 + } catch (SipException | InvalidArgumentException | ParseException e) {
  651 + logger.error("[命令发送失败] invite 服务器端口资源不足: {}", e.getMessage());
  652 + }
595 return; 653 return;
596 } 654 }
597 if (tcpActive != null) { 655 if (tcpActive != null) {
@@ -629,15 +687,23 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -629,15 +687,23 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
629 private void notifyStreamOnline(RequestEvent evt, ServerTransaction serverTransaction, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform, 687 private void notifyStreamOnline(RequestEvent evt, ServerTransaction serverTransaction, GbStream gbStream, StreamPushItem streamPushItem, ParentPlatform platform,
630 CallIdHeader callIdHeader, MediaServerItem mediaServerItem, 688 CallIdHeader callIdHeader, MediaServerItem mediaServerItem,
631 int port, Boolean tcpActive, boolean mediaTransmissionTCP, 689 int port, Boolean tcpActive, boolean mediaTransmissionTCP,
632 - String channelId, String addressStr, String ssrc, String requesterId) throws InvalidArgumentException, ParseException, SipException { 690 + String channelId, String addressStr, String ssrc, String requesterId) {
633 if ("proxy".equals(gbStream.getStreamType())) { 691 if ("proxy".equals(gbStream.getStreamType())) {
634 // TODO 控制启用以使设备上线 692 // TODO 控制启用以使设备上线
635 logger.info("[ app={}, stream={} ]通道未推流,启用流后开始推流", gbStream.getApp(), gbStream.getStream()); 693 logger.info("[ app={}, stream={} ]通道未推流,启用流后开始推流", gbStream.getApp(), gbStream.getStream());
636 - responseAck(serverTransaction, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline"); 694 + try {
  695 + responseAck(serverTransaction, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
  696 + } catch (SipException | InvalidArgumentException | ParseException e) {
  697 + logger.error("[命令发送失败] invite 通道未推流: {}", e.getMessage());
  698 + }
637 } else if ("push".equals(gbStream.getStreamType())) { 699 } else if ("push".equals(gbStream.getStreamType())) {
638 if (!platform.isStartOfflinePush()) { 700 if (!platform.isStartOfflinePush()) {
639 // 平台设置中关闭了拉起离线的推流则直接回复 701 // 平台设置中关闭了拉起离线的推流则直接回复
640 - responseAck(serverTransaction, Response.TEMPORARILY_UNAVAILABLE, "channel stream not pushing"); 702 + try {
  703 + responseAck(serverTransaction, Response.TEMPORARILY_UNAVAILABLE, "channel stream not pushing");
  704 + } catch (SipException | InvalidArgumentException | ParseException e) {
  705 + logger.error("[命令发送失败] invite 通道未推流: {}", e.getMessage());
  706 + }
641 return; 707 return;
642 } 708 }
643 // 发送redis消息以使设备上线 709 // 发送redis消息以使设备上线
@@ -765,38 +831,28 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -765,38 +831,28 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
765 } 831 }
766 redisCatchStorage.updateSendRTPSever(sendRtpItem); 832 redisCatchStorage.updateSendRTPSever(sendRtpItem);
767 }, (wvpResult) -> { 833 }, (wvpResult) -> {
768 - try {  
769 - // 错误  
770 - if (wvpResult.getCode() == RedisGbPlayMsgListener.ERROR_CODE_OFFLINE) {  
771 - // 离线  
772 - // 查询是否在本机上线了  
773 - StreamPushItem currentStreamPushItem = streamPushService.getPush(streamPushItem.getApp(), streamPushItem.getStream());  
774 - if (currentStreamPushItem.isPushIng()) {  
775 - // 在线状态  
776 - pushStream(evt, serverTransaction, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,  
777 - mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);  
778 834
779 - } else {  
780 - // 不在线 拉起  
781 - notifyStreamOnline(evt, serverTransaction, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,  
782 - mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);  
783 - } 835 + // 错误
  836 + if (wvpResult.getCode() == RedisGbPlayMsgListener.ERROR_CODE_OFFLINE) {
  837 + // 离线
  838 + // 查询是否在本机上线了
  839 + StreamPushItem currentStreamPushItem = streamPushService.getPush(streamPushItem.getApp(), streamPushItem.getStream());
  840 + if (currentStreamPushItem.isPushIng()) {
  841 + // 在线状态
  842 + pushStream(evt, serverTransaction, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
  843 + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
  844 +
  845 + } else {
  846 + // 不在线 拉起
  847 + notifyStreamOnline(evt, serverTransaction, gbStream, streamPushItem, platform, callIdHeader, mediaServerItem, port, tcpActive,
  848 + mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
784 } 849 }
785 - } catch (InvalidArgumentException | ParseException | SipException e) {  
786 - logger.error("[命令发送失败] 国标级联 点播回复: {}", e.getMessage());  
787 } 850 }
788 -  
789 -  
790 try { 851 try {
791 responseAck(serverTransaction, Response.BUSY_HERE); 852 responseAck(serverTransaction, Response.BUSY_HERE);
792 - } catch (SipException e) {  
793 - e.printStackTrace();  
794 - } catch (InvalidArgumentException e) {  
795 - e.printStackTrace();  
796 - } catch (ParseException e) {  
797 - e.printStackTrace(); 853 + } catch (InvalidArgumentException | ParseException | SipException e) {
  854 + logger.error("[命令发送失败] 国标级联 点播回复 BUSY_HERE: {}", e.getMessage());
798 } 855 }
799 - return;  
800 }); 856 });
801 } 857 }
802 858
@@ -834,7 +890,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -834,7 +890,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
834 return null; 890 return null;
835 } 891 }
836 892
837 - public void inviteFromDeviceHandle(ServerTransaction serverTransaction, String requesterId, String channelId) throws InvalidArgumentException, ParseException, SipException, SdpException { 893 + public void inviteFromDeviceHandle(ServerTransaction serverTransaction, String requesterId, String channelId) {
838 // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备) 894 // 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
839 Device device = redisCatchStorage.getDevice(requesterId); 895 Device device = redisCatchStorage.getDevice(requesterId);
840 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(requesterId, channelId); 896 AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(requesterId, channelId);
@@ -846,8 +902,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -846,8 +902,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
846 Request request = serverTransaction.getRequest(); 902 Request request = serverTransaction.getRequest();
847 if (device != null) { 903 if (device != null) {
848 logger.info("收到设备" + requesterId + "的语音广播Invite请求"); 904 logger.info("收到设备" + requesterId + "的语音广播Invite请求");
849 - responseAck(serverTransaction, Response.TRYING);  
850 - 905 + try {
  906 + responseAck(serverTransaction, Response.TRYING);
  907 + } catch (SipException | InvalidArgumentException | ParseException e) {
  908 + logger.error("[命令发送失败] invite BAD_REQUEST: {}", e.getMessage());
  909 + }
851 String contentString = new String(serverTransaction.getRequest().getRawContent()); 910 String contentString = new String(serverTransaction.getRequest().getRawContent());
852 // jainSip不支持y=字段, 移除移除以解析。 911 // jainSip不支持y=字段, 移除移除以解析。
853 String substring = contentString; 912 String substring = contentString;
@@ -944,7 +1003,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -944,7 +1003,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
944 } 1003 }
945 } else { 1004 } else {
946 logger.warn("来自无效设备/平台的请求"); 1005 logger.warn("来自无效设备/平台的请求");
947 - responseAck(serverTransaction, Response.BAD_REQUEST); 1006 + try {
  1007 + responseAck(serverTransaction, Response.BAD_REQUEST);; // 不支持的格式,发415
  1008 + } catch (SipException | InvalidArgumentException | ParseException e) {
  1009 + logger.error("[命令发送失败] invite 来自无效设备/平台的请求, {}", e.getMessage());
  1010 + }
948 } 1011 }
949 } 1012 }
950 1013
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -93,46 +93,44 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -93,46 +93,44 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
93 93
94 @Override 94 @Override
95 public void process(RequestEvent evt) { 95 public void process(RequestEvent evt) {
  96 + ServerTransaction serverTransaction = getServerTransaction(evt);
96 try { 97 try {
97 - taskQueue.offer(new HandlerCatchData(evt, null, null));  
98 - ServerTransaction serverTransaction = getServerTransaction(evt);  
99 responseAck(serverTransaction, Response.OK); 98 responseAck(serverTransaction, Response.OK);
100 - if (!taskQueueHandlerRun) {  
101 - taskQueueHandlerRun = true;  
102 - taskExecutor.execute(()-> {  
103 - while (!taskQueue.isEmpty()) {  
104 - try {  
105 - HandlerCatchData take = taskQueue.poll();  
106 - Element rootElement = getRootElement(take.getEvt());  
107 - if (rootElement == null) {  
108 - logger.error("处理NOTIFY消息时未获取到消息体,{}", take.getEvt().getRequest());  
109 - continue;  
110 - }  
111 - String cmd = XmlUtil.getText(rootElement, "CmdType");  
112 -  
113 - if (CmdType.CATALOG.equals(cmd)) {  
114 - logger.info("接收到Catalog通知");  
115 - processNotifyCatalogList(take.getEvt());  
116 - } else if (CmdType.ALARM.equals(cmd)) {  
117 - logger.info("接收到Alarm通知");  
118 - processNotifyAlarm(take.getEvt());  
119 - } else if (CmdType.MOBILE_POSITION.equals(cmd)) {  
120 - logger.info("接收到MobilePosition通知");  
121 - processNotifyMobilePosition(take.getEvt());  
122 - } else {  
123 - logger.info("接收到消息:" + cmd);  
124 - }  
125 - } catch (DocumentException e) {  
126 - logger.error("处理NOTIFY消息时错误", e); 99 + }catch (SipException | InvalidArgumentException | ParseException e) {
  100 + e.printStackTrace();
  101 + }
  102 + taskQueue.offer(new HandlerCatchData(evt, null, null));
  103 + if (!taskQueueHandlerRun) {
  104 + taskQueueHandlerRun = true;
  105 + taskExecutor.execute(()-> {
  106 + while (!taskQueue.isEmpty()) {
  107 + try {
  108 + HandlerCatchData take = taskQueue.poll();
  109 + Element rootElement = getRootElement(take.getEvt());
  110 + if (rootElement == null) {
  111 + logger.error("处理NOTIFY消息时未获取到消息体,{}", take.getEvt().getRequest());
  112 + continue;
  113 + }
  114 + String cmd = XmlUtil.getText(rootElement, "CmdType");
  115 +
  116 + if (CmdType.CATALOG.equals(cmd)) {
  117 + logger.info("接收到Catalog通知");
  118 + processNotifyCatalogList(take.getEvt());
  119 + } else if (CmdType.ALARM.equals(cmd)) {
  120 + logger.info("接收到Alarm通知");
  121 + processNotifyAlarm(take.getEvt());
  122 + } else if (CmdType.MOBILE_POSITION.equals(cmd)) {
  123 + logger.info("接收到MobilePosition通知");
  124 + processNotifyMobilePosition(take.getEvt());
  125 + } else {
  126 + logger.info("接收到消息:" + cmd);
127 } 127 }
  128 + } catch (DocumentException e) {
  129 + logger.error("处理NOTIFY消息时错误", e);
128 } 130 }
129 - taskQueueHandlerRun = false;  
130 - });  
131 - }  
132 - } catch (SipException | InvalidArgumentException | ParseException e) {  
133 - e.printStackTrace();  
134 - } finally {  
135 - taskQueueHandlerRun = false; 131 + }
  132 + taskQueueHandlerRun = false;
  133 + });
136 } 134 }
137 } 135 }
138 136
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
@@ -112,10 +112,10 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent @@ -112,10 +112,10 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
112 if (deviceForPlatform == null) { 112 if (deviceForPlatform == null) {
113 try { 113 try {
114 responseAck(serverTransaction, Response.NOT_FOUND); 114 responseAck(serverTransaction, Response.NOT_FOUND);
115 - return;  
116 } catch (SipException | InvalidArgumentException | ParseException e) { 115 } catch (SipException | InvalidArgumentException | ParseException e) {
117 logger.error("[命令发送失败] 错误信息: {}", e.getMessage()); 116 logger.error("[命令发送失败] 错误信息: {}", e.getMessage());
118 } 117 }
  118 + return;
119 } 119 }
120 try { 120 try {
121 cmder.fronEndCmd(deviceForPlatform, channelId, cmdString, eventResult -> { 121 cmder.fronEndCmd(deviceForPlatform, channelId, cmdString, eventResult -> {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -52,35 +52,36 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp @@ -52,35 +52,36 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
52 // 未注册的设备不做处理 52 // 未注册的设备不做处理
53 return; 53 return;
54 } 54 }
  55 + // 回复200 OK
55 try { 56 try {
56 - // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息  
57 - // 获取到通信地址等信息  
58 - ViaHeader viaHeader = (ViaHeader) evt.getRequest().getHeader(ViaHeader.NAME);  
59 - String received = viaHeader.getReceived();  
60 - int rPort = viaHeader.getRPort();  
61 - // 解析本地地址替代  
62 - if (ObjectUtils.isEmpty(received) || rPort == -1) {  
63 - received = viaHeader.getHost();  
64 - rPort = viaHeader.getPort();  
65 - }  
66 - if (device.getPort() != rPort) {  
67 - device.setPort(rPort);  
68 - device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));  
69 - }  
70 - device.setKeepaliveTime(DateUtil.getNow());  
71 - // 回复200 OK  
72 responseAck(getServerTransaction(evt), Response.OK); 57 responseAck(getServerTransaction(evt), Response.OK);
73 - if (device.getOnline() == 1) {  
74 - deviceService.updateDevice(device);  
75 - }else {  
76 - // 对于已经离线的设备判断他的注册是否已经过期  
77 - if (!deviceService.expire(device)){  
78 - deviceService.online(device);  
79 - }  
80 - }  
81 } catch (SipException | InvalidArgumentException | ParseException e) { 58 } catch (SipException | InvalidArgumentException | ParseException e) {
82 logger.error("[命令发送失败] 国标级联 心跳回复: {}", e.getMessage()); 59 logger.error("[命令发送失败] 国标级联 心跳回复: {}", e.getMessage());
83 } 60 }
  61 + // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息
  62 + // 获取到通信地址等信息
  63 + ViaHeader viaHeader = (ViaHeader) evt.getRequest().getHeader(ViaHeader.NAME);
  64 + String received = viaHeader.getReceived();
  65 + int rPort = viaHeader.getRPort();
  66 + // 解析本地地址替代
  67 + if (ObjectUtils.isEmpty(received) || rPort == -1) {
  68 + received = viaHeader.getHost();
  69 + rPort = viaHeader.getPort();
  70 + }
  71 + if (device.getPort() != rPort) {
  72 + device.setPort(rPort);
  73 + device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
  74 + }
  75 + device.setKeepaliveTime(DateUtil.getNow());
  76 +
  77 + if (device.getOnline() == 1) {
  78 + deviceService.updateDevice(device);
  79 + }else {
  80 + // 对于已经离线的设备判断他的注册是否已经过期
  81 + if (!deviceService.expire(device)){
  82 + deviceService.online(device);
  83 + }
  84 + }
84 } 85 }
85 86
86 @Override 87 @Override
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
@@ -81,8 +81,12 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen @@ -81,8 +81,12 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
81 try { 81 try {
82 Element rootElementAfterCharset = getRootElement(sipMsgInfo.getEvt(), sipMsgInfo.getDevice().getCharset()); 82 Element rootElementAfterCharset = getRootElement(sipMsgInfo.getEvt(), sipMsgInfo.getDevice().getCharset());
83 if (rootElementAfterCharset == null) { 83 if (rootElementAfterCharset == null) {
84 - logger.warn("[ 移动设备位置数据通知 ] content cannot be null, {}", sipMsgInfo.getEvt().getRequest());  
85 - responseAck(getServerTransaction(sipMsgInfo.getEvt()), Response.BAD_REQUEST); 84 + try {
  85 + logger.warn("[ 移动设备位置数据通知 ] content cannot be null, {}", sipMsgInfo.getEvt().getRequest());
  86 + responseAck(getServerTransaction(sipMsgInfo.getEvt()), Response.BAD_REQUEST);
  87 + } catch (SipException | InvalidArgumentException | ParseException e) {
  88 + logger.error("[命令发送失败] 移动设备位置数据通知 内容为空: {}", e.getMessage());
  89 + }
86 continue; 90 continue;
87 } 91 }
88 MobilePosition mobilePosition = new MobilePosition(); 92 MobilePosition mobilePosition = new MobilePosition();
@@ -133,7 +137,11 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen @@ -133,7 +137,11 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
133 } 137 }
134 storager.updateChannelPosition(deviceChannel); 138 storager.updateChannelPosition(deviceChannel);
135 //回复 200 OK 139 //回复 200 OK
136 - responseAck(getServerTransaction(sipMsgInfo.getEvt()), Response.OK); 140 + try {
  141 + responseAck(getServerTransaction(sipMsgInfo.getEvt()), Response.OK);
  142 + } catch (SipException | InvalidArgumentException | ParseException e) {
  143 + logger.error("[命令发送失败] 移动设备位置数据回复200: {}", e.getMessage());
  144 + }
137 145
138 // 发送redis消息。 通知位置信息的变化 146 // 发送redis消息。 通知位置信息的变化
139 JSONObject jsonObject = new JSONObject(); 147 JSONObject jsonObject = new JSONObject();
@@ -147,7 +155,7 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen @@ -147,7 +155,7 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
147 jsonObject.put("speed", mobilePosition.getSpeed()); 155 jsonObject.put("speed", mobilePosition.getSpeed());
148 redisCatchStorage.sendMobilePositionMsg(jsonObject); 156 redisCatchStorage.sendMobilePositionMsg(jsonObject);
149 157
150 - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { 158 + } catch (DocumentException e) {
151 e.printStackTrace(); 159 e.printStackTrace();
152 } 160 }
153 161
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
@@ -67,33 +67,37 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem @@ -67,33 +67,37 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
67 try { 67 try {
68 // 回复200 OK 68 // 回复200 OK
69 responseAck(getServerTransaction(evt), Response.OK); 69 responseAck(getServerTransaction(evt), Response.OK);
70 - Element snElement = rootElement.element("SN");  
71 - String sn = snElement.getText();  
72 - // 准备回复通道信息  
73 - List<DeviceChannel> deviceChannelInPlatforms = storager.queryChannelWithCatalog(parentPlatform.getServerGBId());  
74 - // 查询关联的直播通道  
75 - List<DeviceChannel> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());  
76 - // 回复目录信息  
77 - List<DeviceChannel> catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId());  
78 -  
79 - List<DeviceChannel> allChannels = new ArrayList<>();  
80 -  
81 - // 回复平台 70 + } catch (SipException | InvalidArgumentException | ParseException e) {
  71 + logger.error("[命令发送失败] 国标级联 目录查询回复200OK: {}", e.getMessage());
  72 + }
  73 + Element snElement = rootElement.element("SN");
  74 + String sn = snElement.getText();
  75 + // 准备回复通道信息
  76 + List<DeviceChannel> deviceChannelInPlatforms = storager.queryChannelWithCatalog(parentPlatform.getServerGBId());
  77 + // 查询关联的直播通道
  78 + List<DeviceChannel> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
  79 + // 回复目录信息
  80 + List<DeviceChannel> catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId());
  81 +
  82 + List<DeviceChannel> allChannels = new ArrayList<>();
  83 +
  84 + // 回复平台
82 // DeviceChannel deviceChannel = getChannelForPlatform(parentPlatform); 85 // DeviceChannel deviceChannel = getChannelForPlatform(parentPlatform);
83 // allChannels.add(deviceChannel); 86 // allChannels.add(deviceChannel);
84 87
85 - // 回复目录  
86 - if (catalogs.size() > 0) {  
87 - allChannels.addAll(catalogs);  
88 - }  
89 - // 回复级联的通道  
90 - if (deviceChannelInPlatforms.size() > 0) {  
91 - allChannels.addAll(deviceChannelInPlatforms);  
92 - }  
93 - // 回复直播的通道  
94 - if (gbStreams.size() > 0) {  
95 - allChannels.addAll(gbStreams);  
96 - } 88 + // 回复目录
  89 + if (catalogs.size() > 0) {
  90 + allChannels.addAll(catalogs);
  91 + }
  92 + // 回复级联的通道
  93 + if (deviceChannelInPlatforms.size() > 0) {
  94 + allChannels.addAll(deviceChannelInPlatforms);
  95 + }
  96 + // 回复直播的通道
  97 + if (gbStreams.size() > 0) {
  98 + allChannels.addAll(gbStreams);
  99 + }
  100 + try {
97 if (allChannels.size() > 0) { 101 if (allChannels.size() > 0) {
98 cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag()); 102 cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag());
99 }else { 103 }else {
@@ -101,9 +105,11 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem @@ -101,9 +105,11 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
101 cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), 0); 105 cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), 0);
102 } 106 }
103 } catch (SipException | InvalidArgumentException | ParseException e) { 107 } catch (SipException | InvalidArgumentException | ParseException e) {
104 - logger.error("[命令发送失败] 国标级联 目录查询: {}", e.getMessage()); 108 + logger.error("[命令发送失败] 国标级联 目录查询回复: {}", e.getMessage());
105 } 109 }
106 110
  111 +
  112 +
107 } 113 }
108 114
109 private DeviceChannel getChannelForPlatform(ParentPlatform platform) { 115 private DeviceChannel getChannelForPlatform(ParentPlatform platform) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java
@@ -53,19 +53,20 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar @@ -53,19 +53,20 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar
53 try { 53 try {
54 // 回复200 OK 54 // 回复200 OK
55 responseAck(getServerTransaction(evt), Response.OK); 55 responseAck(getServerTransaction(evt), Response.OK);
56 - // 此处是对本平台发出DeviceControl指令的应答  
57 - JSONObject json = new JSONObject();  
58 - XmlUtil.node2Json(element, json);  
59 - if (logger.isDebugEnabled()) {  
60 - logger.debug(json.toJSONString());  
61 - }  
62 - RequestMessage msg = new RequestMessage();  
63 - msg.setKey(key);  
64 - msg.setData(json);  
65 - deferredResultHolder.invokeAllResult(msg);  
66 } catch (SipException | InvalidArgumentException | ParseException e) { 56 } catch (SipException | InvalidArgumentException | ParseException e) {
67 - logger.error("[命令发送失败] 国标级联 设备配置查询: {}", e.getMessage()); 57 + logger.error("[命令发送失败] 设备配置查询: {}", e.getMessage());
68 } 58 }
  59 + // 此处是对本平台发出DeviceControl指令的应答
  60 + JSONObject json = new JSONObject();
  61 + XmlUtil.node2Json(element, json);
  62 + if (logger.isDebugEnabled()) {
  63 + logger.debug(json.toJSONString());
  64 + }
  65 + RequestMessage msg = new RequestMessage();
  66 + msg.setKey(key);
  67 + msg.setData(json);
  68 + deferredResultHolder.invokeAllResult(msg);
  69 +
69 70
70 } 71 }
71 72
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java
@@ -47,20 +47,21 @@ public class DeviceControlResponseMessageHandler extends SIPRequestProcessorPare @@ -47,20 +47,21 @@ public class DeviceControlResponseMessageHandler extends SIPRequestProcessorPare
47 // 此处是对本平台发出DeviceControl指令的应答 47 // 此处是对本平台发出DeviceControl指令的应答
48 try { 48 try {
49 responseAck(getServerTransaction(evt), Response.OK); 49 responseAck(getServerTransaction(evt), Response.OK);
50 - JSONObject json = new JSONObject();  
51 - String channelId = getText(element, "DeviceID");  
52 - XmlUtil.node2Json(element, json);  
53 - if (logger.isDebugEnabled()) {  
54 - logger.debug(json.toJSONString());  
55 - }  
56 - RequestMessage msg = new RequestMessage();  
57 - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + device.getDeviceId() + channelId;  
58 - msg.setKey(key);  
59 - msg.setData(json);  
60 - deferredResultHolder.invokeAllResult(msg);  
61 } catch (SipException | InvalidArgumentException | ParseException e) { 50 } catch (SipException | InvalidArgumentException | ParseException e) {
62 logger.error("[命令发送失败] 国标级联 设备控制: {}", e.getMessage()); 51 logger.error("[命令发送失败] 国标级联 设备控制: {}", e.getMessage());
63 } 52 }
  53 + JSONObject json = new JSONObject();
  54 + String channelId = getText(element, "DeviceID");
  55 + XmlUtil.node2Json(element, json);
  56 + if (logger.isDebugEnabled()) {
  57 + logger.debug(json.toJSONString());
  58 + }
  59 + RequestMessage msg = new RequestMessage();
  60 + String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + device.getDeviceId() + channelId;
  61 + msg.setKey(key);
  62 + msg.setData(json);
  63 + deferredResultHolder.invokeAllResult(msg);
  64 +
64 } 65 }
65 66
66 @Override 67 @Override
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
@@ -78,9 +78,14 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -78,9 +78,14 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent
78 ServerTransaction serverTransaction = getServerTransaction(evt); 78 ServerTransaction serverTransaction = getServerTransaction(evt);
79 try { 79 try {
80 rootElement = getRootElement(evt, device.getCharset()); 80 rootElement = getRootElement(evt, device.getCharset());
81 - if (rootElement == null) { 81 +
  82 + if (rootElement == null) {
82 logger.warn("[ 接收到DeviceInfo应答消息 ] content cannot be null, {}", evt.getRequest()); 83 logger.warn("[ 接收到DeviceInfo应答消息 ] content cannot be null, {}", evt.getRequest());
83 - responseAck(serverTransaction, Response.BAD_REQUEST); 84 + try {
  85 + responseAck(serverTransaction, Response.BAD_REQUEST);
  86 + } catch (SipException | InvalidArgumentException | ParseException e) {
  87 + logger.error("[命令发送失败] DeviceInfo应答消息 BAD_REQUEST: {}", e.getMessage());
  88 + }
84 return; 89 return;
85 } 90 }
86 Element deviceIdElement = rootElement.element("DeviceID"); 91 Element deviceIdElement = rootElement.element("DeviceID");
@@ -100,17 +105,16 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -100,17 +105,16 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent
100 msg.setKey(key); 105 msg.setKey(key);
101 msg.setData(device); 106 msg.setData(device);
102 deferredResultHolder.invokeAllResult(msg); 107 deferredResultHolder.invokeAllResult(msg);
  108 + } catch (DocumentException e) {
  109 + throw new RuntimeException(e);
  110 + }
  111 + try {
103 // 回复200 OK 112 // 回复200 OK
104 responseAck(serverTransaction, Response.OK); 113 responseAck(serverTransaction, Response.OK);
105 - } catch (DocumentException e) {  
106 - e.printStackTrace();  
107 - } catch (InvalidArgumentException e) {  
108 - e.printStackTrace();  
109 - } catch (ParseException e) {  
110 - e.printStackTrace();  
111 - } catch (SipException e) {  
112 - e.printStackTrace(); 114 + } catch (SipException | InvalidArgumentException | ParseException e) {
  115 + logger.error("[命令发送失败] DeviceInfo应答消息 200: {}", e.getMessage());
113 } 116 }
  117 +
114 } 118 }
115 119
116 @Override 120 @Override
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
@@ -71,7 +71,11 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar @@ -71,7 +71,11 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
71 rootElement = getRootElement(evt, device.getCharset()); 71 rootElement = getRootElement(evt, device.getCharset());
72 if (rootElement == null) { 72 if (rootElement == null) {
73 logger.warn("[ 移动设备位置数据查询回复 ] content cannot be null, {}", evt.getRequest()); 73 logger.warn("[ 移动设备位置数据查询回复 ] content cannot be null, {}", evt.getRequest());
74 - responseAck(serverTransaction, Response.BAD_REQUEST); 74 + try {
  75 + responseAck(serverTransaction, Response.BAD_REQUEST);
  76 + } catch (SipException | InvalidArgumentException | ParseException e) {
  77 + logger.error("[命令发送失败] 移动设备位置数据查询 BAD_REQUEST: {}", e.getMessage());
  78 + }
75 return; 79 return;
76 } 80 }
77 MobilePosition mobilePosition = new MobilePosition(); 81 MobilePosition mobilePosition = new MobilePosition();
@@ -133,8 +137,13 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar @@ -133,8 +137,13 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
133 jsonObject.put("speed", mobilePosition.getSpeed()); 137 jsonObject.put("speed", mobilePosition.getSpeed());
134 redisCatchStorage.sendMobilePositionMsg(jsonObject); 138 redisCatchStorage.sendMobilePositionMsg(jsonObject);
135 //回复 200 OK 139 //回复 200 OK
136 - responseAck(serverTransaction, Response.OK);  
137 - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { 140 + try {
  141 + responseAck(serverTransaction, Response.OK);
  142 + } catch (SipException | InvalidArgumentException | ParseException e) {
  143 + logger.error("[命令发送失败] 移动设备位置数据查询 200: {}", e.getMessage());
  144 + }
  145 +
  146 + } catch (DocumentException e) {
138 e.printStackTrace(); 147 e.printStackTrace();
139 } 148 }
140 } 149 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java
@@ -58,7 +58,11 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent @@ -58,7 +58,11 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent
58 58
59 if (rootElement == null) { 59 if (rootElement == null) {
60 logger.warn("[ 设备预置位查询应答 ] content cannot be null, {}", evt.getRequest()); 60 logger.warn("[ 设备预置位查询应答 ] content cannot be null, {}", evt.getRequest());
61 - responseAck(serverTransaction, Response.BAD_REQUEST); 61 + try {
  62 + responseAck(serverTransaction, Response.BAD_REQUEST);
  63 + } catch (InvalidArgumentException | ParseException | SipException e) {
  64 + logger.error("[命令发送失败] 设备预置位查询应答处理: {}", e.getMessage());
  65 + }
62 return; 66 return;
63 } 67 }
64 Element presetListNumElement = rootElement.element("PresetList"); 68 Element presetListNumElement = rootElement.element("PresetList");
@@ -67,7 +71,11 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent @@ -67,7 +71,11 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent
67 String deviceId = getText(rootElement, "DeviceID"); 71 String deviceId = getText(rootElement, "DeviceID");
68 String key = DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + deviceId; 72 String key = DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + deviceId;
69 if (snElement == null || presetListNumElement == null) { 73 if (snElement == null || presetListNumElement == null) {
70 - responseAck(serverTransaction, Response.BAD_REQUEST, "xml error"); 74 + try {
  75 + responseAck(serverTransaction, Response.BAD_REQUEST, "xml error");
  76 + } catch (InvalidArgumentException | ParseException | SipException e) {
  77 + logger.error("[命令发送失败] 设备预置位查询应答处理: {}", e.getMessage());
  78 + }
71 return; 79 return;
72 } 80 }
73 int sumNum = Integer.parseInt(presetListNumElement.attributeValue("Num")); 81 int sumNum = Integer.parseInt(presetListNumElement.attributeValue("Num"));
@@ -94,11 +102,13 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent @@ -94,11 +102,13 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent
94 requestMessage.setKey(key); 102 requestMessage.setKey(key);
95 requestMessage.setData(presetQuerySipReqList); 103 requestMessage.setData(presetQuerySipReqList);
96 deferredResultHolder.invokeAllResult(requestMessage); 104 deferredResultHolder.invokeAllResult(requestMessage);
97 - responseAck(serverTransaction, Response.OK); 105 + try {
  106 + responseAck(serverTransaction, Response.OK);
  107 + } catch (InvalidArgumentException | ParseException | SipException e) {
  108 + logger.error("[命令发送失败] 设备预置位查询应答处理: {}", e.getMessage());
  109 + }
98 } catch (DocumentException e) { 110 } catch (DocumentException e) {
99 logger.error("[解析xml]失败: ", e); 111 logger.error("[解析xml]失败: ", e);
100 - } catch (InvalidArgumentException | ParseException | SipException e) {  
101 - logger.error("[命令发送失败] 设备预置位查询应答处理: {}", e.getMessage());  
102 } 112 }
103 } 113 }
104 114
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
@@ -69,95 +69,91 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -69,95 +69,91 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
69 69
70 @Override 70 @Override
71 public void handForDevice(RequestEvent evt, Device device, Element rootElement) { 71 public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
72 -  
73 - // 回复200 OK  
74 try { 72 try {
  73 + // 回复200 OK
75 responseAck(getServerTransaction(evt), Response.OK); 74 responseAck(getServerTransaction(evt), Response.OK);
76 - taskQueue.offer(new HandlerCatchData(evt, device, rootElement));  
77 - if (!taskQueueHandlerRun) {  
78 - taskQueueHandlerRun = true;  
79 - taskExecutor.execute(()->{  
80 - while (!taskQueue.isEmpty()) {  
81 - try {  
82 - HandlerCatchData take = taskQueue.poll();  
83 - Element rootElementForCharset = getRootElement(take.getEvt(), take.getDevice().getCharset());  
84 - if (rootElement == null) {  
85 - logger.warn("[ 国标录像 ] content cannot be null, {}", evt.getRequest());  
86 - continue;  
87 - }  
88 - String sn = getText(rootElementForCharset, "SN");  
89 - String channelId = getText(rootElementForCharset, "DeviceID");  
90 - RecordInfo recordInfo = new RecordInfo();  
91 - recordInfo.setChannelId(channelId);  
92 - recordInfo.setDeviceId(take.getDevice().getDeviceId());  
93 - recordInfo.setSn(sn);  
94 - recordInfo.setName(getText(rootElementForCharset, "Name"));  
95 - String sumNumStr = getText(rootElementForCharset, "SumNum");  
96 - int sumNum = 0;  
97 - if (!ObjectUtils.isEmpty(sumNumStr)) {  
98 - sumNum = Integer.parseInt(sumNumStr);  
99 - }  
100 - recordInfo.setSumNum(sumNum);  
101 - Element recordListElement = rootElementForCharset.element("RecordList");  
102 - if (recordListElement == null || sumNum == 0) {  
103 - logger.info("无录像数据");  
104 - eventPublisher.recordEndEventPush(recordInfo);  
105 - recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, new ArrayList<>());  
106 - releaseRequest(take.getDevice().getDeviceId(), sn);  
107 - } else {  
108 - Iterator<Element> recordListIterator = recordListElement.elementIterator();  
109 - if (recordListIterator != null) {  
110 - List<RecordItem> recordList = new ArrayList<>();  
111 - // 遍历DeviceList  
112 - while (recordListIterator.hasNext()) {  
113 - Element itemRecord = recordListIterator.next();  
114 - Element recordElement = itemRecord.element("DeviceID");  
115 - if (recordElement == null) {  
116 - logger.info("记录为空,下一个...");  
117 - continue;  
118 - }  
119 - RecordItem record = new RecordItem();  
120 - record.setDeviceId(getText(itemRecord, "DeviceID"));  
121 - record.setName(getText(itemRecord, "Name"));  
122 - record.setFilePath(getText(itemRecord, "FilePath"));  
123 - record.setFileSize(getText(itemRecord, "FileSize"));  
124 - record.setAddress(getText(itemRecord, "Address"));  
125 -  
126 - String startTimeStr = getText(itemRecord, "StartTime");  
127 - record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr));  
128 -  
129 - String endTimeStr = getText(itemRecord, "EndTime");  
130 - record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr));  
131 -  
132 - record.setSecrecy(itemRecord.element("Secrecy") == null ? 0  
133 - : Integer.parseInt(getText(itemRecord, "Secrecy")));  
134 - record.setType(getText(itemRecord, "Type"));  
135 - record.setRecorderId(getText(itemRecord, "RecorderID"));  
136 - recordList.add(record); 75 + }catch (SipException | InvalidArgumentException | ParseException e) {
  76 + logger.error("[命令发送失败] 国标级联 国标录像: {}", e.getMessage());
  77 + }
  78 + taskQueue.offer(new HandlerCatchData(evt, device, rootElement));
  79 + if (!taskQueueHandlerRun) {
  80 + taskQueueHandlerRun = true;
  81 + taskExecutor.execute(()->{
  82 + while (!taskQueue.isEmpty()) {
  83 + try {
  84 + HandlerCatchData take = taskQueue.poll();
  85 + Element rootElementForCharset = getRootElement(take.getEvt(), take.getDevice().getCharset());
  86 + if (rootElement == null) {
  87 + logger.warn("[ 国标录像 ] content cannot be null, {}", evt.getRequest());
  88 + continue;
  89 + }
  90 + String sn = getText(rootElementForCharset, "SN");
  91 + String channelId = getText(rootElementForCharset, "DeviceID");
  92 + RecordInfo recordInfo = new RecordInfo();
  93 + recordInfo.setChannelId(channelId);
  94 + recordInfo.setDeviceId(take.getDevice().getDeviceId());
  95 + recordInfo.setSn(sn);
  96 + recordInfo.setName(getText(rootElementForCharset, "Name"));
  97 + String sumNumStr = getText(rootElementForCharset, "SumNum");
  98 + int sumNum = 0;
  99 + if (!ObjectUtils.isEmpty(sumNumStr)) {
  100 + sumNum = Integer.parseInt(sumNumStr);
  101 + }
  102 + recordInfo.setSumNum(sumNum);
  103 + Element recordListElement = rootElementForCharset.element("RecordList");
  104 + if (recordListElement == null || sumNum == 0) {
  105 + logger.info("无录像数据");
  106 + eventPublisher.recordEndEventPush(recordInfo);
  107 + recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, new ArrayList<>());
  108 + releaseRequest(take.getDevice().getDeviceId(), sn);
  109 + } else {
  110 + Iterator<Element> recordListIterator = recordListElement.elementIterator();
  111 + if (recordListIterator != null) {
  112 + List<RecordItem> recordList = new ArrayList<>();
  113 + // 遍历DeviceList
  114 + while (recordListIterator.hasNext()) {
  115 + Element itemRecord = recordListIterator.next();
  116 + Element recordElement = itemRecord.element("DeviceID");
  117 + if (recordElement == null) {
  118 + logger.info("记录为空,下一个...");
  119 + continue;
137 } 120 }
138 - recordInfo.setRecordList(recordList);  
139 - // 发送消息,如果是上级查询此录像,则会通过这里通知给上级  
140 - eventPublisher.recordEndEventPush(recordInfo);  
141 - int count = recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, recordList);  
142 - logger.info("[国标录像], {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum); 121 + RecordItem record = new RecordItem();
  122 + record.setDeviceId(getText(itemRecord, "DeviceID"));
  123 + record.setName(getText(itemRecord, "Name"));
  124 + record.setFilePath(getText(itemRecord, "FilePath"));
  125 + record.setFileSize(getText(itemRecord, "FileSize"));
  126 + record.setAddress(getText(itemRecord, "Address"));
  127 +
  128 + String startTimeStr = getText(itemRecord, "StartTime");
  129 + record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr));
  130 +
  131 + String endTimeStr = getText(itemRecord, "EndTime");
  132 + record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr));
  133 +
  134 + record.setSecrecy(itemRecord.element("Secrecy") == null ? 0
  135 + : Integer.parseInt(getText(itemRecord, "Secrecy")));
  136 + record.setType(getText(itemRecord, "Type"));
  137 + record.setRecorderId(getText(itemRecord, "RecorderID"));
  138 + recordList.add(record);
143 } 139 }
  140 + recordInfo.setRecordList(recordList);
  141 + // 发送消息,如果是上级查询此录像,则会通过这里通知给上级
  142 + eventPublisher.recordEndEventPush(recordInfo);
  143 + int count = recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, recordList);
  144 + logger.info("[国标录像], {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum);
  145 + }
144 146
145 - if (recordDataCatch.isComplete(take.getDevice().getDeviceId(), sn)){  
146 - releaseRequest(take.getDevice().getDeviceId(), sn);  
147 - } 147 + if (recordDataCatch.isComplete(take.getDevice().getDeviceId(), sn)){
  148 + releaseRequest(take.getDevice().getDeviceId(), sn);
148 } 149 }
149 - } catch (DocumentException e) {  
150 - logger.error("xml解析异常: ", e);  
151 } 150 }
  151 + } catch (DocumentException e) {
  152 + logger.error("xml解析异常: ", e);
152 } 153 }
153 - taskQueueHandlerRun = false;  
154 - });  
155 - }  
156 -  
157 - } catch (SipException | InvalidArgumentException | ParseException e) {  
158 - logger.error("[命令发送失败] 国标级联 国标录像: {}", e.getMessage());  
159 - } finally {  
160 - taskQueueHandlerRun = false; 154 + }
  155 + taskQueueHandlerRun = false;
  156 + });
161 } 157 }
162 } 158 }
163 159
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -695,9 +695,12 @@ public class ZLMHttpHookListener { @@ -695,9 +695,12 @@ public class ZLMHttpHookListener {
695 String app = json.getString("app"); 695 String app = json.getString("app");
696 JSONObject ret = new JSONObject(); 696 JSONObject ret = new JSONObject();
697 ret.put("code", 0); 697 ret.put("code", 0);
  698 + // 录像下载
  699 + ret.put("close", userSetting.getStreamOnDemand());
698 if ("rtp".equals(app)){ 700 if ("rtp".equals(app)){
699 - ret.put("close", true); 701 + // 国标流, 点播/录像回放/录像下载
700 StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId); 702 StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId);
  703 + // 点播
701 if (streamInfoForPlayCatch != null) { 704 if (streamInfoForPlayCatch != null) {
702 // 收到无人观看说明流也没有在往上级推送 705 // 收到无人观看说明流也没有在往上级推送
703 if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) { 706 if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {
@@ -727,40 +730,39 @@ public class ZLMHttpHookListener { @@ -727,40 +730,39 @@ public class ZLMHttpHookListener {
727 730
728 redisCatchStorage.stopPlay(streamInfoForPlayCatch); 731 redisCatchStorage.stopPlay(streamInfoForPlayCatch);
729 storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId()); 732 storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
730 - }else{  
731 - StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null);  
732 - if (streamInfoForPlayBackCatch != null ) {  
733 - if (streamInfoForPlayBackCatch.isPause()) {  
734 - ret.put("close", false);  
735 - }else {  
736 - Device device = deviceService.queryDevice(streamInfoForPlayBackCatch.getDeviceID());  
737 - if (device != null) {  
738 - try {  
739 - cmder.streamByeCmd(device,streamInfoForPlayBackCatch.getChannelId(),  
740 - streamInfoForPlayBackCatch.getStream(), null);  
741 - } catch (InvalidArgumentException | ParseException | SipException |  
742 - SsrcTransactionNotFoundException e) {  
743 - logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage());  
744 - }  
745 - }  
746 - redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(),  
747 - streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);  
748 - }  
749 - 733 + return ret;
  734 + }
  735 + // 录像回放
  736 + StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null);
  737 + if (streamInfoForPlayBackCatch != null ) {
  738 + if (streamInfoForPlayBackCatch.isPause()) {
  739 + ret.put("close", false);
750 }else { 740 }else {
751 - StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, streamId, null);  
752 - // 进行录像下载时无人观看不断流  
753 - if (streamInfoForDownload != null) {  
754 - ret.put("close", false); 741 + Device device = deviceService.queryDevice(streamInfoForPlayBackCatch.getDeviceID());
  742 + if (device != null) {
  743 + try {
  744 + cmder.streamByeCmd(device,streamInfoForPlayBackCatch.getChannelId(),
  745 + streamInfoForPlayBackCatch.getStream(), null);
  746 + } catch (InvalidArgumentException | ParseException | SipException |
  747 + SsrcTransactionNotFoundException e) {
  748 + logger.error("[无人观看]回放, 发送BYE失败 {}", e.getMessage());
  749 + }
755 } 750 }
  751 + redisCatchStorage.stopPlayback(streamInfoForPlayBackCatch.getDeviceID(),
  752 + streamInfoForPlayBackCatch.getChannelId(), streamInfoForPlayBackCatch.getStream(), null);
756 } 753 }
  754 + return ret;
757 } 755 }
758 - MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);  
759 - if (mediaServerItem != null && mediaServerItem.getStreamNoneReaderDelayMS() == -1) { 756 + // 录像下载
  757 + StreamInfo streamInfoForDownload = redisCatchStorage.queryDownload(null, null, streamId, null);
  758 + // 进行录像下载时无人观看不断流
  759 + if (streamInfoForDownload != null) {
760 ret.put("close", false); 760 ret.put("close", false);
  761 + return ret;
761 } 762 }
762 - return ret;  
763 }else { 763 }else {
  764 + // 非国标流 推流/拉流代理
  765 + // 拉流代理
764 StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, streamId); 766 StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, streamId);
765 if (streamProxyItem != null ) { 767 if (streamProxyItem != null ) {
766 if (streamProxyItem.isEnable_remove_none_reader()) { 768 if (streamProxyItem.isEnable_remove_none_reader()) {
@@ -772,12 +774,21 @@ public class ZLMHttpHookListener { @@ -772,12 +774,21 @@ public class ZLMHttpHookListener {
772 }else if (streamProxyItem.isEnable_disable_none_reader()) { 774 }else if (streamProxyItem.isEnable_disable_none_reader()) {
773 // 无人观看停用 775 // 无人观看停用
774 ret.put("close", true); 776 ret.put("close", true);
  777 + // 修改数据
  778 + streamProxyService.stop(app, streamId);
775 }else { 779 }else {
776 ret.put("close", false); 780 ret.put("close", false);
777 } 781 }
  782 + return ret;
778 } 783 }
779 - return ret; 784 + // 推流具有主动性,暂时不做处理
  785 +// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId);
  786 +// if (streamPushItem != null) {
  787 +// // TODO 发送停止
  788 +//
  789 +// }
780 } 790 }
  791 + return ret;
781 } 792 }
782 793
783 /** 794 /**
@@ -792,19 +803,27 @@ public class ZLMHttpHookListener { @@ -792,19 +803,27 @@ public class ZLMHttpHookListener {
792 } 803 }
793 String mediaServerId = json.getString("mediaServerId"); 804 String mediaServerId = json.getString("mediaServerId");
794 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId); 805 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
795 - if (userSetting.isAutoApplyPlay() && mediaInfo != null && mediaInfo.isRtpEnable()) { 806 + if (userSetting.isAutoApplyPlay() && mediaInfo != null) {
796 String app = json.getString("app"); 807 String app = json.getString("app");
797 String streamId = json.getString("stream"); 808 String streamId = json.getString("stream");
798 if ("rtp".equals(app)) { 809 if ("rtp".equals(app)) {
799 - String[] s = streamId.split("_");  
800 - if (s.length == 2) {  
801 - String deviceId = s[0];  
802 - String channelId = s[1];  
803 - Device device = redisCatchStorage.getDevice(deviceId);  
804 - if (device != null) {  
805 - playService.play(mediaInfo,deviceId, channelId, null, null, null); 810 + if (mediaInfo.isRtpEnable()) {
  811 + String[] s = streamId.split("_");
  812 + if (s.length == 2) {
  813 + String deviceId = s[0];
  814 + String channelId = s[1];
  815 + Device device = redisCatchStorage.getDevice(deviceId);
  816 + if (device != null) {
  817 + playService.play(mediaInfo,deviceId, channelId, null, null, null);
  818 + }
806 } 819 }
807 } 820 }
  821 + }else {
  822 + // 拉流代理
  823 + StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(app, streamId);
  824 + if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnable_disable_none_reader()) {
  825 + streamProxyService.start(app, streamId);
  826 + }
808 } 827 }
809 } 828 }
810 829
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
@@ -54,9 +54,6 @@ public class MediaServerItem{ @@ -54,9 +54,6 @@ public class MediaServerItem{
54 @Schema(description = "ZLM鉴权参数") 54 @Schema(description = "ZLM鉴权参数")
55 private String secret; 55 private String secret;
56 56
57 - @Schema(description = "某个流无人观看时,触发hook.on_stream_none_reader事件的最大等待时间,单位毫秒")  
58 - private int streamNoneReaderDelayMS;  
59 -  
60 @Schema(description = "keepalive hook触发间隔,单位秒") 57 @Schema(description = "keepalive hook触发间隔,单位秒")
61 private int hookAliveInterval; 58 private int hookAliveInterval;
62 59
@@ -119,7 +116,6 @@ public class MediaServerItem{ @@ -119,7 +116,6 @@ public class MediaServerItem{
119 rtspSSLPort = zlmServerConfig.getRtspSSlport(); 116 rtspSSLPort = zlmServerConfig.getRtspSSlport();
120 autoConfig = true; // 默认值true; 117 autoConfig = true; // 默认值true;
121 secret = zlmServerConfig.getApiSecret(); 118 secret = zlmServerConfig.getApiSecret();
122 - streamNoneReaderDelayMS = zlmServerConfig.getGeneralStreamNoneReaderDelayMS();  
123 hookAliveInterval = zlmServerConfig.getHookAliveInterval(); 119 hookAliveInterval = zlmServerConfig.getHookAliveInterval();
124 rtpEnable = false; // 默认使用单端口;直到用户自己设置开启多端口 120 rtpEnable = false; // 默认使用单端口;直到用户自己设置开启多端口
125 rtpPortRange = zlmServerConfig.getPortRange().replace("_",","); // 默认使用30000,30500作为级联时发送流的端口号 121 rtpPortRange = zlmServerConfig.getPortRange().replace("_",","); // 默认使用30000,30500作为级联时发送流的端口号
@@ -240,14 +236,6 @@ public class MediaServerItem{ @@ -240,14 +236,6 @@ public class MediaServerItem{
240 this.secret = secret; 236 this.secret = secret;
241 } 237 }
242 238
243 - public int getStreamNoneReaderDelayMS() {  
244 - return streamNoneReaderDelayMS;  
245 - }  
246 -  
247 - public void setStreamNoneReaderDelayMS(int streamNoneReaderDelayMS) {  
248 - this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;  
249 - }  
250 -  
251 public boolean isRtpEnable() { 239 public boolean isRtpEnable() {
252 return rtpEnable; 240 return rtpEnable;
253 } 241 }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
@@ -38,7 +38,7 @@ public class StreamProxyItem extends GbStream { @@ -38,7 +38,7 @@ public class StreamProxyItem extends GbStream {
38 @Schema(description = "是否 无人观看时删除") 38 @Schema(description = "是否 无人观看时删除")
39 private boolean enable_remove_none_reader; 39 private boolean enable_remove_none_reader;
40 40
41 - @Schema(description = "是否 无人观看时不启用") 41 + @Schema(description = "是否 无人观看时自动停用")
42 private boolean enable_disable_none_reader; 42 private boolean enable_disable_none_reader;
43 @Schema(description = "上级平台国标ID") 43 @Schema(description = "上级平台国标ID")
44 private String platformGbId; 44 private String platformGbId;
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -547,7 +547,6 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -547,7 +547,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
547 param.put("hook.on_record_mp4",""); 547 param.put("hook.on_record_mp4","");
548 } 548 }
549 param.put("hook.timeoutSec","20"); 549 param.put("hook.timeoutSec","20");
550 - param.put("general.streamNoneReaderDelayMS",mediaServerItem.getStreamNoneReaderDelayMS()==-1?"3600000":mediaServerItem.getStreamNoneReaderDelayMS() );  
551 // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。 550 // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
552 // 置0关闭此特性(推流断开会导致立即断开播放器) 551 // 置0关闭此特性(推流断开会导致立即断开播放器)
553 // 此参数不应大于播放器超时时间 552 // 此参数不应大于播放器超时时间
@@ -612,7 +611,6 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -612,7 +611,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
612 mediaServerItem.setStreamIp(ip); 611 mediaServerItem.setStreamIp(ip);
613 mediaServerItem.setHookIp(sipConfig.getIp()); 612 mediaServerItem.setHookIp(sipConfig.getIp());
614 mediaServerItem.setSdpIp(ip); 613 mediaServerItem.setSdpIp(ip);
615 - mediaServerItem.setStreamNoneReaderDelayMS(zlmServerConfig.getGeneralStreamNoneReaderDelayMS());  
616 return mediaServerItem; 614 return mediaServerItem;
617 } 615 }
618 616
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -143,7 +143,7 @@ public class PlayServiceImpl implements IPlayService { @@ -143,7 +143,7 @@ public class PlayServiceImpl implements IPlayService {
143 String uuid = UUID.randomUUID().toString(); 143 String uuid = UUID.randomUUID().toString();
144 msg.setId(uuid); 144 msg.setId(uuid);
145 playResult.setUuid(uuid); 145 playResult.setUuid(uuid);
146 - DeferredResult<WVPResult<String>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); 146 + DeferredResult<WVPResult<StreamInfo>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
147 playResult.setResult(result); 147 playResult.setResult(result);
148 // 录像查询以channelId作为deviceId查询 148 // 录像查询以channelId作为deviceId查询
149 resultHolder.put(key, uuid, result); 149 resultHolder.put(key, uuid, result);
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
@@ -26,7 +26,6 @@ public interface MediaServerMapper { @@ -26,7 +26,6 @@ public interface MediaServerMapper {
26 "rtspSSLPort, " + 26 "rtspSSLPort, " +
27 "autoConfig, " + 27 "autoConfig, " +
28 "secret, " + 28 "secret, " +
29 - "streamNoneReaderDelayMS, " +  
30 "rtpEnable, " + 29 "rtpEnable, " +
31 "rtpPortRange, " + 30 "rtpPortRange, " +
32 "sendRtpPortRange, " + 31 "sendRtpPortRange, " +
@@ -51,7 +50,6 @@ public interface MediaServerMapper { @@ -51,7 +50,6 @@ public interface MediaServerMapper {
51 "${rtspSSLPort}, " + 50 "${rtspSSLPort}, " +
52 "${autoConfig}, " + 51 "${autoConfig}, " +
53 "'${secret}', " + 52 "'${secret}', " +
54 - "${streamNoneReaderDelayMS}, " +  
55 "${rtpEnable}, " + 53 "${rtpEnable}, " +
56 "'${rtpPortRange}', " + 54 "'${rtpPortRange}', " +
57 "'${sendRtpPortRange}', " + 55 "'${sendRtpPortRange}', " +
@@ -77,7 +75,6 @@ public interface MediaServerMapper { @@ -77,7 +75,6 @@ public interface MediaServerMapper {
77 "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" + 75 "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
78 "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" + 76 "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
79 "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" + 77 "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
80 - "<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" +  
81 "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" + 78 "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
82 "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" + 79 "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
83 "<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" + 80 "<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" +
@@ -102,7 +99,6 @@ public interface MediaServerMapper { @@ -102,7 +99,6 @@ public interface MediaServerMapper {
102 "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" + 99 "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
103 "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" + 100 "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
104 "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" + 101 "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
105 - "<if test=\"streamNoneReaderDelayMS != null\">, streamNoneReaderDelayMS=${streamNoneReaderDelayMS}</if>" +  
106 "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" + 102 "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
107 "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" + 103 "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
108 "<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" + 104 "<if test=\"sendRtpPortRange != null\">, sendRtpPortRange='${sendRtpPortRange}'</if>" +
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
@@ -11,10 +11,10 @@ import java.util.List; @@ -11,10 +11,10 @@ import java.util.List;
11 public interface StreamProxyMapper { 11 public interface StreamProxyMapper {
12 12
13 @Insert("INSERT INTO stream_proxy (type, name, app, stream,mediaServerId, url, src_url, dst_url, " + 13 @Insert("INSERT INTO stream_proxy (type, name, app, stream,mediaServerId, url, src_url, dst_url, " +
14 - "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable, status, enable_remove_none_reader, createTime) VALUES" + 14 + "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, createTime) VALUES" +
15 "('${type}','${name}', '${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " + 15 "('${type}','${name}', '${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " +
16 "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable}, ${status}, " + 16 "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable}, ${status}, " +
17 - "${enable_remove_none_reader}, '${createTime}' )") 17 + "${enable_remove_none_reader}, ${enable_disable_none_reader}, '${createTime}' )")
18 int add(StreamProxyItem streamProxyDto); 18 int add(StreamProxyItem streamProxyDto);
19 19
20 @Update("UPDATE stream_proxy " + 20 @Update("UPDATE stream_proxy " +
@@ -33,6 +33,7 @@ public interface StreamProxyMapper { @@ -33,6 +33,7 @@ public interface StreamProxyMapper {
33 "enable=#{enable}, " + 33 "enable=#{enable}, " +
34 "status=#{status}, " + 34 "status=#{status}, " +
35 "enable_remove_none_reader=#{enable_remove_none_reader}, " + 35 "enable_remove_none_reader=#{enable_remove_none_reader}, " +
  36 + "enable_disable_none_reader=#{enable_disable_none_reader}, " +
36 "enable_mp4=#{enable_mp4} " + 37 "enable_mp4=#{enable_mp4} " +
37 "WHERE app=#{app} AND stream=#{stream}") 38 "WHERE app=#{app} AND stream=#{stream}")
38 int update(StreamProxyItem streamProxyDto); 39 int update(StreamProxyItem streamProxyDto);
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -87,7 +87,7 @@ public class PlayController { @@ -87,7 +87,7 @@ public class PlayController {
87 @Parameter(name = "deviceId", description = "设备国标编号", required = true) 87 @Parameter(name = "deviceId", description = "设备国标编号", required = true)
88 @Parameter(name = "channelId", description = "通道国标编号", required = true) 88 @Parameter(name = "channelId", description = "通道国标编号", required = true)
89 @GetMapping("/start/{deviceId}/{channelId}") 89 @GetMapping("/start/{deviceId}/{channelId}")
90 - public DeferredResult<WVPResult<String>> play(@PathVariable String deviceId, 90 + public DeferredResult<WVPResult<StreamInfo>> play(@PathVariable String deviceId,
91 @PathVariable String channelId) { 91 @PathVariable String channelId) {
92 92
93 // 获取可用的zlm 93 // 获取可用的zlm
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/PlayResult.java
1 package com.genersoft.iot.vmp.vmanager.gb28181.play.bean; 1 package com.genersoft.iot.vmp.vmanager.gb28181.play.bean;
2 2
  3 +import com.genersoft.iot.vmp.common.StreamInfo;
3 import com.genersoft.iot.vmp.gb28181.bean.Device; 4 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 5 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
5 import org.springframework.http.ResponseEntity; 6 import org.springframework.http.ResponseEntity;
@@ -7,16 +8,16 @@ import org.springframework.web.context.request.async.DeferredResult; @@ -7,16 +8,16 @@ import org.springframework.web.context.request.async.DeferredResult;
7 8
8 public class PlayResult { 9 public class PlayResult {
9 10
10 - private DeferredResult<WVPResult<String>> result; 11 + private DeferredResult<WVPResult<StreamInfo>> result;
11 private String uuid; 12 private String uuid;
12 13
13 private Device device; 14 private Device device;
14 15
15 - public DeferredResult<WVPResult<String>> getResult() { 16 + public DeferredResult<WVPResult<StreamInfo>> getResult() {
16 return result; 17 return result;
17 } 18 }
18 19
19 - public void setResult(DeferredResult<WVPResult<String>> result) { 20 + public void setResult(DeferredResult<WVPResult<StreamInfo>> result) {
20 this.result = result; 21 this.result = result;
21 } 22 }
22 23
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
@@ -125,8 +125,8 @@ public class UserController { @@ -125,8 +125,8 @@ public class UserController {
125 } 125 }
126 } 126 }
127 127
128 - @DeleteMapping("/删除用户")  
129 - @Operation(summary = "停止视频回放") 128 + @DeleteMapping("/delete")
  129 + @Operation(summary = "删除用户")
130 @Parameter(name = "id", description = "用户Id", required = true) 130 @Parameter(name = "id", description = "用户Id", required = true)
131 public void delete(@RequestParam Integer id){ 131 public void delete(@RequestParam Integer id){
132 // 获取当前登录用户id 132 // 获取当前登录用户id
src/main/resources/all-application.yml
@@ -146,8 +146,6 @@ media: @@ -146,8 +146,6 @@ media:
146 auto-config: true 146 auto-config: true
147 # [可选] zlm服务器的hook.admin_params=secret 147 # [可选] zlm服务器的hook.admin_params=secret
148 secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc 148 secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
149 - # [可选] zlm服务器的general.streamNoneReaderDelayMS  
150 - stream-none-reader-delay-ms: 18000 # 无人观看多久自动关闭流, -1表示永不自动关闭,即 关闭按需拉流  
151 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 149 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
152 rtp: 150 rtp:
153 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输 151 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
@@ -190,6 +188,8 @@ user-settings: @@ -190,6 +188,8 @@ user-settings:
190 logInDatebase: true 188 logInDatebase: true
191 # 使用推流状态作为推流通道状态 189 # 使用推流状态作为推流通道状态
192 use-pushing-as-status: true 190 use-pushing-as-status: true
  191 + # 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放
  192 + stream-on-demand: true
193 193
194 # 关闭在线文档(生产环境建议关闭) 194 # 关闭在线文档(生产环境建议关闭)
195 springdoc: 195 springdoc:
web_src/src/components/dialog/MediaServerEdit.vue
@@ -41,10 +41,6 @@ @@ -41,10 +41,6 @@
41 <el-input v-if="currentStep === 2" v-model="mediaServerForm.httpPort" disabled :disabled="mediaServerForm.defaultServer"></el-input> 41 <el-input v-if="currentStep === 2" v-model="mediaServerForm.httpPort" disabled :disabled="mediaServerForm.defaultServer"></el-input>
42 <el-input v-if="currentStep === 3" v-model="mediaServerForm.httpPort" :disabled="mediaServerForm.defaultServer"></el-input> 42 <el-input v-if="currentStep === 3" v-model="mediaServerForm.httpPort" :disabled="mediaServerForm.defaultServer"></el-input>
43 </el-form-item> 43 </el-form-item>
44 - <el-form-item label="SECRET" prop="secret">  
45 - <el-input v-if="currentStep === 2" v-model="mediaServerForm.secret" disabled :disabled="mediaServerForm.defaultServer"></el-input>  
46 - <el-input v-if="currentStep === 3" v-model="mediaServerForm.secret" :disabled="mediaServerForm.defaultServer"></el-input>  
47 - </el-form-item>  
48 <el-form-item label="HOOK IP" prop="ip"> 44 <el-form-item label="HOOK IP" prop="ip">
49 <el-input v-model="mediaServerForm.hookIp" placeholder="媒体服务HOOK_IP" clearable :disabled="mediaServerForm.defaultServer"></el-input> 45 <el-input v-model="mediaServerForm.hookIp" placeholder="媒体服务HOOK_IP" clearable :disabled="mediaServerForm.defaultServer"></el-input>
50 </el-form-item> 46 </el-form-item>
@@ -74,6 +70,10 @@ @@ -74,6 +70,10 @@
74 <el-form-item label="RTMPS PORT" prop="rtmpSSlPort"> 70 <el-form-item label="RTMPS PORT" prop="rtmpSSlPort">
75 <el-input v-model="mediaServerForm.rtmpSSlPort" placeholder="媒体服务RTMPS_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input> 71 <el-input v-model="mediaServerForm.rtmpSSlPort" placeholder="媒体服务RTMPS_PORT" clearable :disabled="mediaServerForm.defaultServer"></el-input>
76 </el-form-item> 72 </el-form-item>
  73 + <el-form-item label="SECRET" prop="secret">
  74 + <el-input v-if="currentStep === 2" v-model="mediaServerForm.secret" disabled :disabled="mediaServerForm.defaultServer"></el-input>
  75 + <el-input v-if="currentStep === 3" v-model="mediaServerForm.secret" :disabled="mediaServerForm.defaultServer"></el-input>
  76 + </el-form-item>
77 <el-form-item label="自动配置媒体服务" > 77 <el-form-item label="自动配置媒体服务" >
78 <el-switch v-model="mediaServerForm.autoConfig" :disabled="mediaServerForm.defaultServer"></el-switch> 78 <el-switch v-model="mediaServerForm.autoConfig" :disabled="mediaServerForm.defaultServer"></el-switch>
79 </el-form-item> 79 </el-form-item>
@@ -94,9 +94,6 @@ @@ -94,9 +94,6 @@
94 - 94 -
95 <el-input v-model="sendRtpPortRange2" placeholder="终止" @change="portRangeChange" clearable style="width: 100px" prop="sendRtpPortRange2" :disabled="mediaServerForm.defaultServer"></el-input> 95 <el-input v-model="sendRtpPortRange2" placeholder="终止" @change="portRangeChange" clearable style="width: 100px" prop="sendRtpPortRange2" :disabled="mediaServerForm.defaultServer"></el-input>
96 </el-form-item> 96 </el-form-item>
97 - <el-form-item label="无人观看多久后停止拉流" >  
98 - <el-input v-model.number="mediaServerForm.streamNoneReaderDelayMS" clearable :disabled="mediaServerForm.defaultServer"></el-input>  
99 - </el-form-item>  
100 <el-form-item label="录像管理服务端口" prop="recordAssistPort"> 97 <el-form-item label="录像管理服务端口" prop="recordAssistPort">
101 <el-input v-model.number="mediaServerForm.recordAssistPort" :disabled="mediaServerForm.defaultServer"> 98 <el-input v-model.number="mediaServerForm.recordAssistPort" :disabled="mediaServerForm.defaultServer">
102 <!-- <el-button v-if="mediaServerForm.recordAssistPort > 0" slot="append" type="primary" @click="checkRecordServer">测试</el-button>--> 99 <!-- <el-button v-if="mediaServerForm.recordAssistPort > 0" slot="append" type="primary" @click="checkRecordServer">测试</el-button>-->
@@ -172,7 +169,6 @@ export default { @@ -172,7 +169,6 @@ export default {
172 hookIp: "", 169 hookIp: "",
173 sdpIp: "", 170 sdpIp: "",
174 streamIp: "", 171 streamIp: "",
175 - streamNoneReaderDelayMS: "",  
176 secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc", 172 secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
177 httpPort: "", 173 httpPort: "",
178 httpSSlPort: "", 174 httpSSlPort: "",
@@ -332,7 +328,6 @@ export default { @@ -332,7 +328,6 @@ export default {
332 hookIp: "", 328 hookIp: "",
333 sdpIp: "", 329 sdpIp: "",
334 streamIp: "", 330 streamIp: "",
335 - streamNoneReaderDelayMS: "",  
336 secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc", 331 secret: "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
337 httpPort: "", 332 httpPort: "",
338 httpSSlPort: "", 333 httpSSlPort: "",
web_src/src/components/dialog/StreamProxyEdit.vue
@@ -105,7 +105,9 @@ @@ -105,7 +105,9 @@
105 <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox> 105 <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox>
106 <el-checkbox label="转HLS" v-model="proxyParam.enable_hls" ></el-checkbox> 106 <el-checkbox label="转HLS" v-model="proxyParam.enable_hls" ></el-checkbox>
107 <el-checkbox label="MP4录制" v-model="proxyParam.enable_mp4" ></el-checkbox> 107 <el-checkbox label="MP4录制" v-model="proxyParam.enable_mp4" ></el-checkbox>
108 - <el-checkbox label="无人观看自动删除" v-model="proxyParam.enable_remove_none_reader" ></el-checkbox> 108 + <el-checkbox label="无人观看自动删除" v-model="proxyParam.enable_remove_none_reader" @change="removeNoneReader"></el-checkbox>
  109 + <el-checkbox label="无人观看停止拉流" v-model="proxyParam.enable_disable_none_reader" @change="disableNoneReaderHandType"></el-checkbox>
  110 +
109 </div> 111 </div>
110 112
111 </el-form-item> 113 </el-form-item>
@@ -170,6 +172,7 @@ export default { @@ -170,6 +172,7 @@ export default {
170 enable_hls: true, 172 enable_hls: true,
171 enable_mp4: false, 173 enable_mp4: false,
172 enable_remove_none_reader: false, 174 enable_remove_none_reader: false,
  175 + enable_disable_none_reader: true,
173 platformGbId: null, 176 platformGbId: null,
174 mediaServerId: null, 177 mediaServerId: null,
175 }, 178 },
@@ -276,6 +279,12 @@ export default { @@ -276,6 +279,12 @@ export default {
276 if (this.platform.enable && this.platform.expires == "0") { 279 if (this.platform.enable && this.platform.expires == "0") {
277 this.platform.expires = "300"; 280 this.platform.expires = "300";
278 } 281 }
  282 + },
  283 + removeNoneReader: function(checked) {
  284 + this.proxyParam.enable_disable_none_reader = !checked;
  285 + },
  286 + disableNoneReaderHandType: function(checked) {
  287 + this.proxyParam.enable_remove_none_reader = !checked;
279 } 288 }
280 }, 289 },
281 }; 290 };
web_src/src/components/setting/Media.vue
@@ -42,9 +42,6 @@ @@ -42,9 +42,6 @@
42 <el-form-item label="接口密钥" prop="secret"> 42 <el-form-item label="接口密钥" prop="secret">
43 <el-input v-model="form.secret" clearable></el-input> 43 <el-input v-model="form.secret" clearable></el-input>
44 </el-form-item> 44 </el-form-item>
45 - <el-form-item label="无人观看触发时长">  
46 - <el-input v-model.number="form.streamNoneReaderDelayMS" clearable></el-input>  
47 - </el-form-item>  
48 <el-form-item label="自动配置"> 45 <el-form-item label="自动配置">
49 <el-switch v-model="form.autoConfig"></el-switch> 46 <el-switch v-model="form.autoConfig"></el-switch>
50 </el-form-item> 47 </el-form-item>