From 3e041b1bbacd276195ef52ac78c5df5a1f45eb3c Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 25 Nov 2020 11:42:51 +0800 Subject: [PATCH 01/45] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E9=83=A8?= =?UTF-8?q?=E5=88=86NVR=E7=9A=84=E5=85=BC=E5=AE=B9=E6=80=A7=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transmit/request/impl/MessageRequestProcessor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java index 4c95cf16..e7bda4e6 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java @@ -184,10 +184,11 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { DeviceChannel deviceChannel = new DeviceChannel(); deviceChannel.setName(channelName); deviceChannel.setChannelId(channelDeviceId); - if (status.equals("ON") || status.equals("On")) { + // ONLINE OFFLINE 部分NVR的兼容性处理 + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { deviceChannel.setStatus(1); } - if (status.equals("OFF") || status.equals("Off")) { + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) { deviceChannel.setStatus(0); } From 45b27202951fbb9a02885c78d2d8753de8309e83 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 25 Nov 2020 11:49:10 +0800 Subject: [PATCH 02/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gb28181/transmit/request/impl/MessageRequestProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java index e7bda4e6..c987f5ee 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java @@ -184,7 +184,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { DeviceChannel deviceChannel = new DeviceChannel(); deviceChannel.setName(channelName); deviceChannel.setChannelId(channelDeviceId); - // ONLINE OFFLINE 部分NVR的兼容性处理 + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理 if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) { deviceChannel.setStatus(1); } From 9240401b867c35dcb35f583e61ed13ec632e8ac3 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Mon, 30 Nov 2020 17:02:44 +0800 Subject: [PATCH 03/45] =?UTF-8?q?=E4=BD=BF=E7=94=A8APPLICATION=20=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=20Application?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java index 2233ee05..a645680b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java @@ -72,7 +72,7 @@ public class SIPRequestHeaderProvider { request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, toHeader, viaHeaders, maxForwards); - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml"); request.setContent(content, contentTypeHeader); return request; } @@ -119,7 +119,7 @@ public class SIPRequestHeaderProvider { // Subject SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0)); request.addHeader(subjectHeader); - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "SDP"); + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); request.setContent(content, contentTypeHeader); return request; } @@ -164,7 +164,7 @@ public class SIPRequestHeaderProvider { // Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort())); request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "SDP"); + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); request.setContent(content, contentTypeHeader); return request; } From 5e9e0043dc7710b8681ed1569b017f6f7655d3bd Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 2 Dec 2020 15:33:19 +0800 Subject: [PATCH 04/45] =?UTF-8?q?=E5=A2=9E=E5=8A=A0hookip=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE,=20=E6=98=AF=E5=90=A6=E5=BC=80=E5=90=AF=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E9=85=8D=E7=BD=AE=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/media/zlm/ZLMRunner.java | 20 ++++-- .../iot/vmp/vmanager/play/PlayController.java | 1 + src/main/resources/application.yml | 70 ++++++++++++++----- 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java index 66f8e61e..4a4f1f0d 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java @@ -36,6 +36,9 @@ public class ZLMRunner implements CommandLineRunner { @Value("${media.wanIp}") private String mediaWanIp; + @Value("${media.hookIp}") + private String mediaHookIp; + @Value("${media.port}") private int mediaPort; @@ -51,6 +54,9 @@ public class ZLMRunner implements CommandLineRunner { @Value("${server.port}") private String serverPort; + @Value("${media.autoConfig}") + private boolean autoConfig; + @Autowired private ZLMRESTfulUtils zlmresTfulUtils; @@ -61,8 +67,7 @@ public class ZLMRunner implements CommandLineRunner { MediaServerConfig mediaServerConfig = getMediaServerConfig(); if (mediaServerConfig != null) { logger.info("zlm接入成功..."); - logger.info("设置zlm..."); - saveZLMConfig(); + if (autoConfig) saveZLMConfig(); mediaServerConfig = getMediaServerConfig(); storager.updateMediaInfo(mediaServerConfig); } @@ -91,12 +96,15 @@ public class ZLMRunner implements CommandLineRunner { } private void saveZLMConfig() { - String hookIP = sipIP; - if (mediaIp.equals(sipIP)) { - hookIP = "127.0.0.1"; + logger.info("设置zlm..."); + if (StringUtils.isEmpty(mediaHookIp)) { + mediaHookIp = sipIP; + } + if (mediaIp.equals(mediaHookIp)) { + mediaHookIp = "127.0.0.1"; } - String hookPrex = String.format("http://%s:%s/index/hook", hookIP, serverPort); + String hookPrex = String.format("http://%s:%s/index/hook", mediaHookIp, serverPort); Map param = new HashMap<>(); param.put("api.secret",mediaSecret); // -profile:v Baseline param.put("ffmpeg.cmd","%s -fflags nobuffer -rtsp_transport tcp -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s"); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java index 300ffc3d..3594affd 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java @@ -93,6 +93,7 @@ public class PlayController { lockFlag = false; logger.info("流编码信息已获取"); JSONArray tracks = mediaInfo.getJSONArray("tracks"); + logger.info(tracks.toJSONString()); streamInfo.setTracks(tracks); storager.startPlay(streamInfo); } else { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 463548a2..a15c88ca 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,20 +1,24 @@ spring: + # [不需要改] application: name: iot-vmp-vmanager - # 影子数据存储方式,支持redis、jdbc,暂不支持mysql + # [不需要改] 影子数据存储方式,支持redis、jdbc,暂不支持mysql, database: redis - # 通信方式,支持kafka、http + # [不需要改] 通信方式,支持kafka、http communicate: http + # REDIS数据库配置 redis: - # Redis服务器IP - host: 127.0.0.1 - #端口号 + # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 + host: 192.168.1.141 + # [必须修改] 端口号 port: 6379 + # [可选] 数据库 DB database: 6 - #访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 - password: - #超时时间 + # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 + password: 4767cb971b40a1300fa09b7f87b09d1c + # [可选] 超时时间 timeout: 10000 + # [不可用] jdbc数据库配置, 暂不支持 datasource: name: eiot url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true @@ -22,36 +26,62 @@ spring: password: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver + +# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 server: port: 18080 + +# 作为28181服务器的配置 sip: - ip: 192.168.1.44 + # [必须修改] 本机的IP, 必须是网卡上的IP + ip: 192.168.1.20 + # [可选] 28181服务监听的端口 port: 5060 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) # 后两位为行业编码,定义参照附录D.3 # 3701020049标识山东济南历下区 信息行业接入 + # [可选] domain: 3402000000 + # [可选] id: 34020000002000000001 - # 默认设备认证密码,后续扩展使用设备单独密码 + # [可选] 默认设备认证密码,后续扩展使用设备单独密码 password: 12345678 -auth: #32位小写md5加密(默认密码为admin) +# 登陆的用户名密码 +auth: + # [可选] 用户名 username: admin + # [可选] 密码, 默认为admin password: 21232f297a57a5a743894a0e4a801fc3 -media: #zlm服务器的ip与http端口, 重点: 这是http端口 - ip: 192.168.1.44 - wanIp: - port: 80 +#zlm服务器配置 +media: + # [必须修改] zlm服务器的内网IP + ip: 127.0.0.1 + # [可选] zlm服务器的公网IP, 内网部署置空即可 + wanIp: 192.168.1.20 + # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip + hookIp: + # [必须修改] zlm服务器的http.port + port: 6080 + # [可选] 是否自动配置ZLM, 如果希望手动配置ZLM, 可以设为false, 不建议新接触的用户修改 + autoConfig: true + # [可选] zlm服务器的hook.admin_params=secret secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc + # [可选] zlm服务器的general.streamNoneReaderDelayMS streamNoneReaderDelayMS: 600000 # 无人观看多久自动关闭流 - # 关闭等待收到流编码信息后在返回, + # [可选] 关闭等待收到流编码信息后在返回, # 设为false可以获得更好的兼容性,保证返回后流就可以播放, # 设为true可以快速打开播放窗口,可以获得更好的体验 - closeWaitRTPInfo: true - rtp: # 启用udp多端口模式 + closeWaitRTPInfo: false + # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用 + rtp: + # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输 enable: true + # [可选] 在此范围内选择端口用于媒体流传输, 不只是udp, 使用TCP被动传输模式时,也是从这个范围内选择端口 udpPortRange: 30000,30500 # 端口范围 + +# [可选] 日志配置, 一般不需要改 logging: file: name: logs/wvp.log @@ -61,4 +91,6 @@ logging: level: com: genersoft: - iot: debug \ No newline at end of file + iot: debug + + From 35308dfb68ff2811dd0713089acec1c4c7bdd6dd Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 2 Dec 2020 15:35:21 +0800 Subject: [PATCH 05/45] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a15c88ca..bd6527cf 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -9,13 +9,13 @@ spring: # REDIS数据库配置 redis: # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 - host: 192.168.1.141 + host: 127.0.0.1 # [必须修改] 端口号 port: 6379 # [可选] 数据库 DB database: 6 # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 - password: 4767cb971b40a1300fa09b7f87b09d1c + password: # [可选] 超时时间 timeout: 10000 # [不可用] jdbc数据库配置, 暂不支持 @@ -34,7 +34,7 @@ server: # 作为28181服务器的配置 sip: # [必须修改] 本机的IP, 必须是网卡上的IP - ip: 192.168.1.20 + ip: 192.168.1.44 # [可选] 28181服务监听的端口 port: 5060 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) @@ -57,13 +57,13 @@ auth: #zlm服务器配置 media: # [必须修改] zlm服务器的内网IP - ip: 127.0.0.1 + ip: 192.168.1.44 # [可选] zlm服务器的公网IP, 内网部署置空即可 - wanIp: 192.168.1.20 + wanIp: # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip hookIp: # [必须修改] zlm服务器的http.port - port: 6080 + port: 80 # [可选] 是否自动配置ZLM, 如果希望手动配置ZLM, 可以设为false, 不建议新接触的用户修改 autoConfig: true # [可选] zlm服务器的hook.admin_params=secret @@ -91,6 +91,4 @@ logging: level: com: genersoft: - iot: debug - - + iot: debug \ No newline at end of file From 9e135e58f3fb4e59cd75a2481063c3621da4df06 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Fri, 4 Dec 2020 14:29:34 +0800 Subject: [PATCH 06/45] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=BD=BF=E7=94=A8=E6=96=B9=E5=BC=8F,=20?= =?UTF-8?q?=E8=A7=84=E8=8C=83=E5=89=8D=E7=AB=AF=E6=96=87=E4=BB=B6=E6=89=93?= =?UTF-8?q?=E5=8C=85=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 94 +++++++++++++++++++++++++ src/main/resources/application.yml | 95 +------------------------- web_src/config/index.js | 2 +- 3 files changed, 97 insertions(+), 94 deletions(-) create mode 100644 src/main/resources/application-dev.yml diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 00000000..b58c0636 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,94 @@ +spring: + # [不需要改] + application: + name: iot-vmp-vmanager + # [不需要改] 影子数据存储方式,支持redis、jdbc,暂不支持mysql, + database: redis + # [不需要改] 通信方式,支持kafka、http + communicate: http + # REDIS数据库配置 + redis: + # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 + host: 127.0.0.1 + # [必须修改] 端口号 + port: 6379 + # [可选] 数据库 DB + database: 6 + # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 + password: + # [可选] 超时时间 + timeout: 10000 + # [不可用] jdbc数据库配置, 暂不支持 + datasource: + name: eiot + url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true + username: + password: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.jdbc.Driver + +# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 +server: + port: 18080 + +# 作为28181服务器的配置 +sip: + # [必须修改] 本机的IP, 必须是网卡上的IP + ip: 192.168.1.44 + # [可选] 28181服务监听的端口 + port: 5060 + # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) + # 后两位为行业编码,定义参照附录D.3 + # 3701020049标识山东济南历下区 信息行业接入 + # [可选] + domain: 3402000000 + # [可选] + id: 34020000002000000001 + # [可选] 默认设备认证密码,后续扩展使用设备单独密码 + password: 12345678 + +# 登陆的用户名密码 +auth: + # [可选] 用户名 + username: admin + # [可选] 密码, 默认为admin + password: 21232f297a57a5a743894a0e4a801fc3 + +#zlm服务器配置 +media: + # [必须修改] zlm服务器的内网IP + ip: 192.168.1.44 + # [可选] zlm服务器的公网IP, 内网部署置空即可 + wanIp: + # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip + hookIp: + # [必须修改] zlm服务器的http.port + port: 80 + # [可选] 是否自动配置ZLM, 如果希望手动配置ZLM, 可以设为false, 不建议新接触的用户修改 + autoConfig: true + # [可选] zlm服务器的hook.admin_params=secret + secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc + # [可选] zlm服务器的general.streamNoneReaderDelayMS + streamNoneReaderDelayMS: 600000 # 无人观看多久自动关闭流 + # [可选] 关闭等待收到流编码信息后在返回, + # 设为false可以获得更好的兼容性,保证返回后流就可以播放, + # 设为true可以快速打开播放窗口,可以获得更好的体验 + closeWaitRTPInfo: false + # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用 + rtp: + # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输 + enable: true + # [可选] 在此范围内选择端口用于媒体流传输, 不只是udp, 使用TCP被动传输模式时,也是从这个范围内选择端口 + udpPortRange: 30000,30500 # 端口范围 + +# [可选] 日志配置, 一般不需要改 +logging: + file: + name: logs/wvp.log + max-history: 30 + max-size: 10MB + total-size-cap: 300MB + level: + com: + genersoft: + iot: debug \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bd6527cf..caf4dfcd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,94 +1,3 @@ spring: - # [不需要改] - application: - name: iot-vmp-vmanager - # [不需要改] 影子数据存储方式,支持redis、jdbc,暂不支持mysql, - database: redis - # [不需要改] 通信方式,支持kafka、http - communicate: http - # REDIS数据库配置 - redis: - # [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1 - host: 127.0.0.1 - # [必须修改] 端口号 - port: 6379 - # [可选] 数据库 DB - database: 6 - # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接 - password: - # [可选] 超时时间 - timeout: 10000 - # [不可用] jdbc数据库配置, 暂不支持 - datasource: - name: eiot - url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true - username: - password: - type: com.alibaba.druid.pool.DruidDataSource - driver-class-name: com.mysql.jdbc.Driver - -# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 -server: - port: 18080 - -# 作为28181服务器的配置 -sip: - # [必须修改] 本机的IP, 必须是网卡上的IP - ip: 192.168.1.44 - # [可选] 28181服务监听的端口 - port: 5060 - # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) - # 后两位为行业编码,定义参照附录D.3 - # 3701020049标识山东济南历下区 信息行业接入 - # [可选] - domain: 3402000000 - # [可选] - id: 34020000002000000001 - # [可选] 默认设备认证密码,后续扩展使用设备单独密码 - password: 12345678 - -# 登陆的用户名密码 -auth: - # [可选] 用户名 - username: admin - # [可选] 密码, 默认为admin - password: 21232f297a57a5a743894a0e4a801fc3 - -#zlm服务器配置 -media: - # [必须修改] zlm服务器的内网IP - ip: 192.168.1.44 - # [可选] zlm服务器的公网IP, 内网部署置空即可 - wanIp: - # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip - hookIp: - # [必须修改] zlm服务器的http.port - port: 80 - # [可选] 是否自动配置ZLM, 如果希望手动配置ZLM, 可以设为false, 不建议新接触的用户修改 - autoConfig: true - # [可选] zlm服务器的hook.admin_params=secret - secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc - # [可选] zlm服务器的general.streamNoneReaderDelayMS - streamNoneReaderDelayMS: 600000 # 无人观看多久自动关闭流 - # [可选] 关闭等待收到流编码信息后在返回, - # 设为false可以获得更好的兼容性,保证返回后流就可以播放, - # 设为true可以快速打开播放窗口,可以获得更好的体验 - closeWaitRTPInfo: false - # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用 - rtp: - # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输 - enable: true - # [可选] 在此范围内选择端口用于媒体流传输, 不只是udp, 使用TCP被动传输模式时,也是从这个范围内选择端口 - udpPortRange: 30000,30500 # 端口范围 - -# [可选] 日志配置, 一般不需要改 -logging: - file: - name: logs/wvp.log - max-history: 30 - max-size: 10MB - total-size-cap: 300MB - level: - com: - genersoft: - iot: debug \ No newline at end of file + profiles: + active: dev \ No newline at end of file diff --git a/web_src/config/index.js b/web_src/config/index.js index a16611c0..148c7c98 100644 --- a/web_src/config/index.js +++ b/web_src/config/index.js @@ -51,7 +51,7 @@ module.exports = { // Paths assetsRoot: path.resolve(__dirname, '../../src/main/resources/static/'), assetsSubDirectory: '.', - assetsPublicPath: '/', + assetsPublicPath: './', /** * Source Maps From 8f9783ab22b29991cdac15b09a0558929c536c2d Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Mon, 7 Dec 2020 10:54:52 +0800 Subject: [PATCH 07/45] =?UTF-8?q?=E5=8E=BB=E9=99=A4hook=20=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=AF=86=E5=88=AB127.0.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java index 4a4f1f0d..3f88b2a3 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java @@ -100,9 +100,6 @@ public class ZLMRunner implements CommandLineRunner { if (StringUtils.isEmpty(mediaHookIp)) { mediaHookIp = sipIP; } - if (mediaIp.equals(mediaHookIp)) { - mediaHookIp = "127.0.0.1"; - } String hookPrex = String.format("http://%s:%s/index/hook", mediaHookIp, serverPort); Map param = new HashMap<>(); From c36482f78ffd08ce673392807bb9556957df580f Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Mon, 7 Dec 2020 14:19:29 +0800 Subject: [PATCH 08/45] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=9B=BE=E6=A0=87=E4=B8=8D=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_src/config/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/config/index.js b/web_src/config/index.js index 148c7c98..a16611c0 100644 --- a/web_src/config/index.js +++ b/web_src/config/index.js @@ -51,7 +51,7 @@ module.exports = { // Paths assetsRoot: path.resolve(__dirname, '../../src/main/resources/static/'), assetsSubDirectory: '.', - assetsPublicPath: './', + assetsPublicPath: '/', /** * Source Maps From 726730cbaa97e682d0e718fa78cfc42b263b18d4 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 8 Dec 2020 18:11:02 +0800 Subject: [PATCH 09/45] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3,=20=E6=9B=B4=E5=A5=BD=E7=9A=84=E5=B9=B6?= =?UTF-8?q?=E5=8F=91,=20=E5=AF=B9hook=E4=BD=BF=E7=94=A8=E8=AE=A2=E9=98=85?= =?UTF-8?q?=E6=9C=BA=E5=88=B6=20=E6=9B=BF=E6=8D=A2=E5=89=8D=E6=AE=B5?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E5=99=A8,=20=E6=94=AF=E6=8C=81h265=E7=9A=84?= =?UTF-8?q?=E6=92=AD=E6=94=BE=20=E6=94=BE=E5=BC=83=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E7=BC=96=E7=A0=81=E4=BF=A1=E6=81=AF,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/common/StreamInfo.java | 56 ++++- .../callback/DeferredResultHolder.java | 2 + .../gb28181/transmit/cmd/ISIPCommander.java | 49 ++-- .../transmit/cmd/impl/SIPCommander.java | 91 +++---- .../request/impl/ByeRequestProcessor.java | 34 ++- .../vmp/media/zlm/ZLMHttpHookListener.java | 57 +++-- .../vmp/media/zlm/ZLMHttpHookSubscribe.java | 88 +++++++ .../iot/vmp/vmanager/play/PlayController.java | 134 +++++------ .../vmanager/playback/PlaybackController.java | 116 +++------ .../vmp/vmanager/service/IPlayService.java | 13 + .../service/impl/PlayServiceImpl.java | 90 +++++++ .../iot/vmp/web/ApiStreamController.java | 7 +- web_src/build/webpack.dev.conf.js | 5 +- web_src/build/webpack.prod.conf.js | 5 +- web_src/index.html | 2 +- web_src/package-lock.json | 8 +- web_src/package.json | 2 +- .../src/components/gb28181/devicePlayer.vue | 222 +++++++++++------- web_src/src/components/gb28181/player.vue | 57 +++++ web_src/src/components/videoList.vue | 2 - 20 files changed, 681 insertions(+), 359 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java create mode 100644 src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java create mode 100644 src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java create mode 100644 web_src/src/components/gb28181/player.vue 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 1dd3a854..53bda91a 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java @@ -5,12 +5,18 @@ import com.alibaba.fastjson.JSONArray; public class StreamInfo { private String ssrc; + private String streamId; private String deviceID; private String cahnnelId; private String flv; private String ws_flv; - private String rtmp; + private String fmp4; + private String ws_fmp4; private String hls; + private String ws_hls; + private String ts; + private String ws_ts; + private String rtmp; private String rtsp; private JSONArray tracks; @@ -85,4 +91,52 @@ public class StreamInfo { public void setTracks(JSONArray tracks) { this.tracks = tracks; } + + public String getFmp4() { + return fmp4; + } + + public void setFmp4(String fmp4) { + this.fmp4 = fmp4; + } + + public String getWs_fmp4() { + return ws_fmp4; + } + + public void setWs_fmp4(String ws_fmp4) { + this.ws_fmp4 = ws_fmp4; + } + + public String getWs_hls() { + return ws_hls; + } + + public void setWs_hls(String ws_hls) { + this.ws_hls = ws_hls; + } + + public String getTs() { + return ts; + } + + public void setTs(String ts) { + this.ts = ts; + } + + public String getWs_ts() { + return ws_ts; + } + + public void setWs_ts(String ws_ts) { + this.ws_ts = ws_ts; + } + + public String getStreamId() { + return streamId; + } + + public void setStreamId(String streamId) { + this.streamId = streamId; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java index 7c5cbc10..0c1e63d6 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java @@ -22,6 +22,8 @@ public class DeferredResultHolder { public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO"; + public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY"; + private Map map = new HashMap(); public void put(String key, DeferredResult result) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index 923f211a..3da654ad 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; /** * @Description:设备能力接口,用于定义设备的控制、查询能力 @@ -19,7 +20,7 @@ public interface ISIPCommander { * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 * @param moveSpeed 镜头移动速度 */ - public boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown); + boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown); /** * 云台方向放控制 @@ -30,7 +31,7 @@ public interface ISIPCommander { * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 * @param moveSpeed 镜头移动速度 */ - public boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed); + boolean ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed); /** * 云台缩放控制,使用配置文件中的默认镜头缩放速度 @@ -39,7 +40,7 @@ public interface ISIPCommander { * @param channelId 预览通道 * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 */ - public boolean ptzZoomCmd(Device device,String channelId,int inOut); + boolean ptzZoomCmd(Device device,String channelId,int inOut); /** * 云台缩放控制 @@ -49,7 +50,7 @@ public interface ISIPCommander { * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 * @param zoomSpeed 镜头缩放速度 */ - public boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed); + boolean ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed); /** * 云台控制,支持方向与缩放控制 @@ -62,7 +63,7 @@ public interface ISIPCommander { * @param moveSpeed 镜头移动速度 * @param zoomSpeed 镜头缩放速度 */ - public boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed); + boolean ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed); /** * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令 @@ -74,7 +75,7 @@ public interface ISIPCommander { * @param parameter2 数据2 * @param combineCode2 组合码2 */ - public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2); + boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2); /** * 请求预览视频流 @@ -82,7 +83,7 @@ public interface ISIPCommander { * @param device 视频设备 * @param channelId 预览通道 */ - public StreamInfo playStreamCmd(Device device, String channelId); + void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event); /** * 请求回放视频流 @@ -92,14 +93,14 @@ public interface ISIPCommander { * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss */ - public StreamInfo playbackStreamCmd(Device device,String channelId, String startTime, String endTime); + void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event); /** * 视频流停止 * * @param ssrc ssrc */ - public void streamByeCmd(String ssrc); + void streamByeCmd(String ssrc); /** * 语音广播 @@ -107,7 +108,7 @@ public interface ISIPCommander { * @param device 视频设备 * @param channelId 预览通道 */ - public boolean audioBroadcastCmd(Device device,String channelId); + boolean audioBroadcastCmd(Device device,String channelId); /** * 音视频录像控制 @@ -115,21 +116,21 @@ public interface ISIPCommander { * @param device 视频设备 * @param channelId 预览通道 */ - public boolean recordCmd(Device device,String channelId); + boolean recordCmd(Device device,String channelId); /** * 报警布防/撤防命令 * * @param device 视频设备 */ - public boolean guardCmd(Device device); + boolean guardCmd(Device device); /** * 报警复位命令 * * @param device 视频设备 */ - public boolean alarmCmd(Device device); + boolean alarmCmd(Device device); /** * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 @@ -137,21 +138,21 @@ public interface ISIPCommander { * @param device 视频设备 * @param channelId 预览通道 */ - public boolean iFameCmd(Device device,String channelId); + boolean iFameCmd(Device device,String channelId); /** * 看守位控制命令 * * @param device 视频设备 */ - public boolean homePositionCmd(Device device); + boolean homePositionCmd(Device device); /** * 设备配置命令 * * @param device 视频设备 */ - public boolean deviceConfigCmd(Device device); + boolean deviceConfigCmd(Device device); /** @@ -159,7 +160,7 @@ public interface ISIPCommander { * * @param device 视频设备 */ - public boolean deviceStatusQuery(Device device); + boolean deviceStatusQuery(Device device); /** * 查询设备信息 @@ -167,14 +168,14 @@ public interface ISIPCommander { * @param device 视频设备 * @return */ - public boolean deviceInfoQuery(Device device); + boolean deviceInfoQuery(Device device); /** * 查询目录列表 * * @param device 视频设备 */ - public boolean catalogQuery(Device device); + boolean catalogQuery(Device device); /** * 查询录像信息 @@ -183,33 +184,33 @@ public interface ISIPCommander { * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss */ - public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime); + boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime); /** * 查询报警信息 * * @param device 视频设备 */ - public boolean alarmInfoQuery(Device device); + boolean alarmInfoQuery(Device device); /** * 查询设备配置 * * @param device 视频设备 */ - public boolean configQuery(Device device); + boolean configQuery(Device device); /** * 查询设备预置位置 * * @param device 视频设备 */ - public boolean presetQuery(Device device); + boolean presetQuery(Device device); /** * 查询移动设备位置数据 * * @param device 视频设备 */ - public boolean mobilePostitionQuery(Device device); + boolean mobilePostitionQuery(Device device); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 42657a60..33864291 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -19,6 +19,7 @@ import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaServerConfig; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMUtils; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.springframework.beans.factory.annotation.Autowired; @@ -67,6 +68,9 @@ public class SIPCommander implements ISIPCommander { @Value("${media.rtp.enable}") private boolean rtpEnable; + @Autowired + private ZLMHttpHookSubscribe subscribe; + /** @@ -264,12 +268,12 @@ public class SIPCommander implements ISIPCommander { } /** * 请求预览视频流 - * + * * @param device 视频设备 * @param channelId 预览通道 - */ + */ @Override - public StreamInfo playStreamCmd(Device device, String channelId) { + public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event) { try { String ssrc = streamSession.createPlaySsrc(); @@ -282,53 +286,57 @@ public class SIPCommander implements ISIPCommander { }else { mediaPort = mediaInfo.getRtpProxyPort(); } + + String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); + // 添加订阅 + JSONObject subscribeKey = new JSONObject(); + subscribeKey.put("app", "rtp"); + subscribeKey.put("id", streamId); + + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, subscribeKey, event); // StringBuffer content = new StringBuffer(200); - content.append("v=0\r\n"); - content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); - content.append("s=Play\r\n"); - content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); - content.append("t=0 0\r\n"); - if("TCP-PASSIVE".equals(streamMode)) { - content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); + content.append("v=0\r\n"); + content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); + content.append("s=Play\r\n"); + content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); + content.append("t=0 0\r\n"); + if("TCP-PASSIVE".equals(streamMode)) { + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); }else if ("TCP-ACTIVE".equals(streamMode)) { content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); }else if("UDP".equals(streamMode)) { - content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n"); + content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n"); } - content.append("a=recvonly\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 - content.append("a=setup:passive\r\n"); + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 + content.append("a=setup:passive\r\n"); content.append("a=connection:new\r\n"); - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 content.append("a=setup:active\r\n"); content.append("a=connection:new\r\n"); } - content.append("y="+ssrc+"\r\n");//ssrc - - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); - - ClientTransaction transaction = transmitRequest(device, request); - streamSession.put(ssrc, transaction); + content.append("y="+ssrc+"\r\n");//ssrc + + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); + + ClientTransaction transaction = transmitRequest(device, request); + streamSession.put(ssrc, transaction); DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId); if (deviceChannel != null) { deviceChannel.setSsrc(ssrc); storager.updateChannel(device.getDeviceId(), deviceChannel); } - StreamInfo streamInfo = new StreamInfo(); - streamInfo.setSsrc(ssrc); - streamInfo.setCahnnelId(channelId); - streamInfo.setDeviceID(device.getDeviceId()); - storager.startPlay(streamInfo); - return streamInfo; + // TODO 订阅SIP response,处理对方的错误返回 + + } catch ( SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); - return null; - } + } } /** @@ -340,10 +348,18 @@ public class SIPCommander implements ISIPCommander { * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss */ @Override - public StreamInfo playbackStreamCmd(Device device, String channelId, String startTime, String endTime) { + public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event) { try { MediaServerConfig mediaInfo = storager.getMediaInfo(); String ssrc = streamSession.createPlayBackSsrc(); + String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); + // 添加订阅 + JSONObject subscribeKey = new JSONObject(); + subscribeKey.put("app", "rtp"); + subscribeKey.put("id", streamId); + + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, subscribeKey, event); + // StringBuffer content = new StringBuffer(200); content.append("v=0\r\n"); @@ -386,16 +402,8 @@ public class SIPCommander implements ISIPCommander { ClientTransaction transaction = transmitRequest(device, request); streamSession.put(ssrc, transaction); - StreamInfo streamInfo = new StreamInfo(); - streamInfo.setSsrc(ssrc); - streamInfo.setCahnnelId(channelId); - streamInfo.setDeviceID(device.getDeviceId()); - boolean b = storager.startPlayback(streamInfo); - return streamInfo; - } catch ( SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); - return null; } } @@ -433,6 +441,7 @@ public class SIPCommander implements ISIPCommander { clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); } dialog.sendRequest(clientTransaction); + streamSession.remove(ssrc); } catch (TransactionDoesNotExistException e) { e.printStackTrace(); } catch (SipException e) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java index 0730731c..0ba6bd83 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java @@ -1,9 +1,14 @@ package com.genersoft.iot.vmp.gb28181.transmit.request.impl; +import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor; +import java.text.ParseException; + /** * @Description: BYE请求处理器 * @author: swwheihei @@ -11,18 +16,35 @@ import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcesso */ public class ByeRequestProcessor extends SIPRequestAbstractProcessor { - /** + /** * 处理BYE请求 - * * @param evt - * @param layer - * @param transaction - * @param config - */ + */ @Override public void process(RequestEvent evt) { + try { + responseAck(evt); + } catch (SipException e) { + e.printStackTrace(); + } catch (InvalidArgumentException e) { + e.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } // TODO 优先级99 Bye Request消息实现,此消息一般为级联消息,上级给下级发送视频停止指令 } + /*** + * 回复200 OK + * @param evt + * @throws SipException + * @throws InvalidArgumentException + * @throws ParseException + */ + private void responseAck(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException { + Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest()); + getServerTransaction(evt).sendResponse(response); + } + } 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 b9c05e45..99da6243 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -49,6 +49,9 @@ public class ZLMHttpHookListener { @Autowired private ZLMRESTfulUtils zlmresTfulUtils; + @Autowired + private ZLMHttpHookSubscribe subscribe; + @Value("${media.ip}") private String mediaIp; @@ -128,30 +131,38 @@ public class ZLMHttpHookListener { } String app = json.getString("app"); String streamId = json.getString("id"); - if ("rtp".equals(app)) { - String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16)); - StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc); - if ("rtp".equals(app) && streamInfoForPlay != null ) { - MediaServerConfig mediaInfo = storager.getMediaInfo(); - streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); - streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); - streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId)); - streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); - streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); - storager.startPlay(streamInfoForPlay); - } - StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc); - if ("rtp".equals(app) && streamInfoForPlayBack != null ) { - MediaServerConfig mediaInfo = storager.getMediaInfo(); - streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); - streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); - streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId)); - streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); - streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); - storager.startPlayback(streamInfoForPlayBack); - } - } + ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); + if (subscribe != null) subscribe.response(json); + +// if ("rtp".equals(app)) { +// String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16)); +// StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc); +// if ("rtp".equals(app) && streamInfoForPlay != null ) { +// MediaServerConfig mediaInfo = storager.getMediaInfo(); +// streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlay.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlay.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId)); +// streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); +// storager.startPlay(streamInfoForPlay); +// } +// +// StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc); +// if ("rtp".equals(app) && streamInfoForPlayBack != null ) { +// MediaServerConfig mediaInfo = storager.getMediaInfo(); +// streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlayBack.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlayBack.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId)); +// streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); +// streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); +// storager.startPlayback(streamInfoForPlayBack); +// } +// } // TODO Auto-generated method stub diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java new file mode 100644 index 00000000..a4389cf8 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java @@ -0,0 +1,88 @@ +package com.genersoft.iot.vmp.media.zlm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.math.BigInteger; +import java.text.DecimalFormat; +import java.util.HashMap; +import java.util.Map; + +/** + * @Description:针对 ZLMediaServer的hook事件订阅 + * @author: pan + * @date: 2020年12月2日 21:17:32 + */ +@Component +public class ZLMHttpHookSubscribe { + + private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookSubscribe.class); + + public enum HookType{ + on_flow_report, + on_http_access, + on_play, + on_publish, + on_record_mp4, + on_rtsp_auth, + on_rtsp_realm, + on_shell_login, + on_stream_changed, + on_stream_none_reader, + on_stream_not_found, + on_server_started + } + + public interface Event{ + void response(JSONObject response); + } + + private Map> allSubscribes = new HashMap<>(); + + public void addSubscribe(HookType type, JSONObject hookResponse, ZLMHttpHookSubscribe.Event event) { + Map eventMap = allSubscribes.get(type); + if (eventMap == null) { + eventMap = new HashMap(); + allSubscribes.put(type,eventMap); + } + eventMap.put(hookResponse, event); + } + + public ZLMHttpHookSubscribe.Event getSubscribe(HookType type, JSONObject hookResponse) { + ZLMHttpHookSubscribe.Event event= null; + Map eventMap = allSubscribes.get(type); + if (eventMap == null) { + return null; + } + for (JSONObject key : eventMap.keySet()) { + Boolean result = null; + for (String s : key.keySet()) { + String string = hookResponse.getString(s); + String string1 = key.getString(s); + if (result == null) { + result = key.getString(s).equals(hookResponse.getString(s)); + }else { + result = result && key.getString(s).equals(hookResponse.getString(s)); + } + + } + if (result) { + event = eventMap.get(key); + } + } + return event; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java index 3594affd..d0431db7 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java @@ -4,7 +4,10 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; +import com.genersoft.iot.vmp.vmanager.service.IPlayService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -22,6 +25,10 @@ import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import org.springframework.web.context.request.async.DeferredResult; + +import java.text.DecimalFormat; +import java.util.UUID; @CrossOrigin @RestController @@ -39,95 +46,56 @@ public class PlayController { @Autowired private ZLMRESTfulUtils zlmresTfulUtils; - @Value("${media.closeWaitRTPInfo}") - private boolean closeWaitRTPInfo; + @Autowired + private DeferredResultHolder resultHolder; + + @Autowired + private IPlayService playService; @GetMapping("/play/{deviceId}/{channelId}") - public ResponseEntity play(@PathVariable String deviceId, @PathVariable String channelId, - Integer getEncoding) { + public DeferredResult> play(@PathVariable String deviceId, + @PathVariable String channelId) { + - if (getEncoding == null) getEncoding = 0; - getEncoding = closeWaitRTPInfo ? 0 : getEncoding; Device device = storager.queryVideoDevice(deviceId); StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId); + UUID uuid = UUID.randomUUID(); + DeferredResult> result = new DeferredResult>(); + // 超时处理 + result.onTimeout(()->{ + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + msg.setData("Timeout"); + resultHolder.invokeResult(msg); + }); + // 录像查询以channelId作为deviceId查询 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); + if (streamInfo == null) { - streamInfo = cmder.playStreamCmd(device, channelId); + // TODO playStreamCmd 超时处理 + cmder.playStreamCmd(device, channelId, (JSONObject response) -> { + logger.info("收到订阅消息: " + response.toJSONString()); + playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); + }); } else { String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); if (rtpInfo.getBoolean("exist")) { - return new ResponseEntity(JSON.toJSONString(streamInfo), HttpStatus.OK); + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + msg.setData(JSON.toJSONString(streamInfo)); + resultHolder.invokeResult(msg); } else { storager.stopPlay(streamInfo); - streamInfo = cmder.playStreamCmd(device, channelId); + // TODO playStreamCmd 超时处理 + cmder.playStreamCmd(device, channelId, (JSONObject response) -> { + logger.info("收到订阅消息: " + response.toJSONString()); + playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); + }); } } - String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); - // 等待推流, TODO 默认超时30s - boolean lockFlag = true; - boolean rtpPushed = false; - long startTime = System.currentTimeMillis(); - JSONObject rtpInfo = null; - - if (getEncoding == 1) { - while (lockFlag) { - try { - if (System.currentTimeMillis() - startTime > 60 * 1000) { - storager.stopPlay(streamInfo); - logger.info("播放等待超时"); - return new ResponseEntity("timeout", HttpStatus.OK); - } else { - streamInfo = storager.queryPlayByDevice(deviceId, channelId); - if (!rtpPushed) { - logger.info("查询RTP推流信息..."); - rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); - } - if (rtpInfo != null && rtpInfo.getBoolean("exist") && streamInfo != null - && streamInfo.getFlv() != null) { - logger.info("查询流编码信息:" + streamInfo.getFlv()); - rtpPushed = true; - Thread.sleep(2000); - JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId); - if (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")) { - lockFlag = false; - logger.info("流编码信息已获取"); - JSONArray tracks = mediaInfo.getJSONArray("tracks"); - logger.info(tracks.toJSONString()); - streamInfo.setTracks(tracks); - storager.startPlay(streamInfo); - } else { - logger.info("流编码信息未获取,2秒后重试..."); - } - } else { - Thread.sleep(2000); - continue; - } - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } else { - String flv = storager.getMediaInfo().getWanIp() + ":" + storager.getMediaInfo().getHttpPort() + "/rtp/" - + streamId + ".flv"; - streamInfo.setFlv("http://" + flv); - streamInfo.setWs_flv("ws://" + flv); - storager.startPlay(streamInfo); - } - - if (logger.isDebugEnabled()) { - logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); - logger.debug("设备预览 API调用,ssrc:" + streamInfo.getSsrc() + ",ZLMedia streamId:" - + Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()))); - } - - if (streamInfo != null) { - return new ResponseEntity(JSON.toJSONString(streamInfo), HttpStatus.OK); - } else { - logger.warn("设备预览API调用失败!"); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + return result; } @PostMapping("/play/{ssrc}/stop") @@ -180,10 +148,20 @@ public class PlayController { result.put("code", 0); JSONObject data = jsonObject.getJSONObject("data"); if (data != null) { - result.put("key", data.getString("key")); - result.put("rtmp", dstUrl); - result.put("flv", String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); - result.put("ws_flv", String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + result.put("key", data.getString("key")); + StreamInfo streamInfoResult = new StreamInfo(); + streamInfoResult.setRtmp(dstUrl); + streamInfoResult.setRtsp(String.format("rtsp://%s:%s/convert/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); + streamInfoResult.setStreamId(streamId); + streamInfoResult.setFlv(String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + streamInfoResult.setWs_flv(String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + streamInfoResult.setHls(String.format("http://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + streamInfoResult.setWs_hls(String.format("ws://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + streamInfoResult.setFmp4(String.format("http://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + streamInfoResult.setTs(String.format("http://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + streamInfoResult.setWs_ts(String.format("ws://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); + result.put("data", streamInfoResult); } }else { result.put("code", 1); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java index 16713fed..156f5155 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java @@ -3,7 +3,10 @@ package com.genersoft.iot.vmp.vmanager.playback; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; +import com.genersoft.iot.vmp.vmanager.service.IPlayService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -22,6 +25,9 @@ import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import org.springframework.web.context.request.async.DeferredResult; + +import java.util.UUID; @CrossOrigin @RestController @@ -39,105 +45,41 @@ public class PlaybackController { @Autowired private ZLMRESTfulUtils zlmresTfulUtils; - @Value("${media.closeWaitRTPInfo}") - private boolean closeWaitRTPInfo; + @Autowired + private IPlayService playService; + + @Autowired + private DeferredResultHolder resultHolder; @GetMapping("/playback/{deviceId}/{channelId}") - public ResponseEntity play(@PathVariable String deviceId, @PathVariable String channelId, String startTime, - String endTime) { + public DeferredResult> play(@PathVariable String deviceId, @PathVariable String channelId, String startTime, + String endTime) { if (logger.isDebugEnabled()) { logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId)); } - - if (StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(channelId)) { - String log = String.format("设备回放 API调用失败,deviceId:%s ,channelId:%s", deviceId, channelId); - logger.warn(log); - return new ResponseEntity(log, HttpStatus.BAD_REQUEST); - } - + UUID uuid = UUID.randomUUID(); + DeferredResult> result = new DeferredResult>(); + // 超时处理 + result.onTimeout(()->{ + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + msg.setData("Timeout"); + resultHolder.invokeResult(msg); + }); Device device = storager.queryVideoDevice(deviceId); StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId); - if (streamInfo != null) { + // 停止之前的回放 cmder.streamByeCmd(streamInfo.getSsrc()); } + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); + cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { + logger.info("收到订阅消息: " + response.toJSONString()); + playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString()); + }); - // }else { - // String streamId = String.format("%08x", - // Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); - // JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); - // if (rtpInfo.getBoolean("exist")) { - // return new - // ResponseEntity(JSON.toJSONString(streamInfo),HttpStatus.OK); - // }else { - // storager.stopPlayback(streamInfo); - // streamInfo = cmder.playbackStreamCmd(device, channelId, startTime, endTime); - // } - // } - streamInfo = cmder.playbackStreamCmd(device, channelId, startTime, endTime); - - String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); - - if (logger.isDebugEnabled()) { - logger.debug("设备回放 API调用,ssrc:" + streamInfo.getSsrc() + ",ZLMedia streamId:" + streamId); - } - // 等待推流, TODO 默认超时15s - boolean lockFlag = true; - boolean rtpPushed = false; - long lockStartTime = System.currentTimeMillis(); - JSONObject rtpInfo = null; - - if (closeWaitRTPInfo) { - String flv = storager.getMediaInfo().getWanIp() + ":" + storager.getMediaInfo().getHttpPort() + "/rtp/" - + streamId + ".flv"; - streamInfo.setFlv("http://" + flv); - streamInfo.setWs_flv("ws://" + flv); - storager.startPlayback(streamInfo); - } else { - while (lockFlag) { - try { - if (System.currentTimeMillis() - lockStartTime > 75 * 1000) { - storager.stopPlayback(streamInfo); - logger.info("播放等待超时"); - return new ResponseEntity("timeout", HttpStatus.OK); - } else { - streamInfo = storager.queryPlaybackByDevice(deviceId, channelId); - if (!rtpPushed) { - logger.info("查询RTP推流信息..."); - rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); - } - if (rtpInfo != null && rtpInfo.getBoolean("exist") && streamInfo != null - && streamInfo.getFlv() != null) { - logger.info("查询流编码信息:" + streamInfo.getFlv()); - rtpPushed = true; - Thread.sleep(2000); - JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo("rtp", "rtmp", streamId); - if (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online")) { - lockFlag = false; - logger.info("流编码信息已获取"); - JSONArray tracks = mediaInfo.getJSONArray("tracks"); - streamInfo.setTracks(tracks); - storager.startPlayback(streamInfo); - } else { - logger.info("流编码信息未获取,2秒后重试..."); - } - } else { - Thread.sleep(2000); - continue; - } - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - if (streamInfo != null) { - return new ResponseEntity(JSON.toJSONString(streamInfo), HttpStatus.OK); - } else { - logger.warn("设备回放API调用失败!"); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); - } + return result; } @RequestMapping("/playback/{ssrc}/stop") diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java new file mode 100644 index 00000000..a80ab5df --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/service/IPlayService.java @@ -0,0 +1,13 @@ +package com.genersoft.iot.vmp.vmanager.service; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.common.StreamInfo; + +/** + * 点播处理 + */ +public interface IPlayService { + + void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid); + void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid); +} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java new file mode 100644 index 00000000..e9528d1d --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java @@ -0,0 +1,90 @@ +package com.genersoft.iot.vmp.vmanager.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.vmanager.play.PlayController; +import com.genersoft.iot.vmp.vmanager.service.IPlayService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.text.DecimalFormat; + +@Service +public class PlayServiceImpl implements IPlayService { + + private final static Logger logger = LoggerFactory.getLogger(PlayServiceImpl.class); + + @Autowired + private IVideoManagerStorager storager; + + @Autowired + private DeferredResultHolder resultHolder; + + @Override + public void onPublishHandlerForPlay(JSONObject resonse, String deviceId, String channelId, String uuid) { + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); + if (streamInfo != null) { + storager.startPlay(streamInfo); + msg.setData(JSON.toJSONString(streamInfo)); + resultHolder.invokeResult(msg); + } else { + logger.warn("设备预览API调用失败!"); + msg.setData("设备预览API调用失败!"); + resultHolder.invokeResult(msg); + } + } + + @Override + public void onPublishHandlerForPlayBack(JSONObject resonse, String deviceId, String channelId, String uuid) { + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); + if (streamInfo != null) { + storager.startPlayback(streamInfo); + msg.setData(JSON.toJSONString(streamInfo)); + resultHolder.invokeResult(msg); + } else { + logger.warn("设备预览API调用失败!"); + msg.setData("设备预览API调用失败!"); + resultHolder.invokeResult(msg); + } + } + + public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) { + String streamId = resonse.getString("id"); + String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16)); + StreamInfo streamInfo = new StreamInfo(); + streamInfo.setSsrc(ssrc); + streamInfo.setStreamId(streamId); + streamInfo.setDeviceID(deviceId); + streamInfo.setCahnnelId(channelId); + MediaServerConfig mediaServerConfig = storager.getMediaInfo(); + + streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); + streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); + + streamInfo.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); + streamInfo.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); + + streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); + streamInfo.setWs_hls(String.format("ws://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); + + streamInfo.setTs(String.format("http://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); + streamInfo.setWs_ts(String.format("ws://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); + + streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtmpPort(), streamId)); + streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtspPort(), streamId)); + + return streamInfo; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java index 40b1b5b6..6180fbb6 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java @@ -34,8 +34,7 @@ public class ApiStreamController { @Autowired private IVideoManagerStorager storager; - @Value("${media.closeWaitRTPInfo}") - private boolean closeWaitRTPInfo; + private boolean closeWaitRTPInfo = false; @Autowired @@ -94,7 +93,7 @@ public class ApiStreamController { StreamInfo streamInfo = storager.queryPlayByDevice(device.getDeviceId(), code); if (streamInfo == null) { logger.debug("streamInfo 等于null, 重新点播"); - streamInfo = cmder.playStreamCmd(device, code); +// streamInfo = cmder.playStreamCmd(device, code); }else { logger.debug("streamInfo 不等于null, 向流媒体查询是否正在推流"); String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); @@ -136,7 +135,7 @@ public class ApiStreamController { } else { logger.debug("向流媒体查询没有推流, 重新点播"); storager.stopPlay(streamInfo); - streamInfo = cmder.playStreamCmd(device, code); +// streamInfo = cmder.playStreamCmd(device, code); } } diff --git a/web_src/build/webpack.dev.conf.js b/web_src/build/webpack.dev.conf.js index c12be3e9..e33cb017 100755 --- a/web_src/build/webpack.dev.conf.js +++ b/web_src/build/webpack.dev.conf.js @@ -64,9 +64,8 @@ const devWebpackConfig = merge(baseWebpackConfig, { to: config.dev.assetsSubDirectory, ignore: ['.*'] }, - { from: 'node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml'}, - { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf'}, - { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js', to: 'js/'} + { from: 'node_modules/@easydarwin/easywasmplayer/libDecoder.wasm'}, + { from: 'node_modules/@easydarwin/easywasmplayer/EasyWasmPlayer.js', to: 'js/'} ]) ] }) diff --git a/web_src/build/webpack.prod.conf.js b/web_src/build/webpack.prod.conf.js index 2bfb52c2..13d373db 100644 --- a/web_src/build/webpack.prod.conf.js +++ b/web_src/build/webpack.prod.conf.js @@ -115,9 +115,8 @@ const webpackConfig = merge(baseWebpackConfig, { to: config.build.assetsSubDirectory, ignore: ['.*'] }, - { from: 'node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml'}, - { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf'}, - { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js', to: 'js/'} + { from: 'node_modules/@easydarwin/easywasmplayer/libDecoder.wasm'}, + { from: 'node_modules/@easydarwin/easywasmplayer/EasyWasmPlayer.js', to: 'js/'} ]) ] }) diff --git a/web_src/index.html b/web_src/index.html index 9c4e39b2..12241251 100644 --- a/web_src/index.html +++ b/web_src/index.html @@ -6,7 +6,7 @@ 国标28181 - +
diff --git a/web_src/package-lock.json b/web_src/package-lock.json index e00c5cea..334f488a 100644 --- a/web_src/package-lock.json +++ b/web_src/package-lock.json @@ -4,10 +4,10 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@liveqing/liveplayer": { - "version": "1.9.9", - "resolved": "https://registry.npm.taobao.org/@liveqing/liveplayer/download/@liveqing/liveplayer-1.9.9.tgz", - "integrity": "sha1-K7wiab+BiY5qe1/nTpKVyeGdIGo=" + "@easydarwin/easywasmplayer": { + "version": "4.0.7", + "resolved": "https://registry.npm.taobao.org/@easydarwin/easywasmplayer/download/@easydarwin/easywasmplayer-4.0.7.tgz", + "integrity": "sha1-FNtIUXbdwIWdalvIMEaH0+zUGx4=" }, "@types/q": { "version": "1.5.4", diff --git a/web_src/package.json b/web_src/package.json index 05178d42..c949393a 100644 --- a/web_src/package.json +++ b/web_src/package.json @@ -10,7 +10,7 @@ "build": "node build/build.js" }, "dependencies": { - "@liveqing/liveplayer": "^1.9.6", + "@easydarwin/easywasmplayer": "^4.0.7", "axios": "^0.19.2", "core-js": "^2.6.5", "echarts": "^4.7.0", diff --git a/web_src/src/components/gb28181/devicePlayer.vue b/web_src/src/components/gb28181/devicePlayer.vue index c87d0c49..ddf90c21 100644 --- a/web_src/src/components/gb28181/devicePlayer.vue +++ b/web_src/src/components/gb28181/devicePlayer.vue @@ -1,9 +1,11 @@ + + \ No newline at end of file diff --git a/web_src/src/components/videoList.vue b/web_src/src/components/videoList.vue index ebf3ad05..ad2f701d 100644 --- a/web_src/src/components/videoList.vue +++ b/web_src/src/components/videoList.vue @@ -73,12 +73,10 @@ \ No newline at end of file + From e9476821e1029a0825cf66bf19bde8a8eb805821 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Mon, 21 Dec 2020 17:40:05 +0800 Subject: [PATCH 28/45] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ef46c2ad..caf4dfcd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - active: local \ No newline at end of file + active: dev \ No newline at end of file From 762507def6d95f2a1e46d773479406a581f99e0a Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 22 Dec 2020 09:48:51 +0800 Subject: [PATCH 29/45] =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E4=B8=8D=E5=AE=89=E5=85=A8=E7=9A=84map?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vmp/gb28181/transmit/callback/DeferredResultHolder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java index 0c1e63d6..692e31e5 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.callback; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -24,7 +25,7 @@ public class DeferredResultHolder { public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY"; - private Map map = new HashMap(); + private Map map = new ConcurrentHashMap(); public void put(String key, DeferredResult result) { map.put(key, result); From 4ee6962fe62af1b58f4b0ea33494db96a6c07d3c Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Tue, 22 Dec 2020 15:04:19 +0800 Subject: [PATCH 30/45] =?UTF-8?q?=E6=B7=BB=E5=8A=A0maven=E6=BA=90,=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BE=9D=E8=B5=96=E4=B8=8B=E8=BD=BD=E9=80=9F?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/pom.xml b/pom.xml index 86b4c176..2ac45ec2 100644 --- a/pom.xml +++ b/pom.xml @@ -13,6 +13,34 @@ wvp web video platform + + + nexus-aliyun + Nexus aliyun + https://maven.aliyun.com/repository/public + default + + false + + + true + + + + + + nexus-aliyun + Nexus aliyun + https://maven.aliyun.com/repository/public + + false + + + true + + + + UTF-8 From a2ac3c77dd3c7aeec80f1aff61288790f37bd562 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Fri, 25 Dec 2020 15:05:55 +0800 Subject: [PATCH 31/45] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A9=BA=E6=8C=87?= =?UTF-8?q?=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/DigestServerAuthenticationHelper.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java index 54e0334a..16ed56a3 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java @@ -105,11 +105,11 @@ public class DigestServerAuthenticationHelper { proxyAuthenticate.setParameter("realm", realm); proxyAuthenticate.setParameter("nonce", generateNonce()); -// proxyAuthenticate.setParameter("opaque", ""); -// proxyAuthenticate.setParameter("stale", "FALSE"); -// proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM); + proxyAuthenticate.setParameter("opaque", ""); + proxyAuthenticate.setParameter("stale", "FALSE"); + proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM); - proxyAuthenticate.setParameter("qop", "auth"); +// proxyAuthenticate.setParameter("qop", "auth"); response.setHeader(proxyAuthenticate); } catch (Exception ex) { InternalErrorHandler.handleException(ex); @@ -187,11 +187,11 @@ public class DigestServerAuthenticationHelper { return false; } // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略 - String qop = authHeader.getQop().trim(); + String qop = authHeader.getQop(); // 客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。 // 这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护 - String cNonce = authHeader.getCNonce().trim(); + String cNonce = authHeader.getCNonce(); // nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量 int nc = authHeader.getNonceCount(); From 64aae8db3bf013dc746a41ed3e92cc0f241e2626 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Fri, 25 Dec 2020 15:27:25 +0800 Subject: [PATCH 32/45] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BD=95=E5=83=8F?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E7=9A=84VIA=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java index 43138f5b..a606171a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java @@ -129,9 +129,8 @@ public class SIPRequestHeaderProvider { Host host = device.getHost(); //请求行 SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); - //via + // via ArrayList viaHeaders = new ArrayList(); - // ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag); ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag); viaHeader.setRPort(); viaHeaders.add(viaHeader); From 3dcb759bda156e492cadea2a50ef77cc69c4e765 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Fri, 25 Dec 2020 18:11:03 +0800 Subject: [PATCH 33/45] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6=E7=9A=84=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/conf/ApplicationCheckRunner.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java diff --git a/src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java b/src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java new file mode 100644 index 00000000..faa9ef12 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java @@ -0,0 +1,63 @@ +package com.genersoft.iot.vmp.conf; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + + +/** + * 对配置文件进行校验 + */ +@Component +@Order(value=2) +public class ApplicationCheckRunner implements CommandLineRunner { + + private Logger logger = LoggerFactory.getLogger("ApplicationCheckRunner"); + + @Value("${sip.ip}") + private String sipIp; + + @Value("${media.ip}") + private String mediaIp; + + @Value("${media.wanIp}") + private String mediaWanIp; + + @Value("${media.hookIp}") + private String mediaHookIp; + + @Value("${media.port}") + private int mediaPort; + + @Value("${media.secret}") + private String mediaSecret; + + @Value("${media.streamNoneReaderDelayMS}") + private String streamNoneReaderDelayMS; + + @Value("${sip.ip}") + private String sipIP; + + @Value("${server.port}") + private String serverPort; + + @Value("${media.autoConfig}") + private boolean autoConfig; + + + @Override + public void run(String... args) throws Exception { + if (sipIP.equals("localhost") || sipIP.equals("127.0.0.1")) { + logger.error("sip.ip不能使用 {} ,请使用类似192.168.1.44这样的来自网卡的IP!!!", sipIP ); + System.exit(1); + } + + if (mediaIp.equals("localhost") || mediaIp.equals("127.0.0.1")) { + logger.warn("mediaIp.ip使用 {} ,将无法收到网络内其他设备的推流!!!", mediaIp ); + } + + } +} From e4d849304c7cfc96af7b04634a56bc0c323142c7 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Sat, 26 Dec 2020 16:44:27 +0800 Subject: [PATCH 34/45] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=E6=B0=B4?= =?UTF-8?q?=E6=98=9FIPC=E7=9A=84=E5=85=BC=E5=AE=B9=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=AF=B9SIP=E9=94=99=E8=AF=AF=E7=9A=84=E8=AE=A2=E9=98=85?= =?UTF-8?q?=EF=BC=8C=E5=88=B7=E6=96=B0=E9=80=9A=E9=81=93=E6=88=96=E7=82=B9?= =?UTF-8?q?=E6=92=AD=E6=88=96=E5=9B=9E=E6=94=BE=E5=87=BA=E7=8E=B0sip?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E6=97=B6=E5=8F=8A=E6=97=B6=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=BB=99=E9=A1=B5=E9=9D=A2=20=E4=BC=98=E5=8C=96UI=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8C=89=E9=92=AEloading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../genersoft/iot/vmp/gb28181/SipLayer.java | 19 +++++- .../gb28181/auth/RegisterLogicHandler.java | 2 +- .../iot/vmp/gb28181/event/SipSubscribe.java | 37 +++++++++++ .../gb28181/transmit/SIPProcessorFactory.java | 8 ++- .../gb28181/transmit/cmd/ISIPCommander.java | 7 +- .../transmit/cmd/impl/SIPCommander.java | 65 ++++++++++++------- .../request/impl/MessageRequestProcessor.java | 2 +- .../vmp/media/zlm/ZLMHttpHookListener.java | 2 +- .../iot/vmp/utils/SpringBeanFactory.java | 1 + .../vmp/vmanager/device/DeviceController.java | 23 ++++++- .../iot/vmp/vmanager/play/PlayController.java | 13 ++++ .../vmanager/playback/PlaybackController.java | 7 ++ web_src/src/components/videoList.vue | 36 +++++++--- 13 files changed, 176 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java index f1ed477e..92ba204a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java @@ -8,8 +8,10 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.sip.*; +import javax.sip.header.CallIdHeader; import javax.sip.message.Response; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -34,6 +36,9 @@ public class SipLayer implements SipListener { @Autowired private SIPProcessorFactory processorFactory; + @Autowired + private SipSubscribe sipSubscribe; + private SipStack sipStack; private SipFactory sipFactory; @@ -139,11 +144,19 @@ public class SipLayer implements SipListener { // 增加其它无需回复的响应,如101、180等 } else { logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); + if (evt.getResponse() != null && sipSubscribe.getSize() > 0 ) { + CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME); + if (callIdHeader != null) { + SipSubscribe.Event subscribe = sipSubscribe.getSubscribe(callIdHeader.getCallId()); + if (subscribe != null) { + subscribe.response(evt); + } + } + } } - // trying不会回复 - // if (status == Response.TRYING) { - // } + + } /** diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java index 6e4588d2..6fe63cc5 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java @@ -21,6 +21,6 @@ public class RegisterLogicHandler { // TODO 后续处理,只有第一次注册时调用查询设备信息,如需更新调用更新API接口 cmder.deviceInfoQuery(device); - cmder.catalogQuery(device); + cmder.catalogQuery(device, null); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java new file mode 100644 index 00000000..1f78df44 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java @@ -0,0 +1,37 @@ +package com.genersoft.iot.vmp.gb28181.event; + +import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.sip.ResponseEvent; +import javax.sip.message.Request; +import java.util.EventObject; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Component +public class SipSubscribe { + + private final static Logger logger = LoggerFactory.getLogger(SipSubscribe.class); + + private Map allSubscribes = new ConcurrentHashMap<>(); + + public interface Event { + void response(ResponseEvent event); + } + + public void addSubscribe(String key, SipSubscribe.Event event) { + allSubscribes.put(key, event); + } + + public SipSubscribe.Event getSubscribe(String key) { + return allSubscribes.get(key); + } + + public int getSize(){ + return allSubscribes.size(); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java index 73fb474d..d37259ac 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java @@ -4,10 +4,13 @@ import javax.sip.RequestEvent; import javax.sip.ResponseEvent; import javax.sip.SipProvider; import javax.sip.header.CSeqHeader; +import javax.sip.header.CallIdHeader; +import javax.sip.header.Header; import javax.sip.message.Request; import javax.sip.message.Response; import com.alibaba.fastjson.JSON; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -83,7 +86,8 @@ public class SIPProcessorFactory { @Autowired private OtherResponseProcessor otherResponseProcessor; - + + // 注:这里使用注解会导致循环依赖注入,暂用springBean private SipProvider tcpSipProvider; @@ -94,6 +98,7 @@ public class SIPProcessorFactory { Request request = evt.getRequest(); String method = request.getMethod(); // logger.info("接收到消息:"+request.getMethod()); +// sipSubscribe.getSubscribe(evt.getServerTransaction().getBranchId()).response(evt); if (Request.INVITE.equals(method)) { InviteRequestProcessor processor = new InviteRequestProcessor(); processor.setRequestEvent(evt); @@ -145,6 +150,7 @@ public class SIPProcessorFactory { } public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) { + Response response = evt.getResponse(); CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); String method = cseqHeader.getMethod(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index 46e59450..732b2cdc 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; /** @@ -83,7 +84,7 @@ public interface ISIPCommander { * @param device 视频设备 * @param channelId 预览通道 */ - void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event); + void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); /** * 请求回放视频流 @@ -93,7 +94,7 @@ public interface ISIPCommander { * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss */ - void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event); + void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent); /** * 视频流停止 @@ -175,7 +176,7 @@ public interface ISIPCommander { * * @param device 视频设备 */ - boolean catalogQuery(Device device); + boolean catalogQuery(Device device, SipSubscribe.Event errorEvent); /** * 查询录像信息 diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 7d91d7b3..61ed2703 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -4,22 +4,22 @@ import java.text.ParseException; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.sip.ClientTransaction; -import javax.sip.Dialog; -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; -import javax.sip.SipProvider; -import javax.sip.TransactionDoesNotExistException; +import javax.sip.*; import javax.sip.address.SipURI; +import javax.sip.header.CallIdHeader; +import javax.sip.header.Header; import javax.sip.header.ViaHeader; import javax.sip.message.Request; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.conf.MediaServerConfig; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +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.beans.factory.annotation.Value; @@ -39,6 +39,8 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil; */ @Component public class SIPCommander implements ISIPCommander { + + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class); @Autowired private SipConfig sipConfig; @@ -69,6 +71,9 @@ public class SIPCommander implements ISIPCommander { @Autowired private ZLMHttpHookSubscribe subscribe; + @Autowired + private SipSubscribe sipSubscribe; + /** @@ -221,7 +226,7 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag"); - transmitRequest(device, request); + transmitRequest(device, request, null); return true; } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); @@ -256,22 +261,23 @@ public class SIPCommander implements ISIPCommander { ptzXml.append("\r\n"); Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag"); - - transmitRequest(device, request); + transmitRequest(device, request, null); return true; } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); } return false; } + /** - * 请求预览视频流 - * + * 请求预览视频流 * @param device 视频设备 * @param channelId 预览通道 + * @param event hook订阅 + * @param errorEvent sip错误订阅 */ @Override - public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event) { + public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) { try { String ssrc = streamSession.createPlaySsrc(); @@ -300,7 +306,8 @@ public class SIPCommander implements ISIPCommander { // StringBuffer content = new StringBuffer(200); content.append("v=0\r\n"); - content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); +// content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); + content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n"); content.append("s=Play\r\n"); content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); content.append("t=0 0\r\n"); @@ -332,7 +339,7 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); - ClientTransaction transaction = transmitRequest(device, request); + ClientTransaction transaction = transmitRequest(device, request, errorEvent); streamSession.put(streamId, transaction); DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId); if (deviceChannel != null) { @@ -357,7 +364,8 @@ public class SIPCommander implements ISIPCommander { * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss */ @Override - public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event) { + public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event + , SipSubscribe.Event errorEvent) { try { MediaServerConfig mediaInfo = storager.getMediaInfo(); String ssrc = streamSession.createPlayBackSsrc(); @@ -413,8 +421,8 @@ public class SIPCommander implements ISIPCommander { content.append("y="+ssrc+"\r\n");//ssrc Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null); - - ClientTransaction transaction = transmitRequest(device, request); + + ClientTransaction transaction = transmitRequest(device, request, errorEvent); streamSession.put(streamId, transaction); } catch ( SipException | ParseException | InvalidArgumentException e) { @@ -575,7 +583,8 @@ public class SIPCommander implements ISIPCommander { catalogXml.append("\r\n"); Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag"); - transmitRequest(device, request); + + transmitRequest(device, request, null); } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); @@ -590,7 +599,7 @@ public class SIPCommander implements ISIPCommander { * @param device 视频设备 */ @Override - public boolean catalogQuery(Device device) { + public boolean catalogQuery(Device device, SipSubscribe.Event errorEvent) { // 清空通道 storager.cleanChannelsForDevice(device.getDeviceId()); try { @@ -602,8 +611,9 @@ public class SIPCommander implements ISIPCommander { catalogXml.append("" + device.getDeviceId() + "\r\n"); catalogXml.append("\r\n"); - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", "ToCatalogTag"); - transmitRequest(device, request); + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", null); + + transmitRequest(device, request, errorEvent); } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); return false; @@ -636,7 +646,9 @@ public class SIPCommander implements ISIPCommander { recordInfoXml.append("\r\n"); Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag"); - transmitRequest(device, request); + + + transmitRequest(device, request, null); } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); return false; @@ -688,13 +700,20 @@ public class SIPCommander implements ISIPCommander { return false; } - private ClientTransaction transmitRequest(Device device, Request request) throws SipException { + private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException { ClientTransaction clientTransaction = null; if("TCP".equals(device.getTransport())) { clientTransaction = tcpSipProvider.getNewClientTransaction(request); } else if("UDP".equals(device.getTransport())) { clientTransaction = udpSipProvider.getNewClientTransaction(request); } + + // 添加订阅 + if (errorEvent != null) { + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); + sipSubscribe.addSubscribe(callIdHeader.getCallId(), errorEvent); + } + clientTransaction.sendRequest(); return clientTransaction; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java index 3c90e8ea..ba4b2cb0 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java @@ -294,7 +294,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { device.setStreamMode("UDP"); } storager.updateDevice(device); - cmder.catalogQuery(device); + cmder.catalogQuery(device, null); // 回复200 OK responseAck(evt); if (offLineDetector.isOnline(deviceId)) { 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 7249d987..1116ae5a 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -323,7 +323,7 @@ public class ZLMHttpHookListener { cmder.playStreamCmd(device, channelId, (JSONObject response) -> { logger.info("收到订阅消息: " + response.toJSONString()); playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); - }); + }, null); } } diff --git a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java index 3fe7dcc7..ccbe94d6 100644 --- a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java +++ b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java @@ -34,6 +34,7 @@ public class SpringBeanFactory implements ApplicationContextAware { * 获取对象 这里重写了bean方法,起主要作用 */ public static Object getBean(String beanId) throws BeansException { + if (applicationContext == null) return null; return applicationContext.getBean(beanId); } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java index 34a02ee2..65e294a5 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java @@ -4,6 +4,7 @@ import java.util.List; import com.genersoft.iot.vmp.common.PageResult; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -19,6 +20,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import javax.sip.message.Response; + @CrossOrigin @RestController @RequestMapping("/api") @@ -86,11 +89,25 @@ public class DeviceController { if (logger.isDebugEnabled()) { } - logger.debug("设备信息同步API调用,deviceId:" + deviceId); + logger.debug("设备通道信息同步API调用,deviceId:" + deviceId); Device device = storager.queryVideoDevice(deviceId); - cmder.catalogQuery(device); - DeferredResult> result = new DeferredResult>(); + cmder.catalogQuery(device, event -> { + Response response = event.getResponse(); + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId); + msg.setData(String.format("同步通道失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); + resultHolder.invokeResult(msg); + }); + DeferredResult> result = new DeferredResult>(2*1000L); + result.onTimeout(()->{ + logger.warn(String.format("设备通道信息同步超时")); + // 释放rtpserver + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId); + msg.setData("Timeout"); + resultHolder.invokeResult(msg); + }); resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); return result; } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java index ce907e86..eba40bb9 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java @@ -28,6 +28,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.message.Response; import java.text.DecimalFormat; import java.util.UUID; @@ -72,6 +73,12 @@ public class PlayController { cmder.playStreamCmd(device, channelId, (JSONObject response) -> { logger.info("收到订阅消息: " + response.toJSONString()); playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); + }, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + Response response = event.getResponse(); + msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); + resultHolder.invokeResult(msg); }); } else { String streamId = streamInfo.getStreamId(); @@ -86,6 +93,12 @@ public class PlayController { cmder.playStreamCmd(device, channelId, (JSONObject response) -> { logger.info("收到订阅消息: " + response.toJSONString()); playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); + }, event -> { + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + Response response = event.getResponse(); + msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); + resultHolder.invokeResult(msg); }); } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java index 5fbaabfe..c9dc92c3 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java @@ -27,6 +27,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.springframework.web.context.request.async.DeferredResult; +import javax.sip.message.Response; import java.util.UUID; @CrossOrigin @@ -78,6 +79,12 @@ public class PlaybackController { cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { logger.info("收到订阅消息: " + response.toJSONString()); playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString()); + }, event -> { + Response response = event.getResponse(); + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + msg.setData(String.format("回放失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase())); + resultHolder.invokeResult(msg); }); return result; diff --git a/web_src/src/components/videoList.vue b/web_src/src/components/videoList.vue index ad2f701d..50767cc4 100644 --- a/web_src/src/components/videoList.vue +++ b/web_src/src/components/videoList.vue @@ -8,7 +8,7 @@
设备列表
- +
@@ -51,7 +51,7 @@ @@ -90,7 +90,8 @@ winHeight: window.innerHeight - 200, currentPage:1, count:15, - total:0 + total:0, + getDeviceListLoading: false }; }, computed: { @@ -130,7 +131,7 @@ }, getDeviceList: function() { let that = this; - + this.getDeviceListLoading = true; this.$axios.get(`/api/devices`,{ params: { page: that.currentPage - 1, @@ -141,9 +142,11 @@ console.log(res); that.total = res.data.total; that.deviceList = res.data.data; + that.getDeviceListLoading = false; }) .catch(function (error) { console.log(error); + that.getDeviceListLoading = false; }); }, @@ -158,17 +161,30 @@ refDevice: function(itemData) { ///api/devices/{deviceId}/sync console.log("刷新对应设备:" + itemData.deviceId); + var that = this; + that.$refs[itemData.deviceId + 'refbtn' ].loading = true; this.$axios({ method: 'post', url: '/api/devices/' + itemData.deviceId + '/sync' }).then(function(res) { - // console.log("刷新设备结果:"+JSON.stringify(res)); + console.log("刷新设备结果:"+JSON.stringify(res)); + if (!res.data.deviceId) { + that.$message({ + showClose: true, + message: res.data, + type: 'error' + }); + }else{ + that.$message({ + showClose: true, + message: '请求成功', + type: 'success' + }); + } + that.$refs[itemData.deviceId + 'refbtn' ].loading = false; }).catch(function(e) { - that.$message({ - showClose: true, - message: '请求成功', - type: 'success' - }); + console.error(e) + that.$refs[itemData.deviceId + 'refbtn' ].loading = false; });; }, //通知设备上传媒体流 From 071c2de9b8e152a2ffe4f9a4c698ffe8efa8fddb Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Sat, 26 Dec 2020 20:08:04 +0800 Subject: [PATCH 35/45] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=B0=B4=E6=98=9FIPC?= =?UTF-8?q?=E7=9A=84=E5=BD=95=E5=83=8F=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 61ed2703..4c14152b 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -645,7 +645,7 @@ public class SIPCommander implements ISIPCommander { recordInfoXml.append("all\r\n"); recordInfoXml.append("\r\n"); - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag"); + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", null); transmitRequest(device, request, null); From 27c03320528df914c5aa8082b776f5919ae93f79 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Sun, 27 Dec 2020 08:19:34 +0800 Subject: [PATCH 36/45] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A9=BA=E6=8C=87?= =?UTF-8?q?=E9=92=88=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 4c14152b..50ec4551 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -289,6 +289,10 @@ public class SIPCommander implements ISIPCommander { } String streamMode = device.getStreamMode().toUpperCase(); MediaServerConfig mediaInfo = storager.getMediaInfo(); + if (mediaInfo == null) { + logger.warn("点播时发现ZLM尚未连接..."); + return; + } String mediaPort = null; // 使用动态udp端口 if (rtpEnable) { @@ -347,8 +351,6 @@ public class SIPCommander implements ISIPCommander { storager.updateChannel(device.getDeviceId(), deviceChannel); } - // TODO 订阅SIP response,处理对方的错误返回 - } catch ( SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); From 098307cfe80bc61553df93ff5ccf5561834e9c05 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Mon, 28 Dec 2020 11:07:01 +0800 Subject: [PATCH 37/45] =?UTF-8?q?=E6=A3=80=E6=9F=A5=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8=EF=BC=8C=20=E4=B8=8D?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E5=88=99=E4=B8=8D=E5=9B=9E=E5=A4=8D=E5=BF=83?= =?UTF-8?q?=E8=B7=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/impl/MessageRequestProcessor.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java index ba4b2cb0..7b793c09 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java @@ -315,12 +315,16 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { try { Element rootElement = getRootElement(evt); String deviceId = XmlUtil.getText(rootElement, "DeviceID"); - // 回复200 OK - responseAck(evt); - if (offLineDetector.isOnline(deviceId)) { - publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); - } else { + // 检查设备是否存在, 不存在则不回复 + if (storager.exists(deviceId)) { + // 回复200 OK + responseAck(evt); + if (offLineDetector.isOnline(deviceId)) { + publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE); + } else { + } } + } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { e.printStackTrace(); } From 59f7fb106374b46af03f1a0697e8ca70567eaa06 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Mon, 28 Dec 2020 11:45:40 +0800 Subject: [PATCH 38/45] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9=20=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E6=89=A9=E5=B1=95SDP=E7=9A=84=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=9A=84=E5=8D=95=E7=8B=AC=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transmit/cmd/impl/SIPCommander.java | 72 +++++++++++++------ src/main/resources/application-dev.yml | 4 +- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 50ec4551..3f0adfd9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -68,6 +68,9 @@ public class SIPCommander implements ISIPCommander { @Value("${media.rtp.enable}") private boolean rtpEnable; + @Value("${media.seniorSdp}") + private boolean seniorSdp; + @Autowired private ZLMHttpHookSubscribe subscribe; @@ -396,30 +399,53 @@ public class SIPCommander implements ISIPCommander { mediaPort = mediaInfo.getRtpProxyPort(); } String streamMode = device.getStreamMode().toUpperCase(); - if("TCP-PASSIVE".equals(streamMode)) { - content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n"); - }else if ("TCP-ACTIVE".equals(streamMode)) { - content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n"); - }else if("UDP".equals(streamMode)) { - content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n"); - } - content.append("a=recvonly\r\n"); - content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:126 H264/90000\r\n"); - content.append("a=rtpmap:125 H264S/90000\r\n"); - content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); - content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); - content.append("a=fmtp:99 profile-level-id=3\r\n"); - content.append("a=rtpmap:98 H264/90000\r\n"); - content.append("a=rtpmap:97 MPEG4/90000\r\n"); - content.append("a=rtpmap:96 PS/90000\r\n"); - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 - content.append("a=setup:passive\r\n"); - content.append("a=connection:new\r\n"); - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 - content.append("a=setup:active\r\n"); - content.append("a=connection:new\r\n"); + + if (seniorSdp) { + if("TCP-PASSIVE".equals(streamMode)) { + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n"); + }else if ("TCP-ACTIVE".equals(streamMode)) { + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n"); + }else if("UDP".equals(streamMode)) { + content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=fmtp:126 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:126 H264/90000\r\n"); + content.append("a=rtpmap:125 H264S/90000\r\n"); + content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); + content.append("a=rtpmap:99 MP4V-ES/90000\r\n"); + content.append("a=fmtp:99 profile-level-id=3\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } + }else { + if("TCP-PASSIVE".equals(streamMode)) { + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); + }else if ("TCP-ACTIVE".equals(streamMode)) { + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n"); + }else if("UDP".equals(streamMode)) { + content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n"); + } + content.append("a=recvonly\r\n"); + content.append("a=rtpmap:96 PS/90000\r\n"); + content.append("a=rtpmap:98 H264/90000\r\n"); + content.append("a=rtpmap:97 MPEG4/90000\r\n"); + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 + content.append("a=setup:passive\r\n"); + content.append("a=connection:new\r\n"); + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式 + content.append("a=setup:active\r\n"); + content.append("a=connection:new\r\n"); + } } + content.append("y="+ssrc+"\r\n");//ssrc Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null); diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index de777395..34f615ac 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -70,8 +70,10 @@ media: secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc # [可选] zlm服务器的general.streamNoneReaderDelayMS streamNoneReaderDelayMS: 600000 # 无人观看多久自动关闭流, -1表示永不自动关闭,即 关闭按需拉流 - # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播 + # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true autoApplyPlay: true + # [可选] 部分设备需要扩展SDP,需要打开此设置 + seniorSdp: false # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用 rtp: # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输 From 2ab8b942bdd20daa733ea40376034f3080c0ca9b Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Thu, 31 Dec 2020 13:15:50 +0800 Subject: [PATCH 39/45] =?UTF-8?q?=E5=AD=98=E5=82=A8=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BD=BF=E7=94=A8sqlite=E4=BB=A3=E6=9B=BFredis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 + .../genersoft/iot/vmp/gb28181/SipLayer.java | 13 +- .../iot/vmp/gb28181/bean/Device.java | 34 +- .../iot/vmp/gb28181/bean/DeviceChannel.java | 27 +- .../iot/vmp/gb28181/event/SipSubscribe.java | 27 +- .../gb28181/transmit/SIPProcessorFactory.java | 9 +- .../callback/DeferredResultHolder.java | 2 + .../gb28181/transmit/cmd/ISIPCommander.java | 3 +- .../transmit/cmd/impl/SIPCommander.java | 68 ++- .../request/impl/MessageRequestProcessor.java | 14 +- .../impl/RegisterRequestProcessor.java | 8 +- .../vmp/media/zlm/ZLMHTTPProxyController.java | 8 +- .../vmp/media/zlm/ZLMHttpHookListener.java | 24 +- .../iot/vmp/media/zlm/ZLMRunner.java | 6 +- .../iot/vmp/storager/IRedisCatchStorage.java | 58 ++ .../vmp/storager/IVideoManagerStorager.java | 54 +- .../storager/VideoManagerStoragerFactory.java | 36 -- .../iot/vmp/storager/VodeoMannagerTask.java | 4 +- .../vmp/storager/dao/DeviceChannelMapper.java | 20 + .../iot/vmp/storager/dao/DeviceMapper.java | 24 + .../storager/impl/RedisCatchStorageImpl.java | 172 ++++++ .../impl/VideoManagerStoragerImpl.java | 401 +++++++++++++ .../jdbc/VideoManagerJdbcStoragerImpl.java | 217 ------- .../redis/VideoManagerRedisStoragerImpl.java | 561 ------------------ .../iot/vmp/vmanager/play/PlayController.java | 70 ++- .../service/impl/PlayServiceImpl.java | 10 +- .../iot/vmp/web/ApiDeviceController.java | 2 +- .../iot/vmp/web/ApiStreamController.java | 8 +- src/main/resources/wvp.sqlite | Bin 0 -> 32768 bytes web_src/src/components/channelList.vue | 2 +- 30 files changed, 933 insertions(+), 956 deletions(-) create mode 100644 src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java create mode 100644 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java create mode 100644 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java create mode 100644 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java create mode 100644 src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java create mode 100644 src/main/resources/wvp.sqlite diff --git a/pom.xml b/pom.xml index 2ac45ec2..ae4d6666 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,13 @@ 8.0.22 + + + org.xerial + sqlite-jdbc + 3.32.3.2 + + org.mybatis diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java index 92ba204a..e171297c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java @@ -138,16 +138,25 @@ public class SipLayer implements SipListener { // TODO Auto-generated catch block e.printStackTrace(); } + if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) { + CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME); + if (callIdHeader != null) { + SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId()); + if (subscribe != null) { + subscribe.response(evt); + } + } + } // } else if (status == Response.TRYING) { // trying不会回复 } else if ((status >= 100) && (status < 200)) { // 增加其它无需回复的响应,如101、180等 } else { logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); - if (evt.getResponse() != null && sipSubscribe.getSize() > 0 ) { + if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) { CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME); if (callIdHeader != null) { - SipSubscribe.Event subscribe = sipSubscribe.getSubscribe(callIdHeader.getCallId()); + SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()); if (subscribe != null) { subscribe.response(evt); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java index de52ac69..12b8a007 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java @@ -1,11 +1,17 @@ package com.genersoft.iot.vmp.gb28181.bean; +import java.util.Date; import java.util.List; import java.util.Map; public class Device { + /** + * 数据库存储ID + */ + private int id; + /** * 设备Id */ @@ -55,14 +61,24 @@ public class Device { */ private int online; - /** - * 通道列表 - */ -// private Map channelMap; + /** + * 注册时间 + */ + private Long registerTimeMillis; + + /** + * 通道个数 + */ private int channelCount; - private List channelList; + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } public String getDeviceId() { return deviceId; @@ -144,11 +160,11 @@ public class Device { this.channelCount = channelCount; } - public List getChannelList() { - return channelList; + public Long getRegisterTimeMillis() { + return registerTimeMillis; } - public void setChannelList(List channelList) { - this.channelList = channelList; + public void setRegisterTimeMillis(Long registerTimeMillis) { + this.registerTimeMillis = registerTimeMillis; } } 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 19e9eda9..ca6ef60f 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 @@ -2,10 +2,17 @@ package com.genersoft.iot.vmp.gb28181.bean; public class DeviceChannel { + + /** * 通道id */ private String channelId; + + /** + * 设备id + */ + private String deviceId; /** * 通道名 @@ -146,13 +153,15 @@ public class DeviceChannel { /** * 是否含有音频 */ - private boolean hasAudio; + private boolean hasAudio; - /** - * 是否正在播放 - */ - private boolean play; + public String getDeviceId() { + return deviceId; + } + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } public void setPTZType(int PTZType) { this.PTZType = PTZType; @@ -387,14 +396,6 @@ public class DeviceChannel { this.hasAudio = hasAudio; } - public boolean isPlay() { - return play; - } - - public void setPlay(boolean play) { - this.play = play; - } - public String getStreamId() { return streamId; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java index 1f78df44..176a435e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java @@ -17,21 +17,34 @@ public class SipSubscribe { private final static Logger logger = LoggerFactory.getLogger(SipSubscribe.class); - private Map allSubscribes = new ConcurrentHashMap<>(); + private Map errorSubscribes = new ConcurrentHashMap<>(); + + private Map okSubscribes = new ConcurrentHashMap<>(); public interface Event { void response(ResponseEvent event); } - public void addSubscribe(String key, SipSubscribe.Event event) { - allSubscribes.put(key, event); + public void addErrorSubscribe(String key, SipSubscribe.Event event) { + errorSubscribes.put(key, event); } - public SipSubscribe.Event getSubscribe(String key) { - return allSubscribes.get(key); + public void addOkSubscribe(String key, SipSubscribe.Event event) { + okSubscribes.put(key, event); } - public int getSize(){ - return allSubscribes.size(); + public SipSubscribe.Event getErrorSubscribe(String key) { + return errorSubscribes.get(key); + } + + public SipSubscribe.Event getOkSubscribe(String key) { + return okSubscribes.get(key); + } + + public int getErrorSubscribesSize(){ + return errorSubscribes.size(); + } + public int getOkSubscribesSize(){ + return okSubscribes.size(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java index d37259ac..b50cc957 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java @@ -4,13 +4,10 @@ import javax.sip.RequestEvent; import javax.sip.ResponseEvent; import javax.sip.SipProvider; import javax.sip.header.CSeqHeader; -import javax.sip.header.CallIdHeader; -import javax.sip.header.Header; import javax.sip.message.Request; import javax.sip.message.Response; -import com.alibaba.fastjson.JSON; -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -59,6 +56,9 @@ public class SIPProcessorFactory { @Autowired private IVideoManagerStorager storager; + + @Autowired + private IRedisCatchStorage redisCatchStorage; @Autowired private EventPublisher publisher; @@ -143,6 +143,7 @@ public class SIPProcessorFactory { processor.setOffLineDetector(offLineDetector); processor.setCmder(cmder); processor.setStorager(storager); + processor.setRedisCatchStorage(redisCatchStorage); return processor; } else { return new OtherRequestProcessor(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java index 692e31e5..5fd8cbc9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java @@ -25,6 +25,8 @@ public class DeferredResultHolder { public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY"; + public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; + private Map map = new ConcurrentHashMap(); public void put(String key, DeferredResult result) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index 732b2cdc..67fd9967 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -101,8 +101,9 @@ public interface ISIPCommander { * * @param ssrc ssrc */ + void streamByeCmd(String ssrc, SipSubscribe.Event okEvent); void streamByeCmd(String ssrc); - + /** * 语音广播 * diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 3f0adfd9..af9030b9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; import java.text.ParseException; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -12,11 +13,13 @@ import javax.sip.header.ViaHeader; import javax.sip.message.Request; import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaServerConfig; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,6 +56,9 @@ public class SIPCommander implements ISIPCommander { @Autowired private IVideoManagerStorager storager; + + @Autowired + private IRedisCatchStorage redisCatchStorage; @Autowired @Qualifier(value="tcpSipProvider") @@ -229,7 +235,7 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag"); - transmitRequest(device, request, null); + transmitRequest(device, request); return true; } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); @@ -264,7 +270,7 @@ public class SIPCommander implements ISIPCommander { ptzXml.append("\r\n"); Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag"); - transmitRequest(device, request, null); + transmitRequest(device, request); return true; } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); @@ -291,7 +297,7 @@ public class SIPCommander implements ISIPCommander { streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); } String streamMode = device.getStreamMode().toUpperCase(); - MediaServerConfig mediaInfo = storager.getMediaInfo(); + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); if (mediaInfo == null) { logger.warn("点播时发现ZLM尚未连接..."); return; @@ -344,6 +350,9 @@ public class SIPCommander implements ISIPCommander { } content.append("y="+ssrc+"\r\n");//ssrc +// String fromTag = UUID.randomUUID().toString(); +// Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, fromTag, null, ssrc); + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); ClientTransaction transaction = transmitRequest(device, request, errorEvent); @@ -372,7 +381,7 @@ public class SIPCommander implements ISIPCommander { public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event , SipSubscribe.Event errorEvent) { try { - MediaServerConfig mediaInfo = storager.getMediaInfo(); + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); String ssrc = streamSession.createPlayBackSsrc(); String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); // 添加订阅 @@ -457,17 +466,28 @@ public class SIPCommander implements ISIPCommander { e.printStackTrace(); } } - + + + /** * 视频流停止 * */ @Override - public void streamByeCmd(String streamId) { + public void streamByeCmd(String ssrc) { + streamByeCmd(ssrc, null); + } + @Override + public void streamByeCmd(String streamId, SipSubscribe.Event okEvent) { try { ClientTransaction transaction = streamSession.get(streamId); + // 服务重启后 if (transaction == null) { + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); + if (streamInfo != null) { + + } return; } @@ -475,6 +495,9 @@ public class SIPCommander implements ISIPCommander { if (dialog == null) { return; } + + + Request byeRequest = dialog.createRequest(Request.BYE); SipURI byeURI = (SipURI) byeRequest.getRequestURI(); String vh = transaction.getRequest().getHeader(ViaHeader.NAME).toString(); @@ -491,7 +514,14 @@ public class SIPCommander implements ISIPCommander { } else if("UDP".equals(protocol)) { clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); } + + CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME); + if (okEvent != null) { + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent); + } + dialog.sendRequest(clientTransaction); + streamSession.remove(streamId); zlmrtpServerFactory.closeRTPServer(streamId); } catch (TransactionDoesNotExistException e) { @@ -612,7 +642,7 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag"); - transmitRequest(device, request, null); + transmitRequest(device, request); } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); @@ -676,7 +706,7 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", null); - transmitRequest(device, request, null); + transmitRequest(device, request); } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); return false; @@ -727,8 +757,16 @@ public class SIPCommander implements ISIPCommander { // TODO Auto-generated method stub return false; } - + + private ClientTransaction transmitRequest(Device device, Request request) throws SipException { + return transmitRequest(device, request, null, null); + } + private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException { + return transmitRequest(device, request, errorEvent, null); + } + + private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException { ClientTransaction clientTransaction = null; if("TCP".equals(device.getTransport())) { clientTransaction = tcpSipProvider.getNewClientTransaction(request); @@ -736,10 +774,14 @@ public class SIPCommander implements ISIPCommander { clientTransaction = udpSipProvider.getNewClientTransaction(request); } - // 添加订阅 + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); + // 添加错误订阅 if (errorEvent != null) { - CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME); - sipSubscribe.addSubscribe(callIdHeader.getCallId(), errorEvent); + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), errorEvent); + } + // 添加订阅 + if (okEvent != null) { + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent); } clientTransaction.sendRequest(); @@ -747,6 +789,8 @@ public class SIPCommander implements ISIPCommander { } + + @Override public void closeRTPServer(Device device, String channelId) { if (rtpEnable) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java index 7b793c09..cab4a9bb 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java @@ -10,6 +10,7 @@ import javax.sip.SipException; import javax.sip.message.Request; import javax.sip.message.Response; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; @@ -48,6 +49,8 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { private IVideoManagerStorager storager; + private IRedisCatchStorage redisCatchStorage; + private EventPublisher publisher; private RedisUtil redis; @@ -451,9 +454,9 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { String NotifyType =XmlUtil.getText(rootElement, "NotifyType"); if (NotifyType.equals("121")){ logger.info("媒体播放完毕,通知关流"); - StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, "*"); + StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, "*"); if (streamInfo != null) { - storager.stopPlayback(streamInfo); + redisCatchStorage.stopPlayback(streamInfo); cmder.streamByeCmd(streamInfo.getStreamId()); } } @@ -507,4 +510,11 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { this.offLineDetector = offLineDetector; } + public IRedisCatchStorage getRedisCatchStorage() { + return redisCatchStorage; + } + + public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) { + this.redisCatchStorage = redisCatchStorage; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java index be076bd8..bcd44825 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java @@ -141,9 +141,15 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor { // 下发catelog查询目录 if (registerFlag == 1 && device != null) { logger.info("注册成功! deviceId:" + device.getDeviceId()); + boolean exists = storager.exists(device.getDeviceId()); + device.setRegisterTimeMillis(System.currentTimeMillis()); storager.updateDevice(device); publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER); - handler.onRegister(device); + + // 只有第一次注册才更新通道 + if (!exists) { + handler.onRegister(device); + } } else if (registerFlag == 2) { logger.info("注销成功! deviceId:" + device.getDeviceId()); publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java index f76cdd90..9daef230 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.media.zlm; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,6 +30,9 @@ public class ZLMHTTPProxyController { @Autowired private IVideoManagerStorager storager; + @Autowired + private IRedisCatchStorage redisCatchStorage; + @Value("${media.port}") private int mediaHttpPort; @@ -36,10 +40,10 @@ public class ZLMHTTPProxyController { @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8") public Object proxy(HttpServletRequest request, HttpServletResponse response){ - if (storager.getMediaInfo() == null) { + if (redisCatchStorage.getMediaInfo() == null) { return "未接入流媒体"; } - MediaServerConfig mediaInfo = storager.getMediaInfo(); + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); String requestURI = String.format("http://%s:%s%s?%s&%s", mediaInfo.getLocalIP(), mediaHttpPort, 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 1116ae5a..cb8ad055 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -11,6 +11,7 @@ import com.alibaba.fastjson.JSONArray; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaServerConfig; import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.utils.IpUtil; import com.genersoft.iot.vmp.vmanager.service.IPlayService; @@ -52,6 +53,9 @@ public class ZLMHttpHookListener { @Autowired private IVideoManagerStorager storager; + @Autowired + private IRedisCatchStorage redisCatchStorage; + @Autowired private ZLMRESTfulUtils zlmresTfulUtils; @@ -249,13 +253,13 @@ public class ZLMHttpHookListener { String app = json.getString("app"); String streamId = json.getString("stream"); boolean regist = json.getBoolean("regist"); - StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); if ("rtp".equals(app) && !regist ) { if (streamInfo!=null){ - storager.stopPlay(streamInfo); + redisCatchStorage.stopPlay(streamInfo); }else{ - streamInfo = storager.queryPlaybackByStreamId(streamId); - storager.stopPlayback(streamInfo); + streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); + redisCatchStorage.stopPlayback(streamInfo); } } @@ -281,12 +285,12 @@ public class ZLMHttpHookListener { String streamId = json.getString("stream"); cmder.streamByeCmd(streamId); - StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); if (streamInfo!=null){ - storager.stopPlay(streamInfo); + redisCatchStorage.stopPlay(streamInfo); }else{ - streamInfo = storager.queryPlaybackByStreamId(streamId); - storager.stopPlayback(streamInfo); + streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId); + redisCatchStorage.stopPlayback(streamInfo); } JSONObject ret = new JSONObject(); @@ -311,7 +315,7 @@ public class ZLMHttpHookListener { if (autoApplyPlay) { String app = json.getString("app"); String streamId = json.getString("stream"); - StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); if ("rtp".equals(app) && streamId.indexOf("gb_play") > -1 && streamInfo == null) { String[] s = streamId.split("_"); if (s.length == 4) { @@ -355,7 +359,7 @@ public class ZLMHttpHookListener { // MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0); MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class); mediaServerConfig.setLocalIP(mediaIp); - storager.updateMediaInfo(mediaServerConfig); + redisCatchStorage.updateMediaInfo(mediaServerConfig); // TODO Auto-generated method stub JSONObject ret = new JSONObject(); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java index 3f88b2a3..282699f9 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import okhttp3.*; import org.slf4j.Logger; @@ -30,6 +31,9 @@ public class ZLMRunner implements CommandLineRunner { @Autowired private IVideoManagerStorager storager; + @Autowired + private IRedisCatchStorage redisCatchStorage; + @Value("${media.ip}") private String mediaIp; @@ -69,7 +73,7 @@ public class ZLMRunner implements CommandLineRunner { logger.info("zlm接入成功..."); if (autoConfig) saveZLMConfig(); mediaServerConfig = getMediaServerConfig(); - storager.updateMediaInfo(mediaServerConfig); + redisCatchStorage.updateMediaInfo(mediaServerConfig); } } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java new file mode 100644 index 00000000..8bc78b93 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java @@ -0,0 +1,58 @@ +package com.genersoft.iot.vmp.storager; + +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.MediaServerConfig; + +import java.util.Map; + +public interface IRedisCatchStorage { + + /** + * 开始播放时将流存入 + * + * @param stream 流信息 + * @return + */ + boolean startPlay(StreamInfo stream); + + + /** + * 停止播放时删除 + * + * @return + */ + boolean stopPlay(StreamInfo streamInfo); + + /** + * 查询播放列表 + * @return + */ + StreamInfo queryPlay(StreamInfo streamInfo); + + StreamInfo queryPlayByStreamId(String steamId); + + StreamInfo queryPlaybackByStreamId(String steamId); + + StreamInfo queryPlayByDevice(String deviceId, String code); + + /** + * 更新流媒体信息 + * @param mediaServerConfig + * @return + */ + boolean updateMediaInfo(MediaServerConfig mediaServerConfig); + + /** + * 获取流媒体信息 + * @return + */ + MediaServerConfig getMediaInfo(); + + Map queryPlayByDeviceId(String deviceId); + + boolean startPlayback(StreamInfo stream); + + boolean stopPlayback(StreamInfo streamInfo); + + StreamInfo queryPlaybackByDevice(String deviceId, String code); +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java index e85d1ff8..4174507b 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java @@ -17,19 +17,6 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; */ public interface IVideoManagerStorager { - /** - * 更新流媒体信息 - * @param mediaServerConfig - * @return - */ - public boolean updateMediaInfo(MediaServerConfig mediaServerConfig); - - /** - * 获取流媒体信息 - * @return - */ - public MediaServerConfig getMediaInfo(); - /** * 根据设备ID判断设备是否存在 * @@ -106,10 +93,9 @@ public interface IVideoManagerStorager { /** * 获取多个设备 * - * @param deviceIds 设备ID数组 * @return List 设备对象数组 */ - public List queryVideoDeviceList(String[] deviceIds); + public List queryVideoDeviceList(); /** * 删除设备 @@ -135,27 +121,6 @@ public interface IVideoManagerStorager { */ public boolean outline(String deviceId); - /** - * 开始播放时将流存入 - * - * @param stream 流信息 - * @return - */ - public boolean startPlay(StreamInfo stream); - - /** - * 停止播放时删除 - * - * @return - */ - public boolean stopPlay(StreamInfo streamInfo); - - /** - * 查找视频流 - * - * @return - */ - public StreamInfo queryPlay(StreamInfo streamInfo); /** * 查询子设备 @@ -168,10 +133,6 @@ public interface IVideoManagerStorager { */ PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count); - /** - * 更新缓存 - */ - public void updateCatch(); /** * 清空通道 @@ -179,17 +140,4 @@ public interface IVideoManagerStorager { */ void cleanChannelsForDevice(String deviceId); - StreamInfo queryPlayByStreamId(String streamId); - - StreamInfo queryPlayByDevice(String deviceId, String code); - - Map queryPlayByDeviceId(String deviceId); - - boolean startPlayback(StreamInfo streamInfo); - - boolean stopPlayback(StreamInfo streamInfo); - - StreamInfo queryPlaybackByDevice(String deviceId, String channelId); - - StreamInfo queryPlaybackByStreamId(String streamId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java b/src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java deleted file mode 100644 index 70bdad76..00000000 --- a/src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.genersoft.iot.vmp.storager; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.conf.VManagerConfig; - -/** - * @Description:视频设备数据存储工厂,根据存储策略,返回对应的存储器 - * @author: swwheihei - * @date: 2020年5月6日 下午2:15:16 - */ -@Component -public class VideoManagerStoragerFactory { - - @Autowired - private VManagerConfig vmConfig; - - @Autowired - private IVideoManagerStorager jdbcStorager; - - @Autowired - private IVideoManagerStorager redisStorager; - - @Bean("storager") - public IVideoManagerStorager getStorager() { - if ("redis".equals(vmConfig.getDatabase().toLowerCase())) { - return redisStorager; - } else if ("jdbc".equals(vmConfig.getDatabase().toLowerCase())) { - return jdbcStorager; - } - return redisStorager; - } - -} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java b/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java index c96e4bb0..c2074843 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java @@ -8,10 +8,10 @@ import org.springframework.stereotype.Component; public class VodeoMannagerTask implements CommandLineRunner { @Autowired - private IVideoManagerStorager storager; + private IVideoManagerStorager redisStorager; @Override public void run(String... strings) throws Exception { - storager.updateCatch(); + redisStorager.updateCatch(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java new file mode 100644 index 00000000..bf67095f --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java @@ -0,0 +1,20 @@ +package com.genersoft.iot.vmp.storager.dao; + +import com.genersoft.iot.vmp.common.PageResult; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface DeviceChannelMapper { + int update(DeviceChannel channel); + + List queryChannelsByDeviceId(String deviceId); + + List queryChannelsByDeviceId(String deviceId, String parentChannelId); + + DeviceChannel queryChannel(String deviceId, String channelId); + + int cleanChannelsByDeviceId(String deviceId); +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java new file mode 100644 index 00000000..da455fbe --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java @@ -0,0 +1,24 @@ +package com.genersoft.iot.vmp.storager.dao; + +import com.genersoft.iot.vmp.gb28181.bean.Device; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +@Mapper +public interface DeviceMapper { + + @Select("SELECT * FROM device WHERE deviceId = #{deviceId}") + Device getDeviceByDeviceId(String deviceId); + + @Insert("SELECT * FROM device WHERE deviceId = #{deviceId}") + int add(Device device); + + int update(Device device); + + List getDevices(); + + int del(String deviceId); +} 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 new file mode 100644 index 00000000..8eaaf68a --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java @@ -0,0 +1,172 @@ +package com.genersoft.iot.vmp.storager.impl; + +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; +import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; +import com.genersoft.iot.vmp.storager.dao.DeviceMapper; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +@Component +public class RedisCatchStorageImpl implements IRedisCatchStorage { + + @Autowired + private RedisUtil redis; + + @Autowired + private DeviceMapper deviceMapper; + + @Autowired + private DeviceChannelMapper deviceChannelMapper; + + + /** + * 开始播放时将流存入redis + * + * @return + */ + @Override + public boolean startPlay(StreamInfo stream) { + return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()), + stream); + } + + /** + * 停止播放时从redis删除 + * + * @return + */ + @Override + public boolean stopPlay(StreamInfo streamInfo) { + if (streamInfo == null) return false; + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); + if (deviceChannel != null) { + deviceChannel.setStreamId(null); + deviceChannel.setPlay(false); + deviceChannel.setDeviceId(streamInfo.getDeviceID()); + deviceChannelMapper.update(deviceChannel); + } + return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, + streamInfo.getStreamId(), + streamInfo.getDeviceID(), + streamInfo.getCahnnelId())); + } + + /** + * 查询播放列表 + * @return + */ + @Override + public StreamInfo queryPlay(StreamInfo streamInfo) { + return (StreamInfo)redis.get(String.format("%S_%s_%s_%s", + VideoManagerConstants.PLAYER_PREFIX, + streamInfo.getStreamId(), + streamInfo.getDeviceID(), + streamInfo.getCahnnelId())); + } + @Override + public StreamInfo queryPlayByStreamId(String steamId) { + List playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, steamId)); + if (playLeys == null || playLeys.size() == 0) return null; + return (StreamInfo)redis.get(playLeys.get(0).toString()); + } + + @Override + public StreamInfo queryPlaybackByStreamId(String steamId) { + List playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, steamId)); + if (playLeys == null || playLeys.size() == 0) return null; + return (StreamInfo)redis.get(playLeys.get(0).toString()); + } + + @Override + public StreamInfo queryPlayByDevice(String deviceId, String code) { +// List playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX, + List playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX, + deviceId, + code)); + if (playLeys == null || playLeys.size() == 0) return null; + return (StreamInfo)redis.get(playLeys.get(0).toString()); + } + + /** + * 更新流媒体信息 + * @param mediaServerConfig + * @return + */ + @Override + public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) { + return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig); + } + + /** + * 获取流媒体信息 + * @return + */ + @Override + public MediaServerConfig getMediaInfo() { + return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX); + } + + @Override + public Map queryPlayByDeviceId(String deviceId) { + Map streamInfos = new HashMap<>(); +// List playLeys = redis.keys(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId)); + List players = redis.scan(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId)); + if (players.size() == 0) return streamInfos; + for (int i = 0; i < players.size(); i++) { + String key = (String) players.get(i); + StreamInfo streamInfo = (StreamInfo)redis.get(key); + streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getCahnnelId(), streamInfo); + } + return streamInfos; + } + + + @Override + public boolean startPlayback(StreamInfo stream) { + return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()), + stream); + } + + + @Override + public boolean stopPlayback(StreamInfo streamInfo) { + if (streamInfo == null) return false; + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); + if (deviceChannel != null) { + deviceChannel.setStreamId(null); + deviceChannel.setPlay(false); + deviceChannel.setDeviceId(streamInfo.getDeviceID()); + deviceChannelMapper.update(deviceChannel); + } + return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, + streamInfo.getStreamId(), + streamInfo.getDeviceID(), + streamInfo.getCahnnelId())); + } + + @Override + public StreamInfo queryPlaybackByDevice(String deviceId, String code) { + String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, + deviceId, + code); + List playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, + deviceId, + code)); + if (playLeys == null || playLeys.size() == 0) { + playLeys = redis.scan(String.format("%S_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, + deviceId)); + } + if (playLeys == null || playLeys.size() == 0) return null; + return (StreamInfo)redis.get(playLeys.get(0).toString()); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java new file mode 100644 index 00000000..1288efc1 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java @@ -0,0 +1,401 @@ +package com.genersoft.iot.vmp.storager.impl; + +import java.util.*; + +import com.genersoft.iot.vmp.common.PageResult; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; +import com.genersoft.iot.vmp.storager.dao.DeviceMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.utils.redis.RedisUtil; +import org.springframework.util.StringUtils; + +/** + * @Description:视频设备数据存储-jdbc实现 + * @author: swwheihei + * @date: 2020年5月6日 下午2:31:42 + */ +@Component +public class VideoManagerStoragerImpl implements IVideoManagerStorager { + + @Autowired + private DeviceMapper deviceMapper; + + @Autowired + private DeviceChannelMapper deviceChannelMapper; + + + /** + * 根据设备ID判断设备是否存在 + * + * @param deviceId 设备ID + * @return true:存在 false:不存在 + */ + @Override + public boolean exists(String deviceId) { + return deviceMapper.getDeviceByDeviceId(deviceId) != null; + } + + /** + * 视频设备创建 + * + * @param device 设备对象 + * @return true:创建成功 false:创建失败 + */ + @Override + public boolean create(Device device) { + return deviceMapper.add(device) > 0; + } + + + + /** + * 视频设备更新 + * + * @param device 设备对象 + * @return true:更新成功 false:更新失败 + */ + @Override + public boolean updateDevice(Device device) { +// if (deviceMap.get(device.getDeviceId()) == null) { +// deviceMap.put(device.getDeviceId(), new HashMap>()); +// } + // 更新device中的通道数量 +// device.setChannelCount(deviceMap.get(device.getDeviceId()).size()); + int result = deviceMapper.update(device); + // 存储device + return result > 0; + + + } + + @Override + public void updateChannel(String deviceId, DeviceChannel channel) { + String channelId = channel.getChannelId(); + channel.setDeviceId(deviceId); + deviceChannelMapper.update(channel); + +// HashMap> channelMap = deviceMap.get(deviceId); +// if (channelMap == null) return; +// // 作为父设备, 确定自己的子节点数 +// if (channelMap.get(channelId) == null) { +// channelMap.put(channelId, new HashSet()); +// }else if (channelMap.get(channelId).size() > 0) { +// channel.setSubCount(channelMap.get(channelId).size()); +// } +// +// // 存储通道 +// redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + +// "_" + channel.getChannelId() + +// "_" + (channel.getStatus() == 1 ? "on":"off") + +// "_" + (channelMap.get(channelId).size() > 0)+ +// "_" + (StringUtils.isEmpty(channel.getParentId())?null:channel.getParentId()), +// channel); +// // 更新device中的通道数量 +// Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); +// device.setChannelCount(deviceMap.get(deviceId).size()); +// redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); +// +// +// // 如果有父设备,更新父设备内子节点数 +// String parentId = channel.getParentId(); +// if (!StringUtils.isEmpty(parentId) && !parentId.equals(deviceId)) { +// +// if (channelMap.get(parentId) == null) { +// channelMap.put(parentId, new HashSet()); +// } +// channelMap.get(parentId).add(channelId); +// +// DeviceChannel deviceChannel = queryChannel(deviceId, parentId); +// if (deviceChannel != null) { +// deviceChannel.setSubCount(channelMap.get(parentId).size()); +// redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + +// "_" + deviceChannel.getChannelId() + +// "_" + (deviceChannel.getStatus() == 1 ? "on":"off") + +// "_" + (channelMap.get(deviceChannel.getChannelId()).size() > 0)+ +// "_" + (StringUtils.isEmpty(deviceChannel.getParentId())?null:deviceChannel.getParentId()), +// deviceChannel); +// +// } +// } + + } + + /** + * 获取设备 + * + * @param deviceId 设备ID + * @return Device 设备对象 + */ + @Override + public Device queryVideoDevice(String deviceId) { + return deviceMapper.getDeviceByDeviceId(deviceId); + } + + @Override + public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) { + // 获取到所有正在播放的流 + List result = new ArrayList<>(); + PageResult pageResult = new PageResult(); + + deviceChannelMapper.queryChannelsByDeviceId(deviceId); +// String queryContent = "*"; +// if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query); +// String queryHasSubChannel = "*"; +// if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false"; +// String queryOnline = "*"; +// if (!StringUtils.isEmpty(online)) queryOnline = online; +// String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId + +// "_" + queryContent + // 搜索编号和名称 +// "_" + queryOnline + // 搜索是否在线 +// "_" + queryHasSubChannel + // 搜索是否含有子节点 +// "_" + "*"; +// List deviceChannelList = redis.scan(queryStr); +// //对查询结果排序,避免出现通道排列顺序乱序的情况 +// Collections.sort(deviceChannelList,new Comparator(){ +// @Override +// public int compare(Object o1, Object o2) { +// return o1.toString().compareToIgnoreCase(o2.toString()); +// } +// }); +// pageResult.setPage(page); +// pageResult.setCount(count); +// pageResult.setTotal(deviceChannelList.size()); +// int maxCount = (page + 1 ) * count; +// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { +// for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { +// DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); +// StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId()); +// deviceChannel.setPlay(streamInfo != null); +// if (streamInfo != null) deviceChannel.setStreamId(streamInfo.getStreamId()); +// result.add(deviceChannel); +// } +// pageResult.setData(result); +// } + + return pageResult; + } + + + + @Override + public List queryChannelsByDeviceId(String deviceId) { +// List result = new ArrayList<>(); +//// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); +// List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); +// +// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { +// for (int i = 0; i < deviceChannelList.size(); i++) { +// result.add((DeviceChannel)redis.get((String) deviceChannelList.get(i))); +// } +// } + return deviceChannelMapper.queryChannelsByDeviceId(deviceId); + } + + @Override + public PageResult querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) { + + deviceChannelMapper.queryChannelsByDeviceId(deviceId, parentChannelId); + +// List allDeviceChannels = new ArrayList<>(); +// String queryContent = "*"; +// if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query); +// String queryHasSubChannel = "*"; +// if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false"; +// String queryOnline = "*"; +// if (!StringUtils.isEmpty(online)) queryOnline = online; +// String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId + +// "_" + queryContent + // 搜索编号和名称 +// "_" + queryOnline + // 搜索是否在线 +// "_" + queryHasSubChannel + // 搜索是否含有子节点 +// "_" + parentChannelId; +// +//// List deviceChannelList = redis.keys(queryStr); +// List deviceChannelList = redis.scan(queryStr); +// +// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { +// for (int i = 0; i < deviceChannelList.size(); i++) { +// DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); +// if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) { +// allDeviceChannels.add(deviceChannel); +// } +// } +// } +// int maxCount = (page + 1 ) * count; + PageResult pageResult = new PageResult(); +// pageResult.setPage(page); +// pageResult.setCount(count); +// pageResult.setTotal(allDeviceChannels.size()); +// +// if (allDeviceChannels.size() > 0) { +// pageResult.setData(allDeviceChannels.subList( +// page * count, pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() +// )); +// } + return pageResult; + } + + public List querySubChannels(String deviceId, String parentChannelId) { + List allDeviceChannels = new ArrayList<>(); +// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); +// List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); +// +// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { +// for (int i = 0; i < deviceChannelList.size(); i++) { +// DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); +// if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) { +// allDeviceChannels.add(deviceChannel); +// } +// } +// } + + return allDeviceChannels; + } + + @Override + public DeviceChannel queryChannel(String deviceId, String channelId) { + DeviceChannel deviceChannel = null; + return deviceChannelMapper.queryChannel(deviceId, channelId); +//// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + +// List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + +// "_" + channelId + "*"); +// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { +// deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(0)); +// } +// return deviceChannel; + } + + + /** + * 获取多个设备 + * + * @param deviceIds 设备ID数组 + * @return List 设备对象数组 + */ + @Override + public PageResult queryVideoDeviceList(String[] deviceIds, int page, int count) { + List devices = new ArrayList<>(); + PageResult pageResult = new PageResult(); +// pageResult.setPage(page); +// pageResult.setCount(count); +// Device device = null; +// +// if (deviceIds == null || deviceIds.length == 0) { +// +//// List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); +// List deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*"); +// pageResult.setTotal(deviceIdList.size()); +// int maxCount = (page + 1)* count; +// for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { +// // devices.add((Device)redis.get((String)deviceIdList.get(i))); +// device =(Device)redis.get((String)deviceIdList.get(i)); +// if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ +// // outline(device.getDeviceId()); +// } +// devices.add(device); +// } +// } else { +// for (int i = 0; i < deviceIds.length; i++) { +// // devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i])); +// device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]); +// if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ +// // outline(device.getDeviceId()); +// } +// devices.add(device); +// } +// } +// pageResult.setData(devices); + return pageResult; + } + + /** + * 获取多个设备 + * + * @return List 设备对象数组 + */ + @Override + public List queryVideoDeviceList() { + +// if (deviceIds == null || deviceIds.length == 0) { +//// List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); +// List deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*"); +// for (int i = 0; i < deviceIdList.size(); i++) { +// device =(Device)redis.get((String)deviceIdList.get(i)); +// if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ +// outline(device.getDeviceId()); +// } +// devices.add(device); +// } +// } else { +// for (int i = 0; i < deviceIds.length; i++) { +// device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]); +// if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ +// outline(device.getDeviceId()); +// } +// devices.add(device); +// } +// } + + List deviceList = deviceMapper.getDevices(); + return deviceList; + } + + /** + * 删除设备 + * + * @param deviceId 设备ID + * @return true:删除成功 false:删除失败 + */ + @Override + public boolean delete(String deviceId) { + int result = deviceMapper.del(deviceId); + + return result > 0; + } + + /** + * 更新设备在线 + * + * @param deviceId 设备ID + * @return true:更新成功 false:更新失败 + */ + @Override + public boolean online(String deviceId) { + Device device = deviceMapper.getDeviceByDeviceId(deviceId); + device.setOnline(1); + return deviceMapper.update(device) > 0; + } + + /** + * 更新设备离线 + * + * @param deviceId 设备ID + * @return true:更新成功 false:更新失败 + */ + @Override + public boolean outline(String deviceId) { +// Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); +// if (device == null) return false; +// device.setOnline(0); +// return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); + + Device device = deviceMapper.getDeviceByDeviceId(deviceId); + device.setOnline(0); + return deviceMapper.update(device) > 0; + } + + + @Override + public void cleanChannelsForDevice(String deviceId) { + int result = deviceChannelMapper.cleanChannelsByDeviceId(deviceId); + } + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java deleted file mode 100644 index 3302aa35..00000000 --- a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java +++ /dev/null @@ -1,217 +0,0 @@ -package com.genersoft.iot.vmp.storager.jdbc; - -import java.util.List; -import java.util.Map; - -import com.genersoft.iot.vmp.common.PageResult; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.conf.MediaServerConfig; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; - -import com.genersoft.iot.vmp.common.VideoManagerConstants; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; - -/** - * @Description:视频设备数据存储-jdbc实现 - * @author: swwheihei - * @date: 2020年5月6日 下午2:28:12 - */ -@Component("jdbcStorager") -public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager { - - @Override - public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) { - return false; - } - - @Override - public MediaServerConfig getMediaInfo() { - return null; - } - - /** - * 根据设备ID判断设备是否存在 - * - * @param deviceId 设备ID - * @return true:存在 false:不存在 - */ - @Override - public boolean exists(String deviceId) { - // TODO Auto-generated method stub - return false; - } - - /** - * 视频设备创建 - * - * @param device 设备对象 - * @return true:创建成功 false:创建失败 - */ - @Override - public boolean create(Device device) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean updateDevice(Device device) { - return false; - } - - @Override - public void updateChannel(String deviceId, DeviceChannel channel) { - - } - - - /** - * 获取设备 - * - * @param deviceId 设备ID - * @return Device 设备对象 - */ - @Override - public Device queryVideoDevice(String deviceId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) { - return null; - } - - - @Override - public List queryChannelsByDeviceId(String deviceId) { - return null; - } - - @Override - public DeviceChannel queryChannel(String deviceId, String channelId) { - return null; - } - - @Override - public PageResult queryVideoDeviceList(String[] deviceIds, int page, int count) { - return null; - } - - /** - * 获取多个设备 - * - * @param deviceIds 设备ID数组 - * @return List 设备对象数组 - */ - @Override - public List queryVideoDeviceList(String[] deviceIds) { - // TODO Auto-generated method stub - return null; - } - - /** - * 删除设备 - * - * @param deviceId 设备ID - * @return true:删除成功 false:删除失败 - */ - @Override - public boolean delete(String deviceId) { - // TODO Auto-generated method stub - return false; - } - - /** - * 更新设备在线 - * - * @param deviceId 设备ID - * @return true:更新成功 false:更新失败 - */ - @Override - public boolean online(String deviceId) { - // TODO Auto-generated method stub - return false; - } - - /** - * 更新设备离线 - * - * @param deviceId 设备ID - * @return true:更新成功 false:更新失败 - */ - @Override - public boolean outline(String deviceId) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean stopPlay(StreamInfo streamInfo) { - return false; - } - - @Override - public StreamInfo queryPlay(StreamInfo streamInfo) { - return null; - } - - @Override - public PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count) { - return null; - } - - @Override - public void updateCatch() { - System.out.println("##################"); - } - - @Override - public void cleanChannelsForDevice(String deviceId) { - - } - - @Override - public boolean startPlay(StreamInfo stream) { - return false; - } - - - @Override - public StreamInfo queryPlayByDevice(String deviceId, String code) { - return null; - } - - @Override - public Map queryPlayByDeviceId(String deviceId) { - - return null; - } - - @Override - public boolean startPlayback(StreamInfo streamInfo) { - return false; - } - - @Override - public boolean stopPlayback(StreamInfo streamInfo) { - return false; - } - - @Override - public StreamInfo queryPlaybackByDevice(String deviceId, String channelId) { - return null; - } - - @Override - public StreamInfo queryPlayByStreamId(String streamId) { - return null; - } - - @Override - public StreamInfo queryPlaybackByStreamId(String streamId) { - return null; - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java deleted file mode 100644 index 00d41fc4..00000000 --- a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java +++ /dev/null @@ -1,561 +0,0 @@ -package com.genersoft.iot.vmp.storager.redis; - -import java.util.*; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.genersoft.iot.vmp.common.PageResult; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.conf.MediaServerConfig; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import com.genersoft.iot.vmp.common.VideoManagerConstants; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import com.genersoft.iot.vmp.utils.redis.RedisUtil; -import org.springframework.util.StringUtils; - -/** - * @Description:视频设备数据存储-redis实现 - * @author: swwheihei - * @date: 2020年5月6日 下午2:31:42 - */ -@Component("redisStorager") -public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager { - - @Autowired - private RedisUtil redis; - - private HashMap>> deviceMap = new HashMap<>(); - - - /** - * 根据设备ID判断设备是否存在 - * - * @param deviceId 设备ID - * @return true:存在 false:不存在 - */ - @Override - public boolean exists(String deviceId) { - return redis.hasKey(VideoManagerConstants.DEVICE_PREFIX+deviceId); - } - - /** - * 视频设备创建 - * - * @param device 设备对象 - * @return true:创建成功 false:创建失败 - */ - @Override - public boolean create(Device device) { - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - } - - - - /** - * 视频设备更新 - * - * @param device 设备对象 - * @return true:更新成功 false:更新失败 - */ - @Override - public boolean updateDevice(Device device) { - if (deviceMap.get(device.getDeviceId()) == null) { - deviceMap.put(device.getDeviceId(), new HashMap>()); - } - // 更新device中的通道数量 - device.setChannelCount(deviceMap.get(device.getDeviceId()).size()); - // 存储device - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - - - } - - @Override - public void updateChannel(String deviceId, DeviceChannel channel) { - String channelId = channel.getChannelId(); - HashMap> channelMap = deviceMap.get(deviceId); - if (channelMap == null) return; - // 作为父设备, 确定自己的子节点数 - if (channelMap.get(channelId) == null) { - channelMap.put(channelId, new HashSet()); - }else if (channelMap.get(channelId).size() > 0) { - channel.setSubCount(channelMap.get(channelId).size()); - } - - // 存储通道 - redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + - "_" + channel.getChannelId() + - "_" + (channel.getStatus() == 1 ? "on":"off") + - "_" + (channelMap.get(channelId).size() > 0)+ - "_" + (StringUtils.isEmpty(channel.getParentId())?null:channel.getParentId()), - channel); - // 更新device中的通道数量 - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); - device.setChannelCount(deviceMap.get(deviceId).size()); - redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - - - // 如果有父设备,更新父设备内子节点数 - String parentId = channel.getParentId(); - if (!StringUtils.isEmpty(parentId) && !parentId.equals(deviceId)) { - - if (channelMap.get(parentId) == null) { - channelMap.put(parentId, new HashSet()); - } - channelMap.get(parentId).add(channelId); - - DeviceChannel deviceChannel = queryChannel(deviceId, parentId); - if (deviceChannel != null) { - deviceChannel.setSubCount(channelMap.get(parentId).size()); - redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + - "_" + deviceChannel.getChannelId() + - "_" + (deviceChannel.getStatus() == 1 ? "on":"off") + - "_" + (channelMap.get(deviceChannel.getChannelId()).size() > 0)+ - "_" + (StringUtils.isEmpty(deviceChannel.getParentId())?null:deviceChannel.getParentId()), - deviceChannel); - - } - } - - } - - /** - * 获取设备 - * - * @param deviceId 设备ID - * @return Device 设备对象 - */ - @Override - public Device queryVideoDevice(String deviceId) { - return (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); - } - - @Override - public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) { - // 获取到所有正在播放的流 - Map stringStreamInfoMap = queryPlayByDeviceId(deviceId); - List result = new ArrayList<>(); - PageResult pageResult = new PageResult(); - String queryContent = "*"; - if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query); - String queryHasSubChannel = "*"; - if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false"; - String queryOnline = "*"; - if (!StringUtils.isEmpty(online)) queryOnline = online; - String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId + - "_" + queryContent + // 搜索编号和名称 - "_" + queryOnline + // 搜索是否在线 - "_" + queryHasSubChannel + // 搜索是否含有子节点 - "_" + "*"; - List deviceChannelList = redis.scan(queryStr); - //对查询结果排序,避免出现通道排列顺序乱序的情况 - Collections.sort(deviceChannelList,new Comparator(){ - @Override - public int compare(Object o1, Object o2) { - return o1.toString().compareToIgnoreCase(o2.toString()); - } - }); - pageResult.setPage(page); - pageResult.setCount(count); - pageResult.setTotal(deviceChannelList.size()); - int maxCount = (page + 1 ) * count; - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { - DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); - StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId()); - deviceChannel.setPlay(streamInfo != null); - if (streamInfo != null) deviceChannel.setStreamId(streamInfo.getStreamId()); - result.add(deviceChannel); - } - pageResult.setData(result); - } - - return pageResult; - } - - - - @Override - public List queryChannelsByDeviceId(String deviceId) { - List result = new ArrayList<>(); -// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - for (int i = 0; i < deviceChannelList.size(); i++) { - result.add((DeviceChannel)redis.get((String) deviceChannelList.get(i))); - } - } - return result; - } - - @Override - public PageResult querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) { - List allDeviceChannels = new ArrayList<>(); - String queryContent = "*"; - if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query); - String queryHasSubChannel = "*"; - if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false"; - String queryOnline = "*"; - if (!StringUtils.isEmpty(online)) queryOnline = online; - String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId + - "_" + queryContent + // 搜索编号和名称 - "_" + queryOnline + // 搜索是否在线 - "_" + queryHasSubChannel + // 搜索是否含有子节点 - "_" + parentChannelId; - -// List deviceChannelList = redis.keys(queryStr); - List deviceChannelList = redis.scan(queryStr); - - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - for (int i = 0; i < deviceChannelList.size(); i++) { - DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); - if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) { - allDeviceChannels.add(deviceChannel); - } - } - } - int maxCount = (page + 1 ) * count; - PageResult pageResult = new PageResult(); - pageResult.setPage(page); - pageResult.setCount(count); - pageResult.setTotal(allDeviceChannels.size()); - - if (allDeviceChannels.size() > 0) { - pageResult.setData(allDeviceChannels.subList( - page * count, pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() - )); - } - return pageResult; - } - - public List querySubChannels(String deviceId, String parentChannelId) { - List allDeviceChannels = new ArrayList<>(); -// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - for (int i = 0; i < deviceChannelList.size(); i++) { - DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); - if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) { - allDeviceChannels.add(deviceChannel); - } - } - } - - return allDeviceChannels; - } - - @Override - public DeviceChannel queryChannel(String deviceId, String channelId) { - DeviceChannel deviceChannel = null; -// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + - List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + - "_" + channelId + "*"); - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(0)); - } - return deviceChannel; - } - - - /** - * 获取多个设备 - * - * @param deviceIds 设备ID数组 - * @return List 设备对象数组 - */ - @Override - public PageResult queryVideoDeviceList(String[] deviceIds, int page, int count) { - List devices = new ArrayList<>(); - PageResult pageResult = new PageResult(); - pageResult.setPage(page); - pageResult.setCount(count); - Device device = null; - - if (deviceIds == null || deviceIds.length == 0) { - -// List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); - List deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*"); - pageResult.setTotal(deviceIdList.size()); - int maxCount = (page + 1)* count; - for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { - // devices.add((Device)redis.get((String)deviceIdList.get(i))); - device =(Device)redis.get((String)deviceIdList.get(i)); - if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ - // outline(device.getDeviceId()); - } - devices.add(device); - } - } else { - for (int i = 0; i < deviceIds.length; i++) { - // devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i])); - device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]); - if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ - // outline(device.getDeviceId()); - } - devices.add(device); - } - } - pageResult.setData(devices); - return pageResult; - } - - /** - * 获取多个设备 - * - * @param deviceIds 设备ID数组 - * @return List 设备对象数组 - */ - @Override - public List queryVideoDeviceList(String[] deviceIds) { - List devices = new ArrayList<>(); - Device device = null; - - if (deviceIds == null || deviceIds.length == 0) { -// List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); - List deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*"); - for (int i = 0; i < deviceIdList.size(); i++) { - device =(Device)redis.get((String)deviceIdList.get(i)); - if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ - outline(device.getDeviceId()); - } - devices.add(device); - } - } else { - for (int i = 0; i < deviceIds.length; i++) { - device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]); - if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ - outline(device.getDeviceId()); - } - devices.add(device); - } - } - return devices; - } - - /** - * 删除设备 - * - * @param deviceId 设备ID - * @return true:删除成功 false:删除失败 - */ - @Override - public boolean delete(String deviceId) { - return redis.del(VideoManagerConstants.DEVICE_PREFIX+deviceId); - } - - /** - * 更新设备在线 - * - * @param deviceId 设备ID - * @return true:更新成功 false:更新失败 - */ - @Override - public boolean online(String deviceId) { - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); - device.setOnline(1); - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - } - - /** - * 更新设备离线 - * - * @param deviceId 设备ID - * @return true:更新成功 false:更新失败 - */ - @Override - public boolean outline(String deviceId) { - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); - if (device == null) return false; - device.setOnline(0); - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - } - - /** - * 开始播放时将流存入redis - * - * @return - */ - @Override - public boolean startPlay(StreamInfo stream) { - return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()), - stream); - } - - /** - * 停止播放时从redis删除 - * - * @return - */ - @Override - public boolean stopPlay(StreamInfo streamInfo) { - if (streamInfo == null) return false; - DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); - if (deviceChannel != null) { - deviceChannel.setStreamId(null); - deviceChannel.setPlay(false); - updateChannel(streamInfo.getDeviceID(), deviceChannel); - } - return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, - streamInfo.getStreamId(), - streamInfo.getDeviceID(), - streamInfo.getCahnnelId())); - } - - /** - * 查询播放列表 - * @return - */ - @Override - public StreamInfo queryPlay(StreamInfo streamInfo) { - return (StreamInfo)redis.get(String.format("%S_%s_%s_%s", - VideoManagerConstants.PLAYER_PREFIX, - streamInfo.getStreamId(), - streamInfo.getDeviceID(), - streamInfo.getCahnnelId())); - } - @Override - public StreamInfo queryPlayByStreamId(String steamId) { - List playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, steamId)); - if (playLeys == null || playLeys.size() == 0) return null; - return (StreamInfo)redis.get(playLeys.get(0).toString()); - } - - @Override - public StreamInfo queryPlaybackByStreamId(String steamId) { - List playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, steamId)); - if (playLeys == null || playLeys.size() == 0) return null; - return (StreamInfo)redis.get(playLeys.get(0).toString()); - } - - @Override - public StreamInfo queryPlayByDevice(String deviceId, String code) { -// List playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX, - List playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX, - deviceId, - code)); - if (playLeys == null || playLeys.size() == 0) return null; - return (StreamInfo)redis.get(playLeys.get(0).toString()); - } - - /** - * 更新流媒体信息 - * @param mediaServerConfig - * @return - */ - @Override - public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) { - return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig); - } - - /** - * 获取流媒体信息 - * @return - */ - @Override - public MediaServerConfig getMediaInfo() { - return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX); - } - - @Override - public void updateCatch() { - deviceMap = new HashMap<>(); - // 更新设备 - List devices = queryVideoDeviceList(null); - if (devices == null && devices.size() == 0) return; - for (Device device : devices) { - // 更新设备下的通道 - HashMap> channelMap = new HashMap>(); - List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + - device.getDeviceId() + "_" + "*"); - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - for (int i = 0; i < deviceChannelList.size(); i++) { - String key = (String)deviceChannelList.get(i); - String[] s = key.split("_"); - String channelId = s[3]; - HashSet subChannel = channelMap.get(channelId); - if (subChannel == null) { - subChannel = new HashSet<>(); - } - System.out.println(key); - if (s.length == 6 && !"null".equals(s[5])) { - subChannel.add(s[5]); - } - channelMap.put(channelId, subChannel); - } - } - deviceMap.put(device.getDeviceId(),channelMap); - } - System.out.println(); - } - - @Override - public void cleanChannelsForDevice(String deviceId) { - List result = new ArrayList<>(); -// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); - if (deviceChannelList != null && deviceChannelList.size() > 0 ) { - for (int i = 0; i < deviceChannelList.size(); i++) { - redis.del((String)deviceChannelList.get(i)); - } - } - } - - @Override - public Map queryPlayByDeviceId(String deviceId) { - Map streamInfos = new HashMap<>(); -// List playLeys = redis.keys(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId)); - List playLeys = redis.scan(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId)); - if (playLeys.size() == 0) return streamInfos; - for (int i = 0; i < playLeys.size(); i++) { - String key = (String) playLeys.get(i); - StreamInfo streamInfo = (StreamInfo)redis.get(key); - streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getCahnnelId(), streamInfo); - } - return streamInfos; - } - - - @Override - public boolean startPlayback(StreamInfo stream) { - return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()), - stream); - } - - - @Override - public boolean stopPlayback(StreamInfo streamInfo) { - if (streamInfo == null) return false; - DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); - if (deviceChannel != null) { - deviceChannel.setStreamId(null); - deviceChannel.setPlay(false); - updateChannel(streamInfo.getDeviceID(), deviceChannel); - } - return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, - streamInfo.getStreamId(), - streamInfo.getDeviceID(), - streamInfo.getCahnnelId())); - } - - @Override - public StreamInfo queryPlaybackByDevice(String deviceId, String code) { - String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, - deviceId, - code); - List playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, - deviceId, - code)); - if (playLeys == null || playLeys.size() == 0) { - playLeys = redis.scan(String.format("%S_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, - deviceId)); - } - if (playLeys == null || playLeys.size() == 0) return null; - return (StreamInfo)redis.get(playLeys.get(0).toString()); - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java index eba40bb9..59667d09 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.vmanager.service.IPlayService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,6 +46,9 @@ public class PlayController { @Autowired private IVideoManagerStorager storager; + @Autowired + private IRedisCatchStorage redisCatchStorage; + @Autowired private ZLMRESTfulUtils zlmresTfulUtils; @@ -60,7 +64,7 @@ public class PlayController { Device device = storager.queryVideoDevice(deviceId); - StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId); + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); UUID uuid = UUID.randomUUID(); DeferredResult> result = new DeferredResult>(); @@ -89,7 +93,7 @@ public class PlayController { msg.setData(JSON.toJSONString(streamInfo)); resultHolder.invokeResult(msg); } else { - storager.stopPlay(streamInfo); + redisCatchStorage.stopPlay(streamInfo); cmder.playStreamCmd(device, channelId, (JSONObject response) -> { logger.info("收到订阅消息: " + response.toJSONString()); playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); @@ -117,25 +121,59 @@ public class PlayController { } @PostMapping("/play/{streamId}/stop") - public ResponseEntity playStop(@PathVariable String streamId) { + public DeferredResult> playStop(@PathVariable String streamId) { + + logger.debug(String.format("设备预览/回放停止API调用,streamId:%s", streamId)); + + UUID uuid = UUID.randomUUID(); + DeferredResult> result = new DeferredResult>(); + + // 录像查询以channelId作为deviceId查询 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_STOP + uuid, result); + + cmder.streamByeCmd(streamId, event -> { + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); + if (streamInfo == null) { + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + msg.setData("streamId not found"); + resultHolder.invokeResult(msg); + redisCatchStorage.stopPlay(streamInfo); + } + + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid); + Response response = event.getResponse(); + msg.setData(String.format("success")); + resultHolder.invokeResult(msg); + }); + - cmder.streamByeCmd(streamId); - StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); - if (streamInfo == null) - return new ResponseEntity("streamId not found", HttpStatus.OK); - storager.stopPlay(streamInfo); - if (logger.isDebugEnabled()) { - logger.debug(String.format("设备预览停止API调用,streamId:%s", streamId)); - } if (streamId != null) { JSONObject json = new JSONObject(); json.put("streamId", streamId); - return new ResponseEntity(json.toString(), HttpStatus.OK); + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + msg.setData(json.toString()); + resultHolder.invokeResult(msg); } else { - logger.warn("设备预览停止API调用失败!"); - return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + logger.warn("设备预览/回放停止API调用失败!"); + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); + msg.setData("streamId null"); + resultHolder.invokeResult(msg); } + + // 超时处理 + result.onTimeout(()->{ + logger.warn(String.format("设备预览/回放停止超时,streamId:%s ", streamId)); + RequestMessage msg = new RequestMessage(); + msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid); + msg.setData("Timeout"); + resultHolder.invokeResult(msg); + }); + return result; } /** @@ -145,7 +183,7 @@ public class PlayController { */ @PostMapping("/play/{streamId}/convert") public ResponseEntity playConvert(@PathVariable String streamId) { - StreamInfo streamInfo = storager.queryPlayByStreamId(streamId); + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); if (streamInfo == null) { logger.warn("视频转码API调用失败!, 视频流已经停止!"); return new ResponseEntity("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK); @@ -155,7 +193,7 @@ public class PlayController { logger.warn("视频转码API调用失败!, 视频流已停止推流!"); return new ResponseEntity("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK); } else { - MediaServerConfig mediaInfo = storager.getMediaInfo(); + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(), streamId ); String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java index 2800882a..6ce0868f 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaServerConfig; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.vmanager.play.PlayController; import com.genersoft.iot.vmp.vmanager.service.IPlayService; @@ -24,6 +25,9 @@ public class PlayServiceImpl implements IPlayService { @Autowired private IVideoManagerStorager storager; + @Autowired + private IRedisCatchStorage redisCatchStorage; + @Autowired private DeferredResultHolder resultHolder; @@ -33,7 +37,7 @@ public class PlayServiceImpl implements IPlayService { msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); if (streamInfo != null) { - storager.startPlay(streamInfo); + redisCatchStorage.startPlay(streamInfo); msg.setData(JSON.toJSONString(streamInfo)); resultHolder.invokeResult(msg); } else { @@ -49,7 +53,7 @@ public class PlayServiceImpl implements IPlayService { msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); if (streamInfo != null) { - storager.startPlayback(streamInfo); + redisCatchStorage.startPlayback(streamInfo); msg.setData(JSON.toJSONString(streamInfo)); resultHolder.invokeResult(msg); } else { @@ -65,7 +69,7 @@ public class PlayServiceImpl implements IPlayService { streamInfo.setStreamId(streamId); streamInfo.setDeviceID(deviceId); streamInfo.setCahnnelId(channelId); - MediaServerConfig mediaServerConfig = storager.getMediaInfo(); + MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo(); streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java index fdb67781..def98d80 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java @@ -65,7 +65,7 @@ public class ApiDeviceController { JSONObject result = new JSONObject(); List devices; if (start == null || limit ==null) { - devices = storager.queryVideoDeviceList(null); + devices = storager.queryVideoDeviceList(); result.put("DeviceCount", devices.size()); }else { PageResult deviceList = storager.queryVideoDeviceList(null, start/limit, limit); diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java index 6ef3a5f2..5ce51e13 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.vmanager.play.PlayController; import org.slf4j.Logger; @@ -35,6 +36,9 @@ public class ApiStreamController { @Autowired private IVideoManagerStorager storager; + @Autowired + private IRedisCatchStorage redisCatchStorage; + private boolean closeWaitRTPInfo = false; @@ -158,14 +162,14 @@ public class ApiStreamController { ){ - StreamInfo streamInfo = storager.queryPlayByDevice(serial, code); + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code); if (streamInfo == null) { JSONObject result = new JSONObject(); result.put("error","未找到流信息"); return result; } cmder.streamByeCmd(streamInfo.getStreamId()); - storager.stopPlay(streamInfo); + redisCatchStorage.stopPlay(streamInfo); return null; } diff --git a/src/main/resources/wvp.sqlite b/src/main/resources/wvp.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..e781bbcb2e1cb49bb62d2328d56d99fb190437ff GIT binary patch literal 32768 zcmeI*%TE(Q90%}S9<6P%K;og{w&}%I2#GP#0|%^RV~FKpUA2&yX4swL#C??6SqfM6 z;J?EE;n|xe{s|uZ157+P({9-Z2EA~gehHiM`|Zx_GY`@L;rX*R6V&X7+$X}kuPtf1 zu01kMP17p!x|Lir^7W;>=HxZ`&?jG9@mkT=Hoh4~SDUY%Yes3|*MeR>H$E9dV|Ya= z+=2iEAOHafK;XIrjPCr!r~3Y`X-0SMXSOvNf6vCrGhd21#1ObH0i!!ZRox#B9+Yd% zrv5P$ z4P2XL#~e|IQ%AO}Y*e#s(7M#)kc(W+0}@5UkSC(5)Si7{pAGWuCpnv*%F>hSBSAzg zH8Oqj!r+LBSQ*O69L&Ar)D zZDmE@A1$ru*pqLGdJ#R2Y2eU8IG0;og_{kvc2;G{=E9ohUDuW<*1P_&RNHOp8Vg){ zn)HaoA{@oN{POSJ%g3daMya;3{FlN>p|WiGbFuZC8^6=;ISZ6Y;rQFoxIIF zkLC7LZs}i)K(2g4P2bYZokR2-0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U< z00Izz00bZa0r@L`3PJw-fAPoSS9m}G0uX=z1Rwwb2tWV=5P$##AaKJ3?*6&Iw+rdX z`~N~3Ap{@*0SG_<0uX=z1Rwwb2tWV=QzTGTW5M75PtlBGC=h@E1Rwwb2tWV=5P$## zAOL~O0(k#_*#sE~KmY;|fB*y_009U<00Izzz?2H8|K&G3rDMaeAOHafKmY;|fB*y_ N009U<00RHLz;DDmQ6K;S literal 0 HcmV?d00001 diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index 738012d2..b46f1d96 100644 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -104,7 +104,7 @@ export default { mounted() { this.initData(); - this.updateLooper = setInterval(this.initData, 10000); + this.updateLooper = setInterval(this.initData, 1000); }, destroyed() { this.$destroy('videojs'); From 15bee5e37d8dc95a51d594eeb40f9d227616c9af Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Thu, 31 Dec 2020 13:22:22 +0800 Subject: [PATCH 40/45] =?UTF-8?q?=E5=AD=98=E5=82=A8=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BD=BF=E7=94=A8sqlite=E4=BB=A3=E6=9B=BFredis-2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/vmp/storager/impl/RedisCatchStorageImpl.java | 2 -- .../iot/vmp/vmanager/playback/PlaybackController.java | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) 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 8eaaf68a..96b55b09 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java @@ -51,7 +51,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); if (deviceChannel != null) { deviceChannel.setStreamId(null); - deviceChannel.setPlay(false); deviceChannel.setDeviceId(streamInfo.getDeviceID()); deviceChannelMapper.update(deviceChannel); } @@ -144,7 +143,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId()); if (deviceChannel != null) { deviceChannel.setStreamId(null); - deviceChannel.setPlay(false); deviceChannel.setDeviceId(streamInfo.getDeviceID()); deviceChannelMapper.update(deviceChannel); } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java index c9dc92c3..9449d263 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.vmanager.service.IPlayService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,6 +44,9 @@ public class PlaybackController { @Autowired private IVideoManagerStorager storager; + @Autowired + private IRedisCatchStorage redisCatchStorage; + @Autowired private ZLMRESTfulUtils zlmresTfulUtils; @@ -70,7 +74,7 @@ public class PlaybackController { resultHolder.invokeResult(msg); }); Device device = storager.queryVideoDevice(deviceId); - StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId); + StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); if (streamInfo != null) { // 停止之前的回放 cmder.streamByeCmd(streamInfo.getStreamId()); From 82c682c5125baa44944be30c8f5fdcb4f7e2e099 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Mon, 4 Jan 2021 18:30:44 +0800 Subject: [PATCH 41/45] =?UTF-8?q?=E5=AD=98=E5=82=A8=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BD=BF=E7=94=A8sqlite=E4=BB=A3=E6=9B=BFredis-3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 59 +-- .../genersoft/iot/vmp/common/PageResult.java | 45 -- .../iot/vmp/gb28181/bean/Device.java | 53 ++- .../cmd/SIPRequestHeaderProvider.java | 13 +- .../impl/RegisterRequestProcessor.java | 8 +- .../vmp/storager/IVideoManagerStorager.java | 18 +- .../iot/vmp/storager/VodeoMannagerTask.java | 17 - .../vmp/storager/dao/DeviceChannelMapper.java | 40 +- .../iot/vmp/storager/dao/DeviceMapper.java | 50 ++- .../storager/impl/RedisCatchStorageImpl.java | 4 - .../impl/VideoManagerStoragerImpl.java | 281 ++---------- .../vmp/vmanager/device/DeviceController.java | 40 +- .../vmp/vmanager/device/entity/Device.java | 401 ------------------ .../vmanager/device/entity/DeviceChannel.java | 385 ----------------- .../iot/vmp/web/ApiDeviceController.java | 19 +- src/main/resources/application-dev.yml | 1 + src/main/resources/application.yml | 2 +- src/main/resources/wvp.sqlite | Bin 32768 -> 32768 bytes web_src/src/components/channelList.vue | 6 +- web_src/src/components/videoList.vue | 5 +- 20 files changed, 222 insertions(+), 1225 deletions(-) delete mode 100644 src/main/java/com/genersoft/iot/vmp/common/PageResult.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/Device.java delete mode 100644 src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/DeviceChannel.java diff --git a/pom.xml b/pom.xml index ae4d6666..2f45a6d4 100644 --- a/pom.xml +++ b/pom.xml @@ -45,9 +45,6 @@ UTF-8 - 4.1.5 - 3.5.5 - 2.0.5 5.2.0 ${project.build.directory}/generated-snippets ${project.basedir}/docs/asciidoc @@ -59,30 +56,16 @@ org.springframework.boot - spring-boot-starter-jdbc - - - org.springframework.boot - spring-boot-starter-tomcat + spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-web - org.springframework - spring-context - - - - - org.springframework.data - spring-data-redis - - - redis.clients - jedis - 3.3.0 + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.4 @@ -106,36 +89,18 @@ 3.32.3.2 - - - org.mybatis - mybatis - ${mybatis.version} - - - org.mybatis - mybatis-spring - ${mybatis.spring.version} - - - + com.github.pagehelper - pagehelper - ${pagehelper.version} + pagehelper-spring-boot-starter + 1.2.10 - - - tk.mybatis - mapper - ${mapper.version} - - - org.apache.commons - commons-lang3 - 3.11 - + + + + + diff --git a/src/main/java/com/genersoft/iot/vmp/common/PageResult.java b/src/main/java/com/genersoft/iot/vmp/common/PageResult.java deleted file mode 100644 index 6d7c89e6..00000000 --- a/src/main/java/com/genersoft/iot/vmp/common/PageResult.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.genersoft.iot.vmp.common; - - -import java.util.List; - -public class PageResult { - - private int page; - private int count; - private int total; - - private List data; - - public List getData() { - return data; - } - - public int getPage() { - return page; - } - - public void setPage(int page) { - this.page = page; - } - - public int getCount() { - return count; - } - - public void setCount(int count) { - this.count = count; - } - - public int getTotal() { - return total; - } - - public void setTotal(int total) { - this.total = total; - } - - public void setData(List data) { - this.data = data; - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java index 12b8a007..9393106e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java @@ -1,17 +1,8 @@ package com.genersoft.iot.vmp.gb28181.bean; -import java.util.Date; -import java.util.List; -import java.util.Map; - public class Device { - /** - * 数据库存储ID - */ - private int id; - /** * 设备Id */ @@ -51,10 +42,20 @@ public class Device { */ private String streamMode; + /** + * wan地址_ip + */ + private String ip; + + /** + * wan地址_port + */ + private int port; + /** * wan地址 */ - private Host host; + private String hostAddress; /** * 在线 @@ -72,14 +73,6 @@ public class Device { */ private int channelCount; - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - public String getDeviceId() { return deviceId; } @@ -136,12 +129,28 @@ public class Device { this.streamMode = streamMode; } - public Host getHost() { - return host; + public String getIp() { + return ip; } - public void setHost(Host host) { - this.host = host; + public void setIp(String ip) { + this.ip = ip; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getHostAddress() { + return hostAddress; + } + + public void setHostAddress(String hostAddress) { + this.hostAddress = hostAddress; } public int getOnline() { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java index a606171a..8f2c0ddb 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java @@ -44,9 +44,8 @@ public class SIPRequestHeaderProvider { public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException { Request request = null; - Host host = device.getHost(); // sipuri - SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); // via ArrayList viaHeaders = new ArrayList(); ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), @@ -79,12 +78,11 @@ public class SIPRequestHeaderProvider { public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { Request request = null; - Host host = device.getHost(); //请求行 - SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, host.getAddress()); + SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress()); //via ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag); + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag); viaHeader.setRPort(); viaHeaders.add(viaHeader); @@ -126,12 +124,11 @@ public class SIPRequestHeaderProvider { public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException { Request request = null; - Host host = device.getHost(); //请求行 - SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); + SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); // via ArrayList viaHeaders = new ArrayList(); - ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag); + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag); viaHeader.setRPort(); viaHeaders.add(viaHeader); //from diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java index bcd44825..4faab0ef 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java @@ -107,17 +107,15 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor { rPort = viaHeader.getPort(); } // - Host host = new Host(); - host.setIp(received); - host.setPort(rPort); - host.setAddress(received.concat(":").concat(String.valueOf(rPort))); AddressImpl address = (AddressImpl) fromHeader.getAddress(); SipUri uri = (SipUri) address.getURI(); String deviceId = uri.getUser(); device = new Device(); device.setStreamMode("UDP"); device.setDeviceId(deviceId); - device.setHost(host); + device.setIp(received); + device.setPort(rPort); + device.setHostAddress(received.concat(":").concat(String.valueOf(rPort))); // 注销成功 if (expiresHeader != null && expiresHeader.getExpires() == 0) { registerFlag = 2; diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java index 4174507b..c601f7e5 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java @@ -1,14 +1,10 @@ package com.genersoft.iot.vmp.storager; import java.util.List; -import java.util.Map; -import com.alibaba.fastjson.JSONObject; -import com.genersoft.iot.vmp.common.PageResult; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.conf.MediaServerConfig; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.github.pagehelper.PageInfo; /** * @Description:视频设备数据存储接口 @@ -65,7 +61,7 @@ public interface IVideoManagerStorager { * @param count 每页数量 * @return */ - public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count); + public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count); /** * 获取某个设备的通道列表 @@ -82,13 +78,13 @@ public interface IVideoManagerStorager { */ public DeviceChannel queryChannel(String deviceId, String channelId); - /** + /** * 获取多个设备 - * - * @param deviceIds 设备ID数组 + * @param page 当前页数 + * @param count 每页数量 * @return List 设备对象数组 */ - public PageResult queryVideoDeviceList(String[] deviceIds, int page, int count); + public PageInfo queryVideoDeviceList(int page, int count); /** * 获取多个设备 @@ -131,7 +127,7 @@ public interface IVideoManagerStorager { * @param count * @return */ - PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count); + PageInfo querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count); /** diff --git a/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java b/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java deleted file mode 100644 index c2074843..00000000 --- a/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.genersoft.iot.vmp.storager; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.stereotype.Component; - -@Component -public class VodeoMannagerTask implements CommandLineRunner { - - @Autowired - private IVideoManagerStorager redisStorager; - - @Override - public void run(String... strings) throws Exception { - redisStorager.updateCatch(); - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java index bf67095f..072b1bfe 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java @@ -1,20 +1,50 @@ package com.genersoft.iot.vmp.storager.dao; -import com.genersoft.iot.vmp.common.PageResult; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.*; import java.util.List; +/** + * 用于存储设备通道信息 + */ @Mapper public interface DeviceChannelMapper { + + @Insert("INSERT INTO device_channel (channelId, deviceId, name, manufacture, model, owner, civilCode, block, " + + "address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " + + "ipAddress, port, password, PTZType, status) " + + "VALUES ('${channelId}', '${deviceId}', '${name}', '${manufacture}', '${model}', '${owner}', '${civilCode}', '${block}'," + + "'${address}', ${parental}, '${parentId}', ${safetyWay}, ${registerWay}, '${certNum}', ${certifiable}, ${errCode}, '${secrecy}', " + + "'${ipAddress}', ${port}, '${password}', ${PTZType}, ${status})") + int add(DeviceChannel channel); + + @Update("UPDATE device_channel " + + "SET name=#{name}, manufacture=#{manufacture}, model=#{model}, owner=#{owner}, civilCode=#{civilCode}, " + + "block=#{block}, address=#{address}, parental=#{parental}, parentId=#{parentId}, safetyWay=#{safetyWay}, " + + "registerWay=#{registerWay}, certNum=#{certNum}, certifiable=#{certifiable}, errCode=#{errCode}, secrecy=#{secrecy}, " + + "ipAddress=#{ipAddress}, port=#{port}, password=#{password}, PTZType=#{PTZType}, status=#{status} " + + "WHERE deviceId=#{deviceId} AND channelId=#{channelId}") int update(DeviceChannel channel); - List queryChannelsByDeviceId(String deviceId); - - List queryChannelsByDeviceId(String deviceId, String parentChannelId); + @Select(value = {" "}) + List queryChannelsByDeviceId(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online); + @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}") DeviceChannel queryChannel(String deviceId, String channelId); + @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}") int cleanChannelsByDeviceId(String deviceId); + } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java index da455fbe..3c10618e 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java @@ -1,24 +1,66 @@ package com.genersoft.iot.vmp.storager.dao; import com.genersoft.iot.vmp.gb28181.bean.Device; -import org.apache.ibatis.annotations.Insert; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.*; +import org.springframework.stereotype.Repository; import java.util.List; +/** + * 用于存储设备信息 + */ @Mapper +@Repository public interface DeviceMapper { @Select("SELECT * FROM device WHERE deviceId = #{deviceId}") Device getDeviceByDeviceId(String deviceId); - @Insert("SELECT * FROM device WHERE deviceId = #{deviceId}") + @Insert("INSERT INTO device (" + + "deviceId, " + + "name, " + + "manufacturer, " + + "model, " + + "firmware, " + + "transport," + + "streamMode," + + "ip," + + "port," + + "hostAddress," + + "online" + + ") VALUES (" + + "#{deviceId}," + + "#{name}," + + "#{manufacturer}," + + "#{model}," + + "#{firmware}," + + "#{transport}," + + "#{streamMode}," + + "#{ip}," + + "#{port}," + + "#{hostAddress}," + + "#{online}" + + ")") int add(Device device); + + @Update("UPDATE device " + + "SET name=#{name}, " + + "manufacturer=#{manufacturer}," + + "model=#{model}," + + "firmware=#{firmware}, " + + "transport=#{transport}," + + "streamMode=#{streamMode}, " + + "ip=#{ip}, " + + "port=#{port}, " + + "hostAddress=#{hostAddress}, " + + "online=#{online} " + + "WHERE deviceId=#{deviceId}") int update(Device device); + @Select("SELECT *, (SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount FROM device de") List getDevices(); + @Delete("DELETE FROM device WHERE deviceId=#{deviceId}") int del(String deviceId); } 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 96b55b09..cebb30b8 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java @@ -6,7 +6,6 @@ import com.genersoft.iot.vmp.conf.MediaServerConfig; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; -import com.genersoft.iot.vmp.storager.dao.DeviceMapper; import com.genersoft.iot.vmp.utils.redis.RedisUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -22,9 +21,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @Autowired private RedisUtil redis; - @Autowired - private DeviceMapper deviceMapper; - @Autowired private DeviceChannelMapper deviceChannelMapper; diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java index 1288efc1..01ed247e 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java @@ -2,19 +2,17 @@ package com.genersoft.iot.vmp.storager.impl; import java.util.*; -import com.genersoft.iot.vmp.common.PageResult; -import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.conf.MediaServerConfig; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; import com.genersoft.iot.vmp.storager.dao.DeviceMapper; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import io.swagger.models.auth.In; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import com.genersoft.iot.vmp.utils.redis.RedisUtil; import org.springframework.util.StringUtils; /** @@ -50,7 +48,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { * @return true:创建成功 false:创建失败 */ @Override - public boolean create(Device device) { + public synchronized boolean create(Device device) { return deviceMapper.add(device) > 0; } @@ -63,69 +61,26 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { * @return true:更新成功 false:更新失败 */ @Override - public boolean updateDevice(Device device) { -// if (deviceMap.get(device.getDeviceId()) == null) { -// deviceMap.put(device.getDeviceId(), new HashMap>()); -// } - // 更新device中的通道数量 -// device.setChannelCount(deviceMap.get(device.getDeviceId()).size()); - int result = deviceMapper.update(device); - // 存储device - return result > 0; - + public synchronized boolean updateDevice(Device device) { + Device deviceByDeviceId = deviceMapper.getDeviceByDeviceId(device.getDeviceId()); + if (deviceByDeviceId == null) { + return deviceMapper.add(device) > 0; + }else { + return deviceMapper.update(device) > 0; + } } @Override - public void updateChannel(String deviceId, DeviceChannel channel) { + public synchronized void updateChannel(String deviceId, DeviceChannel channel) { String channelId = channel.getChannelId(); channel.setDeviceId(deviceId); - deviceChannelMapper.update(channel); - -// HashMap> channelMap = deviceMap.get(deviceId); -// if (channelMap == null) return; -// // 作为父设备, 确定自己的子节点数 -// if (channelMap.get(channelId) == null) { -// channelMap.put(channelId, new HashSet()); -// }else if (channelMap.get(channelId).size() > 0) { -// channel.setSubCount(channelMap.get(channelId).size()); -// } -// -// // 存储通道 -// redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + -// "_" + channel.getChannelId() + -// "_" + (channel.getStatus() == 1 ? "on":"off") + -// "_" + (channelMap.get(channelId).size() > 0)+ -// "_" + (StringUtils.isEmpty(channel.getParentId())?null:channel.getParentId()), -// channel); -// // 更新device中的通道数量 -// Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); -// device.setChannelCount(deviceMap.get(deviceId).size()); -// redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); -// -// -// // 如果有父设备,更新父设备内子节点数 -// String parentId = channel.getParentId(); -// if (!StringUtils.isEmpty(parentId) && !parentId.equals(deviceId)) { -// -// if (channelMap.get(parentId) == null) { -// channelMap.put(parentId, new HashSet()); -// } -// channelMap.get(parentId).add(channelId); -// -// DeviceChannel deviceChannel = queryChannel(deviceId, parentId); -// if (deviceChannel != null) { -// deviceChannel.setSubCount(channelMap.get(parentId).size()); -// redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + -// "_" + deviceChannel.getChannelId() + -// "_" + (deviceChannel.getStatus() == 1 ? "on":"off") + -// "_" + (channelMap.get(deviceChannel.getChannelId()).size() > 0)+ -// "_" + (StringUtils.isEmpty(deviceChannel.getParentId())?null:deviceChannel.getParentId()), -// deviceChannel); -// -// } -// } - + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId); + if (deviceChannel == null) { + deviceChannelMapper.add(channel); + }else { + deviceChannelMapper.update(channel); + } } /** @@ -140,179 +95,45 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { } @Override - public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) { + public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count) { // 获取到所有正在播放的流 - List result = new ArrayList<>(); - PageResult pageResult = new PageResult(); - - deviceChannelMapper.queryChannelsByDeviceId(deviceId); -// String queryContent = "*"; -// if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query); -// String queryHasSubChannel = "*"; -// if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false"; -// String queryOnline = "*"; -// if (!StringUtils.isEmpty(online)) queryOnline = online; -// String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId + -// "_" + queryContent + // 搜索编号和名称 -// "_" + queryOnline + // 搜索是否在线 -// "_" + queryHasSubChannel + // 搜索是否含有子节点 -// "_" + "*"; -// List deviceChannelList = redis.scan(queryStr); -// //对查询结果排序,避免出现通道排列顺序乱序的情况 -// Collections.sort(deviceChannelList,new Comparator(){ -// @Override -// public int compare(Object o1, Object o2) { -// return o1.toString().compareToIgnoreCase(o2.toString()); -// } -// }); -// pageResult.setPage(page); -// pageResult.setCount(count); -// pageResult.setTotal(deviceChannelList.size()); -// int maxCount = (page + 1 ) * count; -// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { -// for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { -// DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); -// StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId()); -// deviceChannel.setPlay(streamInfo != null); -// if (streamInfo != null) deviceChannel.setStreamId(streamInfo.getStreamId()); -// result.add(deviceChannel); -// } -// pageResult.setData(result); -// } - - return pageResult; + PageHelper.startPage(page, count); + List all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, null, query, hasSubChannel, online); + return new PageInfo<>(all); } @Override public List queryChannelsByDeviceId(String deviceId) { -// List result = new ArrayList<>(); -//// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); -// List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); -// -// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { -// for (int i = 0; i < deviceChannelList.size(); i++) { -// result.add((DeviceChannel)redis.get((String) deviceChannelList.get(i))); -// } -// } - return deviceChannelMapper.queryChannelsByDeviceId(deviceId); + return deviceChannelMapper.queryChannelsByDeviceId(deviceId, null,null, null, null); } @Override - public PageResult querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) { - - deviceChannelMapper.queryChannelsByDeviceId(deviceId, parentChannelId); - -// List allDeviceChannels = new ArrayList<>(); -// String queryContent = "*"; -// if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query); -// String queryHasSubChannel = "*"; -// if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false"; -// String queryOnline = "*"; -// if (!StringUtils.isEmpty(online)) queryOnline = online; -// String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId + -// "_" + queryContent + // 搜索编号和名称 -// "_" + queryOnline + // 搜索是否在线 -// "_" + queryHasSubChannel + // 搜索是否含有子节点 -// "_" + parentChannelId; -// -//// List deviceChannelList = redis.keys(queryStr); -// List deviceChannelList = redis.scan(queryStr); -// -// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { -// for (int i = 0; i < deviceChannelList.size(); i++) { -// DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); -// if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) { -// allDeviceChannels.add(deviceChannel); -// } -// } -// } -// int maxCount = (page + 1 ) * count; - PageResult pageResult = new PageResult(); -// pageResult.setPage(page); -// pageResult.setCount(count); -// pageResult.setTotal(allDeviceChannels.size()); -// -// if (allDeviceChannels.size() > 0) { -// pageResult.setData(allDeviceChannels.subList( -// page * count, pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() -// )); -// } - return pageResult; - } - - public List querySubChannels(String deviceId, String parentChannelId) { - List allDeviceChannels = new ArrayList<>(); -// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); -// List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*"); -// -// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { -// for (int i = 0; i < deviceChannelList.size(); i++) { -// DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i)); -// if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) { -// allDeviceChannels.add(deviceChannel); -// } -// } -// } - - return allDeviceChannels; + public PageInfo querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) { + PageHelper.startPage(page, count); + List all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, parentChannelId, null, null, null); + return new PageInfo<>(all); } @Override public DeviceChannel queryChannel(String deviceId, String channelId) { - DeviceChannel deviceChannel = null; return deviceChannelMapper.queryChannel(deviceId, channelId); -//// List deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + -// List deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + -// "_" + channelId + "*"); -// if (deviceChannelList != null && deviceChannelList.size() > 0 ) { -// deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(0)); -// } -// return deviceChannel; } /** * 获取多个设备 * - * @param deviceIds 设备ID数组 - * @return List 设备对象数组 + * @param page 当前页数 + * @param count 每页数量 + * @return PageInfo 分页设备对象数组 */ @Override - public PageResult queryVideoDeviceList(String[] deviceIds, int page, int count) { - List devices = new ArrayList<>(); - PageResult pageResult = new PageResult(); -// pageResult.setPage(page); -// pageResult.setCount(count); -// Device device = null; -// -// if (deviceIds == null || deviceIds.length == 0) { -// -//// List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); -// List deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*"); -// pageResult.setTotal(deviceIdList.size()); -// int maxCount = (page + 1)* count; -// for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) { -// // devices.add((Device)redis.get((String)deviceIdList.get(i))); -// device =(Device)redis.get((String)deviceIdList.get(i)); -// if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ -// // outline(device.getDeviceId()); -// } -// devices.add(device); -// } -// } else { -// for (int i = 0; i < deviceIds.length; i++) { -// // devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i])); -// device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]); -// if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ -// // outline(device.getDeviceId()); -// } -// devices.add(device); -// } -// } -// pageResult.setData(devices); - return pageResult; + public PageInfo queryVideoDeviceList(int page, int count) { + PageHelper.startPage(page, count); + List all = deviceMapper.getDevices(); + return new PageInfo<>(all); } /** @@ -323,26 +144,6 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { @Override public List queryVideoDeviceList() { -// if (deviceIds == null || deviceIds.length == 0) { -//// List deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*"); -// List deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*"); -// for (int i = 0; i < deviceIdList.size(); i++) { -// device =(Device)redis.get((String)deviceIdList.get(i)); -// if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ -// outline(device.getDeviceId()); -// } -// devices.add(device); -// } -// } else { -// for (int i = 0; i < deviceIds.length; i++) { -// device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]); -// if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){ -// outline(device.getDeviceId()); -// } -// devices.add(device); -// } -// } - List deviceList = deviceMapper.getDevices(); return deviceList; } @@ -367,9 +168,13 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { * @return true:更新成功 false:更新失败 */ @Override - public boolean online(String deviceId) { + public synchronized boolean online(String deviceId) { Device device = deviceMapper.getDeviceByDeviceId(deviceId); device.setOnline(1); + System.out.println("更新设备在线"); + if (device == null) { + return false; + } return deviceMapper.update(device) > 0; } @@ -380,14 +185,10 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { * @return true:更新成功 false:更新失败 */ @Override - public boolean outline(String deviceId) { -// Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId); -// if (device == null) return false; -// device.setOnline(0); -// return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device); - + public synchronized boolean outline(String deviceId) { Device device = deviceMapper.getDeviceByDeviceId(deviceId); device.setOnline(0); + System.out.println("更新设备离线"); return deviceMapper.update(device) > 0; } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java index 65e294a5..d64b6327 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java @@ -1,15 +1,14 @@ package com.genersoft.iot.vmp.vmanager.device; -import java.util.List; - -import com.genersoft.iot.vmp.common.PageResult; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; +import com.github.pagehelper.PageInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; @@ -53,13 +52,13 @@ public class DeviceController { } @GetMapping("/devices") - public PageResult devices(int page, int count){ + public PageInfo devices(int page, int count){ if (logger.isDebugEnabled()) { logger.debug("查询所有视频设备API调用"); } - return storager.queryVideoDeviceList(null, page, count); + return storager.queryVideoDeviceList(page, count); } /** @@ -69,18 +68,33 @@ public class DeviceController { * @param count 每页条数 * @return 通道列表 */ + /** + * 分页查询通道数 + * + * @param deviceId 设备id + * @param page 当前页 + * @param count 每页条数 + * @param query 查询内容 + * @param online 是否在线 在线 true / 离线 false + * @param channelType 设备 false/子目录 true + * @return 通道列表 + */ @GetMapping("/devices/{deviceId}/channels") - public ResponseEntity channels(@PathVariable String deviceId, + public ResponseEntity channels(@PathVariable String deviceId, int page, int count, @RequestParam(required = false) String query, - @RequestParam(required = false) String online, + @RequestParam(required = false) Boolean online, @RequestParam(required = false) Boolean channelType ){ if (logger.isDebugEnabled()) { logger.debug("查询所有视频设备API调用"); } - PageResult pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count); + if (StringUtils.isEmpty(query)) { + query = null; + } + + PageInfo pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count); return new ResponseEntity<>(pageResult,HttpStatus.OK); } @@ -141,7 +155,7 @@ public class DeviceController { * @return 子通道列表 */ @GetMapping("/subChannels/{deviceId}/{channelId}/channels") - public ResponseEntity subChannels(@PathVariable String deviceId, + public ResponseEntity subChannels(@PathVariable String deviceId, @PathVariable String channelId, int page, int count, @@ -154,23 +168,23 @@ public class DeviceController { } DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId); if (deviceChannel == null) { - PageResult deviceChannelPageResult = new PageResult<>(); + PageInfo deviceChannelPageResult = new PageInfo<>(); return new ResponseEntity<>(deviceChannelPageResult,HttpStatus.OK); } - PageResult pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); + PageInfo pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); return new ResponseEntity<>(pageResult,HttpStatus.OK); } @PostMapping("/channel/update/{deviceId}") - public ResponseEntity updateChannel(@PathVariable String deviceId,DeviceChannel channel){ + public ResponseEntity updateChannel(@PathVariable String deviceId,DeviceChannel channel){ storager.updateChannel(deviceId, channel); return new ResponseEntity<>(null,HttpStatus.OK); } @GetMapping("/devices/{deviceId}/transport/{streamMode}") @PostMapping("/devices/{deviceId}/transport/{streamMode}") - public ResponseEntity updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){ + public ResponseEntity updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){ Device device = storager.queryVideoDevice(deviceId); device.setStreamMode(streamMode); storager.updateDevice(device); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/Device.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/Device.java deleted file mode 100644 index e47f796c..00000000 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/Device.java +++ /dev/null @@ -1,401 +0,0 @@ -package com.genersoft.iot.vmp.vmanager.device.entity; - -import java.util.List; - -import javax.persistence.Column; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.Max; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; - -/** - * @Description:视频设备信息 - * @author: songww - * @date: 2020年5月8日 下午2:05:56 - */ -@ApiModel(value = "视频设备信息", description = "视频设备信息") -@Table(name="VMP_VIDEODEVICES") -public class Device { - - /** - * 设备Id - */ - @ApiModelProperty("设备编号") - @Id - @Column(name="DEVICE_ID") - @NotNull(message = "deviceId 不能为 null") - @Size(min = 4, max = 32, message = "deviceId 必须大于 4 位并且小于 32 位") - private String deviceId; - - /** - * 设备名称 - */ - @ApiModelProperty("设备名称") - @Column(name="DEVICE_NAME") - @Size(max = 32, message = "deviceName 必须小于 32 位") - private String deviceName; - - /** - * 生产厂商 - */ - @ApiModelProperty("生产厂商") - @Column(name="MANUFACTURER") - @Size(max = 64, message = "manufacturer 必须小于 64 位") - private String manufacturer; - - /** - * 型号 - */ - @ApiModelProperty("型号") - @Column(name="MODEL") - @Size(max = 64, message = "manufacturer 必须小于 64 位") - private String model; - - /** - * 固件版本 - */ - @ApiModelProperty("固件版本") - @Column(name="FIRMWARE") - @Size(max = 64, message = "firmware 必须小于 64 位") - private String firmware; - - /** - * 通信协议 - * GB28181 ONVIF - */ - @ApiModelProperty("通信协议") - @Column(name="PROTOCOL") - @NotNull(message = "protocol 不能为 null") - @Size(max = 16, message = "protocol 必须小于 16 位") - private String protocol; - - /** - * SIP 传输协议 - * UDP/TCP - */ - @ApiModelProperty("SIP 传输协议") - @Column(name="TRANSPORT") - @Size(min = 3,max = 3 ,message = "transport 必须为 3 位") - private String transport; - - /** - * 数据流传输模式 - * UDP:udp传输 - * TCP-ACTIVE:tcp主动模式 - * TCP-PASSIVE:tcp被动模式 - */ - @ApiModelProperty("数据流传输模式") - @Column(name="STREAM_MODE") - @Size(max = 64, message = "streamMode 必须小于 16 位") - private String streamMode; - - /** - * IP地址 - */ - @ApiModelProperty("IP地址") - @Column(name="IP") - @Size(max = 15, message = "streamMode 必须小于 15 位") - private String ip; - - /** - * 端口号 - */ - @ApiModelProperty("端口号") - @Column(name="PORT") - @Max(value = 65535,message = "port 最大值为 65535") - private Integer port; - - /** - * 在线状态 1在线, 0离线 - */ - @ApiModelProperty("在线状态") - @Size(min = 1,max = 1 ,message = "online 必须为 1 位") - @Column(name="ONLINE") - private String online; - - /** - * 通道数量 - */ - @ApiModelProperty("通道数量") - @Column(name="CHANNEL_SUM") - @Max(value = 1000000000,message = "channelSum 最大值为 1000000000") - private Integer channelSum; - - @Override - public String toString() { - return "Device{" + - "deviceId='" + deviceId + '\'' + - ", deviceName='" + deviceName + '\'' + - ", manufacturer='" + manufacturer + '\'' + - ", model='" + model + '\'' + - ", firmware='" + firmware + '\'' + - ", protocol='" + protocol + '\'' + - ", transport='" + transport + '\'' + - ", streamMode='" + streamMode + '\'' + - ", ip='" + ip + '\'' + - ", port=" + port + - ", online='" + online + '\'' + - ", channelSum=" + channelSum + - ", createTime='" + createTime + '\'' + - ", registerTime='" + registerTime + '\'' + - ", heartbeatTime='" + heartbeatTime + '\'' + - ", updateTime='" + updateTime + '\'' + - ", updatePerson='" + updatePerson + '\'' + - ", syncTime='" + syncTime + '\'' + - ", syncPerson='" + syncPerson + '\'' + - ", username='" + username + '\'' + - ", password='" + password + '\'' + - ", channelList=" + channelList + - '}'; - } - - /** - * 创建时间 - */ - @ApiModelProperty("创建时间") - @Column(name="CREATE_TIME") - private String createTime; - - /** - * 注册时间 - */ - @ApiModelProperty("注册时间") - @Column(name="REGISTER_TIME") - private String registerTime; - - /** - * 心跳时间 - */ - @ApiModelProperty("心跳时间") - @Column(name="HEARTBEAT_TIME") - private String heartbeatTime; - - /** - * 修改时间 - */ - @ApiModelProperty("更新时间") - @Column(name="UPDATE_TIME") - private String updateTime; - - /** - * 修改人 - */ - @ApiModelProperty("修改人") - @Column(name="UPDATE_PERSON") - private String updatePerson; - - /** - * 同步时间 - */ - @ApiModelProperty("同步时间") - @Column(name="SYNC_TIME") - private String syncTime; - - /** - * 同步人 - */ - @ApiModelProperty("同步人") - @Column(name="SYNC_PERSON") - private String syncPerson; - - /** - * ONVIF协议-用户名 - */ - @ApiModelProperty("用户名") - @Column(name="USERNAME") - @Size(max = 32, message = "username 必须小于 32 位") - private String username; - - /** - * ONVIF协议-密码 - */ - @ApiModelProperty("密码") - @Size(max = 32, message = "password 必须小于 32 位") - @Column(name="PASSWORD") - private String password; - - @Transient - private List channelList; - - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public String getDeviceName() { - return deviceName; - } - - public void setDeviceName(String deviceName) { - this.deviceName = deviceName; - } - - public String getManufacturer() { - return manufacturer; - } - - public void setManufacturer(String manufacturer) { - this.manufacturer = manufacturer; - } - - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - - public String getFirmware() { - return firmware; - } - - public void setFirmware(String firmware) { - this.firmware = firmware; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public String getTransport() { - return transport; - } - - public void setTransport(String transport) { - this.transport = transport; - } - - public String getStreamMode() { - return streamMode; - } - - public void setStreamMode(String streamMode) { - this.streamMode = streamMode; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public Integer getPort() { - return port; - } - - public void setPort(Integer port) { - this.port = port; - } - - public String getOnline() { - return online; - } - - public void setOnline(String online) { - this.online = online; - } - - public Integer getChannelSum() { - return channelSum; - } - - public void setChannelSum(Integer channelSum) { - this.channelSum = channelSum; - } - - public String getCreateTime() { - return createTime; - } - - public void setCreateTime(String createTime) { - this.createTime = createTime; - } - - public String getRegisterTime() { - return registerTime; - } - - public void setRegisterTime(String registerTime) { - this.registerTime = registerTime; - } - - public String getHeartbeatTime() { - return heartbeatTime; - } - - public void setHeartbeatTime(String heartbeatTime) { - this.heartbeatTime = heartbeatTime; - } - - public String getUpdateTime() { - return updateTime; - } - - public void setUpdateTime(String updateTime) { - this.updateTime = updateTime; - } - - public String getUpdatePerson() { - return updatePerson; - } - - public void setUpdatePerson(String updatePerson) { - this.updatePerson = updatePerson; - } - - public String getSyncTime() { - return syncTime; - } - - public void setSyncTime(String syncTime) { - this.syncTime = syncTime; - } - - public String getSyncPerson() { - return syncPerson; - } - - public void setSyncPerson(String syncPerson) { - this.syncPerson = syncPerson; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public List getChannelList() { - return channelList; - } - - public void setChannelList(List channelList) { - this.channelList = channelList; - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/DeviceChannel.java deleted file mode 100644 index bedd0755..00000000 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/DeviceChannel.java +++ /dev/null @@ -1,385 +0,0 @@ -package com.genersoft.iot.vmp.vmanager.device.entity; - -import javax.persistence.Column; -import javax.persistence.Id; -import javax.persistence.Table; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; - -/** - * @Description:设备通道信息 - * @author: songww - * @date: 2020年5月20日 下午9:00:46 - */ -@ApiModel(value = "设备通道信息", description = "设备通道信息") -@Table(name="VMP_VIDEOCHANNELS") -public class DeviceChannel { - - /** - * 通道编号 - */ - @ApiModelProperty("通道编号") - @Id - @Column(name="CHANNEL_ID") - private String channelId; - - /** - * 设备编号 - */ - @ApiModelProperty("设备编号") - @Column(name="DEVICE_ID") - private String deviceId; - - /** - * 通道名 - */ - @ApiModelProperty("通道名") - @Column(name="CHANNEL_NAME") - private String channelName; - - /** - * 生产厂商 - */ - @ApiModelProperty("生产厂商") - @Column(name="MANUFACTURER") - private String manufacture; - - /** - * 型号 - */ - @ApiModelProperty("型号") - @Column(name="MODEL") - private String model; - - /** - * 设备归属 - */ - @ApiModelProperty("设备归属") - @Column(name="OWNER") - private String owner; - - /** - * 行政区域 - */ - @ApiModelProperty("行政区域") - @Column(name="CIVIL_CODE") - private String civilCode; - - /** - * 警区 - */ - @ApiModelProperty("警区") - @Column(name="BLOCK") - private String block; - - /** - * 安装地址 - */ - @ApiModelProperty("安装地址") - @Column(name="ADDRESS") - private String address; - - /** - * 是否有子设备 1有, 0没有 - */ - @ApiModelProperty("是否有子设备") - @Column(name="PARENTAL") - private String parental; - - /** - * 父级id - */ - @ApiModelProperty("父级编码") - @Column(name="PARENT_ID") - private String parentId; - - /** - * 信令安全模式 缺省为0; 0:不采用; 2: S/MIME签名方式; 3: S/ MIME加密签名同时采用方式; 4:数字摘要方式 - */ - @ApiModelProperty("信令安全模式") - @Column(name="SAFETY_WAY") - private String safetyWay; - - /** - * 注册方式 缺省为1;1:符合IETFRFC3261标准的认证注册模 式; 2:基于口令的双向认证注册模式; 3:基于数字证书的双向认证注册模式 - */ - @ApiModelProperty("注册方式") - @Column(name="REGISTER_WAY") - private String registerWay; - - /** - * 证书序列号 - */ - @ApiModelProperty("证书序列号") - @Column(name="CERT_NUM") - private String certNum; - - /** - * 证书有效标识 缺省为0;证书有效标识:0:无效1: 有效 - */ - @ApiModelProperty("证书有效标识") - @Column(name="CERT_VALID") - private String certValid; - - /** - * 证书无效原因码 - */ - @ApiModelProperty("证书无效原因码") - @Column(name="CERT_ERRCODE") - private String certErrCode; - - /** - * 证书终止有效期 - */ - @ApiModelProperty("证书终止有效期") - @Column(name="CERT_ENDTIME") - private String certEndTime; - - /** - * 保密属性 缺省为0; 0:不涉密, 1:涉密 - */ - @ApiModelProperty("保密属性") - @Column(name="SECRECY") - private String secrecy; - - /** - * IP地址 - */ - @ApiModelProperty("IP地址") - @Column(name="IP") - private String ip; - - /** - * 端口号 - */ - @ApiModelProperty("端口号") - @Column(name="PORT") - private Integer port; - - /** - * 密码 - */ - @ApiModelProperty("密码") - @Column(name="PASSWORD") - private String password; - - /** - * 在线/离线 - * 1在线,0离线 - * 默认在线 - * 信令: - * ON - * OFF - * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF - */ - @ApiModelProperty("状态") - @Column(name="ONLINE") - private String online; - - /** - * 经度 - */ - @ApiModelProperty("经度") - @Column(name="LONGITUDE") - private double longitude; - - /** - * 纬度 - */ - @ApiModelProperty("纬度") - @Column(name="LATITUDE") - private double latitude; - - public String getChannelId() { - return channelId; - } - - public void setChannelId(String channelId) { - this.channelId = channelId; - } - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public String getChannelName() { - return channelName; - } - - public void setChannelName(String channelName) { - this.channelName = channelName; - } - - public String getManufacture() { - return manufacture; - } - - public void setManufacture(String manufacture) { - this.manufacture = manufacture; - } - - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - - public String getOwner() { - return owner; - } - - public void setOwner(String owner) { - this.owner = owner; - } - - public String getCivilCode() { - return civilCode; - } - - public void setCivilCode(String civilCode) { - this.civilCode = civilCode; - } - - public String getBlock() { - return block; - } - - public void setBlock(String block) { - this.block = block; - } - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public String getParental() { - return parental; - } - - public void setParental(String parental) { - this.parental = parental; - } - - public String getParentId() { - return parentId; - } - - public void setParentId(String parentId) { - this.parentId = parentId; - } - - public String getSafetyWay() { - return safetyWay; - } - - public void setSafetyWay(String safetyWay) { - this.safetyWay = safetyWay; - } - - public String getRegisterWay() { - return registerWay; - } - - public void setRegisterWay(String registerWay) { - this.registerWay = registerWay; - } - - public String getCertNum() { - return certNum; - } - - public void setCertNum(String certNum) { - this.certNum = certNum; - } - - public String getCertValid() { - return certValid; - } - - public void setCertValid(String certValid) { - this.certValid = certValid; - } - - public String getCertErrCode() { - return certErrCode; - } - - public void setCertErrCode(String certErrCode) { - this.certErrCode = certErrCode; - } - - public String getCertEndTime() { - return certEndTime; - } - - public void setCertEndTime(String certEndTime) { - this.certEndTime = certEndTime; - } - - public String getSecrecy() { - return secrecy; - } - - public void setSecrecy(String secrecy) { - this.secrecy = secrecy; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public Integer getPort() { - return port; - } - - public void setPort(Integer port) { - this.port = port; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getOnline() { - return online; - } - - public void setOnline(String online) { - this.online = online; - } - - public double getLongitude() { - return longitude; - } - - public void setLongitude(double longitude) { - this.longitude = longitude; - } - - public double getLatitude() { - return latitude; - } - - public void setLatitude(double latitude) { - this.latitude = latitude; - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java index def98d80..199a9e69 100644 --- a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java +++ b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java @@ -1,22 +1,17 @@ package com.genersoft.iot.vmp.web; -import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; -import com.genersoft.iot.vmp.common.PageResult; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; -import com.genersoft.iot.vmp.vmanager.device.DeviceController; +import com.github.pagehelper.PageInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -68,9 +63,9 @@ public class ApiDeviceController { devices = storager.queryVideoDeviceList(); result.put("DeviceCount", devices.size()); }else { - PageResult deviceList = storager.queryVideoDeviceList(null, start/limit, limit); + PageInfo deviceList = storager.queryVideoDeviceList(start/limit, limit); result.put("DeviceCount", deviceList.getTotal()); - devices = deviceList.getData(); + devices = deviceList.getList(); } JSONArray deviceJSONList = new JSONArray(); @@ -86,8 +81,8 @@ public class ApiDeviceController { deviceJsonObject.put("Online", device.getOnline() == 1); deviceJsonObject.put("Password", ""); deviceJsonObject.put("MediaTransport", device.getTransport()); - deviceJsonObject.put("RemoteIP", device.getHost().getIp()); - deviceJsonObject.put("RemotePort", device.getHost().getPort()); + deviceJsonObject.put("RemoteIP", device.getIp()); + deviceJsonObject.put("RemotePort", device.getPort()); deviceJsonObject.put("LastRegisterAt", ""); deviceJsonObject.put("LastKeepaliveAt", ""); deviceJsonObject.put("UpdatedAt", ""); @@ -123,9 +118,9 @@ public class ApiDeviceController { deviceChannels = storager.queryChannelsByDeviceId(serial); result.put("ChannelCount", deviceChannels.size()); }else { - PageResult pageResult = storager.queryChannelsByDeviceId(serial, null, null, null,start/limit, limit); + PageInfo pageResult = storager.queryChannelsByDeviceId(serial, null, null, null,start/limit, limit); result.put("ChannelCount", pageResult.getTotal()); - deviceChannels = pageResult.getData(); + deviceChannels = pageResult.getList(); } JSONArray channleJSONList = new JSONArray(); diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 34f615ac..6cee0cb6 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -27,6 +27,7 @@ spring: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver + # [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 server: port: 18080 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index caf4dfcd..ef46c2ad 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - active: dev \ No newline at end of file + active: local \ No newline at end of file diff --git a/src/main/resources/wvp.sqlite b/src/main/resources/wvp.sqlite index e781bbcb2e1cb49bb62d2328d56d99fb190437ff..ab68634ccb6fa74bb0b623e28126efafc9832f55 100644 GIT binary patch delta 423 zcmZo@U}|V!njj^_c$9&Gfdh!yfS3u0H%`lTFJo5&d9*a#u>poot=^A zBu^br-Nwcb%;H=tS>6E^BLkq&?TL;e0zeuWZQs}!#sm~(ie+GE2`OL~*VJU}NS?fz zOOcUz@>Q-37AGHnr_GMs`izrXc|s=J@C))4Bo?LSl_cgUafY}?giLDde6k_J#=K%^Z^D};# z*!W?Qfxu=30d@gaMqq%k0>!`ZPYU2*{`34VfFj5E84V{k G>H+}2Ic<{w delta 322 zcmZo@U}|V!njj^_z{$YCzyZZfKss!qj*$#dRL}kh2n( z;O8Hr;1}xSGufI`b}}1p5DT9kL(as;3?^&y$)|a&*x9r-*u?E6C!gn$pS*{ci;3af z#Ku!xO^oX7;*ye#&9Re{I3G@)z$L{Ba*4p^kM?2$n;f3-FES9AB*3xxv;7bLNeRgG Pe|}a*ph{+-$}ju?RlrP6 diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue index b46f1d96..2867d7b7 100644 --- a/web_src/src/components/channelList.vue +++ b/web_src/src/components/channelList.vue @@ -21,8 +21,8 @@ 在线状态: - - + + @@ -161,7 +161,7 @@ export default { .then(function (res) { console.log(res); that.total = res.data.total; - that.deviceChannelList = res.data.data; + that.deviceChannelList = res.data.list; // 防止出现表格错位 that.$nextTick(() => { that.$refs.channelListTable.doLayout(); diff --git a/web_src/src/components/videoList.vue b/web_src/src/components/videoList.vue index 50767cc4..9e036961 100644 --- a/web_src/src/components/videoList.vue +++ b/web_src/src/components/videoList.vue @@ -21,7 +21,7 @@ @@ -140,8 +140,9 @@ } ) .then(function (res) { console.log(res); + console.log(res.data.list); that.total = res.data.total; - that.deviceList = res.data.data; + that.deviceList = res.data.list; that.getDeviceListLoading = false; }) .catch(function (error) { From b88ead03f96a5a8d9bc1b0cbd9d8bde47e1c049a Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Tue, 5 Jan 2021 11:25:05 +0800 Subject: [PATCH 42/45] =?UTF-8?q?=E5=AD=98=E5=82=A8=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BD=BF=E7=94=A8sqlite=E4=BB=A3=E6=9B=BFredis-4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transmit/cmd/impl/SIPCommander.java | 6 +--- .../vmp/storager/dao/DeviceChannelMapper.java | 3 +- .../service/impl/PlayServiceImpl.java | 7 +++++ src/main/resources/application-dev.yml | 13 ++++++-- src/main/resources/wvp.sqlite | Bin 32768 -> 32768 bytes web_src/src/components/channelList.vue | 28 ++++++++++++------ 6 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index af9030b9..13b83d16 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -357,11 +357,7 @@ public class SIPCommander implements ISIPCommander { ClientTransaction transaction = transmitRequest(device, request, errorEvent); streamSession.put(streamId, transaction); - DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId); - if (deviceChannel != null) { - deviceChannel.setStreamId(streamId); - storager.updateChannel(device.getDeviceId(), deviceChannel); - } + } catch ( SipException | ParseException | InvalidArgumentException e) { diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java index 072b1bfe..eecc0bb5 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java @@ -23,7 +23,8 @@ public interface DeviceChannelMapper { "SET name=#{name}, manufacture=#{manufacture}, model=#{model}, owner=#{owner}, civilCode=#{civilCode}, " + "block=#{block}, address=#{address}, parental=#{parental}, parentId=#{parentId}, safetyWay=#{safetyWay}, " + "registerWay=#{registerWay}, certNum=#{certNum}, certifiable=#{certifiable}, errCode=#{errCode}, secrecy=#{secrecy}, " + - "ipAddress=#{ipAddress}, port=#{port}, password=#{password}, PTZType=#{PTZType}, status=#{status} " + + "ipAddress=#{ipAddress}, port=#{port}, password=#{password}, PTZType=#{PTZType}, status=#{status}, streamId=#{streamId}, " + + "hasAudio=#{hasAudio}" + "WHERE deviceId=#{deviceId} AND channelId=#{channelId}") int update(DeviceChannel channel); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java index 6ce0868f..f4bdd2b7 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaServerConfig; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; @@ -37,6 +38,12 @@ public class PlayServiceImpl implements IPlayService { msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); if (streamInfo != null) { + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); + if (deviceChannel != null) { + deviceChannel.setStreamId(streamInfo.getStreamId()); + storager.updateChannel(deviceId, deviceChannel); + } + redisCatchStorage.startPlay(streamInfo); msg.setData(JSON.toJSONString(streamInfo)); resultHolder.invokeResult(msg); diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 6cee0cb6..7b98bd10 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -20,13 +20,20 @@ spring: timeout: 10000 # [不可用] jdbc数据库配置, 暂不支持 datasource: + # name: eiot + # url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true + # username: + # password: + # type: com.alibaba.druid.pool.DruidDataSource + # driver-class-name: com.mysql.jdbc.Driver name: eiot - url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true + url: jdbc:sqlite::resource:wvp.sqlite username: password: type: com.alibaba.druid.pool.DruidDataSource - driver-class-name: com.mysql.jdbc.Driver - + driver-class-name: org.sqlite.JDBC + max-active: 1 + min-idle: 1 # [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 server: diff --git a/src/main/resources/wvp.sqlite b/src/main/resources/wvp.sqlite index ab68634ccb6fa74bb0b623e28126efafc9832f55..023ea355e92eefd18ce96e253a769d687769c5ed 100644 GIT binary patch delta 153 zcmZo@U}|V!njkHBf`Ng71Blsxm%^sma(WyP2Ean2BF0BeB@AG$k`% viPOo)-)XWnrxb^dQc7xBW^(H0AkGSA#@fxNd2EF@f42X@zsZ2Z0n7jZxX>&2 delta 182 zcmZo@U}|V!njkHBl!1YP1BlsxmX zHe;sA#+>4tLpe*C84EX`=CKuK;pgG!0h-Uu&-i6x - 在线状态: + 在线状态: - + 自动刷新 @@ -56,7 +56,7 @@ 播放 - 停止 + 停止 查看 设备录象 @@ -98,13 +98,17 @@ export default { count: parseInt(this.$route.params.count), total: 0, beforeUrl: "/videoList", - isLoging: false + isLoging: false, + autoList: false }; }, mounted() { this.initData(); - this.updateLooper = setInterval(this.initData, 1000); + if (this.autoList) { + this.updateLooper = setInterval(this.initData, 1500); + } + }, destroyed() { this.$destroy('videojs'); @@ -179,12 +183,11 @@ export default { let deviceId = this.deviceId; this.isLoging = true; let channelId = itemData.channelId; - let getEncoding = itemData.hasAudio ? '1' : '0' - console.log("通知设备推流1:" + deviceId + " : " + channelId + ":" + getEncoding); + console.log("通知设备推流1:" + deviceId + " : " + channelId ); let that = this; this.$axios({ method: 'get', - url: '/api/play/' + deviceId + '/' + channelId + '?getEncoding=' + getEncoding + url: '/api/play/' + deviceId + '/' + channelId }).then(function (res) { console.log(res.data) let streamId = res.data.streamId; @@ -258,7 +261,7 @@ export default { }) .then(function (res) { that.total = res.data.total; - that.deviceChannelList = res.data.data; + that.deviceChannelList = res.data.list; // 防止出现表格错位 that.$nextTick(() => { that.$refs.channelListTable.doLayout(); @@ -283,6 +286,13 @@ export default { }).then(function (res) { console.log(JSON.stringify(res)); }); + }, + autoListChange: function () { + if (this.autoList) { + this.updateLooper = setInterval(this.initData, 1500); + }else{ + window.clearInterval(this.updateLooper); + } } } From 37957b74071d4c1e80ddef0b727e0e474685b749 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Tue, 5 Jan 2021 11:52:31 +0800 Subject: [PATCH 43/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c64d25bf..19bcd515 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ https://gitee.com/18010473990/wvp-GB28181.git 9. 支持直接输出RTSP、RTMP、HTTP-FLV、Websocket-FLV、HLS多种协议流地址 10. 支持国标网络校时 11. 支持公网部署, 支持wvp与zlm分开部署 -12. 支持播放h265, g.711格式的流(需要将closeWaitRTPInfo设为false). -13. 支持固定流地址,同时支持未点播时直接播放流地址,代码自动发起点播. +12. 支持播放h265, g.711格式的流 +13. 支持固定流地址和自动点播,同时支持未点播时直接播放流地址,代码自动发起点播. ( [查看WIKI](https://github.com/648540858/wvp-GB28181-pro/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E5%9B%BA%E5%AE%9A%E6%92%AD%E6%94%BE%E5%9C%B0%E5%9D%80%E4%B8%8E%E8%87%AA%E5%8A%A8%E7%82%B9%E6%92%AD)) # 待实现: 上级级联 From 59237e9a55e546e35202a991699a8c69ccf47007 Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Tue, 5 Jan 2021 14:28:18 +0800 Subject: [PATCH 44/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0application.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ef46c2ad..caf4dfcd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - active: local \ No newline at end of file + active: dev \ No newline at end of file From 3a6fc34a119ca12735f781388925bc0098b7bd5f Mon Sep 17 00:00:00 2001 From: panlinlin <648540858@qq.com> Date: Tue, 5 Jan 2021 14:35:43 +0800 Subject: [PATCH 45/45] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BD=95=E5=83=8F?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=EF=BC=8C=E4=BC=98=E5=8C=96=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transmit/cmd/impl/SIPCommander.java | 31 ++++++++++++------- .../iot/vmp/vmanager/ptz/PtzController.java | 17 +++++----- .../vmp/vmanager/record/RecordController.java | 13 ++++++-- web_src/src/components/videoList.vue | 1 + 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 13b83d16..e1d474ff 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -188,19 +188,29 @@ public class SIPCommander implements ISIPCommander { * @param moveSpeed 镜头移动速度 默认 0XFF (0-255) * @param zoomSpeed 镜头缩放速度 默认 0X1 (0-255) */ - public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) { + + /** + * 云台指令码计算 + * + * @param cmdCode 指令码 + * @param horizonSpeed 水平移动速度 + * @param verticalSpeed 垂直移动速度 + * @param zoomSpeed 缩放速度 + * @return + */ + public static String frontEndCmdString(int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed) { StringBuilder builder = new StringBuilder("A50F01"); String strTmp; strTmp = String.format("%02X", cmdCode); builder.append(strTmp, 0, 2); - strTmp = String.format("%02X", parameter1); + strTmp = String.format("%02X", horizonSpeed); builder.append(strTmp, 0, 2); - strTmp = String.format("%02X", parameter2); + strTmp = String.format("%02X", verticalSpeed); builder.append(strTmp, 0, 2); - strTmp = String.format("%X", combineCode2); + strTmp = String.format("%X", zoomSpeed); builder.append(strTmp, 0, 1).append("0"); //计算校验码 - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100; + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + horizonSpeed + verticalSpeed + (zoomSpeed & 0XF0)) % 0X100; strTmp = String.format("%02X", checkCode); builder.append(strTmp, 0, 2); return builder.toString(); @@ -249,14 +259,14 @@ public class SIPCommander implements ISIPCommander { * @param device 控制设备 * @param channelId 预览通道 * @param cmdCode 指令码 - * @param parameter1 数据1 - * @param parameter2 数据2 - * @param combineCode2 组合码2 + * @param horizonSpeed 水平移动速度 + * @param verticalSpeed 垂直移动速度 + * @param zoomSpeed 缩放速度 */ @Override - public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) { + public boolean frontEndCmd(Device device, String channelId, int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed) { try { - String cmdStr= frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2); + String cmdStr= frontEndCmdString(cmdCode, horizonSpeed, verticalSpeed, zoomSpeed); System.out.println("控制字符串:" + cmdStr); StringBuffer ptzXml = new StringBuffer(200); ptzXml.append("\r\n"); @@ -701,7 +711,6 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", null); - transmitRequest(device, request); } catch (SipException | ParseException | InvalidArgumentException e) { e.printStackTrace(); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java index 1a90977b..4c41e16f 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java @@ -29,15 +29,14 @@ public class PtzController { private IVideoManagerStorager storager; /*** - * http://localhost:8080/api/ptz/34020000001320000002_34020000001320000008?leftRight=1&upDown=0&inOut=0&moveSpeed=50&zoomSpeed=0 - * @param deviceId - * @param channelId - * @param leftRight - * @param upDown - * @param inOut - * @param moveSpeed - * @param zoomSpeed - * @return + * 云台控制 + * @param deviceId 设备id + * @param channelId 通道id + * @param cmdCode 指令码 + * @param horizonSpeed 水平移动速度 + * @param verticalSpeed 垂直移动速度 + * @param zoomSpeed 缩放速度 + * @return String 控制结果 */ @PostMapping("/ptz/{deviceId}/{channelId}") public ResponseEntity ptz(@PathVariable String deviceId,@PathVariable String channelId,int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed){ diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java index 502087ef..519d299e 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.vmanager.record; +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -32,7 +33,7 @@ public class RecordController { @Autowired private DeferredResultHolder resultHolder; - + @GetMapping("/record/{deviceId}/{channelId}") public DeferredResult> recordinfo(@PathVariable String deviceId,@PathVariable String channelId, String startTime, String endTime){ @@ -42,9 +43,17 @@ public class RecordController { Device device = storager.queryVideoDevice(deviceId); cmder.recordInfoQuery(device, channelId, startTime, endTime); - DeferredResult> result = new DeferredResult>(); + // 指定超时时间 1分钟30秒 + DeferredResult> result = new DeferredResult>(90*1000L); // 录像查询以channelId作为deviceId查询 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_RECORDINFO+channelId, result); + result.onTimeout(()->{ + RequestMessage msg = new RequestMessage(); + msg.setDeviceId(deviceId); + msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO); + msg.setData("timeout"); + resultHolder.invokeResult(msg); + }); return result; } } diff --git a/web_src/src/components/videoList.vue b/web_src/src/components/videoList.vue index 9e036961..46b4aacf 100644 --- a/web_src/src/components/videoList.vue +++ b/web_src/src/components/videoList.vue @@ -182,6 +182,7 @@ type: 'success' }); } + that.initData() that.$refs[itemData.deviceId + 'refbtn' ].loading = false; }).catch(function(e) { console.error(e)