From eef78c7873ba2426a2163fd10cad965bfc89a5c9 Mon Sep 17 00:00:00 2001 From: mk1990 <153958232@qq.com> Date: Fri, 15 Apr 2022 17:05:26 +0800 Subject: [PATCH 01/59] =?UTF-8?q?=E5=90=8C=E6=AD=A5=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=96=B9=E6=A1=88=E8=A7=A3=E5=86=B3=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E9=80=9A=E9=81=93=E8=B0=83=E7=94=A8=E7=99=BE=E5=BA=A6?= =?UTF-8?q?API=E9=97=AE=E9=A2=98=E4=B9=8B=E5=89=8D=E7=9A=84=E5=86=85?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 16 +++++++++------- src/main/resources/application.yml | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index b1950c5d6..b59419abc 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -7,13 +7,13 @@ spring: # REDIS数据库配置 redis: # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 - host: 127.0.0.1 + host: 192.168.213.114 # [必须修改] 端口号 port: 6379 # [可选] 数据库 DB database: 6 # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 - password: face2020 + password: 123456 # [可选] 超时时间 timeout: 10000 # [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置 @@ -50,7 +50,7 @@ server: # 作为28181服务器的配置 sip: # [必须修改] 本机的IP - ip: 192.168.41.16 + ip: 192.168.213.58 # [可选] 28181服务监听的端口 port: 5060 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) @@ -61,15 +61,17 @@ sip: # [可选] id: 44010200492000000001 # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验 - password: admin123 + password: 12345678 #zlm 默认服务器配置 media: - id: FQ3TF8yT83wh5Wvz + id: mediaServer01 # [必须修改] zlm服务器的内网IP - ip: 192.168.41.16 + ip: 192.168.213.114 # [必须修改] zlm服务器的http.port - http-port: 8091 + http-port: 80 + rtp-proxy-port: 10000 + auto-config: true # [可选] zlm服务器的hook.admin_params=secret secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d74c444c1..3d7808a0c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - active: local + active: dev From 260bfd5935b87edd4e09a2d77b9536d0e85dde47 Mon Sep 17 00:00:00 2001 From: xiaoxie Date: Sun, 1 May 2022 21:32:43 +0800 Subject: [PATCH 02/59] =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E8=BF=87=E6=97=B6=E7=9A=84API=EF=BC=8C=E8=A7=A3=E5=86=B3maven?= =?UTF-8?q?=E6=89=93=E5=8C=85=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/service/impl/PlayServiceImpl.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index 00daf1072..82d90eea3 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -18,17 +18,16 @@ import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.service.IMediaServerService; +import com.genersoft.iot.vmp.service.IMediaService; +import com.genersoft.iot.vmp.service.IPlayService; import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback; import com.genersoft.iot.vmp.service.bean.PlayBackCallback; import com.genersoft.iot.vmp.service.bean.PlayBackResult; import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; -import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult; -import com.genersoft.iot.vmp.service.IMediaService; -import com.genersoft.iot.vmp.service.IPlayService; import gov.nist.javax.sip.stack.SIPDialog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,6 +41,7 @@ import org.springframework.web.context.request.async.DeferredResult; import javax.sip.ResponseEvent; import java.io.FileNotFoundException; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.*; @SuppressWarnings(value = {"rawtypes", "unchecked"}) @@ -62,9 +62,6 @@ public class PlayServiceImpl implements IPlayService { @Autowired private IRedisCatchStorage redisCatchStorage; - @Autowired - private RedisUtil redis; - @Autowired private DeferredResultHolder resultHolder; @@ -556,7 +553,7 @@ public class PlayServiceImpl implements IPlayService { BigDecimal currentCount = new BigDecimal(duration/1000); BigDecimal totalCount = new BigDecimal(end-start); - BigDecimal divide = currentCount.divide(totalCount,2, BigDecimal.ROUND_HALF_UP); + BigDecimal divide = currentCount.divide(totalCount,2, RoundingMode.HALF_UP); double process = divide.doubleValue(); streamInfo.setProgress(process); } From c592740efa9d907eac3ad7d8f6e720608f3e962f Mon Sep 17 00:00:00 2001 From: xiaoxie Date: Sun, 1 May 2022 21:33:56 +0800 Subject: [PATCH 03/59] =?UTF-8?q?=E5=8D=87=E7=BA=A7shelljs=EF=BC=8C?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=BE=83=E9=AB=98=E7=89=88=E6=9C=ACnode?= =?UTF-8?q?=E6=89=93=E5=8C=85=E6=97=B6=E7=9A=84=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/package.json b/web_src/package.json index 1e7f0432d..b825f8403 100644 --- a/web_src/package.json +++ b/web_src/package.json @@ -52,7 +52,7 @@ "postcss-url": "^7.2.1", "rimraf": "^2.6.0", "semver": "^5.3.0", - "shelljs": "^0.7.6", + "shelljs": "^0.8.5", "uglifyjs-webpack-plugin": "^1.1.1", "url-loader": "^0.5.8", "vue-loader": "^13.3.0", From bbf8ab93109cd5b4e2efaf96a6db12a11b55f3f8 Mon Sep 17 00:00:00 2001 From: WuPeng Date: Fri, 13 May 2022 22:22:10 +0800 Subject: [PATCH 04/59] =?UTF-8?q?=E6=B7=BB=E5=8A=A0on=5Frecord=5Fts?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/media/zlm/ZLMHttpHookListener.java | 17 +++++++++++++++++ .../service/impl/MediaServerServiceImpl.java | 10 +++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index 7f62968a8..24899c826 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -248,6 +248,23 @@ public class ZLMHttpHookListener { ret.put("msg", "success"); return new ResponseEntity(ret.toString(),HttpStatus.OK); } + /** + * 录制hls完成后通知事件;此事件对回复不敏感。 + * + */ + @ResponseBody + @PostMapping(value = "/on_record_ts", produces = "application/json;charset=UTF-8") + public ResponseEntity onRecordTs(@RequestBody JSONObject json){ + + if (logger.isDebugEnabled()) { + logger.debug("[ ZLM HOOK ]on_record_ts API调用,参数:" + json.toString()); + } + String mediaServerId = json.getString("mediaServerId"); + JSONObject ret = new JSONObject(); + ret.put("code", 0); + ret.put("msg", "success"); + return new ResponseEntity(ret.toString(),HttpStatus.OK); + } /** * rtsp专用的鉴权事件,先触发on_rtsp_realm事件然后才会触发on_rtsp_auth事件。 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java index 5468faefc..a4d848540 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java @@ -495,14 +495,14 @@ public class MediaServerServiceImpl implements IMediaServerService { param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline param.put("ffmpeg.cmd","%s -fflags nobuffer -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s"); param.put("hook.enable","1"); - param.put("hook.on_flow_report",""); + param.put("hook.on_flow_report",String.format("%s/on_flow_report", hookPrex)); param.put("hook.on_play",String.format("%s/on_play", hookPrex)); - param.put("hook.on_http_access",""); + param.put("hook.on_http_access",String.format("%s/on_http_access", hookPrex)); param.put("hook.on_publish", String.format("%s/on_publish", hookPrex)); param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): ""); - param.put("hook.on_record_ts",""); - param.put("hook.on_rtsp_auth",""); - param.put("hook.on_rtsp_realm",""); + param.put("hook.on_record_ts",String.format("%s/on_record_ts", hookPrex)); + param.put("hook.on_rtsp_auth",String.format("%s/on_rtsp_auth", hookPrex)); + param.put("hook.on_rtsp_realm",String.format("%s/on_rtsp_realm", hookPrex)); param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex)); param.put("hook.on_shell_login",String.format("%s/on_shell_login", hookPrex)); param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex)); From e541341504963df6985e3ecc5d2e910d5328495e Mon Sep 17 00:00:00 2001 From: mk1990 <153958232@qq.com> Date: Mon, 16 May 2022 10:10:50 +0800 Subject: [PATCH 05/59] =?UTF-8?q?=E4=BF=AE=E6=94=B9application-dev.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 16 +++++++--------- src/main/resources/application.yml | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index b59419abc..b1950c5d6 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -7,13 +7,13 @@ spring: # REDIS数据库配置 redis: # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 - host: 192.168.213.114 + host: 127.0.0.1 # [必须修改] 端口号 port: 6379 # [可选] 数据库 DB database: 6 # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 - password: 123456 + password: face2020 # [可选] 超时时间 timeout: 10000 # [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置 @@ -50,7 +50,7 @@ server: # 作为28181服务器的配置 sip: # [必须修改] 本机的IP - ip: 192.168.213.58 + ip: 192.168.41.16 # [可选] 28181服务监听的端口 port: 5060 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) @@ -61,17 +61,15 @@ sip: # [可选] id: 44010200492000000001 # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验 - password: 12345678 + password: admin123 #zlm 默认服务器配置 media: - id: mediaServer01 + id: FQ3TF8yT83wh5Wvz # [必须修改] zlm服务器的内网IP - ip: 192.168.213.114 + ip: 192.168.41.16 # [必须修改] zlm服务器的http.port - http-port: 80 - rtp-proxy-port: 10000 - auto-config: true + http-port: 8091 # [可选] zlm服务器的hook.admin_params=secret secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3d7808a0c..d74c444c1 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - active: dev + active: local From 78fac69cd569ede0ba5bf900f0df4f65c9229400 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 19 May 2022 17:00:47 +0800 Subject: [PATCH 06/59] =?UTF-8?q?=E6=94=AF=E6=8C=81sdp=20ip=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E4=B8=BA=E5=9F=9F=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/conf/MediaConfig.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java index 85f468491..c24e0cad5 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java @@ -6,6 +6,10 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.regex.Pattern; + @Configuration("mediaConfig") public class MediaConfig{ @@ -161,7 +165,18 @@ public class MediaConfig{ if (StringUtils.isEmpty(sdpIp)){ return ip; }else { - return sdpIp; + if (isValidIPAddress(sdpIp)) { + return sdpIp; + }else { + // 按照域名解析 + String hostAddress = null; + try { + hostAddress = InetAddress.getByName(sdpIp).getHostAddress(); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + return hostAddress; + } } } @@ -211,4 +226,11 @@ public class MediaConfig{ return mediaServerItem; } + private boolean isValidIPAddress(String ipAddress) { + if ((ipAddress != null) && (!ipAddress.isEmpty())) { + return Pattern.matches("^([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}$", ipAddress); + } + return false; + } + } From 590358c31381c5fedad14b0c91f3aa64ce29e728 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Sat, 21 May 2022 21:13:12 +0800 Subject: [PATCH 07/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=BD=E6=A0=87?= =?UTF-8?q?=E7=BA=A7=E8=81=94=E5=BD=95=E5=83=8F=E6=9F=A5=E8=AF=A2=20#485?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/cmd/RecordInfoResponseMessageHandler.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java index 4509e424f..1f701715b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java @@ -70,15 +70,20 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent rootElement = getRootElement(evt, device.getCharset()); String sn = getText(rootElement, "SN"); - + RecordInfo recordInfo = new RecordInfo(); + recordInfo.setDeviceId(device.getDeviceId()); + recordInfo.setSn(sn); + recordInfo.setName(getText(rootElement, "Name")); String sumNumStr = getText(rootElement, "SumNum"); int sumNum = 0; if (!StringUtils.isEmpty(sumNumStr)) { sumNum = Integer.parseInt(sumNumStr); } + recordInfo.setSumNum(sumNum); Element recordListElement = rootElement.element("RecordList"); if (recordListElement == null || sumNum == 0) { logger.info("无录像数据"); + eventPublisher.recordEndEventPush(recordInfo); recordDataCatch.put(device.getDeviceId(), sn, sumNum, new ArrayList<>()); releaseRequest(device.getDeviceId(), sn); } else { @@ -112,6 +117,9 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent record.setRecorderId(getText(itemRecord, "RecorderID")); recordList.add(record); } + recordInfo.setRecordList(recordList); + // 发送消息,如果是上级查询此录像,则会通过这里通知给上级 + eventPublisher.recordEndEventPush(recordInfo); int count = recordDataCatch.put(device.getDeviceId(), sn, sumNum, recordList); logger.info("[国标录像], {}->{}: {}/{}", device.getDeviceId(), sn, count, sumNum); } From 07fa589e06415ca41fc29d22c7c8f3f1b4917147 Mon Sep 17 00:00:00 2001 From: xiaoxie Date: Mon, 23 May 2022 09:42:32 +0800 Subject: [PATCH 08/59] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/impl/RegisterRequestProcessor.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java index 47a4e008b..94a9e96c0 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java @@ -1,21 +1,17 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; -import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate; -import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.service.IDeviceService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; -import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import com.genersoft.iot.vmp.utils.DateUtil; import gov.nist.javax.sip.RequestEventExt; import gov.nist.javax.sip.address.AddressImpl; import gov.nist.javax.sip.address.SipUri; +import gov.nist.javax.sip.clientauthutils.DigestServerAuthenticationHelper; import gov.nist.javax.sip.header.Expires; import gov.nist.javax.sip.header.SIPDateHeader; import org.slf4j.Logger; @@ -50,15 +46,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @Autowired private SipConfig sipConfig; - @Autowired - private IRedisCatchStorage redisCatchStorage; - - @Autowired - private IVideoManagerStorage storager; - - @Autowired - private EventPublisher publisher; - @Autowired private SIPProcessorObserver sipProcessorObserver; @@ -86,7 +73,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); Response response = null; boolean passwordCorrect = false; - // 注册标志 0:未携带授权头或者密码错误 1:注册成功 2:注销成功 + // 注册标志 true:注册成功 false:注册成功 boolean registerFlag = false; FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME); AddressImpl address = (AddressImpl) fromHeader.getAddress(); From d739bfa5976e36ced26f906ab16f83c20c8cb27c Mon Sep 17 00:00:00 2001 From: xiaoxie Date: Mon, 23 May 2022 09:44:21 +0800 Subject: [PATCH 09/59] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transmit/event/request/impl/RegisterRequestProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java index 94a9e96c0..751601113 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java @@ -73,7 +73,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); Response response = null; boolean passwordCorrect = false; - // 注册标志 true:注册成功 false:注册成功 + // 注册标志 boolean registerFlag = false; FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME); AddressImpl address = (AddressImpl) fromHeader.getAddress(); From cb845726f63f275e2def6101459833da6cc23681 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Mon, 23 May 2022 10:16:46 +0800 Subject: [PATCH 10/59] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../conf/security/LoginSuccessHandler.java | 3 +++ .../vmp/conf/security/WebSecurityConfig.java | 19 ++++++++++++------- .../cmd/KeepaliveNotifyMessageHandler.java | 6 ++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java b/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java index 9690c6d1e..2d7e8a1b0 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java @@ -11,6 +11,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +/** + * @author lin + */ @Component public class LoginSuccessHandler implements AuthenticationSuccessHandler { diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java index 47cfdaba4..a4bbdbac6 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java @@ -20,6 +20,7 @@ import java.util.List; /** * 配置Spring Security + * @author lin */ @Configuration @EnableWebSecurity @@ -132,15 +133,19 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { .anyRequest().authenticated() // 异常处理(权限拒绝、登录失效等) .and().exceptionHandling() - .authenticationEntryPoint(anonymousAuthenticationEntryPoint)//匿名用户访问无权限资源时的异常处理 + //匿名用户访问无权限资源时的异常处理 + .authenticationEntryPoint(anonymousAuthenticationEntryPoint) // .accessDeniedHandler(accessDeniedHandler)//登录用户没有权限访问资源 - // 登入 - .and().formLogin().permitAll()//允许所有用户 - .successHandler(loginSuccessHandler)//登录成功处理逻辑 - .failureHandler(loginFailureHandler)//登录失败处理逻辑 + // 登入 允许所有用户 + .and().formLogin().permitAll() + //登录成功处理逻辑 + .successHandler(loginSuccessHandler) + //登录失败处理逻辑 + .failureHandler(loginFailureHandler) // 登出 - .and().logout().logoutUrl("/api/user/logout").permitAll()//允许所有用户 - .logoutSuccessHandler(logoutHandler)//登出成功处理逻辑 + .and().logout().logoutUrl("/api/user/logout").permitAll() + //登出成功处理逻辑 + .logoutSuccessHandler(logoutHandler) .deleteCookies("JSESSIONID") // 会话管理 // .and().sessionManagement().invalidSessionStrategy(invalidSessionHandler) // 超时处理 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java index cf07250d9..c4294576a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java @@ -64,16 +64,14 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); } device.setKeepaliveTime(DateUtil.getNow()); + // 回复200 OK + responseAck(evt, Response.OK); if (device.getOnline() == 1) { - // 回复200 OK - responseAck(evt, Response.OK); deviceService.updateDevice(device); }else { // 对于已经离线的设备判断他的注册是否已经过期 if (!deviceService.expire(device)){ deviceService.online(device); - // 回复200 OK - responseAck(evt, Response.OK); } } } catch (SipException e) { From 6cee5a0751188c30d80a7454256eec0657655c8d Mon Sep 17 00:00:00 2001 From: xiaoxie Date: Mon, 23 May 2022 10:37:38 +0800 Subject: [PATCH 11/59] =?UTF-8?q?fix=EF=BC=9A=E4=B9=8B=E5=89=8D=E5=BC=95?= =?UTF-8?q?=E5=85=A5=E4=BA=86=E9=94=99=E8=AF=AF=E7=9A=84DigestServerAuthen?= =?UTF-8?q?ticationHelper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transmit/event/request/impl/RegisterRequestProcessor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java index 751601113..cebc2edae 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java @@ -6,12 +6,12 @@ import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; +import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.utils.DateUtil; import gov.nist.javax.sip.RequestEventExt; import gov.nist.javax.sip.address.AddressImpl; import gov.nist.javax.sip.address.SipUri; -import gov.nist.javax.sip.clientauthutils.DigestServerAuthenticationHelper; import gov.nist.javax.sip.header.Expires; import gov.nist.javax.sip.header.SIPDateHeader; import org.slf4j.Logger; @@ -92,7 +92,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen // 校验密码是否正确 passwordCorrect = StringUtils.isEmpty(sipConfig.getPassword()) || new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, sipConfig.getPassword()); - // 未携带授权头或者密码错误 回复401 if (!passwordCorrect) { // 注册失败 From 7a917ee50a285d26e34e16de215099029c8be836 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Mon, 23 May 2022 10:50:29 +0800 Subject: [PATCH 12/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=BD=E6=A0=87?= =?UTF-8?q?=E5=BD=95=E5=83=8F=E6=92=AD=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_src/src/components/dialog/devicePlayer.vue | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web_src/src/components/dialog/devicePlayer.vue b/web_src/src/components/dialog/devicePlayer.vue index aba35ddb0..9c254c9b7 100644 --- a/web_src/src/components/dialog/devicePlayer.vue +++ b/web_src/src/components/dialog/devicePlayer.vue @@ -605,12 +605,12 @@ export default { url: '/api/playback/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' + row.endTime }).then(function (res) { - var streamInfo = res.data; - that.app = streamInfo.app; - that.streamId = streamInfo.stream; - that.mediaServerId = streamInfo.mediaServerId; - that.ssrc = streamInfo.ssrc; - that.videoUrl = that.getUrlByStreamInfo(streamInfo); + that.streamInfo = res.data; + that.app = that.streamInfo.app; + that.streamId = that.streamInfo.stream; + that.mediaServerId = that.streamInfo.mediaServerId; + that.ssrc = that.streamInfo.ssrc; + that.videoUrl = that.getUrlByStreamInfo(); that.recordPlay = true; }); } From 4e13489366b31b3641ca37e9c41ec5f4ae41958c Mon Sep 17 00:00:00 2001 From: mk1990 <153958232@qq.com> Date: Wed, 25 May 2022 13:39:34 +0800 Subject: [PATCH 13/59] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E6=B3=A8=E5=86=8C=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=B8=8D=E5=88=B0=E8=AE=BE=E5=A4=87=E4=BF=A1=E6=81=AF=E5=92=8C?= =?UTF-8?q?=E9=80=9A=E9=81=93=E4=BF=A1=E6=81=AF=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/service/impl/DeviceServiceImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java index 0144e83bc..e4a2a19c6 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java @@ -77,13 +77,15 @@ public class DeviceServiceImpl implements IDeviceService { if (device.getCreateTime() == null) { device.setCreateTime(now); logger.info("[设备上线,首次注册]: {},查询设备信息以及通道信息", device.getDeviceId()); + deviceMapper.add(device); + redisCatchStorage.updateDevice(device); commander.deviceInfoQuery(device); sync(device); - deviceMapper.add(device); }else { deviceMapper.update(device); + redisCatchStorage.updateDevice(device); } - redisCatchStorage.updateDevice(device); + // 上线添加订阅 if (device.getSubscribeCycleForCatalog() > 0) { // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 From f513f5ef67409a0db26d85a95a5e3b127595aaca Mon Sep 17 00:00:00 2001 From: mk1990 <153958232@qq.com> Date: Wed, 25 May 2022 14:09:43 +0800 Subject: [PATCH 14/59] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=B5=B7=E5=BA=B7?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E5=9C=A8=E5=AE=9E=E6=97=B6=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E4=B8=AD=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=88=B0=E9=80=9A=E9=81=93=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/storager/impl/VideoManagerStorageImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java index 1f3591142..3bb3d9f08 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java @@ -30,7 +30,7 @@ import org.springframework.util.StringUtils; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -/** +/** * 视频设备数据存储-jdbc实现 * swwheihei * 2020年5月6日 下午2:31:42 @@ -315,6 +315,9 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { List all; if (catalogUnderDevice != null && catalogUnderDevice) { all = deviceChannelMapper.queryChannels(deviceId, deviceId, query, hasSubChannel, online); + // 海康设备的parentId是SIP id + List deviceChannels = deviceChannelMapper.queryChannels(deviceId, sipConfig.getId(), query, hasSubChannel, online); + all.addAll(deviceChannels); }else { all = deviceChannelMapper.queryChannels(deviceId, null, query, hasSubChannel, online); } From dc6769664e36ffc70ea3af597e4f3dbb93c2b6bf Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 26 May 2022 12:10:46 +0800 Subject: [PATCH 15/59] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E4=B8=8D=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E7=9A=84=E6=97=B6=E9=97=B4=E6=A0=BC=E5=BC=8Fiso8601?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=EF=BC=9B=E5=8D=87=E7=BA=A7fastjson=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + pom.xml | 3 +- .../session/VideoStreamSessionManager.java | 7 ++-- .../vmp/media/zlm/ZLMHttpHookListener.java | 1 - .../zlm/event/ZLMStatusEventListener.java | 2 +- .../iot/vmp/service/IPlayService.java | 2 + .../vmp/service/impl/DeviceServiceImpl.java | 1 - .../service/impl/MediaServerServiceImpl.java | 13 +++--- .../iot/vmp/service/impl/PlayServiceImpl.java | 5 +++ .../com/genersoft/iot/vmp/utils/DateUtil.java | 42 +++++++++++++++---- .../gb28181/alarm/AlarmController.java | 18 ++------ .../gb28181/record/GBRecordController.java | 4 +- .../iot/vmp/vmanager/log/LogController.java | 9 +--- .../impl/DeviceAlarmServiceImplTest.java | 23 ++++++---- .../src/components/service/DeviceService.js | 33 ++++++++------- 15 files changed, 95 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 7ba443fe1..1b8b985c7 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ QQ私信一般不回, 精力有限.欢迎大家在群里讨论.觉得项目对 [hotcoffie](https://github.com/hotcoffie) [xiaomu](https://github.com/nikmu) [TristingChen](https://github.com/TristingChen) [chenparty](https://github.com/chenparty) [Hotleave](https://github.com/hotleave) [ydwxb](https://github.com/ydwxb) [ydpd](https://github.com/ydpd) [szy833](https://github.com/szy833) [ydwxb](https://github.com/ydwxb) [Albertzhu666](https://github.com/Albertzhu666) +[mk1990](https://github.com/mk1990) ps: 刚增加了这个名单,肯定遗漏了一些大佬,欢迎大佬联系我添加。 diff --git a/pom.xml b/pom.xml index 1546e39cc..9ad41c7f1 100644 --- a/pom.xml +++ b/pom.xml @@ -159,9 +159,10 @@ com.alibaba fastjson - 1.2.73 + 1.2.83 + com.squareup.okhttp3 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index 85bc39dc7..2b76ff787 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -99,8 +99,8 @@ public class VideoStreamSessionManager { return dialog; } - public SIPDialog getDialogByCallId(String deviceId, String channelId, String callID){ - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callID, null); + public SIPDialog getDialogByCallId(String deviceId, String channelId, String callId){ + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null); if (ssrcTransaction == null) { return null; } @@ -108,8 +108,7 @@ public class VideoStreamSessionManager { if (dialogByteArray == null) { return null; } - SIPDialog dialog = (SIPDialog)SerializeUtils.deSerialize(dialogByteArray); - return dialog; + return (SIPDialog)SerializeUtils.deSerialize(dialogByteArray); } public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index 7f62968a8..3694fdf2b 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -11,7 +11,6 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.media.zlm.dto.*; import com.genersoft.iot.vmp.service.*; diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java index f4a9febbb..223ef13f2 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java @@ -42,7 +42,7 @@ public class ZLMStatusEventListener { logger.info("[ZLM] 上线 ID:" + event.getMediaServerId()); streamPushService.zlmServerOnline(event.getMediaServerId()); streamProxyService.zlmServerOnline(event.getMediaServerId()); - + playService.zlmServerOnline(event.getMediaServerId()); } @Async diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java index 9e764931e..0b758d85c 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java @@ -40,4 +40,6 @@ public interface IPlayService { DeferredResult> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack); StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream); + + void zlmServerOnline(String mediaServerId); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java index e4a2a19c6..77c7c617a 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java @@ -68,7 +68,6 @@ public class DeviceServiceImpl implements IDeviceService { if (deviceInRedis != null && deviceInDb == null) { // redis 存在脏数据 redisCatchStorage.clearCatchByDeviceId(device.getDeviceId()); - } device.setUpdateTime(now); device.setOnline(1); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java index 5468faefc..8ad57e85f 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java @@ -6,6 +6,7 @@ import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.session.SsrcConfig; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; @@ -35,7 +36,9 @@ import org.springframework.util.StringUtils; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.LocalDateTime; import java.util.*; +import java.util.stream.Collectors; /** * 媒体服务器节点管理 @@ -189,6 +192,7 @@ public class MediaServerServiceImpl implements IMediaServerService { public void clearRTPServer(MediaServerItem mediaServerItem) { mediaServerItem.setSsrcConfig(new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getDomain())); redisUtil.zAdd(VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId(), mediaServerItem.getId(), 0); + } @@ -229,11 +233,10 @@ public class MediaServerServiceImpl implements IMediaServerService { } result.sort((serverItem1, serverItem2)->{ int sortResult = 0; - try { - sortResult = DateUtil.format.parse(serverItem1.getCreateTime()).compareTo(DateUtil.format.parse(serverItem2.getCreateTime())); - } catch (ParseException e) { - e.printStackTrace(); - } + LocalDateTime localDateTime1 = LocalDateTime.parse(serverItem1.getCreateTime(), DateUtil.formatter); + LocalDateTime localDateTime2 = LocalDateTime.parse(serverItem2.getCreateTime(), DateUtil.formatter); + + sortResult = localDateTime1.compareTo(localDateTime2); return sortResult; }); return result; diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index 2521a0694..b16449290 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -648,4 +648,9 @@ public class PlayServiceImpl implements IPlayService { } } } + + @Override + public void zlmServerOnline(String mediaServerId) { + // 似乎没啥需要做的 + } } diff --git a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java index 9d37dcd31..787bdae9d 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java @@ -18,35 +18,61 @@ import java.util.Locale; */ public class DateUtil { - private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss"; - public static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss"; + /** + * 兼容不规范的iso8601时间格式 + */ + private static final String ISO8601_COMPATIBLE_PATTERN = "yyyy-M-d'T'H:m:s"; - public static final SimpleDateFormat formatISO8601 = new SimpleDateFormat(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()); - public static final SimpleDateFormat format = new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss, Locale.getDefault()); + /** + * 用以输出标准的iso8601时间格式 + */ + private static final String ISO8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss"; - public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()).withZone(ZoneId.systemDefault()); - public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(yyyy_MM_dd_HH_mm_ss, Locale.getDefault()).withZone(ZoneId.systemDefault()); + /** + * wvp内部统一时间格式 + */ + public static final String PATTERN = "yyyy-MM-dd HH:mm:ss"; + + + public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.systemDefault()); + public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.systemDefault()); + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.systemDefault()); public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { return formatterISO8601.format(formatter.parse(formatTime)); } public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) { - return formatter.format(formatterISO8601.parse(formatTime)); + return formatter.format(formatterCompatibleISO8601.parse(formatTime)); } - + + /** + * yyyy_MM_dd_HH_mm_ss 转时间戳 + * @param formatTime + * @return + */ public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) { TemporalAccessor temporalAccessor = formatter.parse(formatTime); Instant instant = Instant.from(temporalAccessor); return instant.getEpochSecond(); } + /** + * 获取当前时间 + * @return + */ public static String getNow() { LocalDateTime nowDateTime = LocalDateTime.now(); return formatter.format(nowDateTime); } + /** + * 格式校验 + * @param timeStr 时间字符串 + * @param dateTimeFormatter 待校验的格式 + * @return + */ public static boolean verification(String timeStr, DateTimeFormatter dateTimeFormatter) { try { LocalDate.parse(timeStr, dateTimeFormatter); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java index 56864dbcd..0edec5103 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java @@ -24,6 +24,7 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import java.text.ParseException; +import java.time.LocalDateTime; import java.util.Arrays; import java.util.List; @@ -98,14 +99,7 @@ public class AlarmController { } - try { - if (startTime != null) { - DateUtil.format.parse(startTime); - } - if (endTime != null) { - DateUtil.format.parse(endTime); - } - } catch (ParseException e) { + if (!DateUtil.verification(startTime, DateUtil.formatter) || !DateUtil.verification(endTime, DateUtil.formatter)){ return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); } @@ -144,11 +138,7 @@ public class AlarmController { if (StringUtils.isEmpty(time)) { time = null; } - try { - if (time != null) { - DateUtil.format.parse(time); - } - } catch (ParseException e) { + if (!DateUtil.verification(time, DateUtil.formatter) ){ return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); } List deviceIdList = null; @@ -189,7 +179,7 @@ public class AlarmController { deviceAlarm.setAlarmDescription("test"); deviceAlarm.setAlarmMethod("1"); deviceAlarm.setAlarmPriority("1"); - deviceAlarm.setAlarmTime(DateUtil.formatISO8601.format(System.currentTimeMillis())); + deviceAlarm.setAlarmTime(DateUtil.formatterISO8601.format(LocalDateTime.now())); deviceAlarm.setAlarmType("1"); deviceAlarm.setLongitude(115.33333); deviceAlarm.setLatitude(39.33333); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java index 8cb923a77..f0f2eb2b8 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java @@ -72,7 +72,7 @@ public class GBRecordController { if (!DateUtil.verification(startTime, DateUtil.formatter)){ WVPResult wvpResult = new WVPResult<>(); wvpResult.setCode(-1); - wvpResult.setMsg("startTime error, format is " + DateUtil.yyyy_MM_dd_HH_mm_ss); + wvpResult.setMsg("startTime error, format is " + DateUtil.PATTERN); ResponseEntity> resultResponseEntity = new ResponseEntity<>(wvpResult, HttpStatus.OK); result.setResult(resultResponseEntity); @@ -81,7 +81,7 @@ public class GBRecordController { if (!DateUtil.verification(endTime, DateUtil.formatter)){ WVPResult wvpResult = new WVPResult<>(); wvpResult.setCode(-1); - wvpResult.setMsg("endTime error, format is " + DateUtil.yyyy_MM_dd_HH_mm_ss); + wvpResult.setMsg("endTime error, format is " + DateUtil.PATTERN); ResponseEntity> resultResponseEntity = new ResponseEntity<>(wvpResult, HttpStatus.OK); result.setResult(resultResponseEntity); return result; diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java index 65f5f7c70..a9b23eff8 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java @@ -76,14 +76,7 @@ public class LogController { logger.warn("自动记录日志功能已关闭,查询结果可能不完整。"); } - try { - if (startTime != null) { - DateUtil.format.parse(startTime); - } - if (endTime != null) { - DateUtil.format.parse(endTime); - } - } catch (ParseException e) { + if (!DateUtil.verification(startTime, DateUtil.formatter) || !DateUtil.verification(endTime, DateUtil.formatter)){ return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST); } diff --git a/src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java b/src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java index 6d6ff37ff..c627511a7 100644 --- a/src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java +++ b/src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java @@ -8,6 +8,10 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.temporal.TemporalAccessor; import java.util.Date; @@ -64,8 +68,8 @@ class DeviceAlarmServiceImplTest { * * 7其他报警;可以为直接组合如12为电话报警或 设备报警- */ deviceAlarm.setAlarmMethod((int)(Math.random()*7 + 1) + ""); - Date date = randomDate("2021-01-01 00:00:00", "2021-06-01 00:00:00"); - deviceAlarm.setAlarmTime(DateUtil.format.format(date)); + Instant date = randomDate("2021-01-01 00:00:00", "2021-06-01 00:00:00"); + deviceAlarm.setAlarmTime(DateUtil.formatter.format(date)); /** * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级 警情- */ @@ -85,17 +89,20 @@ class DeviceAlarmServiceImplTest { - private Date randomDate(String beginDate, String endDate) { + private Instant randomDate(String beginDate, String endDate) { try { - Date start = DateUtil.format.parse(beginDate);//构造开始日期 - Date end = DateUtil.format.parse(endDate);//构造结束日期 + //构造开始日期 + LocalDateTime start = LocalDateTime.parse(beginDate, DateUtil.formatter); + + //构造结束日期 + LocalDateTime end = LocalDateTime.parse(endDate, DateUtil.formatter); //getTime()表示返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。 - if (start.getTime() >= end.getTime()) { + if (start.isAfter(end)) { return null; } - long date = random(start.getTime(), end.getTime()); - return new Date(date); + long date = random(start.toInstant(ZoneOffset.of("+8")).toEpochMilli(), end.toInstant(ZoneOffset.of("+8")).toEpochMilli()); + return Instant.ofEpochMilli(date); } catch (Exception e) { e.printStackTrace(); } diff --git a/web_src/src/components/service/DeviceService.js b/web_src/src/components/service/DeviceService.js index dbe10d189..4700e7938 100644 --- a/web_src/src/components/service/DeviceService.js +++ b/web_src/src/components/service/DeviceService.js @@ -21,47 +21,47 @@ class DeviceService{ if (typeof (errorCallback) == "function") errorCallback(error) }); } - getAllDeviceList(callback, errorCallback) { + getAllDeviceList(callback,endCallback, errorCallback) { let currentPage = 1; let count = 100; let deviceList = [] - this.getAllDeviceListIteration(deviceList, currentPage, count, (data) => { - if (typeof (callback) == "function") callback(data) - }, errorCallback) + this.getAllDeviceListIteration(deviceList, currentPage, count, callback, endCallback, errorCallback) } - getAllDeviceListIteration(deviceList, currentPage, count, callback, errorCallback) { + getAllDeviceListIteration(deviceList, currentPage, count, callback, endCallback, errorCallback) { this.getDeviceList(currentPage, count, (data) => { if (data.list) { + if (typeof (callback) == "function") callback(data.list) deviceList = deviceList.concat(data.list); if (deviceList.length < data.total) { currentPage ++ - this.getAllDeviceListIteration(deviceList, currentPage, count, callback, errorCallback) + this.getAllDeviceListIteration(deviceList, currentPage, count, callback, endCallback, errorCallback) }else { - if (typeof (callback) == "function") callback(deviceList) + if (typeof (endCallback) == "function") endCallback(deviceList) } } }, errorCallback) } - getAllChannel(isCatalog, catalogUnderDevice, deviceId, callback, errorCallback) { + getAllChannel(isCatalog, catalogUnderDevice, deviceId, callback, endCallback, errorCallback) { let currentPage = 1; let count = 100; let catalogList = [] - this.getAllChannelIteration(isCatalog, catalogUnderDevice, deviceId, catalogList, currentPage, count, callback, errorCallback) + this.getAllChannelIteration(isCatalog, catalogUnderDevice, deviceId, catalogList, currentPage, count, callback, endCallback, errorCallback) } - getAllChannelIteration(isCatalog, catalogUnderDevice, deviceId, catalogList, currentPage, count, callback, errorCallback) { + getAllChannelIteration(isCatalog, catalogUnderDevice, deviceId, catalogList, currentPage, count, callback, endCallback, errorCallback) { this.getChanel(isCatalog, catalogUnderDevice, deviceId, currentPage, count, (data) => { if (data.list) { + if (typeof (callback) == "function") callback(data.list) catalogList = catalogList.concat(data.list); if (catalogList.length < data.total) { currentPage ++ this.getAllChannelIteration(isCatalog,catalogUnderDevice, deviceId, catalogList, currentPage, count, callback, errorCallback) }else { console.log(1) - if (typeof (callback) == "function") callback(catalogList) + if (typeof (endCallback) == "function") endCallback(catalogList) } } }, errorCallback) @@ -84,22 +84,23 @@ class DeviceService{ } - getAllSubChannel(isCatalog, deviceId, channelId, callback, errorCallback) { + getAllSubChannel(isCatalog, deviceId, channelId, callback, endCallback, errorCallback) { let currentPage = 1; let count = 100; let catalogList = [] - this.getAllSubChannelIteration(isCatalog, deviceId, channelId, catalogList, currentPage, count, callback, errorCallback) + this.getAllSubChannelIteration(isCatalog, deviceId, channelId, catalogList, currentPage, count, callback, endCallback, errorCallback) } - getAllSubChannelIteration(isCatalog, deviceId,channelId, catalogList, currentPage, count, callback, errorCallback) { + getAllSubChannelIteration(isCatalog, deviceId,channelId, catalogList, currentPage, count, callback, endCallback, errorCallback) { this.getSubChannel(isCatalog, deviceId, channelId, currentPage, count, (data) => { if (data.list) { + if (typeof (callback) == "function") callback(data.list) catalogList = catalogList.concat(data.list); if (catalogList.length < data.total) { currentPage ++ - this.getAllSubChannelIteration(isCatalog, deviceId, channelId, catalogList, currentPage, count, callback, errorCallback) + this.getAllSubChannelIteration(isCatalog, deviceId, channelId, catalogList, currentPage, count, callback, endCallback, errorCallback) }else { - if (typeof (callback) == "function") callback(catalogList) + if (typeof (endCallback) == "function") endCallback(catalogList) } } }, errorCallback) From 2a5404c68f387523a833b8e9f17cda5b0c9ad727 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 26 May 2022 13:45:57 +0800 Subject: [PATCH 16/59] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=B5=B7=E5=BA=B7?= =?UTF-8?q?=E4=BF=A1=E4=BB=A4=E9=97=AE=E9=A2=98=20#493?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../session/VideoStreamSessionManager.java | 7 ++++++ .../transmit/cmd/impl/SIPCommander.java | 12 +++++----- .../impl/message/MessageRequestProcessor.java | 2 +- .../cmd/MediaStatusNotifyMessageHandler.java | 23 ++++++++++++++----- .../com/genersoft/iot/vmp/utils/DateUtil.java | 1 - 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index 2b76ff787..d8fdfad80 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -112,6 +112,13 @@ public class VideoStreamSessionManager { } public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){ + + if (StringUtils.isEmpty(deviceId)) { + deviceId ="*"; + } + if (StringUtils.isEmpty(channelId)) { + channelId ="*"; + } if (StringUtils.isEmpty(callId)) { callId ="*"; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index f2e524e47..f51437d19 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -708,22 +708,22 @@ public class SIPCommander implements ISIPCommander { } SIPDialog dialog; if (callId != null) { - dialog = streamSession.getDialogByCallId(deviceId, channelId, callId); + dialog = streamSession.getDialogByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), callId); }else { - if (stream == null) { + if (stream == null && ssrcTransaction == null && ssrcTransaction.getStream() == null) { return; } - dialog = streamSession.getDialogByStream(deviceId, channelId, stream); + dialog = streamSession.getDialogByStream(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); } if (ssrcTransaction != null) { MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId()); mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc()); - mediaServerService.closeRTPServer(deviceId, channelId, ssrcTransaction.getStream()); - streamSession.remove(deviceId, channelId, ssrcTransaction.getStream()); + mediaServerService.closeRTPServer(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); } if (dialog == null) { - logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId); + logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); return; } SipStack sipStack = udpSipProvider.getSipStack(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java index 136b91206..cd858896c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java @@ -72,7 +72,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); // 先从会话内查找 - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, null, callIdHeader.getCallId()); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题 deviceId = ssrcTransaction.getDeviceId(); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java index 4cf976855..5cb39734d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java @@ -3,6 +3,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; @@ -39,6 +41,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @Autowired private IRedisCatchStorage redisCatchStorage; + @Autowired + private VideoStreamSessionManager sessionManager; + @Override public void afterPropertiesSet() throws Exception { notifyMessageHandler.addHandler(cmdType, this); @@ -61,13 +66,19 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i String NotifyType =getText(rootElement, "NotifyType"); if (NotifyType.equals("121")){ logger.info("[录像流]推送完毕,收到关流通知"); - String channelId =getText(rootElement, "DeviceID"); // 查询是设备 - StreamInfo streamInfo = redisCatchStorage.queryDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); - // 设置进度100% - streamInfo.setProgress(1); - redisCatchStorage.startDownload(streamInfo, callIdHeader.getCallId()); - cmder.streamByeCmd(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); + StreamInfo streamInfo = redisCatchStorage.queryDownload(null, null, null, callIdHeader.getCallId()); + if (streamInfo != null) { + // 设置进度100% + streamInfo.setProgress(1); + redisCatchStorage.startDownload(streamInfo, callIdHeader.getCallId()); + } + + // 先从会话内查找 + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); + if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题 + cmder.streamByeCmd(device.getDeviceId(), ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); + } // TODO 如果级联播放,需要给上级发送此通知 } diff --git a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java index 787bdae9d..3235a49f0 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java @@ -1,7 +1,6 @@ package com.genersoft.iot.vmp.utils; -import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; From 0cd9a202428b185beea5b0c91c7f16d0996b5065 Mon Sep 17 00:00:00 2001 From: chenjialing <595168663@qq.com> Date: Fri, 27 May 2022 18:15:06 +0800 Subject: [PATCH 17/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D--=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=85=A8=E9=83=A8ssrc=E7=9A=84=E7=BC=93=E5=AD=98=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/gb28181/session/VideoStreamSessionManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index d8fdfad80..9925ae1fa 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -185,7 +185,7 @@ public class VideoStreamSessionManager { public List getAllSsrc() { - List ssrcTransactionKeys = redisUtil.scan(String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId() + "_" )); + List ssrcTransactionKeys = redisUtil.scan(String.format("%s*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId() + "_" )); List result= new ArrayList<>(); for (int i = 0; i < ssrcTransactionKeys.size(); i++) { String key = (String)ssrcTransactionKeys.get(i); From f09f1c9a2a3bb53c8d25ad5d82722129b0578be4 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 27 May 2022 18:23:43 +0800 Subject: [PATCH 18/59] =?UTF-8?q?=E6=8D=A2=E7=A7=8D=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/gb28181/session/VideoStreamSessionManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java index 9925ae1fa..a22d24d68 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java @@ -185,7 +185,7 @@ public class VideoStreamSessionManager { public List getAllSsrc() { - List ssrcTransactionKeys = redisUtil.scan(String.format("%s*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId() + "_" )); + List ssrcTransactionKeys = redisUtil.scan(String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId())); List result= new ArrayList<>(); for (int i = 0; i < ssrcTransactionKeys.size(); i++) { String key = (String)ssrcTransactionKeys.get(i); From 0e2908c1be4ba7d092b4cc4dbba6f6fc9481032e Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 27 May 2022 23:14:17 +0800 Subject: [PATCH 19/59] #488 --- .../event/request/impl/NotifyRequestProcessor.java | 9 ++++++++- .../notify/cmd/AlarmNotifyMessageHandler.java | 14 ++++++++++++-- .../vmanager/gb28181/alarm/AlarmController.java | 4 ++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java index e923a54a2..40b9a9ae1 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java @@ -18,6 +18,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils; import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil; import org.dom4j.DocumentException; import org.dom4j.Element; @@ -188,6 +189,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements Device device = redisCatchStorage.getDevice(deviceId); if (device == null) { + responseAck(evt, Response.NOT_FOUND, "device is not found"); return; } rootElement = getRootElement(evt, device.getCharset()); @@ -195,7 +197,12 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements deviceAlarm.setDeviceId(deviceId); deviceAlarm.setAlarmPriority(XmlUtil.getText(rootElement, "AlarmPriority")); deviceAlarm.setAlarmMethod(XmlUtil.getText(rootElement, "AlarmMethod")); - deviceAlarm.setAlarmTime(XmlUtil.getText(rootElement, "AlarmTime")); + String alarmTime = XmlUtil.getText(rootElement, "AlarmTime"); + if (alarmTime == null) { + responseAck(evt, Response.BAD_REQUEST, "AlarmTime cannot be null"); + return; + } + deviceAlarm.setAlarmTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(alarmTime)); if (XmlUtil.getText(rootElement, "AlarmDescription") == null) { deviceAlarm.setAlarmDescription(""); } else { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java index b7e222df0..6a23dfa13 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java @@ -9,9 +9,11 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessag import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; import com.genersoft.iot.vmp.gb28181.utils.Coordtransform; import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.service.IDeviceAlarmService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import com.genersoft.iot.vmp.utils.DateUtil; import org.dom4j.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -84,7 +86,11 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme deviceAlarm.setChannelId(channelId); deviceAlarm.setAlarmPriority(getText(rootElement, "AlarmPriority")); deviceAlarm.setAlarmMethod(getText(rootElement, "AlarmMethod")); - deviceAlarm.setAlarmTime(getText(rootElement, "AlarmTime")); + String alarmTime = XmlUtil.getText(rootElement, "AlarmTime"); + if (alarmTime == null) { + return; + } + deviceAlarm.setAlarmTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(alarmTime)); String alarmDescription = getText(rootElement, "AlarmDescription"); if (alarmDescription == null) { deviceAlarm.setAlarmDescription(""); @@ -175,7 +181,11 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme deviceAlarm.setChannelId(channelId); deviceAlarm.setAlarmPriority(getText(rootElement, "AlarmPriority")); deviceAlarm.setAlarmMethod(getText(rootElement, "AlarmMethod")); - deviceAlarm.setAlarmTime(getText(rootElement, "AlarmTime")); + String alarmTime = XmlUtil.getText(rootElement, "AlarmTime"); + if (alarmTime == null) { + return; + } + deviceAlarm.setAlarmTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(alarmTime)); String alarmDescription = getText(rootElement, "AlarmDescription"); if (alarmDescription == null) { deviceAlarm.setAlarmDescription(""); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java index 0edec5103..509c988c0 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java @@ -69,8 +69,8 @@ public class AlarmController { @ApiImplicitParam(name="alarmMethod", value = "查询内容" ,dataTypeClass = String.class), @ApiImplicitParam(name="alarmMethod", value = "查询内容" ,dataTypeClass = String.class), @ApiImplicitParam(name="alarmType", value = "查询内容" ,dataTypeClass = String.class), - @ApiImplicitParam(name="startTime", value = "查询内容" ,dataTypeClass = String.class), - @ApiImplicitParam(name="endTime", value = "查询内容" ,dataTypeClass = String.class), + @ApiImplicitParam(name="startTime", value = "开始时间" ,dataTypeClass = String.class), + @ApiImplicitParam(name="endTime", value = "结束时间" ,dataTypeClass = String.class), }) public ResponseEntity> getAll( @RequestParam int page, From cf35daeb98b7dc6e20f8fdab8e8c0202c369c78a Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 31 May 2022 15:54:39 +0800 Subject: [PATCH 20/59] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=A4=A7=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=B8=8B=E7=9A=84=E8=AE=BE=E5=A4=87=E6=A0=91=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_src/src/components/MediaServerManger.vue | 2 +- web_src/src/components/common/DeviceTree.vue | 24 +++++++++++++++----- web_src/src/layout/UiHeader.vue | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/web_src/src/components/MediaServerManger.vue b/web_src/src/components/MediaServerManger.vue index 2e3eeeffc..1d3c057ca 100644 --- a/web_src/src/components/MediaServerManger.vue +++ b/web_src/src/components/MediaServerManger.vue @@ -15,7 +15,7 @@ {{item.id}} 编辑 查看 - 移除 + 移除
{{item.ip}} {{item.createTime}} diff --git a/web_src/src/components/common/DeviceTree.vue b/web_src/src/components/common/DeviceTree.vue index 066c344c5..73618cc39 100644 --- a/web_src/src/components/common/DeviceTree.vue +++ b/web_src/src/components/common/DeviceTree.vue @@ -84,22 +84,34 @@ export default { }else { resolve([]) } + }, (list)=>{ + console.log("设备加载完成") }, (error)=>{ }) } if (node.level === 1) { - this.deviceService.getAllChannel(true, true, node.data.id, (catalogData) => { - this.deviceService.getAllChannel(false, true, node.data.id, (channelData) => { - let data = catalogData.concat(channelData) - this.channelDataHandler(data, resolve) + let channelArray = [] + this.deviceService.getAllChannel(true, true, node.data.id, catalogData =>{ + channelArray = channelArray.concat(catalogData) + this.channelDataHandler(channelArray, resolve) + },(endCatalogData) => { + this.deviceService.getAllChannel(false, true, node.data.id, channelData => { + channelArray = channelArray.concat(channelData) + this.channelDataHandler(channelArray, resolve) + }, endChannelList => { + }) }) }else if (node.level > 1){ + let channelArray = [] this.deviceService.getAllSubChannel(true, node.data.deviceId, node.data.id, (catalogData)=>{ + channelArray = channelArray.concat(catalogData) + this.channelDataHandler(channelArray, resolve) + }, (endCatalogData)=>{ this.deviceService.getAllSubChannel(false, node.data.deviceId, node.data.id, (channelData)=>{ - let data = catalogData.concat(channelData) - this.channelDataHandler(data, resolve) + channelArray = channelArray.concat(channelData) + this.channelDataHandler(channelArray, resolve) }) }) } diff --git a/web_src/src/layout/UiHeader.vue b/web_src/src/layout/UiHeader.vue index a0a252c2d..1e05d2125 100644 --- a/web_src/src/layout/UiHeader.vue +++ b/web_src/src/layout/UiHeader.vue @@ -3,7 +3,7 @@ 控制台 - 实时监控 + 分屏监控 国标设备 电子地图 推流列表 From 8555d64f95b154df07ce3bafaa842d90e72ea075 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 31 May 2022 16:20:46 +0800 Subject: [PATCH 21/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=82=B9=E6=92=AD?= =?UTF-8?q?=E8=B6=85=E6=97=B6=E7=9A=84=E4=BA=8B=E4=BB=B6=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transmit/event/request/impl/InviteRequestProcessor.java | 3 ++- .../com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index 2723da477..1afd7c14b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -235,7 +235,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements String username = sdp.getOrigin().getUsername(); String addressStr = sdp.getOrigin().getAddress(); - logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc); + logger.info("[上级点播]用户:{}, 通道:{}, 地址:{}:{}, ssrc:{}", username, channelId, addressStr, port, ssrc); Device device = null; // 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标 if (channel != null) { @@ -377,6 +377,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements // 写入redis, 超时时回复 redisCatchStorage.updateSendRTPSever(sendRtpItem); playService.play(mediaServerItem, ssrcInfo, device, channelId, hookEvent, errorEvent, (code, msg)->{ + logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId); redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); }, null); }else { diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index b16449290..bd1d9979d 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -257,7 +257,7 @@ public class PlayServiceImpl implements IPlayService { mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); } - }, userSetting.getPlayTimeout()*1000); + }, userSetting.getPlayTimeout()); final String ssrc = ssrcInfo.getSsrc(); final String stream = ssrcInfo.getStream(); cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> { @@ -433,7 +433,7 @@ public class PlayServiceImpl implements IPlayService { cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); // 回复之前所有的点播请求 playBackCallback.call(playBackResult); - }, userSetting.getPlayTimeout()*1000); + }, userSetting.getPlayTimeout()); cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack, (InviteStreamInfo inviteStreamInfo) -> { @@ -522,7 +522,7 @@ public class PlayServiceImpl implements IPlayService { cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null); // 回复之前所有的点播请求 hookCallBack.call(downloadResult); - }, userSetting.getPlayTimeout()*1000); + }, userSetting.getPlayTimeout()); cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack, inviteStreamInfo -> { logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString()); From 9a0ea9e3223b3da2943781edaf659ee3567848a1 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 1 Jun 2022 11:35:53 +0800 Subject: [PATCH 22/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BA=A7=E8=81=94?= =?UTF-8?q?=E7=82=B9=E6=92=AD=E6=97=B6=E6=B5=B7=E5=BA=B7=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89ssrc=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vmp/gb28181/transmit/cmd/impl/SIPCommander.java | 10 ++++------ .../transmit/cmd/impl/SIPCommanderFroPlatform.java | 11 +++-------- .../event/request/impl/InviteRequestProcessor.java | 2 +- .../iot/vmp/service/impl/PlayServiceImpl.java | 11 ++++++++--- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index f51437d19..9786ea479 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -715,12 +715,10 @@ public class SIPCommander implements ISIPCommander { } dialog = streamSession.getDialogByStream(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); } - if (ssrcTransaction != null) { - MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId()); - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc()); - mediaServerService.closeRTPServer(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); - } + MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId()); + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc()); + mediaServerService.closeRTPServer(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); if (dialog == null) { logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java index a4fd5079e..76aa4c87d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java @@ -31,6 +31,7 @@ import javax.sip.address.SipURI; import javax.sip.header.*; import javax.sip.message.Request; import java.lang.reflect.Field; +import java.net.InetAddress; import java.text.ParseException; import java.util.ArrayList; import java.util.HashSet; @@ -546,14 +547,8 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { } notifyRequest.addHeader(event); SipURI sipURI = (SipURI) notifyRequest.getRequestURI(); - if (subscribeInfo.getTransaction() != null) { - SIPRequest request = (SIPRequest) subscribeInfo.getTransaction().getRequest(); - sipURI.setHost(request.getRemoteAddress().getHostAddress()); - sipURI.setPort(request.getRemotePort()); - }else { - sipURI.setHost(parentPlatform.getServerIP()); - sipURI.setPort(parentPlatform.getServerPort()); - } + sipURI.setHost(parentPlatform.getServerIP()); + sipURI.setPort(parentPlatform.getServerPort()); ClientTransaction transaction = null; if ("TCP".equals(parentPlatform.getTransport())) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index 1afd7c14b..e43bf9d18 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -372,7 +372,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements if (mediaServerItem.isRtpEnable()) { streamId = String.format("%s_%s", device.getDeviceId(), channelId); } - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, true, false); + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false); sendRtpItem.setStreamId(ssrcInfo.getStream()); // 写入redis, 超时时回复 redisCatchStorage.updateSendRTPSever(sendRtpItem); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index bd1d9979d..811507d01 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -239,19 +239,20 @@ public class PlayServiceImpl implements IPlayService { if (ssrcInfo == null) { ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false); } - + logger.info("[点播开始] deviceId: {}, channelId: {}, SSRC: {}", device.getDeviceId(), channelId, ssrcInfo.getSsrc() ); // 超时处理 String timeOutTaskKey = UUID.randomUUID().toString(); SSRCInfo finalSsrcInfo = ssrcInfo; dynamicTask.startDelay( timeOutTaskKey,()->{ - logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", device.getDeviceId(), channelId)); SIPDialog dialog = streamSession.getDialogByStream(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); if (dialog != null) { + logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {}", device.getDeviceId(), channelId); timeoutCallback.run(1, "收流超时"); // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 cmder.streamByeCmd(device.getDeviceId(), channelId, finalSsrcInfo.getStream(), null); }else { + logger.info("[点播超时] 消息未响应 deviceId: {}, channelId: {}", device.getDeviceId(), channelId); timeoutCallback.run(0, "点播超时"); mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc()); mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream()); @@ -266,6 +267,8 @@ public class PlayServiceImpl implements IPlayService { // hook响应 onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid); hookEvent.response(mediaServerItemInuse, response); + logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); + }, (event) -> { ResponseEvent responseEvent = (ResponseEvent)event.event; String contentString = new String(responseEvent.getResponse().getRawContent()); @@ -279,8 +282,10 @@ public class PlayServiceImpl implements IPlayService { if (ssrc.equals(ssrcInResponse)) { return; } - logger.info("[SIP 消息] 收到invite 200, 发现下级自定义了ssrc 开启修正"); + logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse ); if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) { + logger.info("[SIP 消息] SSRC修正 {}->{}", ssrc, ssrcInResponse); + if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) { // ssrc 不可用 // 释放ssrc From ed2680bf032f76fde675897f7468f64e8b8d5a5e Mon Sep 17 00:00:00 2001 From: chenjialing <595168663@qq.com> Date: Wed, 1 Jun 2022 14:11:06 +0800 Subject: [PATCH 23/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D--=E9=87=8D=E8=AE=BE?= =?UTF-8?q?=E9=80=9A=E9=81=93=E5=A4=9A=E4=B8=AA=E8=AE=BE=E5=A4=87=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E4=B8=8B=E5=8F=91=E7=94=9F=E7=9A=84sql=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/storager/impl/VideoManagerStorageImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java index 3bb3d9f08..338bb7795 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java @@ -25,6 +25,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.util.*; @@ -195,7 +196,7 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @Override public boolean resetChannels(String deviceId, List deviceChannelList) { - if (deviceChannelList == null) { + if (CollectionUtils.isEmpty(deviceChannelList)) { return false; } List allChannelInPlay = deviceChannelMapper.getAllChannelInPlay(); @@ -246,6 +247,10 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { if (stringBuilder.length() > 0) { logger.info("[目录查询]收到的数据存在重复: {}" , stringBuilder); } + if(CollectionUtils.isEmpty(channels)){ + logger.info("通道重设,数据为空={}" , deviceChannelList); + return false; + } try { int cleanChannelsResult = deviceChannelMapper.cleanChannelsNotInList(deviceId, channels); int limitCount = 300; From 9ae0691c806b6b56306c2cda5509b0a0444cec06 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 2 Jun 2022 10:55:41 +0800 Subject: [PATCH 24/59] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BF=AB=E7=85=A7?= =?UTF-8?q?=E7=9A=84=E5=AD=98=E5=82=A8=E4=B8=8E=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vmp/media/zlm/ZLMHttpHookListener.java | 4 +- .../iot/vmp/media/zlm/ZLMRESTfulUtils.java | 2 +- .../iot/vmp/service/impl/PlayServiceImpl.java | 41 +++++--------- .../vmanager/gb28181/device/DeviceQuery.java | 19 +++++++ web_src/src/components/channelList.vue | 54 ++++++++++--------- 5 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index 3694fdf2b..32f42d877 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -91,10 +91,9 @@ public class ZLMHttpHookListener { public ResponseEntity onServerKeepalive(@RequestBody JSONObject json){ if (logger.isDebugEnabled()) { - logger.debug("[ ZLM HOOK ]on_server_keepalive API调用,参数:" + json.toString()); + logger.debug("[ ZLM HOOK ] on_server_keepalive API调用,参数:" + json.toString()); } String mediaServerId = json.getString("mediaServerId"); - List subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_keepalive); if (subscribes != null && subscribes.size() > 0) { for (ZLMHttpHookSubscribe.Event subscribe : subscribes) { @@ -164,7 +163,6 @@ public class ZLMHttpHookListener { if (mediaInfo != null) { subscribe.response(mediaInfo, json); } - } JSONObject ret = new JSONObject(); ret.put("code", 0); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java index 4b2bf487a..5caae66a6 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java @@ -151,7 +151,7 @@ public class ZLMRESTfulUtils { } } - File snapFile = new File(targetPath + "/" + fileName); + File snapFile = new File(targetPath + File.separator + fileName); FileOutputStream outStream = new FileOutputStream(snapFile); outStream.write(Objects.requireNonNull(response.body()).bytes()); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java index 811507d01..200c73161 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java @@ -123,36 +123,19 @@ public class PlayServiceImpl implements IPlayService { result.onCompletion(()->{ // 点播结束时调用截图接口 // TODO 应该在上流时调用更好,结束也可能是错误结束 - try { - String classPath = ResourceUtils.getURL("classpath:").getPath(); - // 兼容打包为jar的class路径 - if(classPath.contains("jar")) { - classPath = classPath.substring(0, classPath.lastIndexOf(".")); - classPath = classPath.substring(0, classPath.lastIndexOf("/") + 1); + String path = "snap"; + String fileName = deviceId + "_" + channelId + ".jpg"; + ResponseEntity responseEntity = (ResponseEntity)result.getResult(); + if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) { + WVPResult wvpResult = (WVPResult)responseEntity.getBody(); + if (Objects.requireNonNull(wvpResult).getCode() == 0) { + StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData(); + MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId()); + String streamUrl = streamInfoForSuccess.getFmp4(); + // 请求截图 + logger.info("[请求截图]: " + fileName); + zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName); } - if (classPath.startsWith("file:")) { - classPath = classPath.substring(classPath.indexOf(":") + 1); - } - String path = classPath + "static/static/snap/"; - // 兼容Windows系统路径(去除前面的“/”) - if(System.getProperty("os.name").contains("indows")) { - path = path.substring(1); - } - String fileName = deviceId + "_" + channelId + ".jpg"; - ResponseEntity responseEntity = (ResponseEntity)result.getResult(); - if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) { - WVPResult wvpResult = (WVPResult)responseEntity.getBody(); - if (Objects.requireNonNull(wvpResult).getCode() == 0) { - StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData(); - MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId()); - String streamUrl = streamInfoForSuccess.getFmp4(); - // 请求截图 - logger.info("[请求截图]: " + fileName); - zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName); - } - } - } catch (FileNotFoundException e) { - e.printStackTrace(); } }); if (streamInfo != null) { diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java index 3e538486e..cd5766697 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java @@ -21,16 +21,22 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; +import org.apache.commons.compress.utils.IOUtils; +import org.apache.http.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; +import javax.servlet.http.HttpServletResponse; import javax.sip.DialogState; +import java.io.*; +import java.nio.file.Files; import java.util.*; @Api(tags = "国标设备查询", value = "国标设备查询") @@ -456,4 +462,17 @@ public class DeviceQuery { wvpResult.setData(dialogStateMap); return wvpResult; } + + @GetMapping("/snap/{deviceId}/{channelId}") + @ApiOperation(value = "请求截图", notes = "请求截图") + public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId) { + + try { + final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + ".jpg").toPath()); + resp.setContentType(MediaType.IMAGE_PNG_VALUE); + IOUtils.copy(in, resp.getOutputStream()); + } catch (IOException e) { + resp.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + } } diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index 2d62e29df..832275a58 100644 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -39,21 +39,22 @@ @@ -227,7 +228,7 @@ export default { setTimeout(() => { let snapId = deviceId + "_" + channelId; - that.loadSnap[snapId] = 0; + that.loadSnap[deviceId + channelId] = 0; that.getSnapErrorEvent(snapId) }, 5000) that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { @@ -269,19 +270,24 @@ export default { }); }, getSnap: function (row) { - return '/static/snap/' + row.deviceId + '_' + row.channelId + '.jpg' + let url = (process.env.NODE_ENV === 'development'? "debug": "") + '/api/device/query/snap/' + row.deviceId + '/' + row.channelId + return url }, - getSnapErrorEvent: function (id) { + getBigSnap: function (row) { + return [this.getSnap(row)] + }, + getSnapErrorEvent: function (deviceId, channelId) { - if (typeof (this.loadSnap[id]) != "undefined") { - console.log("下载截图" + this.loadSnap[id]) - if (this.loadSnap[id] > 5) { - delete this.loadSnap[id]; + if (typeof (this.loadSnap[deviceId + channelId]) != "undefined") { + console.log("下载截图" + this.loadSnap[deviceId + channelId]) + if (this.loadSnap[deviceId + channelId] > 5) { + delete this.loadSnap[deviceId + channelId]; return; } setTimeout(() => { - this.loadSnap[id]++ - document.getElementById(id).setAttribute("src", '/static/snap/' + id + '.jpg?' + new Date().getTime()) + let url = (process.env.NODE_ENV === 'development'? "debug": "") + '/api/device/query/snap/' + deviceId + '/' + channelId + this.loadSnap[deviceId + channelId]++ + document.getElementById(deviceId + channelId).setAttribute("src", url + '?' + new Date().getTime()) }, 1000) } From d88c95f40916b8e6306f092114adb0fae1a51c4f Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 2 Jun 2022 16:01:50 +0800 Subject: [PATCH 25/59] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20DOCKERFILE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCKERFILE | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DOCKERFILE b/DOCKERFILE index d55e06a74..f2a2ffa01 100644 --- a/DOCKERFILE +++ b/DOCKERFILE @@ -1,3 +1,6 @@ +#很久没维护了,已经与定前版本不匹配 + + FROM ubuntu:20.04 AS build ARG DEBIAN_FRONTEND=noninteractive From 47abdde3392f2c5fd88d382ae63c4756b97ed4b0 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 3 Jun 2022 16:24:11 +0800 Subject: [PATCH 26/59] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E4=B8=8A=E7=BA=BF=E5=81=9C=E6=AD=A2=E7=BA=BF=E7=A8=8B=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E6=8A=A5=E9=94=99=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=BD=95=E5=83=8F=E7=9A=84=E8=8E=B7=E5=8F=96=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E9=80=9A=E9=81=93=E7=9A=84=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/conf/DynamicTask.java | 12 +- .../vmp/gb28181/bean/HandlerCatchData.java | 44 +++++ .../iot/vmp/gb28181/bean/SubscribeHolder.java | 15 +- .../subscribe/catalog/CatalogEventLister.java | 2 +- .../transmit/SIPProcessorObserver.java | 18 +-- .../transmit/cmd/impl/SIPCommander.java | 7 +- .../request/impl/NotifyRequestProcessor.java | 99 +++++++----- .../cmd/CatalogResponseMessageHandler.java | 141 +++++++++------- .../cmd/RecordInfoResponseMessageHandler.java | 151 ++++++++++-------- .../vmp/service/impl/DeviceServiceImpl.java | 26 ++- .../vmanager/gb28181/device/DeviceQuery.java | 5 + 11 files changed, 331 insertions(+), 189 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/HandlerCatchData.java diff --git a/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java b/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java index 3b021de41..ade2e6220 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java @@ -103,12 +103,12 @@ public class DynamicTask { public void stop(String key) { if (futureMap.get(key) != null && !futureMap.get(key).isCancelled()) { - futureMap.get(key).cancel(true); - Runnable runnable = runnableMap.get(key); - if (runnable instanceof ISubscribeTask) { - ISubscribeTask subscribeTask = (ISubscribeTask) runnable; - subscribeTask.stop(); - } +// Runnable runnable = runnableMap.get(key); +// if (runnable instanceof ISubscribeTask) { +// ISubscribeTask subscribeTask = (ISubscribeTask) runnable; +// subscribeTask.stop(); +// } + futureMap.get(key).cancel(false); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HandlerCatchData.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HandlerCatchData.java new file mode 100644 index 000000000..97da8630c --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HandlerCatchData.java @@ -0,0 +1,44 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import org.dom4j.Element; + +import javax.sip.RequestEvent; + +/** + * @author lin + */ +public class HandlerCatchData { + private RequestEvent evt; + private Device device; + private Element rootElement; + + public HandlerCatchData(RequestEvent evt, Device device, Element rootElement) { + this.evt = evt; + this.device = device; + this.rootElement = rootElement; + } + + public RequestEvent getEvt() { + return evt; + } + + public void setEvt(RequestEvent evt) { + this.evt = evt; + } + + public Device getDevice() { + return device; + } + + public void setDevice(Device device) { + this.device = device; + } + + public Element getRootElement() { + return rootElement; + } + + public void setRootElement(Element rootElement) { + this.rootElement = rootElement; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java index f191c005e..4a900c164 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.bean; import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.DynamicTask; +import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -38,7 +39,6 @@ public class SubscribeHolder { catalogMap.put(platformId, subscribeInfo); // 添加订阅到期 String taskOverdueKey = taskOverduePrefix + "catalog_" + platformId; - dynamicTask.stop(taskOverdueKey); // 添加任务处理订阅过期 dynamicTask.startDelay(taskOverdueKey, () -> removeCatalogSubscribe(subscribeInfo.getId()), subscribeInfo.getExpires() * 1000); @@ -49,10 +49,17 @@ public class SubscribeHolder { } public void removeCatalogSubscribe(String platformId) { + catalogMap.remove(platformId); String taskOverdueKey = taskOverduePrefix + "catalog_" + platformId; + Runnable runnable = dynamicTask.get(taskOverdueKey); + if (runnable instanceof ISubscribeTask) { + ISubscribeTask subscribeTask = (ISubscribeTask) runnable; + subscribeTask.stop(); + } // 添加任务处理订阅过期 dynamicTask.stop(taskOverdueKey); + } public void putMobilePositionSubscribe(String platformId, SubscribeInfo subscribeInfo) { @@ -63,7 +70,6 @@ public class SubscribeHolder { storager, platformId, subscribeInfo.getSn(), key, this, dynamicTask), subscribeInfo.getGpsInterval() * 1000); String taskOverdueKey = taskOverduePrefix + "MobilePosition_" + platformId; - dynamicTask.stop(taskOverdueKey); // 添加任务处理订阅过期 dynamicTask.startDelay(taskOverdueKey, () -> { removeMobilePositionSubscribe(subscribeInfo.getId()); @@ -81,6 +87,11 @@ public class SubscribeHolder { // 结束任务处理GPS定时推送 dynamicTask.stop(key); String taskOverdueKey = taskOverduePrefix + "MobilePosition_" + platformId; + Runnable runnable = dynamicTask.get(taskOverdueKey); + if (runnable instanceof ISubscribeTask) { + ISubscribeTask subscribeTask = (ISubscribeTask) runnable; + subscribeTask.stop(); + } // 添加任务处理订阅过期 dynamicTask.stop(taskOverdueKey); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java index 7e5ecb495..e38733d5b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java @@ -66,7 +66,7 @@ public class CatalogEventLister implements ApplicationListener { subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId()); if (subscribe == null) { - logger.info("发送订阅消息时发现订阅信息已经不存在"); + logger.info("发送订阅消息时发现订阅信息已经不存在: {}", event.getPlatformId()); return; } }else { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java index a06a73d03..a2fab8138 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java @@ -150,30 +150,24 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { public void processTimeout(TimeoutEvent timeoutEvent) { logger.info("[消息发送超时]"); ClientTransaction clientTransaction = timeoutEvent.getClientTransaction(); - eventPublisher.requestTimeOut(timeoutEvent); + if (clientTransaction != null) { + logger.info("[发送错误订阅] clientTransaction != null"); Request request = clientTransaction.getRequest(); if (request != null) { + logger.info("[发送错误订阅] request != null"); CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); if (callIdHeader != null) { + logger.info("[发送错误订阅]"); SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()); SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(timeoutEvent); subscribe.response(eventResult); + sipSubscribe.removeOkSubscribe(callIdHeader.getCallId()); sipSubscribe.removeErrorSubscribe(callIdHeader.getCallId()); } } } - -// Timeout timeout = timeoutEvent.getTimeout(); -// ServerTransaction serverTransaction = timeoutEvent.getServerTransaction(); -// if (serverTransaction != null) { -// Request request = serverTransaction.getRequest(); -// URI requestURI = request.getRequestURI(); -// Header header = request.getHeader(FromHeader.NAME); -// } -// if(timeoutProcessor != null) { -// timeoutProcessor.process(timeoutEvent); -// } + eventPublisher.requestTimeOut(timeoutEvent); } @Override diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 9786ea479..2bb0307c2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -1487,7 +1487,6 @@ public class SIPCommander implements ISIPCommander { Request request; if (dialog != null) { - logger.info("发送移动位置订阅消息时 dialog的状态为: {}", dialog.getState()); request = dialog.createRequest(Request.SUBSCRIBE); ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); request.setContent(subscribePostitionXml.toString(), contentTypeHeader); @@ -1583,12 +1582,12 @@ public class SIPCommander implements ISIPCommander { Request request; if (dialog != null) { - logger.info("发送目录订阅消息时 dialog的状态为: {}", dialog.getState()); request = dialog.createRequest(Request.SUBSCRIBE); + ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForCatalog()); + request.setExpires(expiresHeader); + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); request.setContent(cmdXml.toString(), contentTypeHeader); - ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForMobilePosition()); - request.addHeader(expireHeader); }else { String tm = Long.toString(System.currentTimeMillis()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java index 40b9a9ae1..38a724656 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java @@ -1,7 +1,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; import com.alibaba.fastjson.JSONObject; -import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.*; @@ -26,6 +25,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -36,6 +37,7 @@ import javax.sip.header.FromHeader; import javax.sip.message.Response; import java.text.ParseException; import java.util.Iterator; +import java.util.concurrent.ConcurrentLinkedQueue; /** * SIP命令类型: NOTIFY请求 @@ -64,11 +66,19 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @Autowired private EventPublisher publisher; - private String method = "NOTIFY"; + private final String method = "NOTIFY"; @Autowired private SIPProcessorObserver sipProcessorObserver; + private boolean taskQueueHandlerRun = false; + + private final ConcurrentLinkedQueue taskQueue = new ConcurrentLinkedQueue<>(); + + @Qualifier("taskExecutor") + @Autowired + private ThreadPoolTaskExecutor taskExecutor; + @Override public void afterPropertiesSet() throws Exception { // 添加消息处理的订阅 @@ -78,23 +88,40 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @Override public void process(RequestEvent evt) { try { - Element rootElement = getRootElement(evt); - String cmd = XmlUtil.getText(rootElement, "CmdType"); - if (CmdType.CATALOG.equals(cmd)) { - logger.info("接收到Catalog通知"); - processNotifyCatalogList(evt); - } else if (CmdType.ALARM.equals(cmd)) { - logger.info("接收到Alarm通知"); - processNotifyAlarm(evt); - } else if (CmdType.MOBILE_POSITION.equals(cmd)) { - logger.info("接收到MobilePosition通知"); - processNotifyMobilePosition(evt); - } else { - logger.info("接收到消息:" + cmd); - responseAck(evt, Response.OK); + taskQueue.offer(new HandlerCatchData(evt, null, null)); + responseAck(evt, Response.OK); + if (!taskQueueHandlerRun) { + taskQueueHandlerRun = true; + taskExecutor.execute(()-> { + while (!taskQueue.isEmpty()) { + try { + HandlerCatchData take = taskQueue.poll(); + Element rootElement = getRootElement(take.getEvt()); + String cmd = XmlUtil.getText(rootElement, "CmdType"); + + if (CmdType.CATALOG.equals(cmd)) { + logger.info("接收到Catalog通知"); + processNotifyCatalogList(take.getEvt()); + } else if (CmdType.ALARM.equals(cmd)) { + logger.info("接收到Alarm通知"); + processNotifyAlarm(take.getEvt()); + } else if (CmdType.MOBILE_POSITION.equals(cmd)) { + logger.info("接收到MobilePosition通知"); + processNotifyMobilePosition(take.getEvt()); + } else { + logger.info("接收到消息:" + cmd); + } + } catch (DocumentException e) { + throw new RuntimeException(e); + } + } + taskQueueHandlerRun = false; + }); } - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + + + } catch (SipException | InvalidArgumentException | ParseException e) { e.printStackTrace(); } } @@ -167,8 +194,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements jsonObject.put("direction", mobilePosition.getDirection()); jsonObject.put("speed", mobilePosition.getSpeed()); redisCatchStorage.sendMobilePositionMsg(jsonObject); - responseAck(evt, Response.OK); - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + } catch (DocumentException e) { e.printStackTrace(); } } @@ -189,7 +215,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements Device device = redisCatchStorage.getDevice(deviceId); if (device == null) { - responseAck(evt, Response.NOT_FOUND, "device is not found"); + logger.warn("[ NotifyAlarm ] 未找到设备:{}", deviceId); return; } rootElement = getRootElement(evt, device.getCharset()); @@ -199,7 +225,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements deviceAlarm.setAlarmMethod(XmlUtil.getText(rootElement, "AlarmMethod")); String alarmTime = XmlUtil.getText(rootElement, "AlarmTime"); if (alarmTime == null) { - responseAck(evt, Response.BAD_REQUEST, "AlarmTime cannot be null"); + logger.warn("[ NotifyAlarm ] AlarmTime cannot be null"); return; } deviceAlarm.setAlarmTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(alarmTime)); @@ -219,7 +245,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements deviceAlarm.setLatitude(0.00); } logger.info("[收到Notify-Alarm]:{}/{}", device.getDeviceId(), deviceAlarm.getChannelId()); - if (deviceAlarm.getAlarmMethod().equals("4")) { + if ("4".equals(deviceAlarm.getAlarmMethod())) { MobilePosition mobilePosition = new MobilePosition(); mobilePosition.setDeviceId(deviceAlarm.getDeviceId()); mobilePosition.setTime(deviceAlarm.getAlarmTime()); @@ -240,11 +266,10 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements // TODO: 需要实现存储报警信息、报警分类 // 回复200 OK - responseAck(evt, Response.OK); if (redisCatchStorage.deviceIsOnline(deviceId)) { publisher.deviceAlarmEventPublish(deviceAlarm); } - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + } catch (DocumentException e) { e.printStackTrace(); } } @@ -280,64 +305,60 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements continue; } Element eventElement = itemDevice.element("Event"); + String event; + if (eventElement == null) { + logger.warn("[收到 目录订阅]:{}, 但是Event为空, 设为默认值 ADD", (device != null ? device.getDeviceId():"" )); + event = CatalogEvent.ADD; + }else { + event = eventElement.getText().toUpperCase(); + } DeviceChannel channel = XmlUtil.channelContentHander(itemDevice); channel.setDeviceId(device.getDeviceId()); logger.info("[收到 目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId()); - switch (eventElement.getText().toUpperCase()) { + switch (event) { case CatalogEvent.ON: // 上线 logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId()); storager.deviceChannelOnline(deviceId, channel.getChannelId()); - // 回复200 OK - responseAck(evt, Response.OK); break; case CatalogEvent.OFF : // 离线 logger.info("收到来自设备【{}】的通道【{}】离线通知", device.getDeviceId(), channel.getChannelId()); storager.deviceChannelOffline(deviceId, channel.getChannelId()); - // 回复200 OK - responseAck(evt, Response.OK); break; case CatalogEvent.VLOST: // 视频丢失 logger.info("收到来自设备【{}】的通道【{}】视频丢失通知", device.getDeviceId(), channel.getChannelId()); storager.deviceChannelOffline(deviceId, channel.getChannelId()); - // 回复200 OK - responseAck(evt, Response.OK); break; case CatalogEvent.DEFECT: // 故障 - // 回复200 OK - responseAck(evt, Response.OK); break; case CatalogEvent.ADD: // 增加 logger.info("收到来自设备【{}】的增加通道【{}】通知", device.getDeviceId(), channel.getChannelId()); storager.updateChannel(deviceId, channel); - responseAck(evt, Response.OK); break; case CatalogEvent.DEL: // 删除 logger.info("收到来自设备【{}】的删除通道【{}】通知", device.getDeviceId(), channel.getChannelId()); storager.delChannel(deviceId, channel.getChannelId()); - responseAck(evt, Response.OK); break; case CatalogEvent.UPDATE: // 更新 logger.info("收到来自设备【{}】的更新通道【{}】通知", device.getDeviceId(), channel.getChannelId()); storager.updateChannel(deviceId, channel); - responseAck(evt, Response.OK); break; default: - responseAck(evt, Response.BAD_REQUEST, "event not found"); + logger.warn("[ NotifyCatalog ] event not found : {}", event ); } // 转发变化信息 - eventPublisher.catalogEventPublish(null, channel, eventElement.getText().toUpperCase()); + eventPublisher.catalogEventPublish(null, channel, event); } } - } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) { + } catch (DocumentException e) { e.printStackTrace(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java index 891b21da4..0fe317ae8 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java @@ -20,6 +20,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -31,6 +33,7 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; @Component public class CatalogResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { @@ -38,9 +41,13 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp private Logger logger = LoggerFactory.getLogger(CatalogResponseMessageHandler.class); private final String cmdType = "Catalog"; + private boolean taskQueueHandlerRun = false; + @Autowired private ResponseMessageHandler responseMessageHandler; + private ConcurrentLinkedQueue taskQueue = new ConcurrentLinkedQueue<>(); + @Autowired private IVideoManagerStorage storager; @@ -63,6 +70,10 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp @Autowired private IRedisCatchStorage redisCatchStorage; + @Qualifier("taskExecutor") + @Autowired + private ThreadPoolTaskExecutor taskExecutor; + @Override public void afterPropertiesSet() throws Exception { responseMessageHandler.addHandler(cmdType, this); @@ -70,68 +81,88 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp @Override public void handForDevice(RequestEvent evt, Device device, Element element) { - String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + device.getDeviceId(); - Element rootElement = null; + taskQueue.offer(new HandlerCatchData(evt, device, element)); + // 回复200 OK try { - rootElement = getRootElement(evt, device.getCharset()); - Element deviceListElement = rootElement.element("DeviceList"); - Element sumNumElement = rootElement.element("SumNum"); - Element snElement = rootElement.element("SN"); - if (snElement == null || sumNumElement == null || deviceListElement == null) { - responseAck(evt, Response.BAD_REQUEST, "xml error"); - return; - } - int sumNum = Integer.parseInt(sumNumElement.getText()); - - if (sumNum == 0) { - // 数据已经完整接收 - storager.cleanChannelsForDevice(device.getDeviceId()); - catalogDataCatch.setChannelSyncEnd(device.getDeviceId(), null); - }else { - Iterator deviceListIterator = deviceListElement.elementIterator(); - if (deviceListIterator != null) { - List channelList = new ArrayList<>(); - // 遍历DeviceList - while (deviceListIterator.hasNext()) { - Element itemDevice = deviceListIterator.next(); - Element channelDeviceElement = itemDevice.element("DeviceID"); - if (channelDeviceElement == null) { - continue; + responseAck(evt, Response.OK); + } catch (SipException e) { + throw new RuntimeException(e); + } catch (InvalidArgumentException e) { + throw new RuntimeException(e); + } catch (ParseException e) { + throw new RuntimeException(e); + } + if (!taskQueueHandlerRun) { + taskQueueHandlerRun = true; + taskExecutor.execute(()-> { + while (!taskQueue.isEmpty()) { + HandlerCatchData take = taskQueue.poll(); + String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + take.getDevice().getDeviceId(); + Element rootElement = null; + try { + rootElement = getRootElement(take.getEvt(), take.getDevice().getCharset()); + Element deviceListElement = rootElement.element("DeviceList"); + Element sumNumElement = rootElement.element("SumNum"); + Element snElement = rootElement.element("SN"); + if (snElement == null || sumNumElement == null || deviceListElement == null) { + responseAck(take.getEvt(), Response.BAD_REQUEST, "xml error"); + return; } - //by brewswang -// if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {//如果包含位置信息,就更新一下位置 -// processNotifyMobilePosition(evt, itemDevice); -// } - DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice); - deviceChannel.setDeviceId(device.getDeviceId()); + int sumNum = Integer.parseInt(sumNumElement.getText()); - channelList.add(deviceChannel); - } - int sn = Integer.parseInt(snElement.getText()); - catalogDataCatch.put(device.getDeviceId(), sn, sumNum, device, channelList); - logger.info("收到来自设备【{}】的通道: {}个,{}/{}", device.getDeviceId(), channelList.size(), catalogDataCatch.get(device.getDeviceId()) == null ? 0 :catalogDataCatch.get(device.getDeviceId()).size(), sumNum); - if (catalogDataCatch.get(device.getDeviceId()).size() == sumNum) { - // 数据已经完整接收 - boolean resetChannelsResult = storager.resetChannels(device.getDeviceId(), catalogDataCatch.get(device.getDeviceId())); - if (!resetChannelsResult) { - String errorMsg = "接收成功,写入失败,共" + sumNum + "条,已接收" + catalogDataCatch.get(device.getDeviceId()).size() + "条"; - catalogDataCatch.setChannelSyncEnd(device.getDeviceId(), errorMsg); + if (sumNum == 0) { + // 数据已经完整接收 + storager.cleanChannelsForDevice(take.getDevice().getDeviceId()); + catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null); }else { - catalogDataCatch.setChannelSyncEnd(device.getDeviceId(), null); + Iterator deviceListIterator = deviceListElement.elementIterator(); + if (deviceListIterator != null) { + List channelList = new ArrayList<>(); + // 遍历DeviceList + while (deviceListIterator.hasNext()) { + Element itemDevice = deviceListIterator.next(); + Element channelDeviceElement = itemDevice.element("DeviceID"); + if (channelDeviceElement == null) { + continue; + } + //by brewswang + // if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {//如果包含位置信息,就更新一下位置 + // processNotifyMobilePosition(evt, itemDevice); + // } + DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice); + deviceChannel.setDeviceId(take.getDevice().getDeviceId()); + + channelList.add(deviceChannel); + } + int sn = Integer.parseInt(snElement.getText()); + catalogDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, take.getDevice(), channelList); + logger.info("收到来自设备【{}】的通道: {}个,{}/{}", take.getDevice().getDeviceId(), channelList.size(), catalogDataCatch.get(take.getDevice().getDeviceId()) == null ? 0 :catalogDataCatch.get(take.getDevice().getDeviceId()).size(), sumNum); + if (catalogDataCatch.get(take.getDevice().getDeviceId()).size() == sumNum) { + // 数据已经完整接收 + boolean resetChannelsResult = storager.resetChannels(take.getDevice().getDeviceId(), catalogDataCatch.get(take.getDevice().getDeviceId())); + if (!resetChannelsResult) { + String errorMsg = "接收成功,写入失败,共" + sumNum + "条,已接收" + catalogDataCatch.get(take.getDevice().getDeviceId()).size() + "条"; + catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), errorMsg); + }else { + catalogDataCatch.setChannelSyncEnd(take.getDevice().getDeviceId(), null); + } + } + } + } + } catch (DocumentException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } catch (SipException e) { + e.printStackTrace(); } } - // 回复200 OK - responseAck(evt, Response.OK); - } - } catch (DocumentException e) { - e.printStackTrace(); - } catch (InvalidArgumentException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } catch (SipException e) { - e.printStackTrace(); + taskQueueHandlerRun = false; + }); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java index 1f701715b..87adc3efc 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java @@ -1,9 +1,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; -import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; -import com.genersoft.iot.vmp.gb28181.bean.RecordItem; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.session.RecordDataCatch; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; @@ -19,6 +16,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -28,6 +27,9 @@ import javax.sip.SipException; import javax.sip.message.Response; import java.text.ParseException; import java.util.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.LinkedBlockingQueue; import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; @@ -42,6 +44,9 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent private final String cmdType = "RecordInfo"; private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_"; + private ConcurrentLinkedQueue taskQueue = new ConcurrentLinkedQueue<>(); + + private boolean taskQueueHandlerRun = false; @Autowired private ResponseMessageHandler responseMessageHandler; @@ -51,11 +56,13 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent @Autowired private DeferredResultHolder deferredResultHolder; - - @Autowired private EventPublisher eventPublisher; + @Qualifier("taskExecutor") + @Autowired + private ThreadPoolTaskExecutor taskExecutor; + @Override public void afterPropertiesSet() throws Exception { responseMessageHandler.addHandler(cmdType, this); @@ -67,75 +74,89 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent // 回复200 OK try { responseAck(evt, Response.OK); + taskQueue.offer(new HandlerCatchData(evt, device, rootElement)); + if (!taskQueueHandlerRun) { + taskQueueHandlerRun = true; + taskExecutor.execute(()->{ + try { + while (!taskQueue.isEmpty()) { + HandlerCatchData take = taskQueue.poll(); + Element rootElementForCharset = getRootElement(take.getEvt(), take.getDevice().getCharset()); + String sn = getText(rootElementForCharset, "SN"); + String channelId = getText(rootElementForCharset, "DeviceID"); + RecordInfo recordInfo = new RecordInfo(); + recordInfo.setChannelId(channelId); + recordInfo.setDeviceId(take.getDevice().getDeviceId()); + recordInfo.setSn(sn); + recordInfo.setName(getText(rootElementForCharset, "Name")); + String sumNumStr = getText(rootElementForCharset, "SumNum"); + int sumNum = 0; + if (!StringUtils.isEmpty(sumNumStr)) { + sumNum = Integer.parseInt(sumNumStr); + } + recordInfo.setSumNum(sumNum); + Element recordListElement = rootElementForCharset.element("RecordList"); + if (recordListElement == null || sumNum == 0) { + logger.info("无录像数据"); + eventPublisher.recordEndEventPush(recordInfo); + recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, new ArrayList<>()); + releaseRequest(take.getDevice().getDeviceId(), sn); + } else { + Iterator recordListIterator = recordListElement.elementIterator(); + if (recordListIterator != null) { + List recordList = new ArrayList<>(); + // 遍历DeviceList + while (recordListIterator.hasNext()) { + Element itemRecord = recordListIterator.next(); + Element recordElement = itemRecord.element("DeviceID"); + if (recordElement == null) { + logger.info("记录为空,下一个..."); + continue; + } + RecordItem record = new RecordItem(); + record.setDeviceId(getText(itemRecord, "DeviceID")); + record.setName(getText(itemRecord, "Name")); + record.setFilePath(getText(itemRecord, "FilePath")); + record.setFileSize(getText(itemRecord, "FileSize")); + record.setAddress(getText(itemRecord, "Address")); - rootElement = getRootElement(evt, device.getCharset()); - String sn = getText(rootElement, "SN"); - RecordInfo recordInfo = new RecordInfo(); - recordInfo.setDeviceId(device.getDeviceId()); - recordInfo.setSn(sn); - recordInfo.setName(getText(rootElement, "Name")); - String sumNumStr = getText(rootElement, "SumNum"); - int sumNum = 0; - if (!StringUtils.isEmpty(sumNumStr)) { - sumNum = Integer.parseInt(sumNumStr); - } - recordInfo.setSumNum(sumNum); - Element recordListElement = rootElement.element("RecordList"); - if (recordListElement == null || sumNum == 0) { - logger.info("无录像数据"); - eventPublisher.recordEndEventPush(recordInfo); - recordDataCatch.put(device.getDeviceId(), sn, sumNum, new ArrayList<>()); - releaseRequest(device.getDeviceId(), sn); - } else { - Iterator recordListIterator = recordListElement.elementIterator(); - if (recordListIterator != null) { - List recordList = new ArrayList<>(); - // 遍历DeviceList - while (recordListIterator.hasNext()) { - Element itemRecord = recordListIterator.next(); - Element recordElement = itemRecord.element("DeviceID"); - if (recordElement == null) { - logger.info("记录为空,下一个..."); - continue; + String startTimeStr = getText(itemRecord, "StartTime"); + record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr)); + + String endTimeStr = getText(itemRecord, "EndTime"); + record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr)); + + record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 + : Integer.parseInt(getText(itemRecord, "Secrecy"))); + record.setType(getText(itemRecord, "Type")); + record.setRecorderId(getText(itemRecord, "RecorderID")); + recordList.add(record); + } + recordInfo.setRecordList(recordList); + // 发送消息,如果是上级查询此录像,则会通过这里通知给上级 + eventPublisher.recordEndEventPush(recordInfo); + int count = recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, recordList); + logger.info("[国标录像], {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum); + } + + if (recordDataCatch.isComplete(take.getDevice().getDeviceId(), sn)){ + releaseRequest(take.getDevice().getDeviceId(), sn); + } + } } - RecordItem record = new RecordItem(); - record.setDeviceId(getText(itemRecord, "DeviceID")); - record.setName(getText(itemRecord, "Name")); - record.setFilePath(getText(itemRecord, "FilePath")); - record.setFileSize(getText(itemRecord, "FileSize")); - record.setAddress(getText(itemRecord, "Address")); - - String startTimeStr = getText(itemRecord, "StartTime"); - record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr)); - - String endTimeStr = getText(itemRecord, "EndTime"); - record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr)); - - record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 - : Integer.parseInt(getText(itemRecord, "Secrecy"))); - record.setType(getText(itemRecord, "Type")); - record.setRecorderId(getText(itemRecord, "RecorderID")); - recordList.add(record); + taskQueueHandlerRun = false; + }catch (DocumentException e) { + throw new RuntimeException(e); } - recordInfo.setRecordList(recordList); - // 发送消息,如果是上级查询此录像,则会通过这里通知给上级 - eventPublisher.recordEndEventPush(recordInfo); - int count = recordDataCatch.put(device.getDeviceId(), sn, sumNum, recordList); - logger.info("[国标录像], {}->{}: {}/{}", device.getDeviceId(), sn, count, sumNum); - } - - if (recordDataCatch.isComplete(device.getDeviceId(), sn)){ - releaseRequest(device.getDeviceId(), sn); - } + }); } + } catch (SipException e) { e.printStackTrace(); } catch (InvalidArgumentException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); - } catch (DocumentException e) { - e.printStackTrace(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java index 77c7c617a..3359b00fc 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java @@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; +import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler; import com.genersoft.iot.vmp.service.IDeviceService; @@ -95,7 +96,6 @@ public class DeviceServiceImpl implements IDeviceService { } // 刷新过期任务 String registerExpireTaskKey = registerExpireTaskKeyPrefix + device.getDeviceId(); - dynamicTask.stop(registerExpireTaskKey); dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId()), device.getExpires() * 1000); } @@ -144,8 +144,16 @@ public class DeviceServiceImpl implements IDeviceService { if (device == null || device.getSubscribeCycleForCatalog() < 0) { return false; } - logger.info("移除目录订阅: {}", device.getDeviceId()); - dynamicTask.stop(device.getDeviceId() + "catalog"); + logger.info("[移除目录订阅]: {}", device.getDeviceId()); + String taskKey = device.getDeviceId() + "catalog"; + if (device.getOnline() == 1) { + Runnable runnable = dynamicTask.get(taskKey); + if (runnable instanceof ISubscribeTask) { + ISubscribeTask subscribeTask = (ISubscribeTask) runnable; + subscribeTask.stop(); + } + } + dynamicTask.stop(taskKey); return true; } @@ -169,8 +177,16 @@ public class DeviceServiceImpl implements IDeviceService { if (device == null || device.getSubscribeCycleForCatalog() < 0) { return false; } - logger.info("移除移动位置订阅: {}", device.getDeviceId()); - dynamicTask.stop(device.getDeviceId() + "mobile_position"); + logger.info("[移除移动位置订阅]: {}", device.getDeviceId()); + String taskKey = device.getDeviceId() + "mobile_position"; + if (device.getOnline() == 1) { + Runnable runnable = dynamicTask.get(taskKey); + if (runnable instanceof ISubscribeTask) { + ISubscribeTask subscribeTask = (ISubscribeTask) runnable; + subscribeTask.stop(); + } + } + dynamicTask.stop(taskKey); return true; } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java index cd5766697..d313c6b02 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java @@ -206,6 +206,11 @@ public class DeviceQuery { Set allKeys = dynamicTask.getAllKeys(); for (String key : allKeys) { if (key.startsWith(deviceId)) { + Runnable runnable = dynamicTask.get(key); + if (runnable instanceof ISubscribeTask) { + ISubscribeTask subscribeTask = (ISubscribeTask) runnable; + subscribeTask.stop(); + } dynamicTask.stop(key); } } From acac24f0dbf39b02ddd3aba89753d7abb412cb6b Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 3 Jun 2022 17:07:19 +0800 Subject: [PATCH 27/59] =?UTF-8?q?okhttp-digest=E7=9A=84Maven=E4=BB=93?= =?UTF-8?q?=E5=BA=93=E8=B0=83=E6=95=B4=20#506?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9ad41c7f1..bd5269ad0 100644 --- a/pom.xml +++ b/pom.xml @@ -181,9 +181,9 @@ - com.burgstaller + io.github.rburgst okhttp-digest - 2.1 + 2.5 From 19a52a20f358b22211dde9da9d25b65c9cbaddcf Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 3 Jun 2022 18:52:40 +0800 Subject: [PATCH 28/59] =?UTF-8?q?=E5=9B=BA=E5=AE=9A=E6=97=B6=E5=8C=BA?= =?UTF-8?q?=E4=B8=BAAsia/Shanghai?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/ISIPCommanderForPlatform.java | 8 ++ .../cmd/impl/SIPCommanderFroPlatform.java | 117 +++++++++++++----- .../request/impl/InviteRequestProcessor.java | 4 +- .../cmd/MediaStatusNotifyMessageHandler.java | 22 +++- .../com/genersoft/iot/vmp/utils/DateUtil.java | 8 +- 5 files changed, 118 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java index 7007e5a60..d000f5afb 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java @@ -103,6 +103,14 @@ public interface ISIPCommanderForPlatform { */ boolean recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo); + /** + * 录像播放推送完成时发送MediaStatus消息 + * @param platform + * @param sendRtpItem + * @return + */ + boolean sendMediaStatusNotify(ParentPlatform platform, SendRtpItem sendRtpItem); + /** * 向发起点播的上级回复bye * @param platform 平台信息 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java index 76aa4c87d..6c06bd3a9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java @@ -745,6 +745,56 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { return true; } + @Override + public boolean sendMediaStatusNotify(ParentPlatform platform, SendRtpItem sendRtpItem) { + if (sendRtpItem == null) { + return false; + } + if (platform == null) { + return false; + } + + byte[] dialogByteArray = sendRtpItem.getDialog(); + if (dialogByteArray == null) { + return false; + } + try{ + SIPDialog dialog = (SIPDialog) SerializeUtils.deSerialize(dialogByteArray); + SIPRequest messageRequest = (SIPRequest)dialog.createRequest(Request.MESSAGE); + String characterSet = platform.getCharacterSet(); + StringBuffer mediaStatusXml = new StringBuffer(200); + mediaStatusXml.append("\r\n"); + mediaStatusXml.append("\r\n"); + mediaStatusXml.append("MediaStatus\r\n"); + mediaStatusXml.append("" + (int)((Math.random()*9+1)*100000) + "\r\n"); + mediaStatusXml.append("" + sendRtpItem.getChannelId() + "\r\n"); + mediaStatusXml.append("121\r\n"); + mediaStatusXml.append("\r\n"); + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); + messageRequest.setContent(mediaStatusXml.toString(), contentTypeHeader); + SipURI sipURI = (SipURI) messageRequest.getRequestURI(); + sipURI.setHost(platform.getServerIP()); + sipURI.setPort(platform.getServerPort()); + + ClientTransaction transaction = null; + if ("TCP".equals(platform.getTransport())) { + transaction = tcpSipProvider.getNewClientTransaction(messageRequest); + } else if ("UDP".equals(platform.getTransport())) { + transaction = udpSipProvider.getNewClientTransaction(messageRequest); + } + transaction.sendRequest(); + } catch (SipException e) { + e.printStackTrace(); + return false; + } catch (ParseException e) { + e.printStackTrace(); + return false; + } + return true; + + + } + @Override public void streamByeCmd(ParentPlatform platform, String callId) { if (platform == null) { @@ -765,41 +815,40 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog); if (dialog != sipDialog) { dialog = sipDialog; - } else { - try { - dialog.setSipProvider(udpSipProvider); - Field sipStackField = SIPDialog.class.getDeclaredField("sipStack"); - sipStackField.setAccessible(true); - sipStackField.set(dialog, sipStack); - Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners"); - eventListenersField.setAccessible(true); - eventListenersField.set(dialog, new HashSet<>()); - - byte[] transactionByteArray = sendRtpItem.getTransaction(); - ClientTransaction clientTransaction = (ClientTransaction) SerializeUtils.deSerialize(transactionByteArray); - Request byeRequest = dialog.createRequest(Request.BYE); - - SipURI byeURI = (SipURI) byeRequest.getRequestURI(); - SIPRequest request = (SIPRequest) clientTransaction.getRequest(); - byeURI.setHost(request.getRemoteAddress().getHostAddress()); - byeURI.setPort(request.getRemotePort()); - if ("TCP".equals(platform.getTransport())) { - clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest); - } else if ("UDP".equals(platform.getTransport())) { - clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); - } - dialog.sendRequest(clientTransaction); - } catch (SipException e) { - e.printStackTrace(); - } catch (ParseException e) { - e.printStackTrace(); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } + try { + dialog.setSipProvider(udpSipProvider); + Field sipStackField = SIPDialog.class.getDeclaredField("sipStack"); + sipStackField.setAccessible(true); + sipStackField.set(dialog, sipStack); + Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners"); + eventListenersField.setAccessible(true); + eventListenersField.set(dialog, new HashSet<>()); + + byte[] transactionByteArray = sendRtpItem.getTransaction(); + ClientTransaction clientTransaction = (ClientTransaction) SerializeUtils.deSerialize(transactionByteArray); + Request byeRequest = dialog.createRequest(Request.BYE); + + SipURI byeURI = (SipURI) byeRequest.getRequestURI(); + SIPRequest request = (SIPRequest) clientTransaction.getRequest(); + byeURI.setHost(request.getRemoteAddress().getHostAddress()); + byeURI.setPort(request.getRemotePort()); + if ("TCP".equals(platform.getTransport())) { + clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest); + } else if ("UDP".equals(platform.getTransport())) { + clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); + } + dialog.sendRequest(clientTransaction); + } catch (SipException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index e43bf9d18..d967fb949 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -188,8 +188,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements startTime = startTimeFiled.getStartTime(); stopTime = startTimeFiled.getStopTime(); - start = Instant.ofEpochMilli(startTime*1000); - end = Instant.ofEpochMilli(stopTime*1000); + start = Instant.ofEpochSecond(startTime); + end = Instant.ofEpochSecond(stopTime); } // 获取支持的格式 Vector mediaDescriptions = sdp.getMediaDescriptions(true); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java index 5cb39734d..b758227e9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java @@ -3,13 +3,16 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import org.dom4j.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,9 +41,15 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @Autowired private SIPCommander cmder; + @Autowired + private SIPCommanderFroPlatform sipCommanderFroPlatform; + @Autowired private IRedisCatchStorage redisCatchStorage; + @Autowired + private IVideoManagerStorage storage; + @Autowired private VideoStreamSessionManager sessionManager; @@ -64,7 +73,7 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i } CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); String NotifyType =getText(rootElement, "NotifyType"); - if (NotifyType.equals("121")){ + if ("121".equals(NotifyType)){ logger.info("[录像流]推送完毕,收到关流通知"); // 查询是设备 StreamInfo streamInfo = redisCatchStorage.queryDownload(null, null, null, callIdHeader.getCallId()); @@ -78,8 +87,17 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题 cmder.streamByeCmd(device.getDeviceId(), ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); + // 如果级联播放,需要给上级发送此通知 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); + if (sendRtpItem != null) { + ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); + if (parentPlatform == null) { + logger.warn("[级联消息发送]:发送MediaStatus发现上级平台{}不存在", sendRtpItem.getPlatformId()); + return; + } + sipCommanderFroPlatform.sendMediaStatusNotify(parentPlatform, sendRtpItem); + } } - // TODO 如果级联播放,需要给上级发送此通知 } } diff --git a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java index 3235a49f0..494bcbbb0 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java @@ -32,12 +32,14 @@ public class DateUtil { */ public static final String PATTERN = "yyyy-MM-dd HH:mm:ss"; + public static final String zoneStr = "Asia/Shanghai"; - public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.systemDefault()); - public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.systemDefault()); - public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.systemDefault()); + public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); + public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { + return formatterISO8601.format(formatter.parse(formatTime)); } From 5df95ba8500540ef5a033512a685b69822e84585 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Sat, 4 Jun 2022 00:02:39 +0800 Subject: [PATCH 29/59] =?UTF-8?q?=E7=BA=A7=E8=81=94=E5=9B=9E=E6=94=BE?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0MediaStatus=E6=B6=88=E6=81=AF=20#377?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cmd/impl/SIPCommanderFroPlatform.java | 61 ++++++++++++++----- .../request/impl/AckRequestProcessor.java | 6 ++ .../request/impl/InviteRequestProcessor.java | 5 +- .../cmd/MediaStatusNotifyMessageHandler.java | 6 +- 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java index 6c06bd3a9..be67e7c60 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java @@ -760,6 +760,29 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { } try{ SIPDialog dialog = (SIPDialog) SerializeUtils.deSerialize(dialogByteArray); + SipStack sipStack; + if ("TCP".equals(platform.getTransport())) { + sipStack = tcpSipProvider.getSipStack(); + } else { + sipStack = udpSipProvider.getSipStack(); + } + SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog); + if (dialog != sipDialog) { + dialog = sipDialog; + } + if ("TCP".equals(platform.getTransport())) { + dialog.setSipProvider(tcpSipProvider); + } else { + dialog.setSipProvider(udpSipProvider); + } + + Field sipStackField = SIPDialog.class.getDeclaredField("sipStack"); + sipStackField.setAccessible(true); + sipStackField.set(dialog, sipStack); + Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners"); + eventListenersField.setAccessible(true); + eventListenersField.set(dialog, new HashSet<>()); + SIPRequest messageRequest = (SIPRequest)dialog.createRequest(Request.MESSAGE); String characterSet = platform.getCharacterSet(); StringBuffer mediaStatusXml = new StringBuffer(200); @@ -775,20 +798,23 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { SipURI sipURI = (SipURI) messageRequest.getRequestURI(); sipURI.setHost(platform.getServerIP()); sipURI.setPort(platform.getServerPort()); - - ClientTransaction transaction = null; + ClientTransaction clientTransaction; if ("TCP".equals(platform.getTransport())) { - transaction = tcpSipProvider.getNewClientTransaction(messageRequest); - } else if ("UDP".equals(platform.getTransport())) { - transaction = udpSipProvider.getNewClientTransaction(messageRequest); + clientTransaction = tcpSipProvider.getNewClientTransaction(messageRequest); + }else { + clientTransaction = udpSipProvider.getNewClientTransaction(messageRequest); } - transaction.sendRequest(); + dialog.sendRequest(clientTransaction); } catch (SipException e) { e.printStackTrace(); return false; } catch (ParseException e) { e.printStackTrace(); return false; + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); } return true; @@ -811,13 +837,22 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { byte[] dialogByteArray = sendRtpItem.getDialog(); if (dialogByteArray != null) { SIPDialog dialog = (SIPDialog) SerializeUtils.deSerialize(dialogByteArray); - SipStack sipStack = udpSipProvider.getSipStack(); + SipStack sipStack; + if ("TCP".equals(platform.getTransport())) { + sipStack = tcpSipProvider.getSipStack(); + } else { + sipStack = udpSipProvider.getSipStack(); + } SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog); if (dialog != sipDialog) { dialog = sipDialog; } try { - dialog.setSipProvider(udpSipProvider); + if ("TCP".equals(platform.getTransport())) { + dialog.setSipProvider(tcpSipProvider); + } else { + dialog.setSipProvider(udpSipProvider); + } Field sipStackField = SIPDialog.class.getDeclaredField("sipStack"); sipStackField.setAccessible(true); sipStackField.set(dialog, sipStack); @@ -825,17 +860,15 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { eventListenersField.setAccessible(true); eventListenersField.set(dialog, new HashSet<>()); - byte[] transactionByteArray = sendRtpItem.getTransaction(); - ClientTransaction clientTransaction = (ClientTransaction) SerializeUtils.deSerialize(transactionByteArray); Request byeRequest = dialog.createRequest(Request.BYE); SipURI byeURI = (SipURI) byeRequest.getRequestURI(); - SIPRequest request = (SIPRequest) clientTransaction.getRequest(); - byeURI.setHost(request.getRemoteAddress().getHostAddress()); - byeURI.setPort(request.getRemotePort()); + byeURI.setHost(platform.getServerIP()); + byeURI.setPort(platform.getServerPort()); + ClientTransaction clientTransaction; if ("TCP".equals(platform.getTransport())) { clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest); - } else if ("UDP".equals(platform.getTransport())) { + } else { clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); } dialog.sendRequest(clientTransaction); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java index af61ed3fa..b3d67dedf 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java @@ -18,6 +18,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; import com.genersoft.iot.vmp.service.IMediaServerService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; +import com.genersoft.iot.vmp.utils.SerializeUtils; import org.ehcache.shadow.org.terracotta.offheapstore.storage.IntegerStorageEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -118,6 +119,11 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In logger.error("RTP推流失败: 请检查ZLM服务"); } else if (jsonObject.getInteger("code") == 0) { logger.info("RTP推流成功[ {}/{} ],{}->{}:{}, " ,param.get("app"), param.get("stream"), jsonObject.getString("local_port"), param.get("dst_url"), param.get("dst_port")); + byte[] dialogByteArray = SerializeUtils.serialize(evt.getDialog()); + sendRtpItem.setDialog(dialogByteArray); + byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction()); + sendRtpItem.setTransaction(transactionByteArray); + redisCatchStorage.updateSendRTPSever(sendRtpItem); } else { logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"),JSONObject.toJSON(param)); if (sendRtpItem.isOnlyAudio()) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index d967fb949..75b4114d5 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -264,10 +264,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements } sendRtpItem.setCallId(callIdHeader.getCallId()); sendRtpItem.setPlayType("Play".equals(sessionName)?InviteStreamType.PLAY:InviteStreamType.PLAYBACK); - byte[] dialogByteArray = SerializeUtils.serialize(evt.getDialog()); - sendRtpItem.setDialog(dialogByteArray); - byte[] transactionByteArray = SerializeUtils.serialize(evt.getServerTransaction()); - sendRtpItem.setTransaction(transactionByteArray); + Long finalStartTime = startTime; Long finalStopTime = stopTime; ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON)->{ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java index b758227e9..8a5ef793c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java @@ -87,8 +87,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题 cmder.streamByeCmd(device.getDeviceId(), ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); - // 如果级联播放,需要给上级发送此通知 - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, callIdHeader.getCallId()); + + // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, ssrcTransaction.getChannelId(), null, null); if (sendRtpItem != null) { ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(sendRtpItem.getPlatformId()); if (parentPlatform == null) { @@ -98,7 +99,6 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i sipCommanderFroPlatform.sendMediaStatusNotify(parentPlatform, sendRtpItem); } } - } } From d3e815bf16541884cf998bda9ae7bcd5b29b87e2 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Sat, 4 Jun 2022 10:18:04 +0800 Subject: [PATCH 30/59] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AE=A2=E9=98=85?= =?UTF-8?q?=E8=B6=85=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transmit/cmd/impl/SIPCommander.java | 24 +++++++++++++++++-- .../impl/SubscribeRequestProcessor.java | 4 +++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 2bb0307c2..0363c912c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -32,7 +32,9 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.sip.*; +import javax.sip.address.Address; import javax.sip.address.SipURI; +import javax.sip.address.URI; import javax.sip.header.*; import javax.sip.message.Request; import java.lang.reflect.Field; @@ -1487,11 +1489,20 @@ public class SIPCommander implements ISIPCommander { Request request; if (dialog != null) { + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); request = dialog.createRequest(Request.SUBSCRIBE); + ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForCatalog()); + request.setExpires(expiresHeader); + + request.setRequestURI(requestURI); + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); request.setContent(subscribePostitionXml.toString(), contentTypeHeader); - ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForMobilePosition()); - request.addHeader(expireHeader); + + CSeqHeader cSeqHeader = (CSeqHeader)request.getHeader(CSeqHeader.NAME); + cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ(Request.SUBSCRIBE)); + request.removeHeader(CSeqHeader.NAME); + request.addHeader(cSeqHeader); }else { String tm = Long.toString(System.currentTimeMillis()); CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() @@ -1582,12 +1593,21 @@ public class SIPCommander implements ISIPCommander { Request request; if (dialog != null) { + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); request = dialog.createRequest(Request.SUBSCRIBE); ExpiresHeader expiresHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForCatalog()); request.setExpires(expiresHeader); + request.setRequestURI(requestURI); + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); request.setContent(cmdXml.toString(), contentTypeHeader); + + CSeqHeader cSeqHeader = (CSeqHeader)request.getHeader(CSeqHeader.NAME); + cSeqHeader.setSeqNumber(redisCatchStorage.getCSEQ(Request.SUBSCRIBE)); + request.removeHeader(CSeqHeader.NAME); + request.addHeader(cSeqHeader); + }else { String tm = Long.toString(System.currentTimeMillis()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java index 548dbde82..4d618d102 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java @@ -82,7 +82,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme @Override public void process(RequestEvent evt) { Request request = evt.getRequest(); - + System.out.println("收到订阅"); try { Element rootElement = getRootElement(evt); String cmd = XmlUtil.getText(rootElement, "CmdType"); @@ -176,6 +176,8 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme } private void processNotifyCatalogList(RequestEvent evt, Element rootElement) throws SipException { + + System.out.println(evt.getRequest().toString()); String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); String deviceId = XmlUtil.getText(rootElement, "DeviceID"); ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); From cba2e6b90b50c208e3354d4561b40576a251c370 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Sat, 4 Jun 2022 23:18:01 +0800 Subject: [PATCH 31/59] =?UTF-8?q?=E4=BC=98=E5=8C=96wasm=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E5=99=A8=E5=86=85=E5=AD=98=E5=8D=A0=E7=94=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_src/src/components/common/jessibuca.vue | 76 ++++++++++----------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/web_src/src/components/common/jessibuca.vue b/web_src/src/components/common/jessibuca.vue index 2eda2dc82..2701a228e 100644 --- a/web_src/src/components/common/jessibuca.vue +++ b/web_src/src/components/common/jessibuca.vue @@ -23,11 +23,11 @@ "}) List queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online); From c827d1518bc30e76259f59186ef10bfc8a989294 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Mon, 13 Jun 2022 23:02:53 +0800 Subject: [PATCH 33/59] =?UTF-8?q?#510=20jessibuca=E5=88=86=E5=B1=8F?= =?UTF-8?q?=E7=9B=91=E6=8E=A7=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_src/src/components/common/jessibuca.vue | 35 +++++++++++---------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/web_src/src/components/common/jessibuca.vue b/web_src/src/components/common/jessibuca.vue index 2701a228e..7ab0b9308 100644 --- a/web_src/src/components/common/jessibuca.vue +++ b/web_src/src/components/common/jessibuca.vue @@ -23,7 +23,7 @@ "}) int update(DeviceChannel channel); @@ -138,7 +142,8 @@ public interface DeviceChannelMapper { "insert into device_channel " + "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " + " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " + - " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, createTime, updateTime) " + + " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " + + " longitudeWgs84, latitudeWgs84, createTime, updateTime) " + "values " + " " + "('${item.channelId}', '${item.deviceId}', '${item.name}', '${item.manufacture}', '${item.model}', " + @@ -146,7 +151,8 @@ public interface DeviceChannelMapper { "'${item.address}', ${item.parental}, '${item.parentId}', ${item.safetyWay}, ${item.registerWay}, " + "'${item.certNum}', ${item.certifiable}, ${item.errCode}, '${item.secrecy}', " + "'${item.ipAddress}', ${item.port}, '${item.password}', ${item.PTZType}, ${item.status}, " + - "'${item.streamId}', ${item.longitude}, ${item.latitude},'${item.createTime}', '${item.updateTime}')" + + "'${item.streamId}', ${item.longitude}, ${item.latitude},${item.longitudeGcj02}, " + + "${item.latitudeGcj02},${item.longitudeWgs84}, ${item.latitudeWgs84},'${item.createTime}', '${item.updateTime}')" + " " + "ON DUPLICATE KEY UPDATE " + "updateTime=VALUES(updateTime), " + @@ -173,7 +179,11 @@ public interface DeviceChannelMapper { "status=VALUES(status), " + "streamId=VALUES(streamId), " + "longitude=VALUES(longitude), " + - "latitude=VALUES(latitude)" + + "latitude=VALUES(latitude), " + + "longitudeGcj02=VALUES(longitudeGcj02), " + + "latitudeGcj02=VALUES(latitudeGcj02), " + + "longitudeWgs84=VALUES(longitudeWgs84), " + + "latitudeWgs84=VALUES(latitudeWgs84) " + "") int batchAdd(List addChannels); @@ -207,7 +217,11 @@ public interface DeviceChannelMapper { ", hasAudio=${item.hasAudio}" + ", longitude=${item.longitude}" + ", latitude=${item.latitude}" + - "WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}"+ + ", longitudeGcj02=${item.longitudeGcj02}" + + ", latitudeGcj02=${item.latitudeGcj02}" + + ", longitudeWgs84=${item.longitudeWgs84}" + + ", latitudeWgs84=${item.latitudeWgs84}" + + "WHERE deviceId='${item.deviceId}' AND channelId='${item.channelId}'"+ "" + ""}) int batchUpdate(List updateChannels); @@ -261,4 +275,6 @@ public interface DeviceChannelMapper { @Select("SELECT * FROM device_channel WHERE length(trim(streamId)) > 0") List getAllChannelInPlay(); + @Select("select * from device_channel where longitude*latitude > 0 and deviceId = #{deviceId}") + List getAllChannelWithCoordinate(String deviceId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java index 37d951e20..3e15b7392 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java @@ -38,6 +38,7 @@ public interface DeviceMapper { "mobilePositionSubmissionInterval," + "subscribeCycleForAlarm," + "ssrcCheck," + + "geoCoordSys," + "online" + ") VALUES (" + "#{deviceId}," + @@ -61,6 +62,7 @@ public interface DeviceMapper { "#{mobilePositionSubmissionInterval}," + "#{subscribeCycleForAlarm}," + "#{ssrcCheck}," + + "#{geoCoordSys}," + "#{online}" + ")") int add(Device device); @@ -87,6 +89,7 @@ public interface DeviceMapper { ", mobilePositionSubmissionInterval=${mobilePositionSubmissionInterval}" + ", subscribeCycleForAlarm=${subscribeCycleForAlarm}" + ", ssrcCheck=${ssrcCheck}" + + ", geoCoordSys=#{geoCoordSys}" + "WHERE deviceId='${deviceId}'"+ " "}) int update(Device device); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java index d313c6b02..4c8953783 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java @@ -317,12 +317,7 @@ public class DeviceQuery { public ResponseEntity> updateDevice(Device device){ if (device != null && device.getDeviceId() != null) { - - - // TODO 报警订阅相关的信息 - deviceService.updateDevice(device); -// cmder.deviceInfoQuery(device); } WVPResult result = new WVPResult<>(); result.setCode(0); diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java index d4928ec7f..3be4be3e7 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java @@ -146,8 +146,8 @@ public class ApiDeviceController { // 2-基于口令的双向认证, // 3-基于数字证书的双向认证 deviceJOSNChannel.put("Status", deviceChannel.getStatus()); - deviceJOSNChannel.put("Longitude", deviceChannel.getLongitude()); - deviceJOSNChannel.put("Latitude", deviceChannel.getLatitude()); + deviceJOSNChannel.put("Longitude", deviceChannel.getLongitudeWgs84()); + deviceJOSNChannel.put("Latitude", deviceChannel.getLatitudeWgs84()); deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球, // 3 - 固定枪机, 4 - 遥控枪机 deviceJOSNChannel.put("CustomPTZType", ""); diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml index 1233a890a..9dedcb143 100644 --- a/src/main/resources/all-application.yml +++ b/src/main/resources/all-application.yml @@ -32,7 +32,7 @@ spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false + url: jdbc:mysql://127.0.0.1:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true username: root password: root123 druid: diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 353143146..35ddc86ce 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -20,7 +20,7 @@ spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false + url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true username: root password: 123456 druid: diff --git a/src/main/resources/application-docker.yml b/src/main/resources/application-docker.yml index 1653a5868..53a863560 100644 --- a/src/main/resources/application-docker.yml +++ b/src/main/resources/application-docker.yml @@ -20,7 +20,7 @@ spring: datasource: # 使用mysql 打开23-28行注释, 删除29-36行 name: wvp - url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true&useSSL=false + url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true&useSSL=false&allowMultiQueries=true username: root password: root type: com.alibaba.druid.pool.DruidDataSource diff --git a/web_src/src/components/dialog/deviceEdit.vue b/web_src/src/components/dialog/deviceEdit.vue index b4dd28556..233fa5671 100644 --- a/web_src/src/components/dialog/deviceEdit.vue +++ b/web_src/src/components/dialog/deviceEdit.vue @@ -36,6 +36,12 @@ + + + + + + diff --git a/web_src/src/components/devicePosition.vue b/web_src/src/components/map.vue similarity index 93% rename from web_src/src/components/devicePosition.vue rename to web_src/src/components/map.vue index db196779f..caf36d4ab 100644 --- a/web_src/src/components/devicePosition.vue +++ b/web_src/src/components/map.vue @@ -49,7 +49,7 @@ import devicePlayer from './dialog/devicePlayer.vue' import queryTrace from './dialog/queryTrace.vue' export default { - name: "devicePosition", + name: "map", components: { MapComponent, DeviceTree, @@ -183,12 +183,27 @@ export default { this.clean() this.closeInfoBox() let params = []; + let longitudeStr; + let latitudeStr; + if (window.mapParam.coordinateSystem == "GCJ-02") { + longitudeStr = "longitudeGcj02"; + latitudeStr = "latitudeGcj02"; + }else if (window.mapParam.coordinateSystem == "WGS84") { + longitudeStr = "longitudeWgs84"; + latitudeStr = "latitudeWgs84"; + }else { + longitudeStr = "longitude"; + latitudeStr = "latitude"; + } + for (let i = 0; i < channels.length; i++) { - if (channels[i].longitude * channels[i].latitude === 0) { + let longitude = channels[i][longitudeStr]; + let latitude = channels[i][latitudeStr]; + if (longitude * latitude === 0) { continue; } let item = { - position: [channels[i].longitude, channels[i].latitude], + position: [longitude, latitude], image: { src: this.getImageByChannel(channels[i]), anchor: [0.5, 1] @@ -202,7 +217,7 @@ export default { this.layer = this.$refs.map.addLayer(params, this.featureClickEvent) console.log(4) if (params.length === 1) { - this.$refs.map.panTo([channels[0].longitude, channels[0].latitude], mapParam.maxZoom) + this.$refs.map.panTo([channels[0][longitudeStr], channels[0][latitudeStr]], mapParam.maxZoom) } else if (params.length > 1) { this.$refs.map.fit(this.layer) } else { diff --git a/web_src/src/router/index.js b/web_src/src/router/index.js index 88448621f..2f44fd854 100644 --- a/web_src/src/router/index.js +++ b/web_src/src/router/index.js @@ -7,7 +7,7 @@ import deviceList from '../components/DeviceList.vue' import channelList from '../components/channelList.vue' import pushVideoList from '../components/PushVideoList.vue' import streamProxyList from '../components/StreamProxyList.vue' -import devicePosition from '../components/devicePosition.vue' +import map from '../components/map.vue' import login from '../components/Login.vue' import parentPlatformList from '../components/ParentPlatformList.vue' import cloudRecord from '../components/CloudRecord.vue' @@ -69,9 +69,9 @@ export default new VueRouter({ component: parentPlatformList, }, { - path: '/devicePosition/:deviceId/:parentChannelId/:count/:page', - name: 'devicePosition', - component: devicePosition, + path: '/map/:deviceId/:parentChannelId/:count/:page', + name: 'map', + component: map, }, { path: '/cloudRecord', @@ -100,8 +100,8 @@ export default new VueRouter({ }, { path: '/map', - name: 'devicePosition', - component: devicePosition, + name: 'map', + component: map, }, ] }, From 9ce6045f56e2b458f96d91dbfaa6694a53258c43 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 14 Jun 2022 17:28:56 +0800 Subject: [PATCH 38/59] =?UTF-8?q?=E6=9B=B4=E6=96=B0README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b8b985c7..1c5f868ba 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,8 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git - [X] 云端录像(需要部署单独服务配合使用) - [X] 多流媒体节点,自动选择负载最低的节点使用。 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。 +- [X] 支持电子地图。 +- [X] 支持接入WGS84和GCJ02两种坐标系。 [//]: # (# docker快速体验) @@ -143,7 +145,7 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git # 合作 目前很多打着合作的幌子来私聊的,其实大家大可不必,目前作者没有精力,你有问题可以付费找我解答,也可以提PR -,如果对代码有建议可以提ISSUE;也可以加群一起聊聊。我们欢迎所有有兴趣但遇到项目中来的人。 +,如果对代码有建议可以提ISSUE;也可以加群一起聊聊。我们欢迎所有有兴趣参与到项目中来的人。 From 31a8e6ea89a08ca5c3460e6158b3d635dddef0ac Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 14 Jun 2022 17:46:53 +0800 Subject: [PATCH 39/59] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_src/src/components/channelList.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index 832275a58..60f3112f8 100644 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -63,7 +63,8 @@ From c801ee62184d13acc4c5d6bd2d9586dca13306fc Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 14 Jun 2022 23:16:58 +0800 Subject: [PATCH 40/59] =?UTF-8?q?=E8=B0=83=E6=95=B4=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_src/src/App.vue | 6 ++- web_src/src/components/DeviceList.vue | 51 +++++++++--------- web_src/src/components/channelList.vue | 71 ++++++++++++-------------- web_src/src/layout/UiHeader.vue | 10 +++- 4 files changed, 72 insertions(+), 66 deletions(-) diff --git a/web_src/src/App.vue b/web_src/src/App.vue index 3590f7377..4ae7ea84d 100644 --- a/web_src/src/App.vue +++ b/web_src/src/App.vue @@ -76,7 +76,7 @@ body, line-height: 60px; } .el-main { - background-color: #e9eef3; + background-color: #f0f2f5; color: #333; text-align: center; padding-top: 0px !important; @@ -101,4 +101,8 @@ body, box-shadow: inset 0 0 6px rgba(0, 0, 0, .1); -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .1); } +.table-header { + color: #727272; + font-weight: 600; +} diff --git a/web_src/src/components/DeviceList.vue b/web_src/src/components/DeviceList.vue index 62cba31fb..d268b8a34 100644 --- a/web_src/src/components/DeviceList.vue +++ b/web_src/src/components/DeviceList.vue @@ -9,21 +9,21 @@
- - + + - + - + - + - + - + - + - + - + - + - + - + @@ -347,4 +349,5 @@ export default { padding: 0.3rem; width: 14.4rem; } + diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index 60f3112f8..f0888c1bd 100644 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -32,49 +32,42 @@ - + - + - + - + - + - + - - + + - +