From 4ad711f61a1a760a0f8f7f8475b75ec93e31d8ae Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 13 Jun 2024 16:21:34 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/impl/NotifyRequestForCatalogProcessor.java | 8 ++++---- .../impl/NotifyRequestForMobilePositionProcessor.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java index 6185cda4..155d5f73 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java @@ -315,8 +315,8 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent } } - @Scheduled(fixedRate = 10000) //每1秒执行一次 - public void execute(){ - logger.info("[待处理Notify-目录订阅消息数量]: {}", taskQueue.size()); - } +// @Scheduled(fixedRate = 10000) //每1秒执行一次 +// public void execute(){ +// logger.info("[待处理Notify-目录订阅消息数量]: {}", taskQueue.size()); +// } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java index c8111778..75a3b0d2 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForMobilePositionProcessor.java @@ -188,8 +188,8 @@ public class NotifyRequestForMobilePositionProcessor extends SIPRequestProcessor } taskQueue.clear(); } - @Scheduled(fixedRate = 10000) - public void execute(){ - logger.info("[待处理Notify-移动位置订阅消息数量]: {}", taskQueue.size()); - } +// @Scheduled(fixedRate = 10000) +// public void execute(){ +// logger.debug("[待处理Notify-移动位置订阅消息数量]: {}", taskQueue.size()); +// } } From f3ea07bdcd722d667e16b7a880f41a30b9374732 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 14 Jun 2024 17:03:55 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=BD=AC=E7=A0=81?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E6=B5=81=E7=9A=84=E8=BE=93=E5=87=BA=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/genersoft/iot/vmp/common/StreamInfo.java | 11 +++++++++++ .../iot/vmp/service/impl/MediaServiceImpl.java | 12 ++++++++---- .../iot/vmp/vmanager/bean/StreamContent.java | 14 ++++++++++++++ src/main/resources/application.yml | 2 +- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java index 979f54a5..2d940347 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java @@ -83,6 +83,9 @@ public class StreamInfo implements Serializable, Cloneable{ @Schema(description = "是否暂停(录像回放使用)") private boolean pause; + @Schema(description = "转码后的视频流") + private StreamInfo transcodeStream; + public void setFlv(StreamURL flv) { this.flv = flv; } @@ -521,6 +524,14 @@ public class StreamInfo implements Serializable, Cloneable{ this.transactionInfo = transactionInfo; } + public StreamInfo getTranscodeStream() { + return transcodeStream; + } + + public void setTranscodeStream(StreamInfo transcodeStream) { + this.transcodeStream = transcodeStream; + } + @Override public StreamInfo clone() { StreamInfo instance = null; diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java index ead5052e..d68261bd 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java @@ -95,10 +95,6 @@ public class MediaServiceImpl implements IMediaService { if (addr == null) { addr = mediaInfo.getStreamIp(); } - if (!"broadcast".equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaInfo.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaInfo.getTranscodeSuffix())) { - stream = stream + "_" + mediaInfo.getTranscodeSuffix(); -// streamInfoResult.setStream(stream); - } streamInfoResult.setIp(addr); streamInfoResult.setMediaServerId(mediaInfo.getId()); @@ -112,6 +108,14 @@ public class MediaServiceImpl implements IMediaService { streamInfoResult.setRtc(addr, mediaInfo.getHttpPort(),mediaInfo.getHttpSSlPort(), app, stream, callIdParam, isPlay); streamInfoResult.setTracks(tracks); + + if (!"broadcast".equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaInfo.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaInfo.getTranscodeSuffix())) { + String newStream = stream + "_" + mediaInfo.getTranscodeSuffix(); + mediaInfo.setTranscodeSuffix(null); + StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaInfo, app, newStream, tracks, addr, callId, isPlay); + streamInfoResult.setTranscodeStream(transcodeStreamInfo); + } + return streamInfoResult; } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java index 4974209a..f9857385 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java @@ -97,6 +97,9 @@ public class StreamContent { @Schema(description = "文件下载地址(录像下载使用)") private DownloadFileInfo downLoadFilePath; + @Schema(description = "转码后的视频流") + private StreamContent transcodeStream; + private double progress; public StreamContent(StreamInfo streamInfo) { @@ -178,6 +181,17 @@ public class StreamContent { if (streamInfo.getDownLoadFilePath() != null) { this.downLoadFilePath = streamInfo.getDownLoadFilePath(); } + if (streamInfo.getTranscodeStream() != null) { + this.transcodeStream = new StreamContent(streamInfo.getTranscodeStream()); + } + } + + public StreamContent getTranscodeStream() { + return transcodeStream; + } + + public void setTranscodeStream(StreamContent transcodeStream) { + this.transcodeStream = transcodeStream; } public String getApp() { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3f478442..ddb05dee 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,4 +2,4 @@ spring: application: name: wvp profiles: - active: local \ No newline at end of file + active: local271 \ No newline at end of file From 107caf11710ee07e511da47312f748339e003fb2 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 14 Jun 2024 17:24:57 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=BD=AC=E7=A0=81=E5=90=8E=E7=9A=84=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/web/gb28181/ApiStreamController.java | 3 +++ web_src/src/components/dialog/devicePlayer.vue | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java index 63d9f310..4f42efd1 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java @@ -120,6 +120,9 @@ public class ApiStreamController { if (errorCode == InviteErrorCode.SUCCESS.getCode()) { if (data != null) { StreamInfo streamInfo = (StreamInfo)data; + if (streamInfo.getTranscodeStream() != null) { + streamInfo = streamInfo.getTranscodeStream(); + } JSONObject resultJjson = new JSONObject(); resultJjson.put("StreamID", streamInfo.getStream()); resultJjson.put("DeviceID", serial); diff --git a/web_src/src/components/dialog/devicePlayer.vue b/web_src/src/components/dialog/devicePlayer.vue index f6bd2b23..64c61f56 100755 --- a/web_src/src/components/dialog/devicePlayer.vue +++ b/web_src/src/components/dialog/devicePlayer.vue @@ -473,10 +473,14 @@ export default { }, getUrlByStreamInfo() { console.log(this.streamInfo) + let streamInfo = this.streamInfo + if (this.streamInfo.transcodeStream) { + streamInfo = this.streamInfo.transcodeStream; + } if (location.protocol === "https:") { - this.videoUrl = this.streamInfo[this.player[this.activePlayer][1]] + this.videoUrl = streamInfo[this.player[this.activePlayer][1]] } else { - this.videoUrl = this.streamInfo[this.player[this.activePlayer][0]] + this.videoUrl = streamInfo[this.player[this.activePlayer][0]] } return this.videoUrl; From f5abf8df4c05439a288a88dedad0f7065901ca21 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 19 Jun 2024 16:00:26 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/CloudRecordServiceMapper.java | 2 +- .../vmp/web/gb28181/ApiStreamController.java | 32 ++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java index b446148a..f641071a 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java @@ -53,7 +53,7 @@ public interface CloudRecordServiceMapper { " and id in " + " #{item}" + " " + - " order by start_time DESC" + + " order by start_time ASC" + " ") List getList(@Param("query") String query, @Param("app") String app, @Param("stream") String stream, @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java index 4f42efd1..1d1919a6 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java @@ -120,22 +120,38 @@ public class ApiStreamController { if (errorCode == InviteErrorCode.SUCCESS.getCode()) { if (data != null) { StreamInfo streamInfo = (StreamInfo)data; - if (streamInfo.getTranscodeStream() != null) { - streamInfo = streamInfo.getTranscodeStream(); - } JSONObject resultJjson = new JSONObject(); resultJjson.put("StreamID", streamInfo.getStream()); resultJjson.put("DeviceID", serial); resultJjson.put("ChannelID", code); resultJjson.put("ChannelName", deviceChannel.getName()); resultJjson.put("ChannelCustomName", ""); - resultJjson.put("FLV", streamInfo.getFlv().getUrl()); - if(streamInfo.getHttps_flv() != null) { - resultJjson.put("HTTPS_FLV", streamInfo.getHttps_flv().getUrl()); + if (streamInfo.getTranscodeStream() != null) { + resultJjson.put("FLV", streamInfo.getTranscodeStream().getFlv().getUrl()); + }else { + resultJjson.put("FLV", streamInfo.getFlv().getUrl()); + } - resultJjson.put("WS_FLV", streamInfo.getWs_flv().getUrl()); + if(streamInfo.getHttps_flv() != null) { + if (streamInfo.getTranscodeStream() != null) { + resultJjson.put("HTTPS_FLV", streamInfo.getTranscodeStream().getHttps_flv().getUrl()); + }else { + resultJjson.put("HTTPS_FLV", streamInfo.getHttps_flv().getUrl()); + } + } + + if (streamInfo.getTranscodeStream() != null) { + resultJjson.put("WS_FLV", streamInfo.getTranscodeStream().getWs_flv().getUrl()); + }else { + resultJjson.put("WS_FLV", streamInfo.getWs_flv().getUrl()); + } + if(streamInfo.getWss_flv() != null) { - resultJjson.put("WSS_FLV", streamInfo.getWss_flv().getUrl()); + if (streamInfo.getTranscodeStream() != null) { + resultJjson.put("WSS_FLV", streamInfo.getTranscodeStream().getWss_flv().getUrl()); + }else { + resultJjson.put("WSS_FLV", streamInfo.getWss_flv().getUrl()); + } } resultJjson.put("RTMP", streamInfo.getRtmp().getUrl()); if (streamInfo.getRtmps() != null) { From 6e4268a670a796a884261ab77d70b59dc95cb909 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 20 Jun 2024 18:12:35 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8E=A8=E6=B5=81?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=86=99=E5=85=A5redis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vmp/media/zlm/ZLMHttpHookListener.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 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 63239b78..73f20bf4 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -375,8 +375,20 @@ public class ZLMHttpHookListener { streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr()); } redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); + + Map params = MediaServerUtils.urlParamToMap(param.getParams()); + param.setParamMap(params); + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, + param.getApp(), param.getStream(), tracks, params.get("callId")); + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); + + param.setSeverId(userSetting.getServerId()); + streamPushService.updatePush(param); + // 冗余数据,自己系统中自用 + redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param); } } + // TODO 修改为第一个为准 后续不再处理 if ("rtsp".equals(param.getSchema())) { logger.info("流变化:注册->{}, app->{}, stream->{}", param.isRegist(), param.getApp(), param.getStream()); if (param.isRegist()) { @@ -464,14 +476,7 @@ public class ZLMHttpHookListener { param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param); - if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() - || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { - param.setSeverId(userSetting.getServerId()); - streamPushService.updatePush(param); - // 冗余数据,自己系统中自用 - redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param); - } + } else { // 兼容流注销时类型从redis记录获取 OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( From 099c65ff40eefd1ad58626c7376c95fb3cf28395 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 20 Jun 2024 19:30:25 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=82=B9=E6=92=AD?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E8=B6=85=E6=97=B6=E6=97=B6=E9=97=B4=E4=B8=BA?= =?UTF-8?q?10=E7=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java index 96253d6e..7a025de0 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java @@ -21,7 +21,7 @@ public class UserSetting { private Boolean seniorSdp = Boolean.FALSE; - private Integer playTimeout = 18000; + private Integer playTimeout = 10000; private int platformPlayTimeout = 20000; From 050882d6a614f87d33d90bc5b344c774d9f6e71d Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Thu, 20 Jun 2024 22:35:48 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8E=A8=E6=B5=81?= =?UTF-8?q?=E6=97=B6=E5=AD=98=E5=85=A5=E6=8E=A8=E6=B5=81=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vmp/media/zlm/ZLMHttpHookListener.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 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 73f20bf4..a676fb92 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -376,17 +376,21 @@ public class ZLMHttpHookListener { } redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); - Map params = MediaServerUtils.urlParamToMap(param.getParams()); - param.setParamMap(params); - StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, - param.getApp(), param.getStream(), tracks, params.get("callId")); - param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); + if (!"broadcast".equals(param.getApp()) && !"talk".equals(param.getApp())) { + Map params = MediaServerUtils.urlParamToMap(param.getParams()); + param.setParamMap(params); + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, + param.getApp(), param.getStream(), tracks, params.get("callId")); + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); - param.setSeverId(userSetting.getServerId()); - streamPushService.updatePush(param); - // 冗余数据,自己系统中自用 - redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param); + param.setSeverId(userSetting.getServerId()); + streamPushService.updatePush(param); + // 冗余数据,自己系统中自用 + redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param); + } } + }else { + redisCatchStorage.removePushListItem(param.getApp(), param.getStream(), param.getMediaServerId()); } // TODO 修改为第一个为准 后续不再处理 if ("rtsp".equals(param.getSchema())) { From 87c071fd5e774091c7d87f3d7c24fd2360148d58 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 25 Jun 2024 10:24:35 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E5=90=88=E5=B9=B6271=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/impl/InviteRequestProcessor.java | 6 ++--- .../media/event/media/MediaArrivalEvent.java | 24 ++++++++++++++++++- .../service/impl/MediaServerServiceImpl.java | 7 ++++++ .../service/impl/StreamPushServiceImpl.java | 18 ++++++-------- .../iot/vmp/storager/IRedisCatchStorage.java | 4 ++-- .../storager/impl/RedisCatchStorageImpl.java | 14 ++++------- 6 files changed, 47 insertions(+), 26 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 ec6f901f..411c40fd 100755 --- 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 @@ -27,6 +27,7 @@ import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.service.IPlayService; import com.genersoft.iot.vmp.service.IStreamProxyService; import com.genersoft.iot.vmp.service.IStreamPushService; @@ -593,12 +594,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements sendRtpItem.setPlayType(InviteStreamType.PUSH); if (streamPushItem != null) { // 从redis查询是否正在接收这个推流 - StreamPushItem pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream()); + OnStreamChangedHookParam pushListItem = redisCatchStorage.getPushListItem(gbStream.getApp(), gbStream.getStream()); if (pushListItem != null) { - sendRtpItem.setServerId(pushListItem.getServerId()); + sendRtpItem.setServerId(pushListItem.getSeverId()); sendRtpItem.setMediaServerId(pushListItem.getMediaServerId()); - pushListItem.setSelf(userSetting.getServerId().equals(pushListItem.getServerId())); redisCatchStorage.updateSendRTPSever(sendRtpItem); // 开始推流 sendPushStream(sendRtpItem, mediaServerItem, platform, request); diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java index 2379321a..2f51a3e2 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/media/event/media/MediaArrivalEvent.java @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.media.event.media; import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; +import com.genersoft.iot.vmp.vmanager.bean.StreamContent; /** * 流到来事件 @@ -19,7 +20,8 @@ public class MediaArrivalEvent extends MediaEvent { mediaArrivalEvent.setStream(hookParam.getStream()); mediaArrivalEvent.setMediaServer(mediaServer); mediaArrivalEvent.setSchema(hookParam.getSchema()); - mediaArrivalEvent.setCallId(hookParam.getCallId()); + mediaArrivalEvent.setSchema(hookParam.getSchema()); + mediaArrivalEvent.setHookParam(hookParam); return mediaArrivalEvent; } @@ -27,6 +29,10 @@ public class MediaArrivalEvent extends MediaEvent { private String callId; + private OnStreamChangedHookParam hookParam; + + private StreamContent streamInfo; + public MediaInfo getMediaInfo() { return mediaInfo; } @@ -43,4 +49,20 @@ public class MediaArrivalEvent extends MediaEvent { public void setCallId(String callId) { this.callId = callId; } + + public OnStreamChangedHookParam getHookParam() { + return hookParam; + } + + public void setHookParam(OnStreamChangedHookParam hookParam) { + this.hookParam = hookParam; + } + + public StreamContent getStreamInfo() { + return streamInfo; + } + + public void setStreamInfo(StreamContent streamInfo) { + this.streamInfo = streamInfo; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java index a0b33413..d8f5ba95 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java @@ -809,6 +809,13 @@ public class MediaServerServiceImpl implements IMediaServerService { streamInfoResult.setRtc(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay); streamInfoResult.setMediaInfo(mediaInfo); + + if (!"broadcast".equalsIgnoreCase(app) && !ObjectUtils.isEmpty(mediaServer.getTranscodeSuffix()) && !"null".equalsIgnoreCase(mediaServer.getTranscodeSuffix())) { + String newStream = stream + "_" + mediaServer.getTranscodeSuffix(); + mediaServer.setTranscodeSuffix(null); + StreamInfo transcodeStreamInfo = getStreamInfoByAppAndStream(mediaServer, app, newStream, null, addr, callId, isPlay); + streamInfoResult.setTranscodeStream(transcodeStreamInfo); + } return streamInfoResult; } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java index 3213eb98..18de78a0 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java @@ -26,6 +26,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.dao.*; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; +import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import org.slf4j.Logger; @@ -126,18 +127,13 @@ public class StreamPushServiceImpl implements IStreamPushService { streamPushMapper.update(transform); gbStreamMapper.updateMediaServer(event.getApp(), event.getStream(), event.getMediaServer().getId()); } - // TODO 相关的事件自行管理,不需要写入ZLMMediaListManager -// ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(transform.getApp(), transform.getStream()); -// if ( channelOnlineEventLister != null) { -// try { -// channelOnlineEventLister.run(transform.getApp(), transform.getStream(), transform.getServerId());; -// } catch (ParseException e) { -// logger.error("addPush: ", e); -// } -// removedChannelOnlineEventLister(transform.getApp(), transform.getStream()); -// } // 冗余数据,自己系统中自用 - redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event); + if (!"broadcast".equals(event.getApp()) && !"talk".equals(event.getApp())) { + StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream( + event.getMediaServer(), event.getApp(), event.getStream(), event.getMediaInfo(), event.getCallId()); + event.getHookParam().setStreamInfo(new StreamContent(streamInfo)); + redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event); + } // 发送流变化redis消息 JSONObject jsonObject = new JSONObject(); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java index 66b483b7..869d39bf 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java @@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; -import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; @@ -216,7 +216,7 @@ public interface IRedisCatchStorage { void addPushListItem(String app, String stream, MediaArrivalEvent param); - StreamPushItem getPushListItem(String app, String stream); + OnStreamChangedHookParam getPushListItem(String app, String stream); void removePushListItem(String app, String stream, String mediaServerId); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java index 9f09e8a4..e70e195c 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java @@ -5,16 +5,13 @@ import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.common.SystemAllInfo; import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.AlarmChannelMessage; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; -import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; -import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -698,14 +695,13 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @Override public void addPushListItem(String app, String stream, MediaArrivalEvent event) { String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; - StreamPushItem streamPushItem = StreamPushItem.getInstance(event, userSetting.getServerId()); - redisTemplate.opsForValue().set(key, streamPushItem); + redisTemplate.opsForValue().set(key, event.getHookParam()); } @Override - public StreamPushItem getPushListItem(String app, String stream) { + public OnStreamChangedHookParam getPushListItem(String app, String stream) { String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; - return (StreamPushItem)redisTemplate.opsForValue().get(key); + return (OnStreamChangedHookParam)redisTemplate.opsForValue().get(key); } @Override From 68fce9177fb3ac2605d6de7f5b0e0d8532d733e2 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 25 Jun 2024 16:45:31 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vmp/gb28181/bean/CatalogChannelEvent.java | 38 + .../iot/vmp/gb28181/bean/CatalogEvent.java | 9 - .../iot/vmp/gb28181/bean/DeviceChannel.java | 206 ++--- .../subscribe/catalog/CatalogEventLister.java | 30 +- .../NotifyRequestForCatalogProcessor.java | 139 +-- .../cmd/CatalogResponseMessageHandler.java | 6 +- .../iot/vmp/gb28181/utils/XmlUtil.java | 810 +++++++++--------- .../iot/vmp/service/IGbStreamService.java | 5 +- .../iot/vmp/service/IStreamPushService.java | 3 + .../vmp/service/impl/GbStreamServiceImpl.java | 12 +- .../service/impl/StreamPushServiceImpl.java | 23 +- .../RedisPushStreamStatusListMsgListener.java | 40 +- .../vmp/storager/dao/StreamPushMapper.java | 6 + src/main/resources/application.yml | 2 +- 14 files changed, 654 insertions(+), 675 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogChannelEvent.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogEvent.java diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogChannelEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogChannelEvent.java new file mode 100644 index 00000000..cf7c9cbd --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogChannelEvent.java @@ -0,0 +1,38 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.dom4j.Element; + +import java.lang.reflect.InvocationTargetException; + +@Data +@Slf4j +@EqualsAndHashCode(callSuper = true) +public class CatalogChannelEvent extends DeviceChannel{ + + private String event; + + private DeviceChannel channel; + + public static CatalogChannelEvent decode(Element element) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + Element eventElement = element.element("Event"); + CatalogChannelEvent catalogChannelEvent = new CatalogChannelEvent(); + if (eventElement != null) { + catalogChannelEvent.setEvent(eventElement.getText()); + }else { + catalogChannelEvent.setEvent(CatalogEvent.ADD); + } + DeviceChannel deviceChannel; + if (CatalogEvent.ADD.equalsIgnoreCase(catalogChannelEvent.getEvent()) || + CatalogEvent.UPDATE.equalsIgnoreCase(catalogChannelEvent.getEvent()) ){ + deviceChannel = DeviceChannel.decode(element); + }else { + deviceChannel = DeviceChannel.decodeWithOnlyDeviceId(element); + } + catalogChannelEvent.setChannel(deviceChannel); + return catalogChannelEvent; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogEvent.java deleted file mode 100644 index a3fcdee8..00000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogEvent.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.bean; - -import com.genersoft.iot.vmp.gb28181.utils.MessageElement; - -public class CatalogEvent extends DeviceChannel{ - - @MessageElement("Event") - private String event; -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java index 5ddf1c46..09f28785 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java @@ -1,257 +1,170 @@ package com.genersoft.iot.vmp.gb28181.bean; import com.genersoft.iot.vmp.gb28181.utils.MessageElement; +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.dom4j.Element; + +import java.lang.reflect.InvocationTargetException; @Data +@Slf4j @Schema(description = "通道信息") @EqualsAndHashCode(callSuper = true) public class DeviceChannel extends CommonGBChannel { + @Schema(description = "数据库自增ID") + private int id; + @MessageElement("DeviceID") @Schema(description = "编码") private String deviceId; - @MessageElement("DeviceID") + @MessageElement("Name") @Schema(description = "名称") private String name; - @MessageElement("DeviceID") + @MessageElement("Manufacturer") @Schema(description = "设备厂商") private String manufacturer; - @MessageElement("DeviceID") + @MessageElement("Model") @Schema(description = "设备型号") private String model; // 2016 - @MessageElement("DeviceID") + @MessageElement("Owner") @Schema(description = "设备归属") private String owner; - @MessageElement("DeviceID") + @MessageElement("CivilCode") @Schema(description = "行政区域") private String civilCode; - @MessageElement("DeviceID") + @MessageElement("Block") @Schema(description = "警区") private String block; - @MessageElement("DeviceID") + @MessageElement("Address") @Schema(description = "安装地址") private String address; - @MessageElement("DeviceID") - @Schema(description = "是否有子设备") - private Boolean parental; + @MessageElement("Parental") + @Schema(description = "是否有子设备(必选)1有,0没有") + private Integer parental; - @MessageElement("DeviceID") + @MessageElement("ParentID") @Schema(description = "父节点ID") private String parentId; // 2016 - @MessageElement("DeviceID") + @MessageElement("SafetyWay") @Schema(description = "信令安全模式") private Integer safetyWay; - @MessageElement("DeviceID") + @MessageElement("RegisterWay") @Schema(description = "注册方式") private Integer registerWay; // 2016 - @MessageElement("DeviceID") + @MessageElement("CertNum") @Schema(description = "证书序列号") - private Integer certNum; + private String certNum; // 2016 - @MessageElement("DeviceID") - @Schema(description = "证书有效标识") + @MessageElement("Certifiable") + @Schema(description = "证书有效标识, 缺省为0;证书有效标识:0:无效 1:有效") private Integer certifiable; // 2016 - @MessageElement("DeviceID") + @MessageElement("ErrCode") @Schema(description = "无效原因码(有证书且证书无效的设备必选)") private Integer errCode; // 2016 - @MessageElement("DeviceID") + @MessageElement("EndTime") @Schema(description = "证书终止有效期(有证书且证书无效的设备必选)") - private Integer endTime; + private String endTime; - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机安全能力等级代码") - private String securityLevelCode; - - @MessageElement("DeviceID") + @MessageElement("Secrecy") @Schema(description = "保密属性(必选)缺省为0;0-不涉密,1-涉密") private Integer secrecy; - @MessageElement("DeviceID") + @MessageElement("IPAddress") @Schema(description = "设备/系统IPv4/IPv6地址") private String ipAddress; - @MessageElement("DeviceID") + @MessageElement("Port") @Schema(description = "设备/系统端口") private Integer port; - @MessageElement("DeviceID") + @MessageElement("Password") @Schema(description = "设备口令") private String password; - @MessageElement("DeviceID") + @MessageElement("Status") @Schema(description = "设备状态") - private Boolean status; + private String status; - @MessageElement("DeviceID") + @MessageElement("Longitude") @Schema(description = "经度 WGS-84坐标系") private Double longitude; - @MessageElement("DeviceID") + @MessageElement("Latitude") @Schema(description = ",纬度 WGS-84坐标系") private Double latitude; - @MessageElement("DeviceID") - @Schema(description = "虚拟组织所属的业务分组ID") - private String businessGroupId; - - @MessageElement("DeviceID") + @MessageElement("Info.PTZType") @Schema(description = "摄像机结构类型,标识摄像机类型: 1-球机; 2-半球; 3-固定枪机; 4-遥控枪机;5-遥控半球;6-多目设备的全景/拼接通道;7-多目设备的分割通道") private Integer ptzType; - @MessageElement("DeviceID") - @Schema(description = "摄像机光电成像类型。1-可见光成像;2-热成像;3-雷达成像;4-X光成像;5-深度光场成像;9-其他。可多值,") - private String photoelectricImagingTyp; + @MessageElement("Info.PositionType") + @Schema(description = "摄像机位置类型扩展。1-省际检查站、2-党政机关、3-车站码头、4-中心广场、5-体育场馆、" + + "6-商业中心、7-宗教场所、8-校园周边、9-治安复杂区域、10-交通干线") + private Integer positionType; - @MessageElement("DeviceID") - @Schema(description = "摄像机采集部位类型") - private String capturePositionType; - - @MessageElement("DeviceID") + @MessageElement("Info.RoomType") @Schema(description = "摄像机安装位置室外、室内属性。1-室外、2-室内。") private Integer roomType; - // 2016 - @MessageElement("DeviceID") - @Schema(description = "用途属性") + @MessageElement("Info.UseType") + @Schema(description = "用途属性, 1-治安、2-交通、3-重点。") private Integer useType; - @MessageElement("DeviceID") + @MessageElement("Info.SupplyLightType") @Schema(description = "摄像机补光属性。1-无补光;2-红外补光;3-白光补光;4-激光补光;9-其他") private Integer supplyLightType; - @MessageElement("DeviceID") + @MessageElement("Info.DirectionType") @Schema(description = "摄像机监视方位(光轴方向)属性。1-东(西向东)、2-西(东向西)、3-南(北向南)、4-北(南向北)、" + "5-东南(西北到东南)、6-东北(西南到东北)、7-西南(东北到西南)、8-西北(东南到西北)") private Integer directionType; - @MessageElement("DeviceID") + @MessageElement("Info.Resolution") @Schema(description = "摄像机支持的分辨率,可多值") private String resolution; - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机支持的码流编号列表,用于实时点播时指定码流编号(可选)") - private String streamNumberList; + @MessageElement("Info.BusinessGroupID") + @Schema(description = "虚拟组织所属的业务分组ID") + private String businessGroupId; - @MessageElement("DeviceID") + @MessageElement("Info.DownloadSpeed") @Schema(description = "下载倍速(可选),可多值") private String downloadSpeed; - @MessageElement("DeviceID") + @MessageElement("Info.SVCSpaceSupportMode") @Schema(description = "空域编码能力,取值0-不支持;1-1级增强(1个增强层);2-2级增强(2个增强层);3-3级增强(3个增强层)") private Integer svcSpaceSupportMod; - @MessageElement("DeviceID") + @MessageElement("Info.SVCTimeSupportMode") @Schema(description = "时域编码能力,取值0-不支持;1-1级增强;2-2级增强;3-3级增强(可选)") private Integer svcTimeSupportMode; - // 2022 - @MessageElement("DeviceID") - @Schema(description = " SSVC增强层与基本层比例能力 ") - private String ssvcRatioSupportList; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "移动采集设备类型(仅移动采集设备适用,必选);1-移动机器人载摄像机;2-执法记录仪;3-移动单兵设备;" + - "4-车载视频记录设备;5-无人机载摄像机;9-其他") - private Integer mobileDeviceType; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机水平视场角(可选),取值范围大于0度小于等于360度") - private Double horizontalFieldAngle; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机竖直视场角(可选),取值范围大于0度小于等于360度 ") - private Double verticalFieldAngle; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机可视距离(可选),单位:米") - private Double maxViewDistance; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "基层组织编码(必选,非基层建设时为“000000”)") - private String grassrootsCode; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "监控点位类型(当为摄像机时必选),1-一类视频监控点;2-二类视频监控点;3-三类视频监控点;9-其他点位。") - private Integer poType; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "点位俗称") - private String poCommonName; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "设备MAC地址(可选),用“XX-XX-XX-XX-XX-XX”格式表达") - private String mac; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机卡口功能类型,01-人脸卡口;02-人员卡口;03-机动车卡口;04-非机动车卡口;05-物品卡口;99-其他") - private String functionType; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机视频编码格式") - private String encodeType; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机安装使用时间") - private String installTime; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机所属管理单位名称") - private String managementUnit; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "摄像机所属管理单位联系人的联系方式(电话号码,可多值,用英文半角“/”分割)") - private String contactInfo; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "录像保存天数(可选)") - private Integer recordSaveDays; - - // 2022 - @MessageElement("DeviceID") - @Schema(description = "国民经济行业分类代码(可选)") - private String industrialClassification; - - @Schema(description = "云台类型描述字符串") private String ptzTypeText; @@ -306,4 +219,15 @@ public class DeviceChannel extends CommonGBChannel { break; } } + + public static DeviceChannel decode(Element element) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + return XmlUtil.elementDecode(element, DeviceChannel.class); + } + + public static DeviceChannel decodeWithOnlyDeviceId(Element element) { + Element deviceElement = element.element("DeviceID"); + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setDeviceId(deviceElement.getText()); + return deviceChannel; + } } 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 18ad2b01..9c65b873 100755 --- 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 @@ -5,8 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; import com.genersoft.iot.vmp.service.IGbStreamService; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @@ -23,11 +22,10 @@ import java.util.Map; /** * catalog事件 */ +@Slf4j @Component public class CatalogEventLister implements ApplicationListener { - private final static Logger logger = LoggerFactory.getLogger(CatalogEventLister.class); - @Autowired private IVideoManagerStorage storager; @@ -66,9 +64,9 @@ public class CatalogEventLister implements ApplicationListener { if (event.getDeviceChannels() != null) { if (platforms.size() > 0) { for (DeviceChannel deviceChannel : event.getDeviceChannels()) { - List parentPlatformsForGB = storager.queryPlatFormListForGBWithGBId(deviceChannel.getChannelId(), platforms); - parentPlatformMap.put(deviceChannel.getChannelId(), parentPlatformsForGB); - channelMap.put(deviceChannel.getChannelId(), deviceChannel); + List parentPlatformsForGB = storager.queryPlatFormListForGBWithGBId(deviceChannel.getDeviceId(), platforms); + parentPlatformMap.put(deviceChannel.getDeviceId(), parentPlatformsForGB); + channelMap.put(deviceChannel.getDeviceId(), deviceChannel); } } }else if (event.getGbStreams() != null) { @@ -106,12 +104,12 @@ public class CatalogEventLister implements ApplicationListener { } } if (deviceChannelList.size() > 0) { - logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); + log.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); try { sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), parentPlatform, deviceChannelList, subscribe, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { - logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } }else if (parentPlatformMap.keySet().size() > 0) { @@ -123,16 +121,16 @@ public class CatalogEventLister implements ApplicationListener { if (subscribeInfo == null) { continue; } - logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); + log.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); List deviceChannelList = new ArrayList<>(); DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setChannelId(gbId); + deviceChannel.setDeviceId(gbId); deviceChannelList.add(deviceChannel); try { sipCommanderFroPlatform.sendNotifyForCatalogOther(event.getType(), platform, deviceChannelList, subscribeInfo, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { - logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } } @@ -157,12 +155,12 @@ public class CatalogEventLister implements ApplicationListener { } } if (!deviceChannelList.isEmpty()) { - logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); + log.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); try { sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { - logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } }else if (!parentPlatformMap.keySet().isEmpty()) { @@ -174,7 +172,7 @@ public class CatalogEventLister implements ApplicationListener { if (subscribeInfo == null) { continue; } - logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); + log.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId); List deviceChannelList = new ArrayList<>(); DeviceChannel deviceChannel = channelMap.get(gbId); deviceChannelList.add(deviceChannel); @@ -187,7 +185,7 @@ public class CatalogEventLister implements ApplicationListener { sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), platform, deviceChannelList, subscribeInfo, null); } catch (InvalidArgumentException | ParseException | NoSuchFieldException | SipException | IllegalAccessException e) { - logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); + log.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java index c832161a..f90b93fc 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.CatalogChannelEvent; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.HandlerCatchData; @@ -10,14 +11,12 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.service.IDeviceChannelService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.utils.DateUtil; +import lombok.extern.slf4j.Slf4j; import org.dom4j.DocumentException; import org.dom4j.Element; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -25,6 +24,8 @@ import org.springframework.transaction.annotation.Transactional; import javax.sip.RequestEvent; import javax.sip.header.FromHeader; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -36,12 +37,10 @@ import java.util.concurrent.CopyOnWriteArrayList; /** * SIP命令类型: NOTIFY请求中的目录请求处理 */ +@Slf4j @Component public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent { - - private final static Logger logger = LoggerFactory.getLogger(NotifyRequestForCatalogProcessor.class); - private final List updateChannelOnlineList = new CopyOnWriteArrayList<>(); private final List updateChannelOfflineList = new CopyOnWriteArrayList<>(); private final Map updateChannelMap = new ConcurrentHashMap<>(); @@ -72,7 +71,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent @Transactional public void process(RequestEvent evt) { if (taskQueue.size() >= userSetting.getMaxNotifyCountQueue()) { - logger.error("[notify-目录订阅] 待处理消息队列已满 {},返回486 BUSY_HERE,消息不做处理", userSetting.getMaxNotifyCountQueue()); + log.error("[notify-目录订阅] 待处理消息队列已满 {},返回486 BUSY_HERE,消息不做处理", userSetting.getMaxNotifyCountQueue()); return; } taskQueue.offer(new HandlerCatchData(evt, null, null)); @@ -95,12 +94,12 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent Device device = redisCatchStorage.getDevice(deviceId); if (device == null || !device.isOnLine()) { - logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId() : "")); + log.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId() : "")); return; } Element rootElement = getRootElement(evt, device.getCharset()); if (rootElement == null) { - logger.warn("[ 收到目录订阅 ] content cannot be null, {}", evt.getRequest()); + log.warn("[ 收到目录订阅 ] content cannot be null, {}", evt.getRequest()); return; } Element deviceListElement = rootElement.element("DeviceList"); @@ -113,132 +112,134 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent // 遍历DeviceList while (deviceListIterator.hasNext()) { Element itemDevice = deviceListIterator.next(); - 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.channelContentHandler(itemDevice, device, event); - - - if (channel == null) { - logger.info("[收到目录订阅]:但是解析失败 {}", new String(evt.getRequest().getRawContent())); + CatalogChannelEvent catalogChannelEvent = null; + try { + catalogChannelEvent = CatalogChannelEvent.decode(itemDevice); + if (catalogChannelEvent.getChannel() == null) { + log.info("[解析CatalogChannelEvent]成功:但是解析通道信息失败, 原文如下: \n{}", new String(evt.getRequest().getRawContent())); + continue; + } + } catch (InvocationTargetException | NoSuchMethodException | InstantiationException | + IllegalAccessException e) { + log.error("[解析CatalogChannelEvent]失败,", e); + log.error("[解析CatalogChannelEvent]失败原文: \n{}", new String(evt.getRequest().getRawContent(), Charset.forName(device.getCharset()))); + continue; + } + if (catalogChannelEvent == null) { continue; } - if (channel.getParentId() != null && channel.getParentId().equals(sipConfig.getId())) { - channel.setParentId(null); - } - channel.setDeviceId(device.getDeviceId()); - logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getDeviceId()); - switch (event) { + + log.info("[收到目录订阅]:{}/{}-{}", device.getDeviceId(), + catalogChannelEvent.getChannel().getDeviceId(), catalogChannelEvent.getEvent()); + switch (catalogChannelEvent.getEvent()) { case CatalogEvent.ON: // 上线 - logger.info("[收到通道上线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); - updateChannelOnlineList.add(channel); + log.info("[收到通道上线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); + updateChannelOnlineList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), true); + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), true); } break; case CatalogEvent.OFF: // 离线 - logger.info("[收到通道离线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道离线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); if (userSetting.getRefuseChannelStatusChannelFormNotify()) { - logger.info("[收到通道离线通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道离线通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); } else { - updateChannelOfflineList.add(channel); + updateChannelOfflineList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false); + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), false); } } break; case CatalogEvent.VLOST: // 视频丢失 - logger.info("[收到通道视频丢失通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道视频丢失通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); if (userSetting.getRefuseChannelStatusChannelFormNotify()) { - logger.info("[收到通道视频丢失通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道视频丢失通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); } else { - updateChannelOfflineList.add(channel); + updateChannelOfflineList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false); + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), false); } } break; case CatalogEvent.DEFECT: // 故障 - logger.info("[收到通道视频故障通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道视频故障通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); if (userSetting.getRefuseChannelStatusChannelFormNotify()) { - logger.info("[收到通道视频故障通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到通道视频故障通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); } else { - updateChannelOfflineList.add(channel); + updateChannelOfflineList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), channel.getChannelId(), false); + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), false); } } break; case CatalogEvent.ADD: // 增加 - logger.info("[收到增加通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到增加通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); // 判断此通道是否存在 - DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, channel.getChannelId()); + DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, catalogChannelEvent.getChannel().getDeviceId()); if (deviceChannel != null) { - logger.info("[增加通道] 已存在,不发送通知只更新,设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[增加通道] 已存在,不发送通知只更新,设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); + DeviceChannel channel = catalogChannelEvent.getChannel(); channel.setId(deviceChannel.getId()); - channel.setHasAudio(null); - updateChannelMap.put(channel.getChannelId(), channel); + channel.setHasAudio(deviceChannel.getHasAudio()); + channel.setUpdateTime(DateUtil.getNow()); + updateChannelMap.put(catalogChannelEvent.getChannel().getDeviceId(), channel); } else { - addChannelMap.put(channel.getChannelId(), channel); + addChannelMap.put(catalogChannelEvent.getChannel().getDeviceId(), catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true); + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), true); } } break; case CatalogEvent.DEL: // 删除 - logger.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); - deleteChannelList.add(channel); + log.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); + deleteChannelList.add(catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), false); + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), false); } break; case CatalogEvent.UPDATE: // 更新 - logger.info("[收到更新通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); + log.info("[收到更新通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId()); // 判断此通道是否存在 - DeviceChannel deviceChannelForUpdate = deviceChannelService.getOne(deviceId, channel.getChannelId()); + DeviceChannel deviceChannelForUpdate = deviceChannelService.getOne(deviceId, catalogChannelEvent.getChannel().getDeviceId()); if (deviceChannelForUpdate != null) { + DeviceChannel channel = catalogChannelEvent.getChannel(); channel.setId(deviceChannelForUpdate.getId()); + channel.setHasAudio(deviceChannelForUpdate.getHasAudio()); channel.setUpdateTime(DateUtil.getNow()); - channel.setHasAudio(null); - updateChannelMap.put(channel.getChannelId(), channel); + updateChannelMap.put(catalogChannelEvent.getChannel().getDeviceId(), channel); } else { - addChannelMap.put(channel.getChannelId(), channel); + addChannelMap.put(catalogChannelEvent.getChannel().getDeviceId(), catalogChannelEvent.getChannel()); if (userSetting.getDeviceStatusNotify()) { // 发送redis消息 - redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true); + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), catalogChannelEvent.getChannel().getDeviceId(), true); } } break; default: - logger.warn("[ NotifyCatalog ] event not found : {}", event); + log.warn("[ NotifyCatalog ] event not found : {}", catalogChannelEvent.getEvent()); } // 转发变化信息 - eventPublisher.catalogEventPublish(null, channel, event); + eventPublisher.catalogEventPublish(null, catalogChannelEvent.getChannel(), catalogChannelEvent.getEvent()); } } } catch (DocumentException e) { - logger.error("未处理的异常 ", e); + log.error("未处理的异常 ", e); } } taskQueue.clear(); @@ -255,33 +256,33 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent try { executeSaveForAdd(); } catch (Exception e) { - logger.error("[存储收到的增加通道] 异常: ", e ); + log.error("[存储收到的增加通道] 异常: ", e ); } try { executeSaveForOnline(); } catch (Exception e) { - logger.error("[存储收到的通道上线] 异常: ", e ); + log.error("[存储收到的通道上线] 异常: ", e ); } try { executeSaveForOffline(); } catch (Exception e) { - logger.error("[存储收到的通道离线] 异常: ", e ); + log.error("[存储收到的通道离线] 异常: ", e ); } try { executeSaveForUpdate(); } catch (Exception e) { - logger.error("[存储收到的更新通道] 异常: ", e ); + log.error("[存储收到的更新通道] 异常: ", e ); } try { executeSaveForDelete(); } catch (Exception e) { - logger.error("[存储收到的删除通道] 异常: ", e ); + log.error("[存储收到的删除通道] 异常: ", e ); } } private void executeSaveForUpdate(){ if (!updateChannelMap.values().isEmpty()) { - logger.info("[存储收到的更新通道], 数量: {}", updateChannelMap.size()); + log.info("[存储收到的更新通道], 数量: {}", updateChannelMap.size()); ArrayList deviceChannels = new ArrayList<>(updateChannelMap.values()); deviceChannelService.batchUpdateChannel(deviceChannels); updateChannelMap.clear(); @@ -319,6 +320,6 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent @Scheduled(fixedRate = 10000) //每1秒执行一次 public void execute(){ - logger.info("[待处理Notify-目录订阅消息数量]: {}", taskQueue.size()); + log.info("[待处理Notify-目录订阅消息数量]: {}", taskQueue.size()); } } 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 c16d7f56..c2b0b2de 100755 --- 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 @@ -7,7 +7,6 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import com.genersoft.iot.vmp.storager.IVideoManagerStorage; import gov.nist.javax.sip.message.SIPRequest; import org.dom4j.DocumentException; @@ -114,8 +113,9 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp if (channelDeviceElement == null) { continue; } - DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, null); - if (channel == null) { + DeviceChannel channel = DeviceChannel.decode(itemDevice); +// DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, null); + if (channel == null || channel.getDeviceId() == null) { logger.info("[收到目录订阅]:但是解析失败 {}", new String(evt.getRequest().getRawContent())); continue; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java index cb874802..46e92480 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java @@ -2,13 +2,6 @@ package com.genersoft.iot.vmp.gb28181.utils; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.common.CivilCodePo; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; -import com.genersoft.iot.vmp.utils.CivilCodeUtil; -import com.genersoft.iot.vmp.utils.DateUtil; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.dom4j.Attribute; import org.dom4j.Document; @@ -240,388 +233,387 @@ public class XmlUtil { CivilCode, BusinessGroup,VirtualOrganization,Other } - public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event){ - loadElement(itemDevice, DeviceChannel.class) - DeviceChannel deviceChannel = new DeviceChannel(); - deviceChannel.setDeviceId(device.getDeviceId()); - Element channdelIdElement = itemDevice.element("DeviceID"); - if (channdelIdElement == null) { - logger.warn("解析Catalog消息时发现缺少 DeviceID"); - return null; - } - String channelId = channdelIdElement.getTextTrim(); - if (ObjectUtils.isEmpty(channelId)) { - logger.warn("解析Catalog消息时发现缺少 DeviceID"); - return null; - } - deviceChannel.setChannelId(channelId); - if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { - // 除了ADD和update情况下需要识别全部内容, - return deviceChannel; - } - Element nameElement = itemDevice.element("Name"); - // 当通道名称为空时,设置通道名称为通道编码,避免级联时因通道名称为空导致上级接收通道失败 - if (nameElement != null && StringUtils.isNotBlank(nameElement.getText())) { - deviceChannel.setName(nameElement.getText()); - } else { - deviceChannel.setName(channelId); - } - if(channelId.length() <= 8) { - deviceChannel.setHasAudio(false); - CivilCodePo parentCode = CivilCodeUtil.INSTANCE.getParentCode(channelId); - if (parentCode != null) { - deviceChannel.setParentId(parentCode.getCode()); - deviceChannel.setCivilCode(parentCode.getCode()); - }else { - logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); - } - deviceChannel.setStatus(true); - return deviceChannel; - }else { - if(channelId.length() != 20) { - logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); - return null; - } - - int code = Integer.parseInt(channelId.substring(10, 13)); - if (code == 136 || code == 137 || code == 138) { - deviceChannel.setHasAudio(true); - }else { - deviceChannel.setHasAudio(false); - } - // 设备厂商 - String manufacturer = getText(itemDevice, "Manufacturer"); - // 设备型号 - String model = getText(itemDevice, "Model"); - // 设备归属 - String owner = getText(itemDevice, "Owner"); - // 行政区域 - String civilCode = getText(itemDevice, "CivilCode"); - // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 - String businessGroupID = getText(itemDevice, "BusinessGroupID"); - // 父设备/区域/系统ID - String parentID = getText(itemDevice, "ParentID"); - if (parentID != null && parentID.equalsIgnoreCase("null")) { - parentID = null; - } - // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 - String registerWay = getText(itemDevice, "RegisterWay"); - // 保密属性(必选)缺省为0;0:不涉密,1:涉密 - String secrecy = getText(itemDevice, "Secrecy"); - // 安装地址 - String address = getText(itemDevice, "Address"); - - switch (code){ - case 200: - // 系统目录 - if (!ObjectUtils.isEmpty(manufacturer)) { - deviceChannel.setManufacture(manufacturer); - } - if (!ObjectUtils.isEmpty(model)) { - deviceChannel.setModel(model); - } - if (!ObjectUtils.isEmpty(owner)) { - deviceChannel.setOwner(owner); - } - if (!ObjectUtils.isEmpty(civilCode)) { - deviceChannel.setCivilCode(civilCode); - deviceChannel.setParentId(civilCode); - }else { - if (!ObjectUtils.isEmpty(parentID)) { - deviceChannel.setParentId(parentID); - } - } - if (!ObjectUtils.isEmpty(address)) { - deviceChannel.setAddress(address); - } - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(registerWay)) { - try { - deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); - }catch (NumberFormatException exception) { - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); - } - } - if (!ObjectUtils.isEmpty(secrecy)) { - deviceChannel.setSecrecy(secrecy); - } - return deviceChannel; - case 215: - // 业务分组 - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(parentID)) { - if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { - deviceChannel.setParentId(parentID); - } - }else { - logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); - if (!ObjectUtils.isEmpty(civilCode)) { - deviceChannel.setCivilCode(civilCode); - } - } - break; - case 216: - // 虚拟组织 - deviceChannel.setStatus(true); - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setBusinessGroupId(businessGroupID); - } - - if (!ObjectUtils.isEmpty(parentID)) { - if (parentID.contains("/")) { - String[] parentIdArray = parentID.split("/"); - parentID = parentIdArray[parentIdArray.length - 1]; - } - deviceChannel.setParentId(parentID); - }else { - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setParentId(businessGroupID); - } - } - break; - default: - // 设备目录 - if (!ObjectUtils.isEmpty(manufacturer)) { - deviceChannel.setManufacture(manufacturer); - } - if (!ObjectUtils.isEmpty(model)) { - deviceChannel.setModel(model); - } - if (!ObjectUtils.isEmpty(owner)) { - deviceChannel.setOwner(owner); - } - if (!ObjectUtils.isEmpty(civilCode) - && civilCode.length() <= 8 - && NumberUtils.isParsable(civilCode) - && civilCode.length()%2 == 0 - ) { - deviceChannel.setCivilCode(civilCode); - } - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setBusinessGroupId(businessGroupID); - } - - // 警区 - String block = getText(itemDevice, "Block"); - if (!ObjectUtils.isEmpty(block)) { - deviceChannel.setBlock(block); - } - if (!ObjectUtils.isEmpty(address)) { - deviceChannel.setAddress(address); - } - - if (!ObjectUtils.isEmpty(secrecy)) { - deviceChannel.setSecrecy(secrecy); - } - - // 当为设备时,是否有子设备(必选)1有,0没有 - String parental = getText(itemDevice, "Parental"); - if (!ObjectUtils.isEmpty(parental)) { - try { - // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 - if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { - deviceChannel.setParental(0); - }else { - deviceChannel.setParental(1); - } - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); - } - } - // 父设备/区域/系统ID - - if (!ObjectUtils.isEmpty(parentID) ) { - if (parentID.contains("/")) { - String[] parentIdArray = parentID.split("/"); - deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]); - }else { - if (parentID.length()%2 == 0) { - deviceChannel.setParentId(parentID); - }else { - logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID); - } - } - }else { - if (!ObjectUtils.isEmpty(businessGroupID)) { - deviceChannel.setParentId(businessGroupID); - }else { - if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) { - deviceChannel.setParentId(deviceChannel.getCivilCode()); - } - } - } - // 注册方式 - if (!ObjectUtils.isEmpty(registerWay)) { - try { - int registerWayInt = Integer.parseInt(registerWay); - deviceChannel.setRegisterWay(registerWayInt); - }catch (NumberFormatException exception) { - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); - deviceChannel.setRegisterWay(1); - } - }else { - deviceChannel.setRegisterWay(1); - } - - // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 - String safetyWay = getText(itemDevice, "SafetyWay"); - if (!ObjectUtils.isEmpty(safetyWay)) { - try { - deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); - } - } - - // 证书序列号(有证书的设备必选) - String certNum = getText(itemDevice, "CertNum"); - if (!ObjectUtils.isEmpty(certNum)) { - deviceChannel.setCertNum(certNum); - } - - // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 - String certifiable = getText(itemDevice, "Certifiable"); - if (!ObjectUtils.isEmpty(certifiable)) { - try { - deviceChannel.setCertifiable(Integer.parseInt(certifiable)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); - } - } - - // 无效原因码(有证书且证书无效的设备必选) - String errCode = getText(itemDevice, "ErrCode"); - if (!ObjectUtils.isEmpty(errCode)) { - try { - deviceChannel.setErrCode(Integer.parseInt(errCode)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); - } - } - - // 证书终止有效期(有证书的设备必选) - String endTime = getText(itemDevice, "EndTime"); - if (!ObjectUtils.isEmpty(endTime)) { - deviceChannel.setEndTime(endTime); - } - - - // 设备/区域/系统IP地址 - String ipAddress = getText(itemDevice, "IPAddress"); - if (!ObjectUtils.isEmpty(ipAddress)) { - deviceChannel.setIpAddress(ipAddress); - } - - // 设备/区域/系统端口 - String port = getText(itemDevice, "Port"); - if (!ObjectUtils.isEmpty(port)) { - try { - deviceChannel.setPort(Integer.parseInt(port)); - }catch (NumberFormatException e) { - logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); - } - } - - // 设备口令 - String password = getText(itemDevice, "Password"); - if (!ObjectUtils.isEmpty(password)) { - deviceChannel.setPassword(password); - } - - - // 设备状态 - String status = getText(itemDevice, "Status"); - if (status != null) { - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 - if (status.equalsIgnoreCase("ON") || status.equalsIgnoreCase("On") || status.equalsIgnoreCase("ONLINE") || status.equalsIgnoreCase("OK")) { - deviceChannel.setStatus(true); - } - if (status.equalsIgnoreCase("OFF") || status.equalsIgnoreCase("Off") || status.equalsIgnoreCase("OFFLINE")) { - deviceChannel.setStatus(false); - } - }else { - deviceChannel.setStatus(true); - } -// logger.info("状态字符串: {}", status); -// logger.info("状态结果: {}", deviceChannel.isStatus()); - // 经度 - String longitude = getText(itemDevice, "Longitude"); - if (NumericUtil.isDouble(longitude)) { - deviceChannel.setLongitude(Double.parseDouble(longitude)); - } else { - deviceChannel.setLongitude(0.00); - } - - // 纬度 - String latitude = getText(itemDevice, "Latitude"); - if (NumericUtil.isDouble(latitude)) { - deviceChannel.setLatitude(Double.parseDouble(latitude)); - } else { - deviceChannel.setLatitude(0.00); - } - - deviceChannel.setGpsTime(DateUtil.getNow()); - - // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 - String ptzType = getText(itemDevice, "PTZType"); - if (ObjectUtils.isEmpty(ptzType)) { - //兼容INFO中的信息 - Element info = itemDevice.element("Info"); - String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); - if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ - try { - deviceChannel.setPtzType(Integer.parseInt(ptzTypeFromInfo)); - }catch (NumberFormatException e){ - logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); - } - } - } else { - try { - deviceChannel.setPtzType(Integer.parseInt(ptzType)); - }catch (NumberFormatException e){ - logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); - } - } - - // TODO 摄像机位置类型扩展。 - // 1-省际检查站、 - // 2-党政机关、 - // 3-车站码头、 - // 4-中心广场、 - // 5-体育场馆、 - // 6-商业中心、 - // 7-宗教场所、 - // 8-校园周边、 - // 9-治安复杂区域、 - // 10-交通干线。 - // String positionType = getText(itemDevice, "PositionType"); - - // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 - // String roomType = getText(itemDevice, "RoomType"); - // TODO 摄像机用途属性 - // String useType = getText(itemDevice, "UseType"); - // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 - // String supplyLightType = getText(itemDevice, "SupplyLightType"); - // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 - // String directionType = getText(itemDevice, "DirectionType"); - // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 - // String resolution = getText(itemDevice, "Resolution"); - - // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 - // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); - // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) - // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); - // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 - // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); - - - deviceChannel.setSecrecy(secrecy); - break; - } - } - - return deviceChannel; - } +// public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event){ +// DeviceChannel deviceChannel = new DeviceChannel(); +// deviceChannel.setDeviceId(device.getDeviceId()); +// Element channdelIdElement = itemDevice.element("DeviceID"); +// if (channdelIdElement == null) { +// logger.warn("解析Catalog消息时发现缺少 DeviceID"); +// return null; +// } +// String channelId = channdelIdElement.getTextTrim(); +// if (ObjectUtils.isEmpty(channelId)) { +// logger.warn("解析Catalog消息时发现缺少 DeviceID"); +// return null; +// } +// deviceChannel.setDeviceId(channelId); +// if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) { +// // 除了ADD和update情况下需要识别全部内容, +// return deviceChannel; +// } +// Element nameElement = itemDevice.element("Name"); +// // 当通道名称为空时,设置通道名称为通道编码,避免级联时因通道名称为空导致上级接收通道失败 +// if (nameElement != null && StringUtils.isNotBlank(nameElement.getText())) { +// deviceChannel.setName(nameElement.getText()); +// } else { +// deviceChannel.setName(channelId); +// } +// if(channelId.length() <= 8) { +// deviceChannel.setHasAudio(false); +// CivilCodePo parentCode = CivilCodeUtil.INSTANCE.getParentCode(channelId); +// if (parentCode != null) { +// deviceChannel.setParentId(parentCode.getCode()); +// deviceChannel.setCivilCode(parentCode.getCode()); +// }else { +// logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId); +// } +// deviceChannel.setStatus("ON"); +// return deviceChannel; +// }else { +// if(channelId.length() != 20) { +// logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId); +// return null; +// } +// +// int code = Integer.parseInt(channelId.substring(10, 13)); +// if (code == 136 || code == 137 || code == 138) { +// deviceChannel.setHasAudio(true); +// }else { +// deviceChannel.setHasAudio(false); +// } +// // 设备厂商 +// String manufacturer = getText(itemDevice, "Manufacturer"); +// // 设备型号 +// String model = getText(itemDevice, "Model"); +// // 设备归属 +// String owner = getText(itemDevice, "Owner"); +// // 行政区域 +// String civilCode = getText(itemDevice, "CivilCode"); +// // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织 +// String businessGroupID = getText(itemDevice, "BusinessGroupID"); +// // 父设备/区域/系统ID +// String parentID = getText(itemDevice, "ParentID"); +// if (parentID != null && parentID.equalsIgnoreCase("null")) { +// parentID = null; +// } +// // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式 +// String registerWay = getText(itemDevice, "RegisterWay"); +// // 保密属性(必选)缺省为0;0:不涉密,1:涉密 +// String secrecy = getText(itemDevice, "Secrecy"); +// // 安装地址 +// String address = getText(itemDevice, "Address"); +// +// switch (code){ +// case 200: +// // 系统目录 +// if (!ObjectUtils.isEmpty(manufacturer)) { +// deviceChannel.setManufacture(manufacturer); +// } +// if (!ObjectUtils.isEmpty(model)) { +// deviceChannel.setModel(model); +// } +// if (!ObjectUtils.isEmpty(owner)) { +// deviceChannel.setOwner(owner); +// } +// if (!ObjectUtils.isEmpty(civilCode)) { +// deviceChannel.setCivilCode(civilCode); +// deviceChannel.setParentId(civilCode); +// }else { +// if (!ObjectUtils.isEmpty(parentID)) { +// deviceChannel.setParentId(parentID); +// } +// } +// if (!ObjectUtils.isEmpty(address)) { +// deviceChannel.setAddress(address); +// } +// deviceChannel.setStatus(true); +// if (!ObjectUtils.isEmpty(registerWay)) { +// try { +// deviceChannel.setRegisterWay(Integer.parseInt(registerWay)); +// }catch (NumberFormatException exception) { +// logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); +// } +// } +// if (!ObjectUtils.isEmpty(secrecy)) { +// deviceChannel.setSecrecy(secrecy); +// } +// return deviceChannel; +// case 215: +// // 业务分组 +// deviceChannel.setStatus(true); +// if (!ObjectUtils.isEmpty(parentID)) { +// if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) { +// deviceChannel.setParentId(parentID); +// } +// }else { +// logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId"); +// if (!ObjectUtils.isEmpty(civilCode)) { +// deviceChannel.setCivilCode(civilCode); +// } +// } +// break; +// case 216: +// // 虚拟组织 +// deviceChannel.setStatus(true); +// if (!ObjectUtils.isEmpty(businessGroupID)) { +// deviceChannel.setBusinessGroupId(businessGroupID); +// } +// +// if (!ObjectUtils.isEmpty(parentID)) { +// if (parentID.contains("/")) { +// String[] parentIdArray = parentID.split("/"); +// parentID = parentIdArray[parentIdArray.length - 1]; +// } +// deviceChannel.setParentId(parentID); +// }else { +// if (!ObjectUtils.isEmpty(businessGroupID)) { +// deviceChannel.setParentId(businessGroupID); +// } +// } +// break; +// default: +// // 设备目录 +// if (!ObjectUtils.isEmpty(manufacturer)) { +// deviceChannel.setManufacture(manufacturer); +// } +// if (!ObjectUtils.isEmpty(model)) { +// deviceChannel.setModel(model); +// } +// if (!ObjectUtils.isEmpty(owner)) { +// deviceChannel.setOwner(owner); +// } +// if (!ObjectUtils.isEmpty(civilCode) +// && civilCode.length() <= 8 +// && NumberUtils.isParsable(civilCode) +// && civilCode.length()%2 == 0 +// ) { +// deviceChannel.setCivilCode(civilCode); +// } +// if (!ObjectUtils.isEmpty(businessGroupID)) { +// deviceChannel.setBusinessGroupId(businessGroupID); +// } +// +// // 警区 +// String block = getText(itemDevice, "Block"); +// if (!ObjectUtils.isEmpty(block)) { +// deviceChannel.setBlock(block); +// } +// if (!ObjectUtils.isEmpty(address)) { +// deviceChannel.setAddress(address); +// } +// +// if (!ObjectUtils.isEmpty(secrecy)) { +// deviceChannel.setSecrecy(secrecy); +// } +// +// // 当为设备时,是否有子设备(必选)1有,0没有 +// String parental = getText(itemDevice, "Parental"); +// if (!ObjectUtils.isEmpty(parental)) { +// try { +// // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1 +// if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) { +// deviceChannel.setParental(0); +// }else { +// deviceChannel.setParental(1); +// } +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental); +// } +// } +// // 父设备/区域/系统ID +// +// if (!ObjectUtils.isEmpty(parentID) ) { +// if (parentID.contains("/")) { +// String[] parentIdArray = parentID.split("/"); +// deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]); +// }else { +// if (parentID.length()%2 == 0) { +// deviceChannel.setParentId(parentID); +// }else { +// logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID); +// } +// } +// }else { +// if (!ObjectUtils.isEmpty(businessGroupID)) { +// deviceChannel.setParentId(businessGroupID); +// }else { +// if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) { +// deviceChannel.setParentId(deviceChannel.getCivilCode()); +// } +// } +// } +// // 注册方式 +// if (!ObjectUtils.isEmpty(registerWay)) { +// try { +// int registerWayInt = Integer.parseInt(registerWay); +// deviceChannel.setRegisterWay(registerWayInt); +// }catch (NumberFormatException exception) { +// logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay); +// deviceChannel.setRegisterWay(1); +// } +// }else { +// deviceChannel.setRegisterWay(1); +// } +// +// // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式 +// String safetyWay = getText(itemDevice, "SafetyWay"); +// if (!ObjectUtils.isEmpty(safetyWay)) { +// try { +// deviceChannel.setSafetyWay(Integer.parseInt(safetyWay)); +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay); +// } +// } +// +// // 证书序列号(有证书的设备必选) +// String certNum = getText(itemDevice, "CertNum"); +// if (!ObjectUtils.isEmpty(certNum)) { +// deviceChannel.setCertNum(certNum); +// } +// +// // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效 +// String certifiable = getText(itemDevice, "Certifiable"); +// if (!ObjectUtils.isEmpty(certifiable)) { +// try { +// deviceChannel.setCertifiable(Integer.parseInt(certifiable)); +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable); +// } +// } +// +// // 无效原因码(有证书且证书无效的设备必选) +// String errCode = getText(itemDevice, "ErrCode"); +// if (!ObjectUtils.isEmpty(errCode)) { +// try { +// deviceChannel.setErrCode(Integer.parseInt(errCode)); +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode); +// } +// } +// +// // 证书终止有效期(有证书的设备必选) +// String endTime = getText(itemDevice, "EndTime"); +// if (!ObjectUtils.isEmpty(endTime)) { +// deviceChannel.setEndTime(endTime); +// } +// +// +// // 设备/区域/系统IP地址 +// String ipAddress = getText(itemDevice, "IPAddress"); +// if (!ObjectUtils.isEmpty(ipAddress)) { +// deviceChannel.setIpAddress(ipAddress); +// } +// +// // 设备/区域/系统端口 +// String port = getText(itemDevice, "Port"); +// if (!ObjectUtils.isEmpty(port)) { +// try { +// deviceChannel.setPort(Integer.parseInt(port)); +// }catch (NumberFormatException e) { +// logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port); +// } +// } +// +// // 设备口令 +// String password = getText(itemDevice, "Password"); +// if (!ObjectUtils.isEmpty(password)) { +// deviceChannel.setPassword(password); +// } +// +// +// // 设备状态 +// String status = getText(itemDevice, "Status"); +// if (status != null) { +// // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 +// if (status.equalsIgnoreCase("ON") || status.equalsIgnoreCase("On") || status.equalsIgnoreCase("ONLINE") || status.equalsIgnoreCase("OK")) { +// deviceChannel.setStatus(true); +// } +// if (status.equalsIgnoreCase("OFF") || status.equalsIgnoreCase("Off") || status.equalsIgnoreCase("OFFLINE")) { +// deviceChannel.setStatus(false); +// } +// }else { +// deviceChannel.setStatus(true); +// } +//// logger.info("状态字符串: {}", status); +//// logger.info("状态结果: {}", deviceChannel.isStatus()); +// // 经度 +// String longitude = getText(itemDevice, "Longitude"); +// if (NumericUtil.isDouble(longitude)) { +// deviceChannel.setLongitude(Double.parseDouble(longitude)); +// } else { +// deviceChannel.setLongitude(0.00); +// } +// +// // 纬度 +// String latitude = getText(itemDevice, "Latitude"); +// if (NumericUtil.isDouble(latitude)) { +// deviceChannel.setLatitude(Double.parseDouble(latitude)); +// } else { +// deviceChannel.setLatitude(0.00); +// } +// +// deviceChannel.setGpsTime(DateUtil.getNow()); +// +// // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选 +// String ptzType = getText(itemDevice, "PTZType"); +// if (ObjectUtils.isEmpty(ptzType)) { +// //兼容INFO中的信息 +// Element info = itemDevice.element("Info"); +// String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType"); +// if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){ +// try { +// deviceChannel.setPtzType(Integer.parseInt(ptzTypeFromInfo)); +// }catch (NumberFormatException e){ +// logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo); +// } +// } +// } else { +// try { +// deviceChannel.setPtzType(Integer.parseInt(ptzType)); +// }catch (NumberFormatException e){ +// logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType); +// } +// } +// +// // TODO 摄像机位置类型扩展。 +// // 1-省际检查站、 +// // 2-党政机关、 +// // 3-车站码头、 +// // 4-中心广场、 +// // 5-体育场馆、 +// // 6-商业中心、 +// // 7-宗教场所、 +// // 8-校园周边、 +// // 9-治安复杂区域、 +// // 10-交通干线。 +// // String positionType = getText(itemDevice, "PositionType"); +// +// // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。 +// // String roomType = getText(itemDevice, "RoomType"); +// // TODO 摄像机用途属性 +// // String useType = getText(itemDevice, "UseType"); +// // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光 +// // String supplyLightType = getText(itemDevice, "SupplyLightType"); +// // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。 +// // String directionType = getText(itemDevice, "DirectionType"); +// // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定 +// // String resolution = getText(itemDevice, "Resolution"); +// +// // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4 +// // String downloadSpeed = getText(itemDevice, "DownloadSpeed"); +// // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层) +// // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode"); +// // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强 +// // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode"); +// +// +// deviceChannel.setSecrecy(secrecy); +// break; +// } +// } +// +// return deviceChannel; +// } /** * 新增方法支持内部嵌套 @@ -672,6 +664,46 @@ public class XmlUtil { return t; } + public static T elementDecode(Element element, Class clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Field[] fields = clazz.getDeclaredFields(); + T t = clazz.getDeclaredConstructor().newInstance(); + for (Field field : fields) { + ReflectionUtils.makeAccessible(field); + MessageElement annotation = field.getAnnotation(MessageElement.class); + if (annotation == null) { + continue; + } + String value = annotation.value(); + boolean subVal = value.contains("."); + Element element1 = element.element(value); + if (element1 == null) { + continue; + } + if (!subVal) { + // 无下级数据 + Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType()); + Object o = simpleTypeDeal(field.getType(), fieldVal); + ReflectionUtils.setField(field, t, o); + } else { + String[] pathArray = value.split("."); + Element subElement = element1; + for (String path : pathArray) { + subElement = subElement.element(path); + if (subElement == null) { + break; + } + } + if (subElement == null) { + continue; + } + Object fieldVal = subElement.isTextOnly() ? subElement.getText() : loadElement(subElement, field.getType()); + Object o = simpleTypeDeal(field.getType(), fieldVal); + ReflectionUtils.setField(field, t, o); + } + } + return t; + } + /** * 简单类型处理 * diff --git a/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java b/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java index f37539cd..f4477283 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.service; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; @@ -45,8 +46,8 @@ public interface IGbStreamService { DeviceChannel getDeviceChannelListByStream(GbStream gbStream, String catalogId, ParentPlatform platform); - void sendCatalogMsg(GbStream gbStream, String type); - void sendCatalogMsgs(List gbStreams, String type); + void sendCatalogMsg(CommonGBChannel gbStream, String type); + void sendCatalogMsgs(List gbStreams, String type); /** * 修改gbId或name diff --git a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java index b99106e7..8936c642 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java @@ -116,4 +116,7 @@ public interface IStreamPushService { void updatePush(OnStreamChangedHookParam param); + + Map getAllGBId(); + } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java index 46b70f18..0f199378 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java @@ -157,16 +157,16 @@ public class GbStreamServiceImpl implements IGbStreamService { } @Override - public void sendCatalogMsg(GbStream gbStream, String type) { - if (gbStream == null || type == null) { + public void sendCatalogMsg(CommonGBChannel channel, String type) { + if (channel == null || type == null) { logger.warn("[发送目录订阅]类型:流信息或类型为NULL"); return; } - List gbStreams = new ArrayList<>(); - if (gbStream.getGbId() != null) { - gbStreams.add(gbStream); + List gbStreams = new ArrayList<>(); + if (channel.getGbDeviceId() != null) { + gbStreams.add(channel); }else { - GbStream gbStreamIndb = gbStreamMapper.selectOne(gbStream.getApp(), gbStream.getStream()); + GbStream gbStreamIndb = gbStreamMapper.selectOne(channel.getApp(), channel.getStream()); if (gbStreamIndb != null && gbStreamIndb.getGbId() != null){ gbStreams.add(gbStreamIndb); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java index 0d8a8ec6..c73b055c 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java @@ -48,9 +48,6 @@ public class StreamPushServiceImpl implements IStreamPushService { private final static Logger logger = LoggerFactory.getLogger(StreamPushServiceImpl.class); - @Autowired - private GbStreamMapper gbStreamMapper; - @Autowired private StreamPushMapper streamPushMapper; @@ -66,9 +63,6 @@ public class StreamPushServiceImpl implements IStreamPushService { @Autowired private PlatformGbStreamMapper platformGbStreamMapper; - @Autowired - private IGbStreamService gbStreamService; - @Autowired private EventPublisher eventPublisher; @@ -126,16 +120,7 @@ public class StreamPushServiceImpl implements IStreamPushService { streamPushMapper.update(transform); gbStreamMapper.updateMediaServer(event.getApp(), event.getStream(), event.getMediaServer().getId()); } - // TODO 相关的事件自行管理,不需要写入ZLMMediaListManager -// ChannelOnlineEvent channelOnlineEventLister = getChannelOnlineEventLister(transform.getApp(), transform.getStream()); -// if ( channelOnlineEventLister != null) { -// try { -// channelOnlineEventLister.run(transform.getApp(), transform.getStream(), transform.getServerId());; -// } catch (ParseException e) { -// logger.error("addPush: ", e); -// } -// removedChannelOnlineEventLister(transform.getApp(), transform.getStream()); -// } + // 冗余数据,自己系统中自用 redisCatchStorage.addPushListItem(event.getApp(), event.getStream(), event); @@ -216,7 +201,6 @@ public class StreamPushServiceImpl implements IStreamPushService { streamPushItem.setMediaServerId(item.getMediaServerId()); streamPushItem.setStream(item.getStream()); streamPushItem.setCreateTime(DateUtil.getNow()); - streamPushItem.setVhost(item.getVhost()); streamPushItem.setServerId(item.getSeverId()); return streamPushItem; } @@ -625,6 +609,11 @@ public class StreamPushServiceImpl implements IStreamPushService { return streamPushMapper.getAllAppAndStreamMap(); } + @Override + public Map getAllGBId() { + return streamPushMapper.getAllGBId(); + } + @Override public void updatePush(OnStreamChangedHookParam param) { StreamPush transform = transform(param); diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java index 48b08eac..842277a8 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java @@ -2,10 +2,9 @@ package com.genersoft.iot.vmp.service.redisMsg; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.gb28181.bean.GbStream; +import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.zlm.dto.StreamPush; import com.genersoft.iot.vmp.service.IGbStreamService; -import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.IStreamPushService; import com.genersoft.iot.vmp.utils.DateUtil; import org.slf4j.Logger; @@ -60,43 +59,40 @@ public class RedisPushStreamStatusListMsgListener implements MessageListener { List streamPushItems = JSON.parseArray(new String(msg.getBody()), StreamPush.class); //查询全部的app+stream 用于判断是添加还是修改 Map allAppAndStream = streamPushService.getAllAppAndStreamMap(); - Map allGBId = gbStreamService.getAllGBId(); + Map allGBId = streamPushService.getAllGBId(); /** * 用于存储更具APP+Stream过滤后的数据,可以直接存入stream_push表与gb_stream表 */ List streamPushItemForSave = new ArrayList<>(); List streamPushItemForUpdate = new ArrayList<>(); - for (StreamPush streamPushItem : streamPushItems) { - String app = streamPushItem.getApp(); - String stream = streamPushItem.getStream(); + for (StreamPush streamPush : streamPushItems) { + String app = streamPush.getApp(); + String stream = streamPush.getStream(); boolean contains = allAppAndStream.containsKey(app + stream); //不存在就添加 if (!contains) { - if (allGBId.containsKey(streamPushItem.getGbId())) { - GbStream gbStream = allGBId.get(streamPushItem.getGbId()); + if (allGBId.containsKey(streamPush.getGbDeviceId())) { + StreamPush streamPushInDb = allGBId.get(streamPush.getGbDeviceId()); logger.warn("[REDIS消息-推流设备列表更新-INSERT] 国标编号重复: {}, 已分配给{}/{}", - streamPushItem.getGbId(), gbStream.getApp(), gbStream.getStream()); + streamPushInDb.getGbDeviceId(), streamPushInDb.getApp(), streamPushInDb.getStream()); continue; } - streamPushItem.setStreamType("push"); - streamPushItem.setCreateTime(DateUtil.getNow()); - streamPushItem.setMediaServerId(mediaServerService.getDefaultMediaServer().getId()); - streamPushItem.setOriginType(2); - streamPushItem.setOriginTypeStr("rtsp_push"); - streamPushItem.setTotalReaderCount(0); - streamPushItemForSave.add(streamPushItem); - allGBId.put(streamPushItem.getGbId(), streamPushItem); + streamPush.setCreateTime(DateUtil.getNow()); + streamPush.setMediaServerId(mediaServerService.getDefaultMediaServer().getId()); + streamPushItemForSave.add(streamPush); + allGBId.put(streamPush.getGbDeviceId(), streamPush); } else { - if (allGBId.containsKey(streamPushItem.getGbId()) - && (!allGBId.get(streamPushItem.getGbId()).getApp().equals(streamPushItem.getApp()) || !allGBId.get(streamPushItem.getGbId()).getStream().equals(streamPushItem.getStream()))) { - GbStream gbStream = allGBId.get(streamPushItem.getGbId()); + if (allGBId.containsKey(streamPush.getGbDeviceId()) + && (!allGBId.get(streamPush.getGbDeviceId()).getApp().equals(streamPush.getApp()) + || !allGBId.get(streamPush.getGbDeviceId()).getStream().equals(streamPush.getStream()))) { + StreamPush streamPushInDb = allGBId.get(streamPush.getGbDeviceId()); logger.warn("[REDIS消息-推流设备列表更新-UPDATE] 国标编号重复: {}, 已分配给{}/{}", - streamPushItem.getGbId(), gbStream.getApp(), gbStream.getStream()); + streamPush.getGbDeviceId(), streamPushInDb.getApp(), streamPushInDb.getStream()); continue; } //存在就只修改 name和gbId - streamPushItemForUpdate.add(streamPushItem); + streamPushItemForUpdate.add(streamPush); } } if (!streamPushItemForSave.isEmpty()) { diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java index a0746dc5..6c6f93d0 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java @@ -204,4 +204,10 @@ public interface StreamPushMapper { Map getAllAppAndStreamMap(); + @MapKey("gb_id") + @Select("SELECT wgs.gb_id, wsp.app, wsp.stream, wgs.gb_id, wgs.name " + + " from wvp_stream_push wsp " + + " left join wvp_gb_stream wgs on wgs.app = wsp.app and wgs.stream = wsp.stream") + Map getAllGBId(); + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3f478442..ddb05dee 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,4 +2,4 @@ spring: application: name: wvp profiles: - active: local \ No newline at end of file + active: local271 \ No newline at end of file From 7255e5a8875f83b597ad26ef7705afcd5f0e15f8 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 25 Jun 2024 16:59:22 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/service/IStreamPushService.java | 3 + .../service/impl/StreamPushServiceImpl.java | 63 +++++++++---------- .../streamPush/StreamPushController.java | 19 ------ 3 files changed, 31 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java index 8936c642..650908e7 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java @@ -100,6 +100,8 @@ public interface IStreamPushService { */ boolean add(StreamPush stream); + boolean update(StreamPush stream); + /** * 获取全部的app+Streanm 用于判断推流列表是新增还是修改 * @return @@ -119,4 +121,5 @@ public interface IStreamPushService { Map getAllGBId(); + void updateStatus(StreamPush push); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java index 15285dd7..aa7296ed 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java @@ -19,7 +19,6 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamPush; import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OriginType; -import com.genersoft.iot.vmp.service.IGbStreamService; import com.genersoft.iot.vmp.service.IStreamPushService; import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -116,10 +115,9 @@ public class StreamPushServiceImpl implements IStreamPushService { StreamPush pushInDb = getPush(event.getApp(), event.getStream()); if (pushInDb == null) { transform.setCreateTime(DateUtil.getNow()); - streamPushMapper.add(transform); + add(transform); }else { - streamPushMapper.update(transform); - gbStreamMapper.updateMediaServer(event.getApp(), event.getStream(), event.getMediaServer().getId()); + update(transform); } // 冗余数据,自己系统中自用 if (!"broadcast".equals(event.getApp()) && !"talk".equals(event.getApp())) { @@ -166,14 +164,17 @@ public class StreamPushServiceImpl implements IStreamPushService { redisCatchStorage.sendStreamChangeMsg(type, jsonObject); } } - GbStream gbStream = gbStreamMapper.selectOne(event.getApp(), event.getStream()); - if (gbStream != null) { + StreamPush push = getPush(event.getApp(), event.getStream()); + push.setPushIng(false); + if (push.getGbDeviceId() != null) { if (userSetting.isUsePushingAsStatus()) { - streamPushMapper.updatePushStatus(event.getApp(), event.getStream(), false); - eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); + push.setGbStatus(false); + updateStatus(push); +// streamPushMapper.updatePushStatus(event.getApp(), event.getStream(), false); +// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); } }else { - streamPushMapper.del(event.getApp(), event.getStream()); + deleteByAppAndStream(event.getApp(), event.getStream()); } } @@ -222,31 +223,6 @@ public class StreamPushServiceImpl implements IStreamPushService { return streamPushMapper.selectAllByMediaServerIdWithOutGbID(mediaServerId); } - @Override - public boolean saveToGB(GbStream stream) { - stream.setStreamType("push"); - stream.setStatus(true); - stream.setCreateTime(DateUtil.getNow()); - stream.setStreamType("push"); - stream.setMediaServerId(mediaConfig.getId()); - int add = gbStreamMapper.add(stream); - return add > 0; - } - - @Override - public boolean removeFromGB(GbStream stream) { - // 判断是否需要发送事件 - gbStreamService.sendCatalogMsg(stream, CatalogEvent.DEL); - platformGbStreamMapper.delByAppAndStream(stream.getApp(), stream.getStream()); - int del = gbStreamMapper.del(stream.getApp(), stream.getStream()); - MediaServer mediaInfo = mediaServerService.getOne(stream.getMediaServerId()); - List mediaList = mediaServerService.getMediaList(mediaInfo, stream.getApp(), stream.getStream(), null); - if (mediaList != null && mediaList.isEmpty()) { - streamPushMapper.del(stream.getApp(), stream.getStream()); - } - return del > 0; - } - @Override public StreamPush getPush(String app, String streamId) { @@ -255,7 +231,7 @@ public class StreamPushServiceImpl implements IStreamPushService { @Override public boolean stop(String app, String stream) { - logger.info("[推流 ] 停止流: {}/{}", app, stream); + logger.info("[推流] 停止流: {}/{}", app, stream); StreamPush streamPushItem = streamPushMapper.selectOne(app, stream); if (streamPushItem != null) { gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); @@ -595,6 +571,11 @@ public class StreamPushServiceImpl implements IStreamPushService { return result; } + @Override + public boolean update(StreamPush stream) { + + } + @Override public List getAllAppAndStream() { @@ -635,4 +616,16 @@ public class StreamPushServiceImpl implements IStreamPushService { gbStreamMapper.updateMediaServer(param.getApp(), param.getStream(), param.getMediaServerId()); } } + + @Override + public void updateStatus(StreamPush push) { + + } + + @Override + public void deleteByAppAndStream(String app, String stream) { + + } + + } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java index 41f12419..34ba4b0e 100755 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java @@ -88,25 +88,6 @@ public class StreamPushController { return pushList; } - @PostMapping(value = "/save_to_gb") - @ResponseBody - @Operation(summary = "将推流添加到国标", security = @SecurityRequirement(name = JwtUtils.HEADER)) - public void saveToGB(@RequestBody GbStream stream){ - if (!streamPushService.saveToGB(stream)){ - throw new ControllerException(ErrorCode.ERROR100); - } - } - - - @DeleteMapping(value = "/remove_form_gb") - @ResponseBody - @Operation(summary = "将推流移出到国标", security = @SecurityRequirement(name = JwtUtils.HEADER)) - public void removeFormGB(@RequestBody GbStream stream){ - if (!streamPushService.removeFromGB(stream)){ - throw new ControllerException(ErrorCode.ERROR100); - } - } - @PostMapping(value = "/stop") @ResponseBody From 81049b5a9ec89eb8e3ec2eacd051bc68a162ced4 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 25 Jun 2024 17:46:33 +0800 Subject: [PATCH 11/12] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/service/impl/StreamPushServiceImpl.java | 2 +- .../redisMsg/RedisCloseStreamMsgListener.java | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java index aa7296ed..2f159336 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java @@ -231,7 +231,7 @@ public class StreamPushServiceImpl implements IStreamPushService { @Override public boolean stop(String app, String stream) { - logger.info("[推流] 停止流: {}/{}", app, stream); + logger.info("[推流] 停止推流: {}/{}", app, stream); StreamPush streamPushItem = streamPushMapper.selectOne(app, stream); if (streamPushItem != null) { gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java index d0104756..38eb5344 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java @@ -3,9 +3,8 @@ package com.genersoft.iot.vmp.service.redisMsg; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.service.IStreamPushService; +import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.connection.Message; @@ -17,14 +16,13 @@ import java.util.concurrent.ConcurrentLinkedQueue; /** * 接收来自redis的关闭流更新通知 + * 消息举例: PUBLISH VM_MSG_STREAM_PUSH_CLOSE "{'app': 'live', 'stream': 'stream'}" * @author lin */ +@Slf4j @Component public class RedisCloseStreamMsgListener implements MessageListener { - private final static Logger logger = LoggerFactory.getLogger(RedisCloseStreamMsgListener.class); - - @Autowired private IStreamPushService pushService; @@ -47,10 +45,9 @@ public class RedisCloseStreamMsgListener implements MessageListener { String app = jsonObject.getString("app"); String stream = jsonObject.getString("stream"); pushService.stop(app, stream); - }catch (Exception e) { - logger.warn("[REDIS的关闭推流通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); - logger.error("[REDIS的关闭推流通知] 异常内容: ", e); + log.warn("[REDIS的关闭推流通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); + log.error("[REDIS的关闭推流通知] 异常内容: ", e); } } }); From f32eb14125f6f5c2a38a4ded11286f20d96caaef Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 26 Jun 2024 18:36:32 +0800 Subject: [PATCH 12/12] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/gb28181/bean/CommonGBChannel.java | 3 + .../gb28181/service/IGbChannelService.java | 25 ++ .../service/impl/GbChannelServiceImpl.java | 10 + .../MediaServerStatusEventListener.java | 6 - .../iot/vmp/media/zlm/dto/StreamPush.java | 11 + .../iot/vmp/service/IStreamPushService.java | 8 +- .../service/impl/StreamPushServiceImpl.java | 380 ++++++++++-------- .../redisMsg/RedisCloseStreamMsgListener.java | 2 +- .../vmp/storager/dao/StreamPushMapper.java | 2 +- .../streamPush/StreamPushController.java | 3 +- 10 files changed, 269 insertions(+), 181 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java index a9842123..816917d4 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java @@ -7,6 +7,9 @@ import lombok.Data; @Schema(description = "国标通道") public class CommonGBChannel { + @Schema(description = "国标-数据库自增ID") + private int gbId; + @Schema(description = "国标-编码") private String gbDeviceId; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java new file mode 100644 index 00000000..4858bc5a --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java @@ -0,0 +1,25 @@ +package com.genersoft.iot.vmp.gb28181.service; + +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; + +import java.util.List; + +public interface IGbChannelService { + + CommonGBChannel queryByDeviceId(String gbDeviceId); + + int add(CommonGBChannel commonGBChannel); + + int delete(int gbId); + + int update(CommonGBChannel commonGBChannel); + + int offline(CommonGBChannel commonGBChannel); + + int online(CommonGBChannel commonGBChannel); + + void closeSend(CommonGBChannel commonGBChannel); + + void batchAdd(List commonGBChannels); + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java new file mode 100644 index 00000000..adf5251c --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java @@ -0,0 +1,10 @@ +package com.genersoft.iot.vmp.gb28181.service.impl; + +import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class GbChannelServiceImpl implements IGbChannelService { +} diff --git a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java index 2413f567..1e1fcca1 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/event/mediaServer/MediaServerStatusEventListener.java @@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.media.event.mediaServer; import com.genersoft.iot.vmp.service.IPlayService; import com.genersoft.iot.vmp.service.IStreamProxyService; -import com.genersoft.iot.vmp.service.IStreamPushService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -23,9 +22,6 @@ public class MediaServerStatusEventListener { private final static Logger logger = LoggerFactory.getLogger(MediaServerStatusEventListener.class); - @Autowired - private IStreamPushService streamPushService; - @Autowired private IStreamProxyService streamProxyService; @@ -36,7 +32,6 @@ public class MediaServerStatusEventListener { @EventListener public void onApplicationEvent(MediaServerOnlineEvent event) { logger.info("[媒体节点] 上线 ID:" + event.getMediaServerId()); - streamPushService.zlmServerOnline(event.getMediaServerId()); streamProxyService.zlmServerOnline(event.getMediaServerId()); playService.zlmServerOnline(event.getMediaServerId()); } @@ -48,7 +43,6 @@ public class MediaServerStatusEventListener { logger.info("[媒体节点] 离线,ID:" + event.getMediaServerId()); // 处理ZLM离线 streamProxyService.zlmServerOffline(event.getMediaServerId()); - streamPushService.zlmServerOffline(event.getMediaServerId()); playService.zlmServerOffline(event.getMediaServerId()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPush.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPush.java index 41d4af96..eeb444dc 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPush.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPush.java @@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import org.jetbrains.annotations.NotNull; +import org.springframework.util.ObjectUtils; @Data @@ -102,6 +103,16 @@ public class StreamPush extends CommonGBChannel implements Comparable getAllGBId(); void updateStatus(StreamPush push); + + void deleteByAppAndStream(String app, String stream); + + void updatePushStatus(Integer streamPushId, boolean pushIng); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java index 2f159336..31dfe4cc 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java @@ -5,19 +5,22 @@ import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaConfig; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.GbStream; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.media.bean.MediaInfo; +import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent; +import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent; +import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent; import com.genersoft.iot.vmp.media.service.IMediaServerService; -import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamPush; -import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.media.zlm.dto.hook.OriginType; import com.genersoft.iot.vmp.service.IStreamPushService; import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; @@ -28,6 +31,7 @@ import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; import com.genersoft.iot.vmp.vmanager.bean.StreamContent; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -36,18 +40,17 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionDefinition; -import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import java.util.*; import java.util.stream.Collectors; @Service +@Slf4j @DS("master") public class StreamPushServiceImpl implements IStreamPushService { - private final static Logger logger = LoggerFactory.getLogger(StreamPushServiceImpl.class); - @Autowired private StreamPushMapper streamPushMapper; @@ -84,6 +87,9 @@ public class StreamPushServiceImpl implements IStreamPushService { @Autowired private MediaConfig mediaConfig; + @Autowired + private IGbChannelService gbChannelService; + /** * 流到来的处理 */ @@ -107,17 +113,17 @@ public class StreamPushServiceImpl implements IStreamPushService { streamAuthorityInfo.setOriginType(mediaInfo.getOriginType()); } redisCatchStorage.updateStreamAuthorityInfo(event.getApp(), event.getStream(), streamAuthorityInfo); - StreamPush transform = StreamPush.getInstance(event, userSetting.getServerId()); - transform.setPushIng(true); - transform.setUpdateTime(DateUtil.getNow()); - transform.setPushTime(DateUtil.getNow()); - transform.setSelf(true); - StreamPush pushInDb = getPush(event.getApp(), event.getStream()); - if (pushInDb == null) { - transform.setCreateTime(DateUtil.getNow()); - add(transform); + + StreamPush streamPushInDb = getPush(event.getApp(), event.getStream()); + if (streamPushInDb == null) { + StreamPush streamPush = StreamPush.getInstance(event, userSetting.getServerId()); + streamPush.setPushIng(true); + streamPush.setUpdateTime(DateUtil.getNow()); + streamPush.setPushTime(DateUtil.getNow()); + streamPush.setSelf(true); + add(streamPush); }else { - update(transform); + updatePushStatus(streamPushInDb.getId(), true); } // 冗余数据,自己系统中自用 if (!"broadcast".equals(event.getApp()) && !"talk".equals(event.getApp())) { @@ -143,6 +149,7 @@ public class StreamPushServiceImpl implements IStreamPushService { @Async("taskExecutor") @EventListener public void onApplicationEvent(MediaDepartureEvent event) { + // 兼容流注销时类型从redis记录获取 MediaInfo mediaInfo = redisCatchStorage.getStreamInfo( event.getApp(), event.getStream(), event.getMediaServer().getId()); @@ -178,37 +185,22 @@ public class StreamPushServiceImpl implements IStreamPushService { } } - - private List handleJSON(List streamInfoList) { - if (streamInfoList == null || streamInfoList.isEmpty()) { - return null; - } - Map result = new HashMap<>(); - for (StreamInfo streamInfo : streamInfoList) { - // 不保存国标推理以及拉流代理的流 - if (streamInfo.getOriginType() == OriginType.RTSP_PUSH.ordinal() - || streamInfo.getOriginType() == OriginType.RTMP_PUSH.ordinal() - || streamInfo.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { - String key = streamInfo.getApp() + "_" + streamInfo.getStream(); - StreamPush streamPushItem = result.get(key); - if (streamPushItem == null) { - streamPushItem = streamPushItem.getInstance(streamInfo); - result.put(key, streamPushItem); - } - } - } - return new ArrayList<>(result.values()); + /** + * 流媒体节点上线 + */ + @Async("taskExecutor") + @EventListener + public void onApplicationEvent(MediaServerOnlineEvent event) { + zlmServerOnline(event.getMediaServerId()); } - @Override - public StreamPush transform(OnStreamChangedHookParam item) { - StreamPush streamPushItem = new StreamPush(); - streamPushItem.setApp(item.getApp()); - streamPushItem.setMediaServerId(item.getMediaServerId()); - streamPushItem.setStream(item.getStream()); - streamPushItem.setCreateTime(DateUtil.getNow()); - streamPushItem.setServerId(item.getSeverId()); - return streamPushItem; + /** + * 流媒体节点离线 + */ + @Async("taskExecutor") + @EventListener + public void onApplicationEvent(MediaServerOfflineEvent event) { + zlmServerOffline(event.getMediaServerId()); } @Override @@ -225,29 +217,113 @@ public class StreamPushServiceImpl implements IStreamPushService { @Override - public StreamPush getPush(String app, String streamId) { - return streamPushMapper.selectOne(app, streamId); + public StreamPush getPush(String app, String stream) { + return streamPushMapper.selectByAppAndStream(app, stream); } @Override - public boolean stop(String app, String stream) { - logger.info("[推流] 停止推流: {}/{}", app, stream); - StreamPush streamPushItem = streamPushMapper.selectOne(app, stream); - if (streamPushItem != null) { - gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL); + @Transactional + public boolean add(StreamPush stream) { + log.info("[添加推流] app: {}, stream: {}, 国标编号: {}", stream.getApp(), stream.getStream(), stream.getGbDeviceId()); + stream.setUpdateTime(DateUtil.getNow()); + stream.setCreateTime(DateUtil.getNow()); + int addResult = streamPushMapper.add(stream); + if (addResult <= 0) { + return false; } + if (ObjectUtils.isEmpty(stream.getGbDeviceId())) { + return true; + } + CommonGBChannel channel = gbChannelService.queryByDeviceId(stream.getGbDeviceId()); + if (channel != null) { + log.info("[添加推流]失败,国标编号已存在: {} app: {}, stream: {}, ", stream.getGbDeviceId(), stream.getApp(), stream.getStream()); + } + int addChannelResult = gbChannelService.add(stream.getCommonGBChannel()); + return addChannelResult > 0; + } - platformGbStreamMapper.delByAppAndStream(app, stream); - gbStreamMapper.del(app, stream); - int delStream = streamPushMapper.del(app, stream); - if (delStream > 0) { - MediaServer mediaServerItem = mediaServerService.getOne(streamPushItem.getMediaServerId()); - mediaServerService.closeStreams(mediaServerItem,app, stream); + @Override + @Transactional + public void deleteByAppAndStream(String app, String stream) { + log.info("[删除推流] app: {}, stream: {}, ", app, stream); + StreamPush streamPush = streamPushMapper.selectByAppAndStream(app, stream); + if (streamPush == null) { + log.info("[删除推流]失败, 不存在 app: {}, stream: {}, ", app, stream); + return; + } + if (streamPush.isPushIng()) { + stop(streamPush); + } + if (streamPush.getGbId() > 0) { + gbChannelService.delete(streamPush.getGbId()); + } + } + @Override + @Transactional + public boolean update(StreamPush streamPush) { + log.info("[更新推流]:id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + assert streamPush.getId() != null; + streamPush.setUpdateTime(DateUtil.getNow()); + streamPushMapper.update(streamPush); + if (streamPush.getGbId() > 0) { + gbChannelService.update(streamPush.getCommonGBChannel()); + } + return true; + } + + + @Override + @Transactional + public boolean stop(StreamPush streamPush) { + log.info("[主动停止推流] id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + MediaServer mediaServer = null; + if (streamPush.getMediaServerId() == null) { + log.info("[主动停止推流]未找到使用MediaServer,开始自动检索 id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + mediaServer = mediaServerService.getMediaServerByAppAndStream(streamPush.getApp(), streamPush.getStream()); + if (mediaServer != null) { + log.info("[主动停止推流] 检索到MediaServer为{}, id: {}, app: {}, stream: {}, ", mediaServer.getId(), streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + }else { + log.info("[主动停止推流]未找到使用MediaServer id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + } + }else { + mediaServer = mediaServerService.getOne(streamPush.getMediaServerId()); + if (mediaServer == null) { + log.info("[主动停止推流]未找到使用的MediaServer: {},开始自动检索 id: {}, app: {}, stream: {}, ",streamPush.getMediaServerId(), streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + mediaServer = mediaServerService.getMediaServerByAppAndStream(streamPush.getApp(), streamPush.getStream()); + if (mediaServer != null) { + log.info("[主动停止推流] 检索到MediaServer为{}, id: {}, app: {}, stream: {}, ", mediaServer.getId(), streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + }else { + log.info("[主动停止推流]未找到使用MediaServer id: {}, app: {}, stream: {}, ", streamPush.getId(), streamPush.getApp(), streamPush.getStream()); + } + } + } + if (mediaServer != null) { + mediaServerService.closeStreams(mediaServer, streamPush.getApp(), streamPush.getStream()); + } + streamPush.setPushIng(false); + if (userSetting.isUsePushingAsStatus()) { + streamPush.setGbStatus(false); + gbChannelService.offline(streamPush.getCommonGBChannel()); + } + gbChannelService.closeSend(streamPush.getCommonGBChannel()); + streamPush.setUpdateTime(DateUtil.getNow()); + streamPushMapper.update(streamPush); + return true; + } + + @Override + @Transactional + public boolean stopByAppAndStream(String app, String stream) { + log.info("[主动停止推流] : app: {}, stream: {}, ", app, stream); + StreamPush streamPushItem = streamPushMapper.selectByAppAndStream(app, stream); + if (streamPushItem != null) { + stop(streamPushItem); } return true; } @Override + @Transactional public void zlmServerOnline(String mediaServerId) { // 同步zlm推流信息 MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId); @@ -260,14 +336,14 @@ public class StreamPushServiceImpl implements IStreamPushService { // redis记录 List mediaInfoList = redisCatchStorage.getStreams(mediaServerId, "PUSH"); Map streamInfoPushItemMap = new HashMap<>(); - if (pushList.size() > 0) { + if (!pushList.isEmpty()) { for (StreamPush streamPushItem : pushList) { if (ObjectUtils.isEmpty(streamPushItem.getGbId())) { pushItemMap.put(streamPushItem.getApp() + streamPushItem.getStream(), streamPushItem); } } } - if (mediaInfoList.size() > 0) { + if (!mediaInfoList.isEmpty()) { for (MediaInfo mediaInfo : mediaInfoList) { streamInfoPushItemMap.put(mediaInfo.getApp() + mediaInfo.getStream(), mediaInfo); } @@ -290,26 +366,33 @@ public class StreamPushServiceImpl implements IStreamPushService { streamAuthorityInfoInfoMap.remove(streamPushItem.getApp() + streamPushItem.getStream()); } } - List offlinePushItems = new ArrayList<>(pushItemMap.values()); - if (offlinePushItems.size() > 0) { - String type = "PUSH"; - int runLimit = 300; - if (offlinePushItems.size() > runLimit) { - for (int i = 0; i < offlinePushItems.size(); i += runLimit) { - int toIndex = i + runLimit; - if (i + runLimit > offlinePushItems.size()) { - toIndex = offlinePushItems.size(); - } - List streamPushItemsSub = offlinePushItems.subList(i, toIndex); - streamPushMapper.delAll(streamPushItemsSub); - } - }else { - streamPushMapper.delAll(offlinePushItems); + List changedStreamPushList = new ArrayList<>(pushItemMap.values()); + if (!changedStreamPushList.isEmpty()) { + for (StreamPush streamPush : changedStreamPushList) { + stop(streamPush); } - } + + +// if (!changedStreamPushList.isEmpty()) { +// String type = "PUSH"; +// int runLimit = 300; +// if (changedStreamPushList.size() > runLimit) { +// for (int i = 0; i < changedStreamPushList.size(); i += runLimit) { +// int toIndex = i + runLimit; +// if (i + runLimit > changedStreamPushList.size()) { +// toIndex = changedStreamPushList.size(); +// } +// List streamPushItemsSub = changedStreamPushList.subList(i, toIndex); +// streamPushMapper.delAll(streamPushItemsSub); +// } +// }else { +// streamPushMapper.delAll(changedStreamPushList); +// } +// +// } Collection mediaInfos = streamInfoPushItemMap.values(); - if (mediaInfos.size() > 0) { + if (!mediaInfos.isEmpty()) { String type = "PUSH"; for (MediaInfo mediaInfo : mediaInfos) { JSONObject jsonObject = new JSONObject(); @@ -327,7 +410,7 @@ public class StreamPushServiceImpl implements IStreamPushService { } Collection streamAuthorityInfos = streamAuthorityInfoInfoMap.values(); - if (streamAuthorityInfos.size() > 0) { + if (!streamAuthorityInfos.isEmpty()) { for (StreamAuthorityInfo streamAuthorityInfo : streamAuthorityInfos) { // 移除redis内流的信息 redisCatchStorage.removeStreamAuthorityInfo(streamAuthorityInfo.getApp(), streamAuthorityInfo.getStream()); @@ -336,19 +419,24 @@ public class StreamPushServiceImpl implements IStreamPushService { } @Override + @Transactional public void zlmServerOffline(String mediaServerId) { - List streamPushItems = streamPushMapper.selectAllByMediaServerIdWithOutGbID(mediaServerId); - // 移除没有GBId的推流 - streamPushMapper.deleteWithoutGBId(mediaServerId); - gbStreamMapper.deleteWithoutGBId("push", mediaServerId); - // 其他的流设置未启用 - streamPushMapper.updateStatusByMediaServerId(mediaServerId, false); - streamProxyMapper.updateStatusByMediaServerId(mediaServerId, false); + List streamPushItems = streamPushMapper.selectAllByMediaServerId(mediaServerId); + if (!streamPushItems.isEmpty()) { + for (StreamPush streamPushItem : streamPushItems) { + stop(streamPushItem); + } + } +// // 移除没有GBId的推流 +// streamPushMapper.deleteWithoutGBId(mediaServerId); +// // 其他的流设置未启用 +// streamPushMapper.updateStatusByMediaServerId(mediaServerId, false); +// streamProxyMapper.updateStatusByMediaServerId(mediaServerId, false); // 发送流停止消息 String type = "PUSH"; // 发送redis消息 List mediaInfoList = redisCatchStorage.getStreams(mediaServerId, type); - if (mediaInfoList.size() > 0) { + if (!mediaInfoList.isEmpty()) { for (MediaInfo mediaInfo : mediaInfoList) { // 移除redis内流的信息 redisCatchStorage.removeStream(mediaServerId, type, mediaInfo.getApp(), mediaInfo.getStream()); @@ -367,41 +455,16 @@ public class StreamPushServiceImpl implements IStreamPushService { } @Override - public void clean() { - - } - - @Override - public boolean saveToRandomGB() { - List streamPushItems = streamPushMapper.selectAll(); - long gbId = 100001; - for (StreamPush streamPushItem : streamPushItems) { - streamPushItem.setStreamType("push"); - streamPushItem.setStatus(true); - streamPushItem.setGbId("34020000004111" + gbId); - streamPushItem.setCreateTime(DateUtil.getNow()); - gbId ++; - } - int limitCount = 30; - - if (streamPushItems.size() > limitCount) { - for (int i = 0; i < streamPushItems.size(); i += limitCount) { - int toIndex = i + limitCount; - if (i + limitCount > streamPushItems.size()) { - toIndex = streamPushItems.size(); - } - gbStreamMapper.batchAdd(streamPushItems.subList(i, toIndex)); - } - }else { - gbStreamMapper.batchAdd(streamPushItems); - } - return true; - } - - @Override + @Transactional public void batchAdd(List streamPushItems) { streamPushMapper.addAll(streamPushItems); - gbStreamMapper.batchAdd(streamPushItems); + List commonGBChannels = new ArrayList<>(); + for (StreamPush streamPush : streamPushItems) { + if (ObjectUtils.isEmpty(streamPush.getGbDeviceId())) { + commonGBChannels.add(streamPush.getCommonGBChannel()); + } + } + gbChannelService.batchAdd(commonGBChannels); } @@ -459,7 +522,7 @@ public class StreamPushServiceImpl implements IStreamPushService { // 不存在这个平台,则忽略导入此关联关系 if (platformInfoMap.get(platFormInfoArray[0]) == null || platformInfoMap.get(platFormInfoArray[0]).get(platFormInfoArray[1]) == null) { - logger.info("导入数据时不存在平台或目录{}/{},已导入未分配", platFormInfoArray[0], platFormInfoArray[1] ); + log.info("导入数据时不存在平台或目录{}/{},已导入未分配", platFormInfoArray[0], platFormInfoArray[1] ); continue; } streamPushItemForPlatform.setPlatformId(platFormInfoArray[0]); @@ -544,38 +607,6 @@ public class StreamPushServiceImpl implements IStreamPushService { eventPublisher.catalogEventPublishForStream(null, onlinePushers, CatalogEvent.ON); } - @Override - public boolean add(StreamPush stream) { - stream.setUpdateTime(DateUtil.getNow()); - stream.setCreateTime(DateUtil.getNow()); - stream.setServerId(userSetting.getServerId()); - stream.setMediaServerId(mediaConfig.getId()); - stream.setSelf(true); - stream.setPushIng(true); - - // 放在事务内执行 - boolean result = false; - TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); - try { - int addStreamResult = streamPushMapper.add(stream); - if (!ObjectUtils.isEmpty(stream.getGbId())) { - stream.setStreamType("push"); - gbStreamMapper.add(stream); - } - dataSourceTransactionManager.commit(transactionStatus); - result = true; - }catch (Exception e) { - logger.error("批量移除流与平台的关系时错误", e); - dataSourceTransactionManager.rollback(transactionStatus); - } - return result; - } - - @Override - public boolean update(StreamPush stream) { - - } - @Override public List getAllAppAndStream() { @@ -600,32 +631,41 @@ public class StreamPushServiceImpl implements IStreamPushService { return streamPushMapper.getAllGBId(); } - @Override - public void updatePush(OnStreamChangedHookParam param) { - StreamPush transform = transform(param); - StreamPush pushInDb = getPush(param.getApp(), param.getStream()); - transform.setPushIng(param.isRegist()); - transform.setUpdateTime(DateUtil.getNow()); - transform.setPushTime(DateUtil.getNow()); - transform.setSelf(userSetting.getServerId().equals(param.getSeverId())); - if (pushInDb == null) { - transform.setCreateTime(DateUtil.getNow()); - streamPushMapper.add(transform); - }else { - streamPushMapper.update(transform); - gbStreamMapper.updateMediaServer(param.getApp(), param.getStream(), param.getMediaServerId()); - } - } - @Override public void updateStatus(StreamPush push) { } - @Override - public void deleteByAppAndStream(String app, String stream) { + + @Override + public void updatePushStatus(Integer streamPushId, boolean pushIng) { + streamPushInDb.setPushIng(true); + if (userSetting.isUsePushingAsStatus()) { + streamPushInDb.setGbStatus(true); + } + streamPushInDb.setPushTime(DateUtil.getNow()); } + private List handleJSON(List streamInfoList) { + if (streamInfoList == null || streamInfoList.isEmpty()) { + return null; + } + Map result = new HashMap<>(); + for (StreamInfo streamInfo : streamInfoList) { + // 不保存国标推理以及拉流代理的流 + if (streamInfo.getOriginType() == OriginType.RTSP_PUSH.ordinal() + || streamInfo.getOriginType() == OriginType.RTMP_PUSH.ordinal() + || streamInfo.getOriginType() == OriginType.RTC_PUSH.ordinal() ) { + String key = streamInfo.getApp() + "_" + streamInfo.getStream(); + StreamPush streamPushItem = result.get(key); + if (streamPushItem == null) { + streamPushItem = streamPushItem.getInstance(streamInfo); + result.put(key, streamPushItem); + } + } + } + return new ArrayList<>(result.values()); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java index 38eb5344..d9c35e27 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java @@ -44,7 +44,7 @@ public class RedisCloseStreamMsgListener implements MessageListener { JSONObject jsonObject = JSON.parseObject(msg.getBody()); String app = jsonObject.getString("app"); String stream = jsonObject.getString("stream"); - pushService.stop(app, stream); + pushService.stopByAppAndStream(app, stream); }catch (Exception e) { log.warn("[REDIS的关闭推流通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); log.error("[REDIS的关闭推流通知] 异常内容: ", e); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java index 6c6f93d0..10372851 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java @@ -87,7 +87,7 @@ public interface StreamPushMapper { List selectAll(); @Select("SELECT st.*, gs.gb_id, gs.name, gs.longitude, gs.latitude FROM wvp_stream_push st LEFT join wvp_gb_stream gs on st.app = gs.app AND st.stream = gs.stream WHERE st.app=#{app} AND st.stream=#{stream}") - StreamPush selectOne(@Param("app") String app, @Param("stream") String stream); + StreamPush selectByAppAndStream(@Param("app") String app, @Param("stream") String stream); @Insert("