Pārlūkot izejas kodu

Merge branch 'wvp-28181-2.0'

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
#	src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
#	src/main/resources/all-application.yml
#	web_src/src/components/dialog/devicePlayer.vue
648540858 3 gadi atpakaļ
vecāks
revīzija
dea44dcd78
81 mainītis faili ar 1832 papildinājumiem un 1260 dzēšanām
  1. 59 100
      README.md
  2. BIN
      doc/_media/2.png
  3. BIN
      doc/_media/3-1.png
  4. BIN
      doc/_media/3-2.png
  5. BIN
      doc/_media/3-3.png
  6. BIN
      doc/_media/3.png
  7. BIN
      doc/_media/index.png
  8. 1 1
      pom.xml
  9. 15 15
      sql/mysql.sql
  10. 2 42
      sql/update.sql
  11. 2 0
      src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
  12. 4 0
      src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
  13. 20 0
      src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
  14. 5 1
      src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
  15. 15 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
  16. 27 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java
  17. 35 3
      src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java
  18. 0 107
      src/main/java/com/genersoft/iot/vmp/gb28181/conf/SipLoggerPass.java
  19. 2 1
      src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
  20. 1 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
  21. 3 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  22. 4 4
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  23. 12 12
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
  24. 2 1
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
  25. 33 20
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
  26. 11 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
  27. 29 0
      src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
  28. 6 5
      src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
  29. 4 4
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
  30. 1 1
      src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
  31. 9 4
      src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
  32. 2 5
      src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java
  33. 1 1
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
  34. 13 12
      src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
  35. 25 3
      src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
  36. 23 8
      src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
  37. 63 74
      src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
  38. 1 1
      src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
  39. 7 6
      src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
  40. 4 4
      src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
  41. 10 10
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java
  42. 94 88
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
  43. 41 33
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
  44. 1 1
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
  45. 9 9
      src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
  46. 5 5
      src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java
  47. 62 62
      src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
  48. 4 4
      src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
  49. 8 8
      src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
  50. 1 1
      src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
  51. 2 2
      src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java
  52. 4 4
      src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java
  53. 7 7
      src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
  54. 18 18
      src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
  55. 8 8
      src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
  56. 12 12
      src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
  57. 3 4
      src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
  58. 1 2
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java
  59. 358 0
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
  60. 2 6
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
  61. 1 1
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
  62. 9 10
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
  63. 19 21
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
  64. 24 9
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
  65. 28 5
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
  66. 3 3
      src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
  67. 4 12
      src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
  68. 15 7
      src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java
  69. 6 7
      src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
  70. 6 2
      src/main/resources/all-application.yml
  71. 15 2
      web_src/src/components/CloudRecordDetail.vue
  72. 513 0
      web_src/src/components/GBRecordDetail.vue
  73. 2 2
      web_src/src/components/channelList.vue
  74. 8 5
      web_src/src/components/console.vue
  75. 8 4
      web_src/src/components/console/ConsoleResource.vue
  76. 47 425
      web_src/src/components/dialog/devicePlayer.vue
  77. 14 16
      web_src/src/components/dialog/recordDownload.vue
  78. 2 2
      web_src/src/components/live.vue
  79. 6 0
      web_src/src/router/index.js
  80. 11 3
      web_src/static/css/iconfont.css
  81. BIN
      web_src/static/css/iconfont.woff2

+ 59 - 100
README.md

@@ -1,4 +1,4 @@
-![logo](https://raw.githubusercontent.com/648540858/wvp-GB28181-pro/wvp-28181-2.0/web_src/static/logo.png)
+![logo](doc/_media/logo.png)
 # 开箱即用的28181协议视频平台
 
 [![Build Status](https://travis-ci.org/xia-chu/ZLMediaKit.svg?branch=master)](https://travis-ci.org/xia-chu/ZLMediaKit)
@@ -17,7 +17,7 @@ WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的开箱即用的网
 # 应用场景:
 支持浏览器无插件播放摄像头视频。  
 支持摄像机、平台、NVR等设备接入。 
-支持国标级联。  
+支持国标级联。多平台级联。跨网视频预览。
 支持rtsp/rtmp等视频流转发到国标平台。  
 支持rtsp/rtmp等推流转发到国标平台。  
 
@@ -31,62 +31,49 @@ WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的开箱即用的网
 https://gitee.com/pan648540858/wvp-GB28181-pro.git
 
 # 截图
-![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101513_79632720_1018729.png "2022-03-04_09-51.png")
-![build_1.png](https://images.gitee.com/uploads/images/2022/0304/103025_5df016f9_1018729.png "2022-03-04_10-27.png")
-![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101706_088fbafa_1018729.png "2022-03-04_09-52_1.png")
-![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101756_3d662828_1018729.png "2022-03-04_10-00_1.png")
-![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101823_19050c66_1018729.png "2022-03-04_10-12_1.png")
-![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101848_e5a39557_1018729.png "2022-03-04_10-12_2.png")
-![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101919_ee5b8c79_1018729.png "2022-03-04_10-13.png")
-
-# 1.0 基础特性  
-1. 视频预览;  
-2. 云台控制(方向、缩放控制);  
-3. 视频设备信息同步;   
-4. 离在线监控;  
-5. 录像查询与回放(基于NVR\DVR,暂不支持快进、seek操作);  
-6. 无人观看自动断流;    
-7. 支持UDP和TCP两种国标信令传输模式; 
-8. 集成web界面, 不需要单独部署前端服务, 直接利用wvp内置文件服务部署, 随wvp一起部署;   
-9. 支持平台接入, 针对大平台大量设备的情况进行优化;  
-10. 支持检索,通道筛选;  
-11. 支持自动配置ZLM媒体服务, 减少因配置问题所出现的问题;  
-12. 支持启用udp多端口模式, 提高udp模式下媒体传输性能;  
-13. 支持通道是否含有音频的设置;  
-14. 支持通道子目录查询;  
-15. 支持udp/tcp国标流传输模式;  
-16. 支持直接输出RTSP、RTMP、HTTP-FLV、Websocket-FLV、HLS多种协议流地址  
-17. 支持国标网络校时  
-18. 支持公网部署, 支持wvp与zlm分开部署   
-19. 支持播放h265, g.711格式的流(需要将closeWaitRTPInfo设为false)
-20. 报警信息处理,支持向前端推送报警信息
-
-# 1.0 新支持特性  
-1. 集成web界面, 不需要单独部署前端服务, 直接利用wvp内置文件服务部署, 随wvp一起部署;   
-2. 支持平台接入, 针对大平台大量设备的情况进行优化;  
-3. 支持检索,通道筛选;  
-4. 支持自动配置ZLM媒体服务, 减少因配置问题所出现的问题;  
-5. 支持启用udp多端口模式, 提高udp模式下媒体传输性能;  
-6. 支持通道是否含有音频的设置;  
-7. 支持通道子目录查询;  
-8. 支持udp/tcp国标流传输模式;  
-9. 支持直接输出RTSP、RTMP、HTTP-FLV、Websocket-FLV、HLS多种协议流地址  
-10. 支持国标网络校时  
-11. 支持公网部署, 支持wvp与zlm分开部署   
-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))
-14. 报警信息处理,支持向前端推送报警信息
-15. 支持订阅与通知方法
-   -  [X] 移动位置订阅
-   -  [X] 移动位置通知处理
-   -  [X] 报警事件订阅
-   -  [X] 报警事件通知处理
-   -  [X] 设备目录订阅
-   -  [X] 设备目录通知处理
-16. 移动位置查询和显示,可通过配置文件设置移动位置历史是否存储
-
-# 2.0 支持特性
-- [X] 国标通道向上级联
+![index](doc/_media/index.png "index.png")
+![2](doc/_media/2.png "2.png")
+![3](doc/_media/3.png "3.png")
+![3-1](doc/_media/3-1.png "3-1.png")
+![3-2](doc/_media/3-2.png "3-2.png")
+![3-3](doc/_media/3-3.png "3-3.png")
+![build_1](https://images.gitee.com/uploads/images/2022/0304/101919_ee5b8c79_1018729.png "2022-03-04_10-13.png")
+
+# 功能特性 
+- [X] 集成web界面
+- [X] 兼容性良好
+- [X] 支持电子地图,支持接入WGS84和GCJ02两种坐标系,并且自动转化为合适的坐标系进行展示和分发
+- [X] 接入设备
+  - [X] 视频预览
+  - [X] 无限制接入路数,能接入多少设备只取决于你的服务器性能
+  - [X] 云台控制,控制设备转向,拉近,拉远
+  - [X] 预置位查询,使用与设置
+  - [X] 查询NVR/IPC上的录像与播放,支持指定时间播放与下载
+  - [X] 无人观看自动断流,节省流量
+  - [X] 视频设备信息同步
+  - [X] 离在线监控
+  - [X] 支持直接输出RTSP、RTMP、HTTP-FLV、Websocket-FLV、HLS多种协议流地址
+  - [X] 支持通过一个流地址直接观看摄像头,无需登录以及调用任何接口
+  - [X] 支持UDP和TCP两种国标信令传输模式
+  - [X] 支持UDP和TCP两种国标流传输模式
+  - [X] 支持检索,通道筛选
+  - [X] 支持通道子目录查询
+  - [X] 支持过滤音频,防止杂音影响观看
+  - [X] 支持国标网络校时
+  - [X] 支持播放H264和H265
+  - [X] 报警信息处理,支持向前端推送报警信息
+  - [X] 支持订阅与通知方法
+    - [X] 移动位置订阅
+    - [X] 移动位置通知处理
+    - [X] 报警事件订阅
+    - [X] 报警事件通知处理
+    - [X] 设备目录订阅
+    - [X] 设备目录通知处理
+  -  [X] 移动位置查询和显示
+  - [X] 支持手动添加设备和给设备设置单独的密码
+-  [X] 支持平台对接接入
+-  [X] 支持国标级联
+  - [X] 国标通道向上级联
     - [X] WEB添加上级平台
     - [X] 注册
     - [X] 心跳保活
@@ -101,61 +88,33 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
     - [X] 目录订阅与通知
     - [X] 录像查看与播放
     - [X] GPS订阅与通知(直播推流)
-- [X] 支持手动添加设备和给设备设置单独的密码
-- [X] 添加RTSP视频
-- [X] 添加接口鉴权
-- [X] 添加RTMP视频
-- [X] 云端录像(需要部署单独服务配合使用)
+- [X] 支持自动配置ZLM媒体服务, 减少因配置问题所出现的问题;  
 - [X] 多流媒体节点,自动选择负载最低的节点使用。
-- [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。
-- [X] 支持电子地图。
-- [X] 支持接入WGS84和GCJ02两种坐标系。
-
-[//]: # (# docker快速体验)
-
-[//]: # (目前作者的docker-compose因为时间有限维护不及时,这里提供第三方提供的供大家使用,维护不易,大家记得给这位小伙伴点个star。  )
-
-[//]: # (https://github.com/SaltFish001/wvp_pro_compose)
-
-[//]: # ([https://github.com/SaltFish001/wvp_pro_compose](https://github.com/SaltFish001/wvp_pro_compose))
-
-[//]: # (这是作者维护的一个镜像,可能存在不及时的问题。)
-
-[//]: # (```shell)
-
-[//]: # (docker pull 648540858/wvp_pro)
-
-[//]: # ()
-[//]: # (docker run  --env WVP_IP="你的IP" -it -p 18080:18080 -p 30000-30500:30000-30500/udp -p 30000-30500:30000-30500/tcp -p 80:80 -p 5060:5060 -p 5060:5060/udp 648540858/wvp_pro)
-
-[//]: # (```)
-
-[//]: # (docker使用详情查看:[https://hub.docker.com/r/648540858/wvp_pro](https://hub.docker.com/r/648540858/wvp_pro))
-
-# gitee同步仓库
-https://gitee.com/pan648540858/wvp-GB28181-pro.git  
-
-# 遇到问题
+- [X] 支持启用udp多端口模式, 提高udp模式下媒体传输性能;
+- [X] 支持公网部署; 
+- [X] 支持wvp与zlm分开部署,提升平台并发能力
+- [X] 支持拉流RTSP/RTMP,分发为各种流格式,或者推送到其他国标平台
+- [X] 支持推流RTSP/RTMP,分发为各种流格式,或者推送到其他国标平台
+- [X] 支持推流鉴权
+- [X] 支持接口鉴权
+- [X] 云端录像,推流/代理/国标视频均可以录制在云端服务器,支持预览和下载
+ 
+
+# 遇到问题如何解决
 国标最麻烦的地方在于设备的兼容性,所以需要大量的设备来测试,目前作者手里的设备有限,再加上作者水平有限,所以遇到问题在所难免;
 1. 查看wiki,仔细的阅读可以帮你避免几乎所有的问题
 2. 搜索issues,这里有大部分的答案
-3. 加QQ群,这里有大量热心的小伙伴,但是前提新希望你已经仔细阅读了wiki和搜索了issues。
+3. 加QQ群(901799015),这里有大量热心的小伙伴,但是前提新希望你已经仔细阅读了wiki和搜索了issues。
 4. 你可以请作者为你解答,但是我不是免费的。
 5. 你可以把遇到问题的设备寄给我,可以更容易的复现问题。
 
-
-# 合作
-目前很多打着合作的幌子来私聊的,其实大家大可不必,目前作者没有精力,你有问题可以付费找我解答,也可以提PR
-,如果对代码有建议可以提ISSUE;也可以加群一起聊聊。我们欢迎所有有兴趣参与到项目中来的人。
-
-
-
 # 使用帮助
 QQ群: 901799015, ZLM使用文档[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)  
 QQ私信一般不回, 精力有限.欢迎大家在群里讨论.觉得项目对你有帮助,欢迎star和提交pr。
 
 # 授权协议
 本项目自有代码使用宽松的MIT协议,在保留版权信息的情况下可以自由应用于各自商用、非商业的项目。 但是本项目也零碎的使用了一些其他的开源代码,在商用的情况下请自行替代或剔除; 由于使用本项目而产生的商业纠纷或侵权行为一概与本项目及开发者无关,请自行承担法律风险。 在使用本项目代码时,也应该在授权协议中同时表明本项目依赖的第三方库的协议
+
 # 致谢
 感谢作者[夏楚](https://github.com/xia-chu) 提供这么棒的开源流媒体服务框架,并在开发过程中给予支持与帮助。     
 感谢作者[dexter langhuihui](https://github.com/langhuihui) 开源这么好用的WEB播放器。     

BIN
doc/_media/2.png


BIN
doc/_media/3-1.png


BIN
doc/_media/3-2.png


BIN
doc/_media/3-3.png


BIN
doc/_media/3.png


BIN
doc/_media/index.png


+ 1 - 1
pom.xml

@@ -11,7 +11,7 @@
 
 	<groupId>com.genersoft</groupId>
 	<artifactId>wvp-pro</artifactId>
-	<version>2.6.6</version>
+	<version>2.6.7</version>
 	<name>web video platform</name>
 	<description>国标28181视频平台</description>
 

+ 15 - 15
sql/mysql.sql

@@ -54,7 +54,7 @@ CREATE TABLE `device` (
                           `localIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
                           PRIMARY KEY (`id`),
                           UNIQUE KEY `device_deviceId_uindex` (`deviceId`)
-) ENGINE=InnoDB AUTO_INCREMENT=57 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -86,7 +86,7 @@ CREATE TABLE `device_alarm` (
                                 `alarmType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
                                 `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
                                 PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -146,7 +146,7 @@ CREATE TABLE `device_channel` (
                                   PRIMARY KEY (`id`),
                                   UNIQUE KEY `device_channel_id_uindex` (`id`),
                                   UNIQUE KEY `device_channel_pk` (`channelId`,`deviceId`)
-) ENGINE=InnoDB AUTO_INCREMENT=74416 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -183,7 +183,7 @@ CREATE TABLE `device_mobile_position` (
                                           `latitudeWgs84` double DEFAULT NULL,
                                           `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
                                           PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=55589 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -216,7 +216,7 @@ CREATE TABLE `gb_stream` (
                              PRIMARY KEY (`gbStreamId`) USING BTREE,
                              UNIQUE KEY `app` (`app`,`stream`) USING BTREE,
                              UNIQUE KEY `gbId` (`gbId`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=331060 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -246,7 +246,7 @@ CREATE TABLE `log` (
                        `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                        `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                        PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=760908 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -338,7 +338,7 @@ CREATE TABLE `parent_platform` (
                                    PRIMARY KEY (`id`),
                                    UNIQUE KEY `parent_platform_id_uindex` (`id`),
                                    UNIQUE KEY `parent_platform_pk` (`serverGBId`)
-) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -390,7 +390,7 @@ CREATE TABLE `platform_gb_channel` (
                                        `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                                        `deviceChannelId` int NOT NULL,
                                        PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=3146 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -410,13 +410,13 @@ DROP TABLE IF EXISTS `platform_gb_stream`;
 /*!40101 SET @saved_cs_client     = @@character_set_client */;
 /*!50503 SET character_set_client = utf8mb4 */;
 CREATE TABLE `platform_gb_stream` (
+                                      `id` int NOT NULL AUTO_INCREMENT,
                                       `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                                       `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                                       `gbStreamId` int NOT NULL,
-                                      `id` int NOT NULL AUTO_INCREMENT,
                                       PRIMARY KEY (`id`),
                                       UNIQUE KEY `platform_gb_stream_pk` (`platformId`,`catalogId`,`gbStreamId`)
-) ENGINE=InnoDB AUTO_INCREMENT=391772 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -458,7 +458,7 @@ CREATE TABLE `stream_proxy` (
                                 `enable_disable_none_reader` bit(1) DEFAULT NULL,
                                 PRIMARY KEY (`id`),
                                 UNIQUE KEY `stream_proxy_pk` (`app`,`stream`)
-) ENGINE=InnoDB AUTO_INCREMENT=568 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -495,7 +495,7 @@ CREATE TABLE `stream_push` (
                                `self` int DEFAULT NULL,
                                PRIMARY KEY (`id`),
                                UNIQUE KEY `stream_push_pk` (`app`,`stream`)
-) ENGINE=InnoDB AUTO_INCREMENT=361492 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -524,7 +524,7 @@ CREATE TABLE `user` (
                         `pushKey` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
                         PRIMARY KEY (`id`) USING BTREE,
                         UNIQUE KEY `user_username_uindex` (`username`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --
@@ -533,7 +533,7 @@ CREATE TABLE `user` (
 
 LOCK TABLES `user` WRITE;
 /*!40000 ALTER TABLE `user` DISABLE KEYS */;
-INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021 - 04 - 13 14:14:57','2021 - 04 - 13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
+INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
 /*!40000 ALTER TABLE `user` ENABLE KEYS */;
 UNLOCK TABLES;
 
@@ -551,7 +551,7 @@ CREATE TABLE `user_role` (
                              `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                              `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
                              PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
 /*!40101 SET character_set_client = @saved_cs_client */;
 
 --

+ 2 - 42
sql/update.sql

@@ -1,43 +1,3 @@
-alter table media_server
-    drop column streamNoneReaderDelayMS;
-
-alter table media_server
-    drop column sendRtpPortRange;
-
-alter table stream_proxy
-    add enable_disable_none_reader bit(1) default null;
-
+-- 2.6.6->2.6.7
 alter table device
-    add mediaServerId varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'auto';
-
-alter table device
-    add custom_name varchar(255) default null;
-
-alter table device
-    add sdpIp varchar(50) default null;
-
-alter table device
-    add localIp varchar(50) default null;
-
-alter table device
-    add password varchar(255) default null;
-
-alter table device
-    modify ip varchar(50) null;
-
-alter table device
-    modify port int null;
-
-alter table device
-    modify expires int null;
-
-alter table device
-    modify subscribeCycleForCatalog int null;
-
-alter table device
-    modify hostAddress varchar(50) null;
-
-alter table stream_proxy
-    change enable_hls enable_audio bit null;
-
-
+    add keepaliveIntervalTime int default null;

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java

@@ -71,6 +71,8 @@ public class VideoManagerConstants {
 	public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_";
 	public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_";
 
+	public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_";
+
 
 
 

+ 4 - 0
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java

@@ -10,6 +10,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.filter.OncePerRequestFilter;
 
 import javax.servlet.*;
@@ -51,6 +52,9 @@ public class ApiAccessFilter extends OncePerRequestFilter {
 
             LogDto logDto = new LogDto();
             logDto.setName(uriName);
+            if (ObjectUtils.isEmpty(username)) {
+                username = "";
+            }
             logDto.setUsername(username);
             logDto.setAddress(servletRequest.getRemoteAddr());
             logDto.setResult(HttpStatus.valueOf(servletResponse.getStatus()).toString());

+ 20 - 0
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java

@@ -35,6 +35,8 @@ public class UserSetting {
 
     private Boolean useSourceIpAsStreamIp = Boolean.FALSE;
 
+    private Boolean sipUseSourceIpAsRemoteAddress = Boolean.FALSE;
+
     private Boolean streamOnDemand = Boolean.TRUE;
 
     private Boolean pushAuthority = Boolean.TRUE;
@@ -45,6 +47,8 @@ public class UserSetting {
 
     private Boolean pushStreamAfterAck = Boolean.FALSE;
 
+    private Boolean sipLog = Boolean.FALSE;
+
     private String serverId = "000000";
 
     private String thirdPartyGBIdReg = "[\\s\\S]*";
@@ -206,4 +210,20 @@ public class UserSetting {
     public void setPushStreamAfterAck(Boolean pushStreamAfterAck) {
         this.pushStreamAfterAck = pushStreamAfterAck;
     }
+
+    public Boolean getSipUseSourceIpAsRemoteAddress() {
+        return sipUseSourceIpAsRemoteAddress;
+    }
+
+    public void setSipUseSourceIpAsRemoteAddress(Boolean sipUseSourceIpAsRemoteAddress) {
+        this.sipUseSourceIpAsRemoteAddress = sipUseSourceIpAsRemoteAddress;
+    }
+
+    public Boolean getSipLog() {
+        return sipLog;
+    }
+
+    public void setSipLog(Boolean sipLog) {
+        this.sipLog = sipLog;
+    }
 }

+ 5 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java

@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.gb28181;
 
 import com.genersoft.iot.vmp.conf.SipConfig;
+import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.conf.DefaultProperties;
 import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver;
 import gov.nist.javax.sip.SipProviderImpl;
@@ -29,6 +30,9 @@ public class SipLayer implements CommandLineRunner {
 	@Autowired
 	private ISIPProcessorObserver sipProcessorObserver;
 
+	@Autowired
+	private UserSetting userSetting;
+
 	private final Map<String, SipProviderImpl> tcpSipProviderMap = new ConcurrentHashMap<>();
 	private final Map<String, SipProviderImpl> udpSipProviderMap = new ConcurrentHashMap<>();
 
@@ -61,7 +65,7 @@ public class SipLayer implements CommandLineRunner {
 	private void addListeningPoint(String monitorIp, int port){
 		SipStackImpl sipStack;
 		try {
-			sipStack = (SipStackImpl)sipFactory.createSipStack(DefaultProperties.getProperties(monitorIp, false));
+			sipStack = (SipStackImpl)sipFactory.createSipStack(DefaultProperties.getProperties(monitorIp, false, userSetting.getSipLog()));
 		} catch (PeerUnavailableException e) {
 			logger.error("[Sip Server] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp);
 			return;

+ 15 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java

@@ -94,6 +94,13 @@ public class Device {
 	@Schema(description = "心跳时间")
 	private String keepaliveTime;
 
+
+	/**
+	 * 心跳间隔
+	 */
+	@Schema(description = "心跳间隔")
+	private int keepaliveIntervalTime;
+
 	/**
 	 * 通道个数
 	 */
@@ -414,4 +421,12 @@ public class Device {
 	public void setLocalIp(String localIp) {
 		this.localIp = localIp;
 	}
+
+	public int getKeepaliveIntervalTime() {
+		return keepaliveIntervalTime;
+	}
+
+	public void setKeepaliveIntervalTime(int keepaliveIntervalTime) {
+		this.keepaliveIntervalTime = keepaliveIntervalTime;
+	}
 }

+ 27 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java

@@ -0,0 +1,27 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+public class RemoteAddressInfo {
+    private String ip;
+    private int port;
+
+    public RemoteAddressInfo(String ip, int port) {
+        this.ip = ip;
+        this.port = port;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+}

+ 35 - 3
src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java

@@ -1,5 +1,9 @@
 package com.genersoft.iot.vmp.gb28181.conf;
 
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd.AlarmNotifyMessageHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.util.Properties;
 
 /**
@@ -8,10 +12,11 @@ import java.util.Properties;
  */
 public class DefaultProperties {
 
-    public static Properties getProperties(String ip, boolean isDebug) {
+    public static Properties getProperties(String ip, boolean isDebug, boolean sipLog) {
         Properties properties = new Properties();
         properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
         properties.setProperty("javax.sip.IP_ADDRESS", ip);
+        // 关闭自动会话
         properties.setProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "off");
         /**
          * 完整配置参考 gov.nist.javax.sip.SipStackImpl,需要下载源码
@@ -26,7 +31,7 @@ public class DefaultProperties {
         // 接收所有notify请求,即使没有订阅
         properties.setProperty("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "true");
         properties.setProperty("gov.nist.javax.sip.AUTOMATIC_DIALOG_ERROR_HANDLING", "false");
-        properties.setProperty("gov.nist.javax.sip.CANCEL_CLIENT_TRANSACTION_CHECKED", "false");
+        properties.setProperty("gov.nist.javax.sip.CANCEL_CLIENT_TRANSACTION_CHECKED", "true");
         // 为_NULL _对话框传递_终止的_事件
         properties.setProperty("gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG", "true");
         // 会话清理策略
@@ -35,11 +40,38 @@ public class DefaultProperties {
         properties.setProperty("gov.nist.javax.sip.RELIABLE_CONNECTION_KEEP_ALIVE_TIMEOUT", "60");
         // 获取实际内容长度,不使用header中的长度信息
         properties.setProperty("gov.nist.javax.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY", "true");
+        // 线程可重入
+        properties.setProperty("gov.nist.javax.sip.REENTRANT_LISTENER", "true");
+        // 定义应用程序打算多久审计一次 SIP 堆栈,了解其内部线程的健康状况(该属性指定连续审计之间的时间(以毫秒为单位))
+        properties.setProperty("gov.nist.javax.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS", "30000");
 
         /**
          * sip_server_log.log 和 sip_debug_log.log ERROR, INFO, WARNING, OFF, DEBUG, TRACE
          */
-        properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "ERROR");
+        Logger logger = LoggerFactory.getLogger(AlarmNotifyMessageHandler.class);
+        if (sipLog) {
+            if (logger.isDebugEnabled()) {
+                System.out.println("DEBUG");
+                properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "DEBUG");
+            }else if (logger.isInfoEnabled()) {
+                System.out.println("INFO1");
+                properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "INFO");
+            }else if (logger.isWarnEnabled()) {
+                System.out.println("WARNING");
+                properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "WARNING");
+            }else if (logger.isErrorEnabled()) {
+                System.out.println("ERROR");
+                properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "ERROR");
+            }else {
+                System.out.println("INFO2");
+                properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "INFO");
+            }
+            logger.info("[SIP日志]级别为: {}", properties.getProperty("gov.nist.javax.sip.TRACE_LEVEL"));
+        }else {
+            logger.info("[SIP日志]已关闭");
+        }
+
+
 
         return properties;
     }

+ 0 - 107
src/main/java/com/genersoft/iot/vmp/gb28181/conf/SipLoggerPass.java

@@ -1,107 +0,0 @@
-package com.genersoft.iot.vmp.gb28181.conf;
-
-import gov.nist.core.StackLogger;
-
-import java.util.Properties;
-
-/**
- * sip日志格式化
- * 暂不使用
- */
-public class SipLoggerPass implements StackLogger {
-
-    @Override
-    public void logStackTrace() {
-
-    }
-
-    @Override
-    public void logStackTrace(int traceLevel) {
-
-    }
-
-    @Override
-    public int getLineCount() {
-        return 0;
-    }
-
-    @Override
-    public void logException(Throwable ex) {
-
-    }
-
-    @Override
-    public void logDebug(String message) {
-
-    }
-
-    @Override
-    public void logDebug(String message, Exception ex) {
-
-    }
-
-    @Override
-    public void logTrace(String message) {
-
-    }
-
-    @Override
-    public void logFatalError(String message) {
-
-    }
-
-    @Override
-    public void logError(String message) {
-
-    }
-
-    @Override
-    public boolean isLoggingEnabled() {
-        return false;
-    }
-
-    @Override
-    public boolean isLoggingEnabled(int logLevel) {
-        return false;
-    }
-
-    @Override
-    public void logError(String message, Exception ex) {
-
-    }
-
-    @Override
-    public void logWarning(String string) {
-
-    }
-
-    @Override
-    public void logInfo(String string) {
-
-    }
-
-    @Override
-    public void disableLogging() {
-
-    }
-
-    @Override
-    public void enableLogging() {
-
-    }
-
-    @Override
-    public void setBuildTimeStamp(String buildTimeStamp) {
-
-    }
-
-    @Override
-    public void setStackProperties(Properties stackProperties) {
-
-    }
-
-    @Override
-    public String getLoggerName() {
-        return null;
-    }
-}

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java

@@ -13,7 +13,7 @@ import org.springframework.util.ObjectUtils;
 import java.util.ArrayList;
 import java.util.List;
 
-/**    
+/**
  * @description:视频流session管理器,管理视频预览、预览回放的通信句柄 
  * @author: swwheihei
  * @date:   2020年5月13日 下午4:03:02     
@@ -51,6 +51,7 @@ public class VideoStreamSessionManager {
 		ssrcTransaction.setSsrc(ssrc);
 		ssrcTransaction.setMediaServerId(mediaServerId);
 		ssrcTransaction.setType(type);
+
 		RedisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId()
 				+ "_" +  deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
 	}

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java

@@ -64,7 +64,7 @@ public interface ISIPCommanderForPlatform {
      * @param fromTag
      * @return
      */
-    void deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException;
+    void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException;
 
     /**
      * 向上级回复移动位置订阅消息

+ 3 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@@ -574,10 +574,11 @@ public class SIPCommander implements ISIPCommander {
         if (inviteStreamCallback != null) {
             inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream()));
         }
+
         sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent -> {
             ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
             SIPResponse response = (SIPResponse) responseEvent.getResponse();
-            streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download);
+            streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download);
         });
     }
 
@@ -774,7 +775,7 @@ public class SIPCommander implements ISIPCommander {
         cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
         cmdXml.append("</Control>\r\n");
 
-
+        
 
         Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
         sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);

+ 4 - 4
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@@ -287,19 +287,20 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
      * @return
      */
     @Override
-    public void deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag) throws SipException, InvalidArgumentException, ParseException {
+    public void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException {
         if (parentPlatform == null) {
             return ;
         }
+        String statusStr = (status==1)?"ONLINE":"OFFLINE";
         String characterSet = parentPlatform.getCharacterSet();
         StringBuffer deviceStatusXml = new StringBuffer(600);
         deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
         deviceStatusXml.append("<Response>\r\n");
         deviceStatusXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
         deviceStatusXml.append("<SN>" +sn + "</SN>\r\n");
-        deviceStatusXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n");
+        deviceStatusXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
         deviceStatusXml.append("<Result>OK</Result>\r\n");
-        deviceStatusXml.append("<Online>ONLINE</Online>\r\n");
+        deviceStatusXml.append("<Online>"+statusStr+"</Online>\r\n");
         deviceStatusXml.append("<Status>OK</Status>\r\n");
         deviceStatusXml.append("</Response>\r\n");
 
@@ -307,7 +308,6 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
 
         Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceStatusXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader);
         sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);
-
     }
 
     @Override

+ 12 - 12
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java

@@ -1,13 +1,16 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
 
 import com.genersoft.iot.vmp.conf.SipConfig;
+import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
 import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
+import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import gov.nist.javax.sip.RequestEventExt;
@@ -59,6 +62,9 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
     @Autowired
     private SIPSender sipSender;
 
+    @Autowired
+    private UserSetting userSetting;
+
     @Override
     public void afterPropertiesSet() throws Exception {
         // 添加消息处理的订阅
@@ -128,15 +134,9 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
             // 添加Expires头
             response.addHeader(request.getExpires());
 
-            // 获取到通信地址等信息
-            ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
-            String received = viaHeader.getReceived();
-            int rPort = viaHeader.getRPort();
-            // 解析本地地址替代
-            if (ObjectUtils.isEmpty(received) || rPort == -1) {
-                received = viaHeader.getHost();
-                rPort = viaHeader.getPort();
-            }
+            RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
+                    userSetting.getSipUseSourceIpAsRemoteAddress());
+
             if (device == null) {
                 device = new Device();
                 device.setStreamMode("UDP");
@@ -146,9 +146,9 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
                 device.setDeviceId(deviceId);
                 device.setOnline(0);
             }
-            device.setIp(received);
-            device.setPort(rPort);
-            device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
+            device.setIp(remoteAddressInfo.getIp());
+            device.setPort(remoteAddressInfo.getPort());
+            device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort())));
             device.setLocalIp(request.getLocalAddress().getHostAddress());
             if (request.getExpires().getExpires() == 0) {
                 // 注销成功

+ 2 - 1
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java

@@ -67,6 +67,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
     @Override
     public void process(RequestEvent evt) {
         SIPRequest sipRequest = (SIPRequest)evt.getRequest();
+        logger.info("接收到消息:" + evt.getRequest());
         logger.debug("接收到消息:" + evt.getRequest());
         String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
         CallIdHeader callIdHeader = sipRequest.getCallIdHeader();
@@ -94,7 +95,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
             if (device == null && parentPlatform == null) {
                 // 不存在则回复404
                 responseAck(request, Response.NOT_FOUND, "device "+ deviceId +" not found");
-                logger.warn("[设备未找到 ]: {}", deviceId);
+                logger.warn("[设备未找到 ]deviceId: {}, callId: {}", deviceId, callIdHeader.getCallId());
                 if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){
                     DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog());
                     deviceNotFoundEvent.setCallId(callIdHeader.getCallId());

+ 33 - 20
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java

@@ -1,14 +1,16 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
 
+import com.genersoft.iot.vmp.common.VideoManagerConstants;
+import com.genersoft.iot.vmp.conf.DynamicTask;
+import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
-import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
+import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
+import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import com.genersoft.iot.vmp.service.IDeviceService;
-import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
-import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import gov.nist.javax.sip.message.SIPRequest;
 import org.dom4j.Element;
@@ -17,13 +19,10 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
-import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
 
 import javax.sip.InvalidArgumentException;
 import javax.sip.RequestEvent;
 import javax.sip.SipException;
-import javax.sip.header.ViaHeader;
 import javax.sip.message.Response;
 import java.text.ParseException;
 
@@ -33,6 +32,7 @@ import java.text.ParseException;
 @Component
 public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
 
+
     private Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class);
     private final static String cmdType = "Keepalive";
 
@@ -42,6 +42,12 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
     @Autowired
     private IDeviceService deviceService;
 
+    @Autowired
+    private UserSetting userSetting;
+
+    @Autowired
+    private DynamicTask dynamicTask;
+
     @Override
     public void afterPropertiesSet() throws Exception {
         notifyMessageHandler.addHandler(cmdType, this);
@@ -53,26 +59,27 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
             // 未注册的设备不做处理
             return;
         }
+        SIPRequest request = (SIPRequest) evt.getRequest();
         // 回复200 OK
         try {
-            responseAck((SIPRequest) evt.getRequest(), Response.OK);
+            responseAck(request, Response.OK);
         } catch (SipException | InvalidArgumentException | ParseException e) {
-            logger.error("[命令发送失败] 国标级联 心跳回复: {}", e.getMessage());
+            logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
         }
-        // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息
-        // 获取到通信地址等信息
-        ViaHeader viaHeader = (ViaHeader) evt.getRequest().getHeader(ViaHeader.NAME);
-        String received = viaHeader.getReceived();
-        int rPort = viaHeader.getRPort();
-        // 解析本地地址替代
-        if (ObjectUtils.isEmpty(received) || rPort == -1) {
-            received = viaHeader.getHost();
-            rPort = viaHeader.getPort();
+
+        RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress());
+        if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) {
+            device.setPort(remoteAddressInfo.getPort());
+            device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort())));
+            device.setIp(remoteAddressInfo.getIp());
         }
-        if (device.getPort() != rPort) {
-            device.setPort(rPort);
-            device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
+        if (device.getKeepaliveTime() == null) {
+            device.setKeepaliveIntervalTime(60);
+        }else {
+            long lastTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(device.getKeepaliveTime());
+            device.setKeepaliveIntervalTime(new Long(System.currentTimeMillis()/1000-lastTime).intValue());
         }
+
         device.setKeepaliveTime(DateUtil.getNow());
 
         if (device.getOnline() == 1) {
@@ -80,9 +87,15 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
         }else {
             // 对于已经离线的设备判断他的注册是否已经过期
             if (!deviceService.expire(device)){
+                device.setOnline(0);
                 deviceService.online(device);
             }
         }
+        // 刷新过期任务
+        String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId();
+        // 如果三次心跳失败,则设置设备离线
+        dynamicTask.startDelay(registerExpireTaskKey, ()-> deviceService.offline(device.getDeviceId()), device.getKeepaliveIntervalTime()*1000*3);
+
     }
 
     @Override

+ 11 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java

@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.
 
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
@@ -24,6 +25,8 @@ import javax.sip.header.FromHeader;
 import javax.sip.message.Response;
 import java.text.ParseException;
 
+import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
+
 @Component
 public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
 
@@ -62,13 +65,19 @@ public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent i
         FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
         // 回复200 OK
         try {
-             responseAck((SIPRequest) evt.getRequest(), Response.OK);
+            responseAck((SIPRequest) evt.getRequest(), Response.OK);
         } catch (SipException | InvalidArgumentException | ParseException e) {
             logger.error("[命令发送失败] 国标级联 DeviceStatus查询回复200OK: {}", e.getMessage());
         }
         String sn = rootElement.element("SN").getText();
+        String channelId = getText(rootElement, "DeviceID");
+        DeviceChannel deviceChannel = storager.queryChannelInParentPlatform(parentPlatform.getServerGBId(), channelId);
+        if (deviceChannel ==null){
+            logger.error("[平台没有该通道的使用权限]:platformId"+parentPlatform.getServerGBId()+"  deviceID:"+channelId);
+            return;
+        }
         try {
-            cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag());
+            cmderFroPlatform.deviceStatusResponse(parentPlatform,channelId, sn, fromHeader.getTag(),deviceChannel.getStatus());
         } catch (SipException | InvalidArgumentException | ParseException e) {
             logger.error("[命令发送失败] 国标级联 DeviceStatus查询回复: {}", e.getMessage());
         }

+ 29 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java

@@ -1,9 +1,11 @@
 package com.genersoft.iot.vmp.gb28181.utils;
 
+import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
 import com.genersoft.iot.vmp.utils.GitUtil;
 import gov.nist.javax.sip.address.AddressImpl;
 import gov.nist.javax.sip.address.SipUri;
 import gov.nist.javax.sip.header.Subject;
+import gov.nist.javax.sip.message.SIPRequest;
 import org.springframework.util.ObjectUtils;
 
 import javax.sip.PeerUnavailableException;
@@ -139,4 +141,31 @@ public class SipUtils {
         int typeCodeFromGbCode = getTypeCodeFromGbCode(deviceId);
         return typeCodeFromGbCode > 130 && typeCodeFromGbCode < 199;
     }
+    /**
+     * 从请求中获取设备ip地址和端口号
+     * @param request 请求
+     * @param sipUseSourceIpAsRemoteAddress  false 从via中获取地址, true 直接获取远程地址
+     * @return 地址信息
+     */
+    public static RemoteAddressInfo getRemoteAddressFromRequest(SIPRequest request, boolean sipUseSourceIpAsRemoteAddress) {
+
+        String remoteAddress;
+        int remotePort;
+        if (sipUseSourceIpAsRemoteAddress) {
+            remoteAddress = request.getRemoteAddress().getHostAddress();
+            remotePort = request.getRemotePort();
+        }else {
+            // 判断RPort是否改变,改变则说明路由nat信息变化,修改设备信息
+            // 获取到通信地址等信息
+            remoteAddress = request.getTopmostViaHeader().getReceived();
+            remotePort = request.getTopmostViaHeader().getRPort();
+            // 解析本地地址替代
+            if (ObjectUtils.isEmpty(remoteAddress) || remotePort == -1) {
+                remoteAddress = request.getTopmostViaHeader().getHost();
+                remotePort = request.getTopmostViaHeader().getPort();
+            }
+        }
+
+        return new RemoteAddressInfo(remoteAddress, remotePort);
+    }
 }

+ 6 - 5
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java

@@ -19,6 +19,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
 import com.genersoft.iot.vmp.service.*;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -445,7 +446,7 @@ public class ZLMHttpHookListener {
 								}
 								StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem,
 										param.getApp(), param.getStream(), param.getTracks(), callId);
-								param.setStreamInfo(streamInfoByAppAndStream);
+								param.setStreamInfo(new StreamContent(streamInfoByAppAndStream));
 								redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param);
 								if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
 										|| param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
@@ -463,7 +464,7 @@ public class ZLMHttpHookListener {
 								}
 								GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
 								if (gbStream != null) {
-//								eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
+//									eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
 								}
 								zlmMediaListManager.removeMedia(param.getApp(), param.getStream());
 							}
@@ -534,7 +535,7 @@ public class ZLMHttpHookListener {
 		logger.info("[ZLM HOOK]流无人观看:{]->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
-		// 录像下载
+		// 国标类型的流
 		if ("rtp".equals(param.getApp())){
 			ret.put("close", userSetting.getStreamOnDemand());
 			// 国标流, 点播/录像回放/录像下载
@@ -641,7 +642,7 @@ public class ZLMHttpHookListener {
 	@ResponseBody
 	@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
 	public JSONObject onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param){
-		logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}" + param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
+		logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
 		taskExecutor.execute(()->{
 			MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
 			if (userSetting.isAutoApplyPlay() && mediaInfo != null) {
@@ -709,7 +710,7 @@ public class ZLMHttpHookListener {
 	@PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8")
 	public JSONObject onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param){
 
-		logger.info("[ZLM HOOK] 发送rtp被动关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream());
+		logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream());
 
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);

+ 4 - 4
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java

@@ -1,6 +1,6 @@
 package com.genersoft.iot.vmp.media.zlm.dto.hook;
 
-import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 
 import java.util.List;
 
@@ -291,7 +291,7 @@ public class OnStreamChangedHookParam extends HookParam{
         }
     }
 
-    private StreamInfo streamInfo;
+    private StreamContent streamInfo;
 
     public String getApp() {
         return app;
@@ -407,11 +407,11 @@ public class OnStreamChangedHookParam extends HookParam{
         this.docker = docker;
     }
 
-    public StreamInfo getStreamInfo() {
+    public StreamContent getStreamInfo() {
         return streamInfo;
     }
 
-    public void setStreamInfo(StreamInfo streamInfo) {
+    public void setStreamInfo(StreamContent streamInfo) {
         this.streamInfo = streamInfo;
     }
 

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java

@@ -37,7 +37,7 @@ public interface IMediaServerService {
      */
     void zlmServerOffline(String mediaServerId);
 
-    MediaServerItem getMediaServerForMinimumLoad();
+    MediaServerItem getMediaServerForMinimumLoad(Boolean hasAssist);
 
     void setZLMConfig(MediaServerItem mediaServerItem, boolean restart);
 

+ 9 - 4
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java

@@ -40,15 +40,20 @@ public interface IPlayService {
 
     MediaServerItem getNewMediaServerItem(Device device);
 
+    /**
+     * 获取包含assist服务的节点
+     */
+    MediaServerItem getNewMediaServerItemHasAssist(Device device);
+
     void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String toString);
 
-    DeferredResult<WVPResult<StreamInfo>> playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
-    DeferredResult<WVPResult<StreamInfo>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
+    void playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback);
+    void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
 
     void zlmServerOffline(String mediaServerId);
 
-    DeferredResult<WVPResult<StreamInfo>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
-    DeferredResult<WVPResult<StreamInfo>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId,  String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
+    void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback);
+    void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId,  String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
 
     StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
 

+ 2 - 5
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java

@@ -1,10 +1,7 @@
 package com.genersoft.iot.vmp.service.bean;
 
-import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
-import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+public interface PlayBackCallback<T> {
 
-public interface PlayBackCallback {
-
-    void call(PlayBackResult<RequestMessage> msg);
+    void call(PlayBackResult<T> msg);
 
 }

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java

@@ -99,7 +99,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
         HashMap<String, DeviceChannel> channelsInStore = new HashMap<>();
         Device device = deviceMapper.getDeviceByDeviceId(deviceId);
         if (channels != null && channels.size() > 0) {
-            List<DeviceChannel> channelList = channelMapper.queryChannels(deviceId, null, null, null, null);
+            List<DeviceChannel> channelList = channelMapper.queryChannels(deviceId, null, null, null, null,null);
             if (channelList.size() == 0) {
                 for (DeviceChannel channel : channels) {
                     channel.setDeviceId(deviceId);

+ 13 - 12
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.service.impl;
 
+import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.*;
@@ -46,8 +47,6 @@ public class DeviceServiceImpl implements IDeviceService {
 
     private final static Logger logger = LoggerFactory.getLogger(DeviceServiceImpl.class);
 
-    private final String  registerExpireTaskKeyPrefix = "device-register-expire-";
-
     @Autowired
     private DynamicTask dynamicTask;
 
@@ -108,7 +107,10 @@ public class DeviceServiceImpl implements IDeviceService {
             redisCatchStorage.clearCatchByDeviceId(device.getDeviceId());
         }
         device.setUpdateTime(now);
-
+        if (device.getKeepaliveIntervalTime() == 0) {
+            // 默认心跳间隔60
+            device.setKeepaliveIntervalTime(60);
+        }
         // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询
         if (device.getCreateTime() == null) {
             device.setOnline(1);
@@ -123,7 +125,6 @@ public class DeviceServiceImpl implements IDeviceService {
             }
             sync(device);
         }else {
-
             if(device.getOnline() == 0){
                 device.setOnline(1);
                 device.setCreateTime(now);
@@ -160,18 +161,19 @@ public class DeviceServiceImpl implements IDeviceService {
             addMobilePositionSubscribe(device);
         }
         // 刷新过期任务
-        String registerExpireTaskKey = registerExpireTaskKeyPrefix + device.getDeviceId();
-        dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId()), device.getExpires() * 1000);
+        String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId();
+        // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线
+        dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId()), device.getKeepaliveIntervalTime() * 1000 * 3);
     }
 
     @Override
     public void offline(String deviceId) {
-        logger.info("[设备离线], device:{}", deviceId);
+        logger.error("[设备离线], device:{}", deviceId);
         Device device = deviceMapper.getDeviceByDeviceId(deviceId);
         if (device == null) {
             return;
         }
-        String registerExpireTaskKey = registerExpireTaskKeyPrefix + deviceId;
+        String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId;
         dynamicTask.stop(registerExpireTaskKey);
         device.setOnline(0);
         redisCatchStorage.updateDevice(device);
@@ -356,7 +358,6 @@ public class DeviceServiceImpl implements IDeviceService {
         device.setUpdateTime(DateUtil.getNow());
         if (deviceMapper.update(device) > 0) {
             redisCatchStorage.updateDevice(device);
-
         }
     }
 
@@ -432,7 +433,7 @@ public class DeviceServiceImpl implements IDeviceService {
             if (parentId.length() < 14 ) {
                 return null;
             }
-            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null);
+            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null);
             List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(deviceChannels, parentId);
             return trees;
         }
@@ -477,7 +478,7 @@ public class DeviceServiceImpl implements IDeviceService {
             if (parentId.length() < 14 ) {
                 return null;
             }
-            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null);
+            List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null);
             return deviceChannels;
         }
 
@@ -541,7 +542,7 @@ public class DeviceServiceImpl implements IDeviceService {
                 }
             }else {
                 if (haveChannel) {
-                    List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, null, null, null, null);
+                    List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, null, null, null, null,null);
                     if (deviceChannels != null && deviceChannels.size() > 0) {
                         result.addAll(deviceChannels);
                     }

+ 25 - 3
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java

@@ -501,7 +501,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
      * @return MediaServerItem
      */
     @Override
-    public MediaServerItem getMediaServerForMinimumLoad() {
+    public MediaServerItem getMediaServerForMinimumLoad(Boolean hasAssist) {
         String key = VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId();
 
         if (RedisUtil.zSize(key)  == null || RedisUtil.zSize(key) == 0) {
@@ -514,9 +514,31 @@ public class MediaServerServiceImpl implements IMediaServerService {
         // 获取分数最低的,及并发最低的
         Set<Object> objects = RedisUtil.zRange(key, 0, -1);
         ArrayList<Object> mediaServerObjectS = new ArrayList<>(objects);
+        MediaServerItem mediaServerItem = null;
+        if (hasAssist == null) {
+            String mediaServerId = (String)mediaServerObjectS.get(0);
+            mediaServerItem = getOne(mediaServerId);
+        }else if (hasAssist) {
+            for (Object mediaServerObject : mediaServerObjectS) {
+                String mediaServerId = (String)mediaServerObject;
+                MediaServerItem serverItem = getOne(mediaServerId);
+                if (serverItem.getRecordAssistPort() > 0) {
+                    mediaServerItem = serverItem;
+                    break;
+                }
+            }
+        }else if (!hasAssist) {
+            for (Object mediaServerObject : mediaServerObjectS) {
+                String mediaServerId = (String)mediaServerObject;
+                MediaServerItem serverItem = getOne(mediaServerId);
+                if (serverItem.getRecordAssistPort() == 0) {
+                    mediaServerItem = serverItem;
+                    break;
+                }
+            }
+        }
 
-        String mediaServerId = (String)mediaServerObjectS.get(0);
-        return getOne(mediaServerId);
+        return mediaServerItem;
     }
 
     /**

+ 23 - 8
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java

@@ -135,14 +135,7 @@ public class PlatformServiceImpl implements IPlatformService {
             dynamicTask.startCron(registerTaskKey,
                 // 注册失败(注册成功时由程序直接调用了online方法)
                 ()-> {
-                    try {
-                        logger.info("[国标级联] 平台:{}注册即将到期,重新注册", parentPlatform.getServerGBId());
-                        commanderForPlatform.register(parentPlatform, eventResult -> {
-                            offline(parentPlatform, false);
-                        },null);
-                    } catch (InvalidArgumentException | ParseException | SipException e) {
-                        logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage());
-                    }
+                    registerTask(parentPlatform);
                 },
                 (parentPlatform.getExpires() - 10) *1000);
         }
@@ -194,6 +187,28 @@ public class PlatformServiceImpl implements IPlatformService {
         }
     }
 
+    private void registerTask(ParentPlatform parentPlatform){
+        try {
+            // 设置超时重发, 后续从底层支持消息重发
+            String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout";
+            if (dynamicTask.isAlive(key)) {
+                return;
+            }
+            dynamicTask.startDelay(key, ()->{
+                registerTask(parentPlatform);
+            }, 1000);
+            logger.info("[国标级联] 平台:{}注册即将到期,重新注册", parentPlatform.getServerGBId());
+            commanderForPlatform.register(parentPlatform, eventResult -> {
+                dynamicTask.stop(key);
+                offline(parentPlatform, false);
+            },eventResult -> {
+                dynamicTask.stop(key);
+            });
+        } catch (InvalidArgumentException | ParseException | SipException e) {
+            logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage());
+        }
+    }
+
     @Override
     public void offline(ParentPlatform parentPlatform, boolean stopRegister) {
         logger.info("[平台离线]:{}", parentPlatform.getServerGBId());

+ 63 - 74
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java

@@ -45,11 +45,8 @@ import gov.nist.javax.sip.message.SIPResponse;
 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.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Service;
 import org.springframework.util.ObjectUtils;
-import org.springframework.web.context.request.async.DeferredResult;
 
 import javax.sip.InvalidArgumentException;
 import javax.sip.ResponseEvent;
@@ -454,6 +451,9 @@ public class PlayServiceImpl implements IPlayService {
                     mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
                     streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
                     mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
+                    // 取消订阅消息监听
+                    HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
+                    subscribe.removeSubscribe(hookSubscribe);
                 }
             }
         }, userSetting.getPlayTimeout());
@@ -463,7 +463,6 @@ public class PlayServiceImpl implements IPlayService {
             dynamicTask.stop(timeOutTaskKey);
             // 释放ssrc
             mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
-
             streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
 
             RequestMessage msg = new RequestMessage();
@@ -481,7 +480,7 @@ public class PlayServiceImpl implements IPlayService {
                 onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId);
                 hookEvent.response(mediaServerItemInuse, response);
                 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
-                String streamUrl = String.format("rtsp://127.0.0.1:%s/%s/%s", mediaServerItemInuse.getRtspPort(), "rtp",  ssrcInfo.getStream());
+                String streamUrl = String.format("http://127.0.0.1:%s/%s/%s.live.flv", mediaServerItemInuse.getHttpPort(), "rtp",  ssrcInfo.getStream());
                 String path = "snap";
                 String fileName = device.getDeviceId() + "_" + channelId + ".jpg";
                 // 请求截图
@@ -589,14 +588,10 @@ public class PlayServiceImpl implements IPlayService {
         }
     }
 
-    private void onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) {
-        RequestMessage msg = new RequestMessage();
-        msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId);
-        if (!ObjectUtils.isEmpty(uuid)) {
-            msg.setId(uuid);
-        }
-        StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
+    private void onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, PlayBackCallback playBackCallback) {
 
+        StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
+        PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>();
         if (streamInfo != null) {
             DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
             if (deviceChannel != null) {
@@ -605,17 +600,16 @@ public class PlayServiceImpl implements IPlayService {
             }
             redisCatchStorage.startPlay(streamInfo);
 
-            WVPResult wvpResult = new WVPResult();
-            wvpResult.setCode(ErrorCode.SUCCESS.getCode());
-            wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
-            wvpResult.setData(streamInfo);
-            msg.setData(wvpResult);
 
-            resultHolder.invokeAllResult(msg);
+            playBackResult.setCode(ErrorCode.SUCCESS.getCode());
+            playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());
+            playBackResult.setData(streamInfo);
+            playBackCallback.call(playBackResult);
         } else {
             logger.warn("录像回放调用失败!");
-            msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "录像回放调用失败!"));
-            resultHolder.invokeAllResult(msg);
+            playBackResult.setCode(ErrorCode.ERROR100.getCode());
+            playBackResult.setMsg("录像回放调用失败!");
+            playBackCallback.call(playBackResult);
         }
     }
 
@@ -626,7 +620,7 @@ public class PlayServiceImpl implements IPlayService {
         }
         MediaServerItem mediaServerItem;
         if (ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
-            mediaServerItem = mediaServerService.getMediaServerForMinimumLoad();
+            mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(null);
         } else {
             mediaServerItem = mediaServerService.getOne(device.getMediaServerId());
         }
@@ -637,45 +631,56 @@ public class PlayServiceImpl implements IPlayService {
     }
 
     @Override
-    public DeferredResult<WVPResult<StreamInfo>> playBack(String deviceId, String channelId, String startTime,
+    public MediaServerItem getNewMediaServerItemHasAssist(Device device) {
+        if (device == null) {
+            return null;
+        }
+        MediaServerItem mediaServerItem;
+        if (ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
+            mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(true);
+        } else {
+            mediaServerItem = mediaServerService.getOne(device.getMediaServerId());
+        }
+        if (mediaServerItem == null) {
+            logger.warn("[获取可用的ZLM节点]未找到可使用的ZLM...");
+        }
+        return mediaServerItem;
+    }
+
+    @Override
+    public void playBack(String deviceId, String channelId, String startTime,
                                                           String endTime, InviteStreamCallback inviteStreamCallback,
                                                           PlayBackCallback callback) {
         Device device = storager.queryVideoDevice(deviceId);
         if (device == null) {
-            return null;
+            return;
         }
         MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
         SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, device.isSsrcCheck(), true);
 
-        return playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback);
+        playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback);
     }
 
     @Override
-    public DeferredResult<WVPResult<StreamInfo>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
+    public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
                                                           String deviceId, String channelId, String startTime,
                                                           String endTime, InviteStreamCallback infoCallBack,
                                                           PlayBackCallback playBackCallback) {
         if (mediaServerItem == null || ssrcInfo == null) {
-            return null;
+            return;
         }
-        String uuid = UUID.randomUUID().toString();
-        String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
+
         Device device = storager.queryVideoDevice(deviceId);
         if (device == null) {
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在");
         }
-        DeferredResult<WVPResult<StreamInfo>> result = new DeferredResult<>(30000L);
-        resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId, uuid, result);
-        RequestMessage requestMessage = new RequestMessage();
-        requestMessage.setId(uuid);
-        requestMessage.setKey(key);
-        PlayBackResult<RequestMessage> playBackResult = new PlayBackResult<>();
+
+        PlayBackResult<StreamInfo> playBackResult = new PlayBackResult<>();
         String playBackTimeOutTaskKey = UUID.randomUUID().toString();
         dynamicTask.startDelay(playBackTimeOutTaskKey, () -> {
             logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
             playBackResult.setCode(ErrorCode.ERROR100.getCode());
             playBackResult.setMsg("回放超时");
-            playBackResult.setData(requestMessage);
 
             try {
                 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
@@ -687,19 +692,14 @@ public class PlayServiceImpl implements IPlayService {
                 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
                 streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
             }
-
             // 回复之前所有的点播请求
             playBackCallback.call(playBackResult);
-            result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "回放超时"));
-            resultHolder.exist(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId, uuid);
         }, userSetting.getPlayTimeout());
 
         SipSubscribe.Event errorEvent = event -> {
             dynamicTask.stop(playBackTimeOutTaskKey);
-            requestMessage.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg)));
             playBackResult.setCode(ErrorCode.ERROR100.getCode());
             playBackResult.setMsg(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
-            playBackResult.setData(requestMessage);
             playBackResult.setEvent(event);
             playBackCallback.call(playBackResult);
             streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
@@ -717,11 +717,9 @@ public class PlayServiceImpl implements IPlayService {
                 return;
             }
             redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());
-            WVPResult<StreamInfo> success = WVPResult.success(streamInfo);
-            requestMessage.setData(success);
             playBackResult.setCode(ErrorCode.SUCCESS.getCode());
             playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());
-            playBackResult.setData(requestMessage);
+            playBackResult.setData(streamInfo);
             playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
             playBackResult.setResponse(inviteStreamInfo.getResponse());
             playBackCallback.call(playBackResult);
@@ -768,7 +766,7 @@ public class PlayServiceImpl implements IPlayService {
                                             logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
                                             dynamicTask.stop(playBackTimeOutTaskKey);
                                             // hook响应
-                                            onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid);
+                                            onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, playBackCallback);
                                             hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));
                                         });
                                     }
@@ -788,50 +786,45 @@ public class PlayServiceImpl implements IPlayService {
             eventResult.msg = "命令发送失败";
             errorEvent.response(eventResult);
         }
-        return result;
     }
 
 
 
     @Override
-    public DeferredResult<WVPResult<StreamInfo>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
+    public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback playBackCallback) {
         Device device = storager.queryVideoDevice(deviceId);
         if (device == null) {
-            return null;
+            return;
+        }
+        MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device);
+        if (newMediaServerItem == null) {
+            PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();
+            downloadResult.setCode(ErrorCode.ERROR100.getCode());
+            downloadResult.setMsg("未找到assist服务");
+            playBackCallback.call(downloadResult);
+            return;
         }
-        MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
         SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, device.isSsrcCheck(), true);
 
-        return download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, hookCallBack);
+        download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed, infoCallBack, playBackCallback);
     }
 
+
     @Override
-    public DeferredResult<WVPResult<StreamInfo>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
+    public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
         if (mediaServerItem == null || ssrcInfo == null) {
-            return null;
+            return;
         }
-        String uuid = UUID.randomUUID().toString();
-        String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
-        DeferredResult<WVPResult<StreamInfo>> result = new DeferredResult<>(30000L);
+
         Device device = storager.queryVideoDevice(deviceId);
         if (device == null) {
             throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在");
         }
-
-        resultHolder.put(key, uuid, result);
-        RequestMessage requestMessage = new RequestMessage();
-        requestMessage.setId(uuid);
-        requestMessage.setKey(key);
-        WVPResult<StreamInfo> wvpResult = new WVPResult<>();
-        requestMessage.setData(wvpResult);
-        PlayBackResult<RequestMessage> downloadResult = new PlayBackResult<>();
-        downloadResult.setData(requestMessage);
+        PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();
 
         String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
         dynamicTask.startDelay(downLoadTimeOutTaskKey, () -> {
             logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
-            wvpResult.setCode(ErrorCode.ERROR100.getCode());
-            wvpResult.setMsg("录像下载请求超时");
             downloadResult.setCode(ErrorCode.ERROR100.getCode());
             downloadResult.setMsg("录像下载请求超时");
             hookCallBack.call(downloadResult);
@@ -846,16 +839,12 @@ public class PlayServiceImpl implements IPlayService {
                 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
                 streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
             }
-            // 回复之前所有的点播请求
-            hookCallBack.call(downloadResult);
         }, userSetting.getPlayTimeout());
 
         SipSubscribe.Event errorEvent = event -> {
             dynamicTask.stop(downLoadTimeOutTaskKey);
             downloadResult.setCode(ErrorCode.ERROR100.getCode());
             downloadResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg));
-            wvpResult.setCode(ErrorCode.ERROR100.getCode());
-            wvpResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg));
             downloadResult.setEvent(event);
             hookCallBack.call(downloadResult);
             streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
@@ -870,11 +859,9 @@ public class PlayServiceImpl implements IPlayService {
                         streamInfo.setStartTime(startTime);
                         streamInfo.setEndTime(endTime);
                         redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());
-                        wvpResult.setCode(ErrorCode.SUCCESS.getCode());
-                        wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
-                        wvpResult.setData(streamInfo);
                         downloadResult.setCode(ErrorCode.SUCCESS.getCode());
                         downloadResult.setMsg(ErrorCode.SUCCESS.getMsg());
+                        downloadResult.setData(streamInfo);
                         downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
                         downloadResult.setResponse(inviteStreamInfo.getResponse());
                         hookCallBack.call(downloadResult);
@@ -886,7 +873,6 @@ public class PlayServiceImpl implements IPlayService {
             eventResult.msg = "命令发送失败";
             errorEvent.response(eventResult);
         }
-        return result;
     }
 
     @Override
@@ -906,7 +892,10 @@ public class PlayServiceImpl implements IPlayService {
             }
             if (mediaServerItem.getRecordAssistPort() > 0) {
                 JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, streamInfo.getApp(), streamInfo.getStream(), null);
-                if (jsonObject != null && jsonObject.getInteger("code") == 0) {
+                if (jsonObject == null) {
+                    throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败");
+                }
+                if (jsonObject.getInteger("code") == 0) {
                     long duration = jsonObject.getLong("data");
 
                     if (duration == 0) {

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java

@@ -90,7 +90,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
     public StreamInfo save(StreamProxyItem param) {
         MediaServerItem mediaInfo;
         if (ObjectUtils.isEmpty(param.getMediaServerId()) || "auto".equals(param.getMediaServerId())){
-            mediaInfo = mediaServerService.getMediaServerForMinimumLoad();
+            mediaInfo = mediaServerService.getMediaServerForMinimumLoad(null);
         }else {
             mediaInfo = mediaServerService.getOne(param.getMediaServerId());
         }

+ 7 - 6
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java

@@ -117,7 +117,7 @@ public class RedisGbPlayMsgListener implements MessageListener {
                     Message msg = taskQueue.poll();
                     try {
                         JSONObject msgJSON = JSON.parseObject(msg.getBody(), JSONObject.class);
-                        WvpRedisMsg wvpRedisMsg = JSON.toJavaObject(msgJSON, WvpRedisMsg.class);
+                        WvpRedisMsg wvpRedisMsg = JSON.to(WvpRedisMsg.class, msgJSON);
                         if (!userSetting.getServerId().equals(wvpRedisMsg.getToId())) {
                             continue;
                         }
@@ -126,11 +126,11 @@ public class RedisGbPlayMsgListener implements MessageListener {
 
                             switch (wvpRedisMsg.getCmd()){
                                 case WvpRedisMsgCmd.GET_SEND_ITEM:
-                                    RequestSendItemMsg content = JSON.toJavaObject((JSONObject)wvpRedisMsg.getContent(), RequestSendItemMsg.class);
+                                    RequestSendItemMsg content = JSON.to(RequestSendItemMsg.class, wvpRedisMsg.getContent());
                                     requestSendItemMsgHand(content, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial());
                                     break;
                                 case WvpRedisMsgCmd.REQUEST_PUSH_STREAM:
-                                    RequestPushStreamMsg param = JSON.toJavaObject((JSONObject)wvpRedisMsg.getContent(), RequestPushStreamMsg.class);;
+                                    RequestPushStreamMsg param = JSON.to(RequestPushStreamMsg.class, wvpRedisMsg.getContent());
                                     requestPushStreamMsgHand(param, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial());
                                     break;
                                 default:
@@ -142,12 +142,12 @@ public class RedisGbPlayMsgListener implements MessageListener {
                             switch (wvpRedisMsg.getCmd()){
                                 case WvpRedisMsgCmd.GET_SEND_ITEM:
 
-                                    WVPResult content  = JSON.toJavaObject((JSONObject)wvpRedisMsg.getContent(), WVPResult.class);
+                                   WVPResult content  = JSON.to(WVPResult.class, wvpRedisMsg.getContent());
 
                                     String key = wvpRedisMsg.getSerial();
                                     switch (content.getCode()) {
                                         case 0:
-                                            ResponseSendItemMsg responseSendItemMsg =JSON.toJavaObject((JSONObject)content.getData(), ResponseSendItemMsg.class);
+                                           ResponseSendItemMsg responseSendItemMsg =JSON.to(ResponseSendItemMsg.class, content.getData());
                                             PlayMsgCallback playMsgCallback = callbacks.get(key);
                                             if (playMsgCallback != null) {
                                                 callbacksForError.remove(key);
@@ -172,7 +172,7 @@ public class RedisGbPlayMsgListener implements MessageListener {
                                     }
                                     break;
                                 case WvpRedisMsgCmd.REQUEST_PUSH_STREAM:
-                                    WVPResult wvpResult  = JSON.toJavaObject((JSONObject)wvpRedisMsg.getContent(), WVPResult.class);
+                                    WVPResult wvpResult  = JSON.to(WVPResult.class, wvpRedisMsg.getContent());
                                     String serial = wvpRedisMsg.getSerial();
                                     switch (wvpResult.getCode()) {
                                         case 0:
@@ -199,6 +199,7 @@ public class RedisGbPlayMsgListener implements MessageListener {
                                 default:
                                     break;
                             }
+
                         }
                     }catch (Exception e) {
                         logger.warn("[RedisGbPlayMsg] 发现未处理的异常, {}",e.getMessage());

+ 4 - 4
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java

@@ -59,7 +59,7 @@ public interface IVideoManagerStorage {
 	 */
 	public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, Boolean catalogUnderDevice, int page, int count);
 	
-	public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit);
+	public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit,List<String> channelIds);
 
 
 	/**
@@ -68,7 +68,7 @@ public interface IVideoManagerStorage {
 	 * @param deviceId 设备ID
 	 * @return
 	 */
-	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId);
+	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId,Boolean online,List<String> channelIds);
 	public List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId);
 
 	/**
@@ -91,14 +91,14 @@ public interface IVideoManagerStorage {
 	 * @param count 每页数量
 	 * @return List<Device> 设备对象数组
 	 */
-	public PageInfo<Device> queryVideoDeviceList(int page, int count);
+	public PageInfo<Device> queryVideoDeviceList(int page, int count,Boolean online);
 
 	/**
 	 * 获取多个设备
 	 *
 	 * @return List<Device> 设备对象数组
 	 */
-	public List<Device> queryVideoDeviceList();
+	public List<Device> queryVideoDeviceList(Boolean online);
 
 
 

+ 10 - 10
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java

@@ -16,19 +16,19 @@ import java.util.List;
 public interface DeviceAlarmMapper {
 
     @Insert("INSERT INTO device_alarm (deviceId, channelId, alarmPriority, alarmMethod, alarmTime, alarmDescription, longitude, latitude, alarmType , createTime ) " +
-            "VALUES ('${deviceId}', '${channelId}', '${alarmPriority}', '${alarmMethod}', '${alarmTime}', '${alarmDescription}', ${longitude}, ${latitude}, '${alarmType}', '${createTime}')")
+            "VALUES (#{deviceId}, #{channelId}, #{alarmPriority}, #{alarmMethod}, #{alarmTime}, #{alarmDescription}, #{longitude}, #{latitude}, #{alarmType}, #{createTime})")
     int add(DeviceAlarm alarm);
 
 
     @Select(value = {" <script>" +
             " SELECT * FROM device_alarm " +
             " WHERE 1=1 " +
-            " <if test=\"deviceId != null\" >  AND deviceId = '${deviceId}'</if>" +
-            " <if test=\"alarmPriority != null\" >  AND alarmPriority = '${alarmPriority}' </if>" +
-            " <if test=\"alarmMethod != null\" >  AND alarmMethod = '${alarmMethod}' </if>" +
-            " <if test=\"alarmType != null\" >  AND alarmType = '${alarmType}' </if>" +
-            " <if test=\"startTime != null\" >  AND alarmTime &gt;= '${startTime}' </if>" +
-            " <if test=\"endTime != null\" >  AND alarmTime &lt;= '${endTime}' </if>" +
+            " <if test=\"deviceId != null\" >  AND deviceId = #{deviceId}</if>" +
+            " <if test=\"alarmPriority != null\" >  AND alarmPriority = #{alarmPriority} </if>" +
+            " <if test=\"alarmMethod != null\" >  AND alarmMethod = #{alarmMethod} </if>" +
+            " <if test=\"alarmType != null\" >  AND alarmType = #{alarmType} </if>" +
+            " <if test=\"startTime != null\" >  AND alarmTime &gt;= #{startTime} </if>" +
+            " <if test=\"endTime != null\" >  AND alarmTime &lt;= #{endTime} </if>" +
             " ORDER BY alarmTime ASC " +
             " </script>"})
     List<DeviceAlarm> query(String deviceId, String alarmPriority, String alarmMethod,
@@ -38,10 +38,10 @@ public interface DeviceAlarmMapper {
     @Delete(" <script>" +
             "DELETE FROM device_alarm WHERE 1=1 " +
             " <if test=\"deviceIdList != null and id == null \" > AND deviceId in " +
-            "<foreach collection='deviceIdList'  item='item'  open='(' separator=',' close=')' > '${item}'</foreach>" +
+            "<foreach collection='deviceIdList'  item='item'  open='(' separator=',' close=')' > #{item}</foreach>" +
             "</if>" +
-            " <if test=\"time != null and id == null \" > AND alarmTime &lt;= '${time}'</if>" +
-            " <if test=\"id != null\" > AND id = ${id}</if>" +
+            " <if test=\"time != null and id == null \" > AND alarmTime &lt;= #{time}</if>" +
+            " <if test=\"id != null\" > AND id = #{id}</if>" +
             " </script>"
             )
     int clearAlarmBeforeTime(Integer id, List<String> deviceIdList, String time);

+ 94 - 88
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java

@@ -20,46 +20,46 @@ public interface DeviceChannelMapper {
             "address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
             "ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " +
             "longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
-            "VALUES ('${channelId}', '${deviceId}', '${name}', '${manufacture}', '${model}', '${owner}', '${civilCode}', '${block}'," +
-            "'${address}', ${parental}, '${parentId}', ${safetyWay}, ${registerWay}, '${certNum}', ${certifiable}, ${errCode}, '${secrecy}', " +
-            "'${ipAddress}', ${port}, '${password}', ${PTZType}, ${status}, '${streamId}', ${longitude}, ${latitude}, ${longitudeGcj02}, " +
-            "${latitudeGcj02}, ${longitudeWgs84}, ${latitudeWgs84}, ${hasAudio}, '${createTime}', '${updateTime}', '${businessGroupId}', '${gpsTime}')")
+            "VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," +
+            "#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " +
+            "#{ipAddress}, #{port}, #{password}, #{PTZType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " +
+            "#{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{hasAudio}, #{createTime}, #{updateTime}, #{businessGroupId}, #{gpsTime})")
     int add(DeviceChannel channel);
 
     @Update(value = {" <script>" +
             "UPDATE device_channel " +
-            "SET updateTime='${updateTime}'" +
-            "<if test='name != null'>, name='${name}'</if>" +
-            "<if test='manufacture != null'>, manufacture='${manufacture}'</if>" +
-            "<if test='model != null'>, model='${model}'</if>" +
-            "<if test='owner != null'>, owner='${owner}'</if>" +
-            "<if test='civilCode != null'>, civilCode='${civilCode}'</if>" +
-            "<if test='block != null'>, block='${block}'</if>" +
-            "<if test='address != null'>, address='${address}'</if>" +
-            "<if test='parental != null'>, parental=${parental}</if>" +
-            "<if test='parentId != null'>, parentId='${parentId}'</if>" +
-            "<if test='safetyWay != null'>, safetyWay=${safetyWay}</if>" +
-            "<if test='registerWay != null'>, registerWay=${registerWay}</if>" +
-            "<if test='certNum != null'>, certNum='${certNum}'</if>" +
-            "<if test='certifiable != null'>, certifiable=${certifiable}</if>" +
-            "<if test='errCode != null'>, errCode=${errCode}</if>" +
-            "<if test='secrecy != null'>, secrecy='${secrecy}'</if>" +
-            "<if test='ipAddress != null'>, ipAddress='${ipAddress}'</if>" +
-            "<if test='port != null'>, port=${port}</if>" +
-            "<if test='password != null'>, password='${password}'</if>" +
-            "<if test='PTZType != null'>, PTZType=${PTZType}</if>" +
-            "<if test='status != null'>, status='${status}'</if>" +
-            "<if test='streamId != null'>, streamId='${streamId}'</if>" +
-            "<if test='hasAudio != null'>, hasAudio=${hasAudio}</if>" +
-            "<if test='longitude != null'>, longitude=${longitude}</if>" +
-            "<if test='latitude != null'>, latitude=${latitude}</if>" +
-            "<if test='longitudeGcj02 != null'>, longitudeGcj02=${longitudeGcj02}</if>" +
-            "<if test='latitudeGcj02 != null'>, latitudeGcj02=${latitudeGcj02}</if>" +
-            "<if test='longitudeWgs84 != null'>, longitudeWgs84=${longitudeWgs84}</if>" +
-            "<if test='latitudeWgs84 != null'>, latitudeWgs84=${latitudeWgs84}</if>" +
+            "SET updateTime=#{updateTime}" +
+            "<if test='name != null'>, name=#{name}</if>" +
+            "<if test='manufacture != null'>, manufacture=#{manufacture}</if>" +
+            "<if test='model != null'>, model=#{model}</if>" +
+            "<if test='owner != null'>, owner=#{owner}</if>" +
+            "<if test='civilCode != null'>, civilCode=#{civilCode}</if>" +
+            "<if test='block != null'>, block=#{block}</if>" +
+            "<if test='address != null'>, address=#{address}</if>" +
+            "<if test='parental != null'>, parental=#{parental}</if>" +
+            "<if test='parentId != null'>, parentId=#{parentId}</if>" +
+            "<if test='safetyWay != null'>, safetyWay=#{safetyWay}</if>" +
+            "<if test='registerWay != null'>, registerWay=#{registerWay}</if>" +
+            "<if test='certNum != null'>, certNum=#{certNum}</if>" +
+            "<if test='certifiable != null'>, certifiable=#{certifiable}</if>" +
+            "<if test='errCode != null'>, errCode=#{errCode}</if>" +
+            "<if test='secrecy != null'>, secrecy=#{secrecy}</if>" +
+            "<if test='ipAddress != null'>, ipAddress=#{ipAddress}</if>" +
+            "<if test='port != null'>, port=#{port}</if>" +
+            "<if test='password != null'>, password=#{password}</if>" +
+            "<if test='PTZType != null'>, PTZType=#{PTZType}</if>" +
+            "<if test='status != null'>, status=#{status}</if>" +
+            "<if test='streamId != null'>, streamId=#{streamId}</if>" +
+            "<if test='hasAudio != null'>, hasAudio=#{hasAudio}</if>" +
+            "<if test='longitude != null'>, longitude=#{longitude}</if>" +
+            "<if test='latitude != null'>, latitude=#{latitude}</if>" +
+            "<if test='longitudeGcj02 != null'>, longitudeGcj02=#{longitudeGcj02}</if>" +
+            "<if test='latitudeGcj02 != null'>, latitudeGcj02=#{latitudeGcj02}</if>" +
+            "<if test='longitudeWgs84 != null'>, longitudeWgs84=#{longitudeWgs84}</if>" +
+            "<if test='latitudeWgs84 != null'>, latitudeWgs84=#{latitudeWgs84}</if>" +
             "<if test='businessGroupId != null'>, businessGroupId=#{businessGroupId}</if>" +
             "<if test='gpsTime != null'>, gpsTime=#{gpsTime}</if>" +
-            "WHERE deviceId='${deviceId}' AND channelId='${channelId}'"+
+            "WHERE deviceId=#{deviceId} AND channelId=#{channelId}"+
             " </script>"})
     int update(DeviceChannel channel);
 
@@ -70,15 +70,18 @@ public interface DeviceChannelMapper {
             "device_channel dc " +
             "WHERE " +
             "dc.deviceId = #{deviceId} " +
-            " <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
+" <if test='query != null'> AND (dc.channelId LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " +
             " <if test='parentChannelId != null'> AND (dc.parentId=#{parentChannelId} OR dc.civilCode = #{parentChannelId}) </if> " +
             " <if test='online == true' > AND dc.status=1</if>" +
             " <if test='online == false' > AND dc.status=0</if>" +
             " <if test='hasSubChannel == true' >  AND dc.subCount > 0 </if>" +
             " <if test='hasSubChannel == false' >  AND dc.subCount = 0 </if>" +
+            "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
+            "#{item} " +
+            "</foreach> </if>" +
             "ORDER BY dc.channelId " +
             " </script>"})
-    List<DeviceChannel> queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online);
+    List<DeviceChannel> queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online,List<String> channelIds);
 
     @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}")
     DeviceChannel queryChannel(String deviceId, String channelId);
@@ -110,7 +113,7 @@ public interface DeviceChannelMapper {
             " LEFT JOIN device de ON dc.deviceId = de.deviceId " +
             " LEFT JOIN platform_gb_channel pgc on pgc.deviceChannelId = dc.id " +
             " WHERE 1=1 " +
-            " <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
+            " <if test='query != null'> AND (dc.channelId LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " +
             " <if test='online == true' > AND dc.status=1</if> " +
             " <if test='online == false' > AND dc.status=0</if> " +
             " <if test='hasSubChannel!= null and hasSubChannel == true' >  AND dc.subCount > 0</if> " +
@@ -151,14 +154,14 @@ public interface DeviceChannelMapper {
             "  longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
             "values " +
             "<foreach collection='addChannels' index='index' item='item' separator=','> " +
-            "('${item.channelId}', '${item.deviceId}', '${item.name}', '${item.manufacture}', '${item.model}', " +
-            "'${item.owner}', '${item.civilCode}', '${item.block}',${item.subCount}," +
-            "'${item.address}', ${item.parental}, '${item.parentId}', ${item.safetyWay}, ${item.registerWay}, " +
-            "'${item.certNum}', ${item.certifiable}, ${item.errCode}, '${item.secrecy}', " +
-            "'${item.ipAddress}', ${item.port}, '${item.password}', ${item.PTZType}, ${item.status}, " +
-            "'${item.streamId}', ${item.longitude}, ${item.latitude},${item.longitudeGcj02}, " +
-            "${item.latitudeGcj02},${item.longitudeWgs84}, ${item.latitudeWgs84}, ${item.hasAudio},'${item.createTime}', '${item.updateTime}', " +
-            "'${item.businessGroupId}', '${item.gpsTime}') " +
+            "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " +
+            "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," +
+            "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " +
+            "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " +
+            "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " +
+            "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " +
+            "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " +
+            "#{item.businessGroupId}, #{item.gpsTime}) " +
             "</foreach> " +
             "ON DUPLICATE KEY UPDATE " +
             "updateTime=VALUES(updateTime), " +
@@ -203,39 +206,39 @@ public interface DeviceChannelMapper {
             "<foreach collection='updateChannels' item='item' separator=';'>" +
             " UPDATE" +
             " device_channel" +
-            " SET updateTime='${item.updateTime}'" +
-            "<if test='item.name != null'>, name='${item.name}'</if>" +
-            "<if test='item.manufacture != null'>, manufacture='${item.manufacture}'</if>" +
-            "<if test='item.model != null'>, model='${item.model}'</if>" +
-            "<if test='item.owner != null'>, owner='${item.owner}'</if>" +
-            "<if test='item.civilCode != null'>, civilCode='${item.civilCode}'</if>" +
-            "<if test='item.block != null'>, block='${item.block}'</if>" +
-            "<if test='item.subCount != null'>, block=${item.subCount}</if>" +
-            "<if test='item.address != null'>, address='${item.address}'</if>" +
-            "<if test='item.parental != null'>, parental=${item.parental}</if>" +
-            "<if test='item.parentId != null'>, parentId='${item.parentId}'</if>" +
-            "<if test='item.safetyWay != null'>, safetyWay=${item.safetyWay}</if>" +
-            "<if test='item.registerWay != null'>, registerWay=${item.registerWay}</if>" +
-            "<if test='item.certNum != null'>, certNum='${item.certNum}'</if>" +
-            "<if test='item.certifiable != null'>, certifiable=${item.certifiable}</if>" +
-            "<if test='item.errCode != null'>, errCode=${item.errCode}</if>" +
-            "<if test='item.secrecy != null'>, secrecy='${item.secrecy}'</if>" +
-            "<if test='item.ipAddress != null'>, ipAddress='${item.ipAddress}'</if>" +
-            "<if test='item.port != null'>, port=${item.port}</if>" +
-            "<if test='item.password != null'>, password='${item.password}'</if>" +
-            "<if test='item.PTZType != null'>, PTZType=${item.PTZType}</if>" +
-            "<if test='item.status != null'>, status='${item.status}'</if>" +
-            "<if test='item.streamId != null'>, streamId='${item.streamId}'</if>" +
-            "<if test='item.hasAudio != null'>, hasAudio=${item.hasAudio}</if>" +
-            "<if test='item.longitude != null'>, longitude=${item.longitude}</if>" +
-            "<if test='item.latitude != null'>, latitude=${item.latitude}</if>" +
-            "<if test='item.longitudeGcj02 != null'>, longitudeGcj02=${item.longitudeGcj02}</if>" +
-            "<if test='item.latitudeGcj02 != null'>, latitudeGcj02=${item.latitudeGcj02}</if>" +
-            "<if test='item.longitudeWgs84 != null'>, longitudeWgs84=${item.longitudeWgs84}</if>" +
-            "<if test='item.latitudeWgs84 != null'>, latitudeWgs84=${item.latitudeWgs84}</if>" +
+            " SET updateTime=#{item.updateTime}" +
+            "<if test='item.name != null'>, name=#{item.name}</if>" +
+            "<if test='item.manufacture != null'>, manufacture=#{item.manufacture}</if>" +
+            "<if test='item.model != null'>, model=#{item.model}</if>" +
+            "<if test='item.owner != null'>, owner=#{item.owner}</if>" +
+            "<if test='item.civilCode != null'>, civilCode=#{item.civilCode}</if>" +
+            "<if test='item.block != null'>, block=#{item.block}</if>" +
+            "<if test='item.subCount != null'>, block=#{item.subCount}</if>" +
+            "<if test='item.address != null'>, address=#{item.address}</if>" +
+            "<if test='item.parental != null'>, parental=#{item.parental}</if>" +
+            "<if test='item.parentId != null'>, parentId=#{item.parentId}</if>" +
+            "<if test='item.safetyWay != null'>, safetyWay=#{item.safetyWay}</if>" +
+            "<if test='item.registerWay != null'>, registerWay=#{item.registerWay}</if>" +
+            "<if test='item.certNum != null'>, certNum=#{item.certNum}</if>" +
+            "<if test='item.certifiable != null'>, certifiable=#{item.certifiable}</if>" +
+            "<if test='item.errCode != null'>, errCode=#{item.errCode}</if>" +
+            "<if test='item.secrecy != null'>, secrecy=#{item.secrecy}</if>" +
+            "<if test='item.ipAddress != null'>, ipAddress=#{item.ipAddress}</if>" +
+            "<if test='item.port != null'>, port=#{item.port}</if>" +
+            "<if test='item.password != null'>, password=#{item.password}</if>" +
+            "<if test='item.PTZType != null'>, PTZType=#{item.PTZType}</if>" +
+            "<if test='item.status != null'>, status=#{item.status}</if>" +
+            "<if test='item.streamId != null'>, streamId=#{item.streamId}</if>" +
+            "<if test='item.hasAudio != null'>, hasAudio=#{item.hasAudio}</if>" +
+            "<if test='item.longitude != null'>, longitude=#{item.longitude}</if>" +
+            "<if test='item.latitude != null'>, latitude=#{item.latitude}</if>" +
+            "<if test='item.longitudeGcj02 != null'>, longitudeGcj02=#{item.longitudeGcj02}</if>" +
+            "<if test='item.latitudeGcj02 != null'>, latitudeGcj02=#{item.latitudeGcj02}</if>" +
+            "<if test='item.longitudeWgs84 != null'>, longitudeWgs84=#{item.longitudeWgs84}</if>" +
+            "<if test='item.latitudeWgs84 != null'>, latitudeWgs84=#{item.latitudeWgs84}</if>" +
             "<if test='item.businessGroupId != null'>, businessGroupId=#{item.businessGroupId}</if>" +
             "<if test='item.gpsTime != null'>, gpsTime=#{item.gpsTime}</if>" +
-            "WHERE deviceId='${item.deviceId}' AND channelId='${item.channelId}'"+
+            "WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}"+
             "</foreach>" +
             "</script>"})
     int batchUpdate(List<DeviceChannel> updateChannels);
@@ -248,17 +251,20 @@ public interface DeviceChannelMapper {
             "device_channel dc1 " +
             "WHERE " +
             "dc1.deviceId = #{deviceId} " +
-            " <if test='query != null'> AND (dc1.channelId LIKE '%${query}%' OR dc1.name LIKE '%${query}%' OR dc1.name LIKE '%${query}%')</if> " +
+            " <if test='query != null'> AND (dc1.channelId LIKE concat('%',#{query},'%') OR dc1.name LIKE concat('%',#{query},'%') OR dc1.name LIKE concat('%',#{query},'%'))</if> " +
             " <if test='parentChannelId != null'> AND dc1.parentId=#{parentChannelId} </if> " +
             " <if test='online == true' > AND dc1.status=1</if>" +
             " <if test='online == false' > AND dc1.status=0</if>" +
             " <if test='hasSubChannel == true' >  AND dc1.subCount >0</if>" +
             " <if test='hasSubChannel == false' >  AND dc1.subCount=0</if>" +
+            "<if test='channelIds != null'> AND dc1.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
+            "#{item} " +
+            "</foreach> </if>" +
             "ORDER BY dc1.channelId ASC " +
             "Limit #{limit} OFFSET #{start}" +
             " </script>"})
     List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String parentChannelId, String query,
-                                                                 Boolean hasSubChannel, Boolean online, int start, int limit);
+                                                                 Boolean hasSubChannel, Boolean online, int start, int limit,List<String> channelIds);
 
     @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND status=1")
     List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId);
@@ -286,13 +292,13 @@ public interface DeviceChannelMapper {
     @Update(value = {" <script>" +
             "UPDATE device_channel " +
             "SET " +
-            "latitude=${latitude}, " +
-            "longitude=${longitude}, " +
-            "longitudeGcj02=${longitudeGcj02}, " +
-            "latitudeGcj02=${latitudeGcj02}, " +
-            "longitudeWgs84=${longitudeWgs84}, " +
-            "latitudeWgs84=${latitudeWgs84}, " +
-            "gpsTime='${gpsTime}' " +
+            "latitude=#{latitude}, " +
+            "longitude=#{longitude}, " +
+            "longitudeGcj02=#{longitudeGcj02}, " +
+            "latitudeGcj02=#{latitudeGcj02}, " +
+            "longitudeWgs84=#{longitudeWgs84}, " +
+            "latitudeWgs84=#{latitudeWgs84}, " +
+            "gpsTime=#{gpsTime} " +
             "WHERE deviceId=#{deviceId} " +
             " <if test='channelId != null' >  AND channelId=#{channelId}</if>" +
             " </script>"})
@@ -309,10 +315,10 @@ public interface DeviceChannelMapper {
             "select * " +
             "from device_channel " +
             "where deviceId=#{deviceId}" +
-            " <if test='parentId != null and length != null' > and parentId = #{parentId} or left(channelId, ${parentId.length()}) = #{parentId} and length(channelId)=${length} </if>" +
-            " <if test='parentId == null and length != null' > and parentId = #{parentId} or length(channelId)=${length} </if>" +
+            " <if test='parentId != null and length != null' > and parentId = #{parentId} or left(channelId, #{parentId.length()}) = #{parentId} and length(channelId)=#{length} </if>" +
+            " <if test='parentId == null and length != null' > and parentId = #{parentId} or length(channelId)=#{length} </if>" +
             " <if test='parentId == null and length == null' > and parentId = #{parentId} </if>" +
-            " <if test='parentId != null and length == null' > and parentId = #{parentId} or left(channelId, ${parentId.length()}) = #{parentId} </if>" +
+            " <if test='parentId != null and length == null' > and parentId = #{parentId} or left(channelId, #{parentId.length()}) = #{parentId} </if>" +
             " </script>"})
     List<DeviceChannel> getChannelsWithCivilCodeAndLength(String deviceId, String parentId, Integer length);
 

+ 41 - 33
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java

@@ -61,6 +61,7 @@ public interface DeviceMapper {
                 "expires," +
                 "registerTime," +
                 "keepaliveTime," +
+                "keepaliveIntervalTime," +
                 "createTime," +
                 "updateTime," +
                 "charset," +
@@ -88,6 +89,7 @@ public interface DeviceMapper {
                 "#{expires}," +
                 "#{registerTime}," +
                 "#{keepaliveTime}," +
+                "#{keepaliveIntervalTime}," +
                 "#{createTime}," +
                 "#{updateTime}," +
                 "#{charset}," +
@@ -104,25 +106,28 @@ public interface DeviceMapper {
 
     @Update(value = {" <script>" +
                 "UPDATE device " +
-                "SET updateTime='${updateTime}'" +
-                "<if test=\"name != null\">, name='${name}'</if>" +
-                "<if test=\"manufacturer != null\">, manufacturer='${manufacturer}'</if>" +
-                "<if test=\"model != null\">, model='${model}'</if>" +
-                "<if test=\"firmware != null\">, firmware='${firmware}'</if>" +
-                "<if test=\"transport != null\">, transport='${transport}'</if>" +
-                "<if test=\"ip != null\">, ip='${ip}'</if>" +
-                "<if test=\"localIp != null\">, localIp='${localIp}'</if>" +
-                "<if test=\"port != null\">, port=${port}</if>" +
-                "<if test=\"hostAddress != null\">, hostAddress='${hostAddress}'</if>" +
-                "<if test=\"online != null\">, online=${online}</if>" +
-                "<if test=\"registerTime != null\">, registerTime='${registerTime}'</if>" +
-                "<if test=\"keepaliveTime != null\">, keepaliveTime='${keepaliveTime}'</if>" +
-                "<if test=\"expires != null\">, expires=${expires}</if>" +
-                "WHERE deviceId='${deviceId}'"+
+                "SET updateTime=#{updateTime}" +
+                "<if test=\"name != null\">, name=#{name}</if>" +
+                "<if test=\"manufacturer != null\">, manufacturer=#{manufacturer}</if>" +
+                "<if test=\"model != null\">, model=#{model}</if>" +
+                "<if test=\"firmware != null\">, firmware=#{firmware}</if>" +
+                "<if test=\"transport != null\">, transport=#{transport}</if>" +
+                "<if test=\"ip != null\">, ip=#{ip}</if>" +
+                "<if test=\"localIp != null\">, localIp=#{localIp}</if>" +
+                "<if test=\"port != null\">, port=#{port}</if>" +
+                "<if test=\"hostAddress != null\">, hostAddress=#{hostAddress}</if>" +
+                "<if test=\"online != null\">, online=#{online}</if>" +
+                "<if test=\"registerTime != null\">, registerTime=#{registerTime}</if>" +
+                "<if test=\"keepaliveTime != null\">, keepaliveTime=#{keepaliveTime}</if>" +
+                "<if test=\"keepaliveIntervalTime != null\">, keepaliveIntervalTime=#{keepaliveIntervalTime}</if>" +
+                "<if test=\"expires != null\">, expires=#{expires}</if>" +
+                "WHERE deviceId=#{deviceId}"+
             " </script>"})
     int update(Device device);
 
-    @Select("SELECT " +
+    @Select(
+            " <script>" +
+            "SELECT " +
             "deviceId, " +
             "coalesce(custom_name, name) as name, " +
             "password, " +
@@ -150,8 +155,11 @@ public interface DeviceMapper {
             "geoCoordSys," +
             "treeType," +
             "online," +
-            "(SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount  FROM device de")
-    List<Device> getDevices();
+            "(SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount  FROM device de" +
+            "<if test=\"online != null\"> where online=${online}</if>"+
+            " </script>"
+    )
+    List<Device> getDevices(Boolean online);
 
     @Delete("DELETE FROM device WHERE deviceId=#{deviceId}")
     int del(String deviceId);
@@ -217,28 +225,28 @@ public interface DeviceMapper {
             "geoCoordSys," +
             "treeType," +
             "online" +
-            " FROM device WHERE ip = #{host} AND port=${port}")
+            " FROM device WHERE ip = #{host} AND port=#{port}")
     Device getDeviceByHostAndPort(String host, int port);
 
     @Update(value = {" <script>" +
             "UPDATE device " +
-            "SET updateTime='${updateTime}'" +
-            "<if test=\"name != null\">, custom_name='${name}'</if>" +
-            "<if test=\"password != null\">, password='${password}'</if>" +
-            "<if test=\"streamMode != null\">, streamMode='${streamMode}'</if>" +
-            "<if test=\"ip != null\">, ip='${ip}'</if>" +
-            "<if test=\"sdpIp != null\">, sdpIp='${sdpIp}'</if>" +
-            "<if test=\"port != null\">, port=${port}</if>" +
-            "<if test=\"charset != null\">, charset='${charset}'</if>" +
-            "<if test=\"subscribeCycleForCatalog != null\">, subscribeCycleForCatalog=${subscribeCycleForCatalog}</if>" +
-            "<if test=\"subscribeCycleForMobilePosition != null\">, subscribeCycleForMobilePosition=${subscribeCycleForMobilePosition}</if>" +
-            "<if test=\"mobilePositionSubmissionInterval != null\">, mobilePositionSubmissionInterval=${mobilePositionSubmissionInterval}</if>" +
-            "<if test=\"subscribeCycleForAlarm != null\">, subscribeCycleForAlarm=${subscribeCycleForAlarm}</if>" +
-            "<if test=\"ssrcCheck != null\">, ssrcCheck=${ssrcCheck}</if>" +
+            "SET updateTime=#{updateTime}" +
+            "<if test=\"name != null\">, custom_name=#{name}</if>" +
+            "<if test=\"password != null\">, password=#{password}</if>" +
+            "<if test=\"streamMode != null\">, streamMode=#{streamMode}</if>" +
+            "<if test=\"ip != null\">, ip=#{ip}</if>" +
+            "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" +
+            "<if test=\"port != null\">, port=#{port}</if>" +
+            "<if test=\"charset != null\">, charset=#{charset}</if>" +
+            "<if test=\"subscribeCycleForCatalog != null\">, subscribeCycleForCatalog=#{subscribeCycleForCatalog}</if>" +
+            "<if test=\"subscribeCycleForMobilePosition != null\">, subscribeCycleForMobilePosition=#{subscribeCycleForMobilePosition}</if>" +
+            "<if test=\"mobilePositionSubmissionInterval != null\">, mobilePositionSubmissionInterval=#{mobilePositionSubmissionInterval}</if>" +
+            "<if test=\"subscribeCycleForAlarm != null\">, subscribeCycleForAlarm=#{subscribeCycleForAlarm}</if>" +
+            "<if test=\"ssrcCheck != null\">, ssrcCheck=#{ssrcCheck}</if>" +
             "<if test=\"geoCoordSys != null\">, geoCoordSys=#{geoCoordSys}</if>" +
             "<if test=\"treeType != null\">, treeType=#{treeType}</if>" +
             "<if test=\"mediaServerId != null\">, mediaServerId=#{mediaServerId}</if>" +
-            "WHERE deviceId='${deviceId}'"+
+            "WHERE deviceId=#{deviceId}"+
             " </script>"})
     int updateCustom(Device device);
 

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java

@@ -9,7 +9,7 @@ import org.apache.ibatis.annotations.*;
 public interface DeviceMobilePositionMapper {
 
     @Insert("INSERT INTO device_mobile_position (deviceId,channelId, deviceName, time, longitude, latitude, altitude, speed, direction, reportSource, longitudeGcj02, latitudeGcj02, longitudeWgs84, latitudeWgs84, createTime) " +
-            "VALUES ('${deviceId}','${channelId}', '${deviceName}', '${time}', ${longitude}, ${latitude}, ${altitude}, ${speed}, ${direction}, '${reportSource}', ${longitudeGcj02}, ${latitudeGcj02}, ${longitudeWgs84}, ${latitudeWgs84}, '${createTime}')")
+            "VALUES (#{deviceId},#{channelId}, #{deviceName}, #{time}, #{longitude}, #{latitude}, #{altitude}, #{speed}, #{direction}, #{reportSource}, #{longitudeGcj02}, #{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{createTime})")
     int insertNewPosition(MobilePosition mobilePosition);
 
     @Select(value = {" <script>" +

+ 9 - 9
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java

@@ -16,9 +16,9 @@ public interface GbStreamMapper {
 
     @Insert("REPLACE INTO gb_stream (app, stream, gbId, name, " +
             "longitude, latitude, streamType, mediaServerId, createTime) VALUES" +
-            "('${app}', '${stream}', '${gbId}', '${name}', " +
-            "'${longitude}', '${latitude}', '${streamType}', " +
-            "'${mediaServerId}', '${createTime}')")
+            "(#{app}, #{stream}, #{gbId}, #{name}, " +
+            "#{longitude}, #{latitude}, #{streamType}, " +
+            "#{mediaServerId}, #{createTime})")
     @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId")
     int add(GbStream gbStream);
 
@@ -57,7 +57,7 @@ public interface GbStreamMapper {
             "(select pgs.gbStreamId from platform_gb_stream pgs where pgs.platformId = #{platformId} and pgs.catalogId=#{catalogId})</if> " +
             " <if test='catalogId == null'> AND gs.gbStreamId not in" +
             "(select pgs.gbStreamId from platform_gb_stream pgs where pgs.platformId = #{platformId}) </if> " +
-            " <if test='query != null'> AND (gs.app LIKE '%${query}%' OR gs.stream LIKE '%${query}%' OR gs.gbId LIKE '%${query}%' OR gs.name LIKE '%${query}%')</if> " +
+            " <if test='query != null'> AND (gs.app LIKE concat('%',#{query},'%') OR gs.stream LIKE concat('%',#{query},'%') OR gs.gbId LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " +
             " <if test='mediaServerId != null' > AND gs.mediaServerId=#{mediaServerId} </if>" +
             " order by gs.gbStreamId asc " +
             "</script>")
@@ -71,7 +71,7 @@ public interface GbStreamMapper {
 
     @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " +
             "LEFT JOIN platform_gb_stream pgs ON gs.gbStreamId = pgs.gbStreamId " +
-            "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'")
+            "WHERE gs.gbId = #{gbId} AND pgs.platformId = #{platformId}")
     GbStream queryStreamInPlatform(String platformId, String gbId);
 
     @Select("<script> "+
@@ -122,9 +122,9 @@ public interface GbStreamMapper {
             "longitude, latitude, streamType, mediaServerId, createTime)" +
             "values " +
             "<foreach collection='subList' index='index' item='item' separator=','> " +
-            "('${item.app}', '${item.stream}', '${item.gbId}', '${item.name}', " +
-            "'${item.longitude}', '${item.latitude}', '${item.streamType}', " +
-            "'${item.mediaServerId}', '${item.createTime}') "+
+            "(#{item.app}, #{item.stream}, #{item.gbId}, #{item.name}, " +
+            "#{item.longitude}, #{item.latitude}, #{item.streamType}, " +
+            "#{item.mediaServerId}, #{item.createTime}) "+
             "</foreach> " +
             "</script>")
     @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId")
@@ -134,7 +134,7 @@ public interface GbStreamMapper {
             "<foreach collection='gpsMsgInfos' item='item' separator=';'>" +
             " UPDATE" +
             " gb_stream" +
-            " SET longitude=${item.lng}, latitude=${item.lat} " +
+            " SET longitude=#{item.lng}, latitude=#{item.lat} " +
             "WHERE gbId=#{item.id}"+
             "</foreach>" +
             "</script>"})

+ 5 - 5
src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java

@@ -18,16 +18,16 @@ import java.util.List;
 public interface LogMapper {
 
     @Insert("insert into log ( name, type, uri, address, result, timing, username, createTime) " +
-            "values ('${name}', '${type}', '${uri}', '${address}', '${result}', ${timing}, '${username}', '${createTime}')")
+            "values (#{name}, #{type}, #{uri}, #{address}, #{result}, #{timing}, #{username}, #{createTime})")
     int add(LogDto logDto);
 
     @Select(value = {"<script>" +
             " SELECT * FROM log " +
             " WHERE 1=1 " +
-            " <if test=\"query != null\"> AND (name LIKE '%${query}%')</if> " +
-            " <if test=\"type != null\" >  AND type = '${type}'</if>" +
-            " <if test=\"startTime != null\" >  AND createTime &gt;= '${startTime}' </if>" +
-            " <if test=\"endTime != null\" >  AND createTime &lt;= '${endTime}' </if>" +
+            " <if test=\"query != null\"> AND (name LIKE concat('%',#{query},'%'))</if> " +
+            " <if test=\"type != null\" >  AND type = #{type}</if>" +
+            " <if test=\"startTime != null\" >  AND createTime &gt;= #{startTime} </if>" +
+            " <if test=\"endTime != null\" >  AND createTime &lt;= #{endTime} </if>" +
             " ORDER BY createTime DESC " +
             " </script>"})
     List<LogDto> query(String query, String type, String startTime, String endTime);

+ 62 - 62
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java

@@ -35,92 +35,92 @@ public interface MediaServerMapper {
             "hookAliveInterval" +
             ") VALUES " +
             "(" +
-            "'${id}', " +
-            "'${ip}', " +
-            "'${hookIp}', " +
-            "'${sdpIp}', " +
-            "'${streamIp}', " +
-            "${httpPort}, " +
-            "${httpSSlPort}, " +
-            "${rtmpPort}, " +
-            "${rtmpSSlPort}, " +
-            "${rtpProxyPort}, " +
-            "${rtspPort}, " +
-            "${rtspSSLPort}, " +
-            "${autoConfig}, " +
-            "'${secret}', " +
-            "${rtpEnable}, " +
-            "'${rtpPortRange}', " +
-            "${recordAssistPort}, " +
-            "${defaultServer}, " +
-            "'${createTime}', " +
-            "'${updateTime}', " +
-            "${hookAliveInterval})")
+            "#{id}, " +
+            "#{ip}, " +
+            "#{hookIp}, " +
+            "#{sdpIp}, " +
+            "#{streamIp}, " +
+            "#{httpPort}, " +
+            "#{httpSSlPort}, " +
+            "#{rtmpPort}, " +
+            "#{rtmpSSlPort}, " +
+            "#{rtpProxyPort}, " +
+            "#{rtspPort}, " +
+            "#{rtspSSLPort}, " +
+            "#{autoConfig}, " +
+            "#{secret}, " +
+            "#{rtpEnable}, " +
+            "#{rtpPortRange}, " +
+            "#{recordAssistPort}, " +
+            "#{defaultServer}, " +
+            "#{createTime}, " +
+            "#{updateTime}, " +
+            "#{hookAliveInterval})")
     int add(MediaServerItem mediaServerItem);
 
     @Update(value = {" <script>" +
             "UPDATE media_server " +
-            "SET updateTime='${updateTime}'" +
-            "<if test=\"ip != null\">, ip='${ip}'</if>" +
-            "<if test=\"hookIp != null\">, hookIp='${hookIp}'</if>" +
-            "<if test=\"sdpIp != null\">, sdpIp='${sdpIp}'</if>" +
-            "<if test=\"streamIp != null\">, streamIp='${streamIp}'</if>" +
-            "<if test=\"httpPort != null\">, httpPort=${httpPort}</if>" +
-            "<if test=\"httpSSlPort != null\">, httpSSlPort=${httpSSlPort}</if>" +
-            "<if test=\"rtmpPort != null\">, rtmpPort=${rtmpPort}</if>" +
-            "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=${rtmpSSlPort}</if>" +
-            "<if test=\"rtpProxyPort != null\">, rtpProxyPort=${rtpProxyPort}</if>" +
-            "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
-            "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
-            "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
-            "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
-            "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
-            "<if test=\"secret != null\">, secret='${secret}'</if>" +
-            "<if test=\"recordAssistPort != null\">, recordAssistPort=${recordAssistPort}</if>" +
-            "<if test=\"hookAliveInterval != null\">, hookAliveInterval=${hookAliveInterval}</if>" +
-            "WHERE id='${id}'"+
+            "SET updateTime=#{updateTime}" +
+            "<if test=\"ip != null\">, ip=#{ip}</if>" +
+            "<if test=\"hookIp != null\">, hookIp=#{hookIp}</if>" +
+            "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" +
+            "<if test=\"streamIp != null\">, streamIp=#{streamIp}</if>" +
+            "<if test=\"httpPort != null\">, httpPort=#{httpPort}</if>" +
+            "<if test=\"httpSSlPort != null\">, httpSSlPort=#{httpSSlPort}</if>" +
+            "<if test=\"rtmpPort != null\">, rtmpPort=#{rtmpPort}</if>" +
+            "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=#{rtmpSSlPort}</if>" +
+            "<if test=\"rtpProxyPort != null\">, rtpProxyPort=#{rtpProxyPort}</if>" +
+            "<if test=\"rtspPort != null\">, rtspPort=#{rtspPort}</if>" +
+            "<if test=\"rtspSSLPort != null\">, rtspSSLPort=#{rtspSSLPort}</if>" +
+            "<if test=\"autoConfig != null\">, autoConfig=#{autoConfig}</if>" +
+            "<if test=\"rtpEnable != null\">, rtpEnable=#{rtpEnable}</if>" +
+            "<if test=\"rtpPortRange != null\">, rtpPortRange=#{rtpPortRange}</if>" +
+            "<if test=\"secret != null\">, secret=#{secret}</if>" +
+            "<if test=\"recordAssistPort != null\">, recordAssistPort=#{recordAssistPort}</if>" +
+            "<if test=\"hookAliveInterval != null\">, hookAliveInterval=#{hookAliveInterval}</if>" +
+            "WHERE id=#{id}"+
             " </script>"})
     int update(MediaServerItem mediaServerItem);
 
     @Update(value = {" <script>" +
             "UPDATE media_server " +
-            "SET updateTime='${updateTime}'" +
-            "<if test=\"id != null\">, id='${id}'</if>" +
-            "<if test=\"hookIp != null\">, hookIp='${hookIp}'</if>" +
-            "<if test=\"sdpIp != null\">, sdpIp='${sdpIp}'</if>" +
-            "<if test=\"streamIp != null\">, streamIp='${streamIp}'</if>" +
-            "<if test=\"httpSSlPort != null\">, httpSSlPort=${httpSSlPort}</if>" +
-            "<if test=\"rtmpPort != null\">, rtmpPort=${rtmpPort}</if>" +
-            "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=${rtmpSSlPort}</if>" +
-            "<if test=\"rtpProxyPort != null\">, rtpProxyPort=${rtpProxyPort}</if>" +
-            "<if test=\"rtspPort != null\">, rtspPort=${rtspPort}</if>" +
-            "<if test=\"rtspSSLPort != null\">, rtspSSLPort=${rtspSSLPort}</if>" +
-            "<if test=\"autoConfig != null\">, autoConfig=${autoConfig}</if>" +
-            "<if test=\"rtpEnable != null\">, rtpEnable=${rtpEnable}</if>" +
-            "<if test=\"rtpPortRange != null\">, rtpPortRange='${rtpPortRange}'</if>" +
-            "<if test=\"secret != null\">, secret='${secret}'</if>" +
-            "<if test=\"recordAssistPort != null\">, recordAssistPort=${recordAssistPort}</if>" +
-            "<if test=\"hookAliveInterval != null\">, hookAliveInterval=${hookAliveInterval}</if>" +
-            "WHERE ip='${ip}' and httpPort=${httpPort}"+
+            "SET updateTime=#{updateTime}" +
+            "<if test=\"id != null\">, id=#{id}</if>" +
+            "<if test=\"hookIp != null\">, hookIp=#{hookIp}</if>" +
+            "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" +
+            "<if test=\"streamIp != null\">, streamIp=#{streamIp}</if>" +
+            "<if test=\"httpSSlPort != null\">, httpSSlPort=#{httpSSlPort}</if>" +
+            "<if test=\"rtmpPort != null\">, rtmpPort=#{rtmpPort}</if>" +
+            "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=#{rtmpSSlPort}</if>" +
+            "<if test=\"rtpProxyPort != null\">, rtpProxyPort=#{rtpProxyPort}</if>" +
+            "<if test=\"rtspPort != null\">, rtspPort=#{rtspPort}</if>" +
+            "<if test=\"rtspSSLPort != null\">, rtspSSLPort=#{rtspSSLPort}</if>" +
+            "<if test=\"autoConfig != null\">, autoConfig=#{autoConfig}</if>" +
+            "<if test=\"rtpEnable != null\">, rtpEnable=#{rtpEnable}</if>" +
+            "<if test=\"rtpPortRange != null\">, rtpPortRange=#{rtpPortRange}</if>" +
+            "<if test=\"secret != null\">, secret=#{secret}</if>" +
+            "<if test=\"recordAssistPort != null\">, recordAssistPort=#{recordAssistPort}</if>" +
+            "<if test=\"hookAliveInterval != null\">, hookAliveInterval=#{hookAliveInterval}</if>" +
+            "WHERE ip=#{ip} and httpPort=#{httpPort}"+
             " </script>"})
     int updateByHostAndPort(MediaServerItem mediaServerItem);
 
-    @Select("SELECT * FROM media_server WHERE id='${id}'")
+    @Select("SELECT * FROM media_server WHERE id=#{id}")
     MediaServerItem queryOne(String id);
 
     @Select("SELECT * FROM media_server")
     List<MediaServerItem> queryAll();
 
-    @Delete("DELETE FROM media_server WHERE id='${id}'")
+    @Delete("DELETE FROM media_server WHERE id=#{id}")
     void delOne(String id);
 
-    @Select("DELETE FROM media_server WHERE ip='${host}' and httpPort=${port}")
+    @Select("DELETE FROM media_server WHERE ip=#{host} and httpPort=#{port}")
     void delOneByIPAndPort(String host, int port);
 
     @Delete("DELETE FROM media_server WHERE defaultServer=1")
     int delDefault();
 
-    @Select("SELECT * FROM media_server WHERE ip='${host}' and httpPort=${port}")
+    @Select("SELECT * FROM media_server WHERE ip=#{host} and httpPort=#{port}")
     MediaServerItem queryOneByHostAndPort(String host, int port);
 
     @Select("SELECT * FROM media_server WHERE defaultServer=1")

+ 4 - 4
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java

@@ -17,9 +17,9 @@ public interface ParentPlatformMapper {
     @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp,  " +
             "            devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " +
             "            status, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime, treeType) " +
-            "            VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " +
-            "            '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " +
-            "            ${status},  ${startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})")
+            "            VALUES (#{enable}, #{name}, #{serverGBId}, #{serverGBDomain}, #{serverIP}, #{serverPort}, #{deviceGBId}, #{deviceIp}, " +
+            "            #{devicePort}, #{username}, #{password}, #{expires}, #{keepTimeout}, #{transport}, #{characterSet}, #{ptz}, #{rtcp}, " +
+            "            #{status},  #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})")
     int addParentPlatform(ParentPlatform parentPlatform);
 
     @Update("UPDATE parent_platform " +
@@ -41,7 +41,7 @@ public interface ParentPlatformMapper {
             "ptz=#{ptz}, " +
             "rtcp=#{rtcp}, " +
             "status=#{status}, " +
-            "startOfflinePush=${startOfflinePush}, " +
+            "startOfflinePush=#{startOfflinePush}, " +
             "catalogGroup=#{catalogGroup}, " +
             "administrativeDivision=#{administrativeDivision}, " +
             "createTime=#{createTime}, " +

+ 8 - 8
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java

@@ -21,22 +21,22 @@ public interface PlatformChannelMapper {
      * 查询列表里已经关联的
      */
     @Select("<script> "+
-            "SELECT deviceChannelId FROM platform_gb_channel WHERE platformId='${platformId}' AND deviceChannelId in" +
-            "<foreach collection='channelReduces' open='(' item='item' separator=',' close=')'> '${item.id}'</foreach>" +
+            "SELECT deviceChannelId FROM platform_gb_channel WHERE platformId=#{platformId} AND deviceChannelId in" +
+            "<foreach collection='channelReduces' open='(' item='item' separator=',' close=')'> #{item.id}</foreach>" +
             "</script>")
     List<Integer> findChannelRelatedPlatform(String platformId, List<ChannelReduce> channelReduces);
 
     @Insert("<script> "+
             "INSERT INTO platform_gb_channel (platformId, deviceChannelId, catalogId) VALUES" +
             "<foreach collection='channelReducesToAdd'  item='item' separator=','>" +
-            " ('${platformId}', '${item.id}' , '${item.catalogId}' )" +
+            " (#{platformId}, #{item.id} , #{item.catalogId} )" +
             "</foreach>" +
             "</script>")
     int addChannels(String platformId, List<ChannelReduce> channelReducesToAdd);
 
     @Delete("<script> "+
-            "DELETE FROM platform_gb_channel WHERE platformId='${platformId}' AND deviceChannelId in" +
-            "<foreach collection='channelReducesToDel'  item='item'  open='(' separator=',' close=')' > '${item.id}'</foreach>" +
+            "DELETE FROM platform_gb_channel WHERE platformId=#{platformId} AND deviceChannelId in" +
+            "<foreach collection='channelReducesToDel'  item='item'  open='(' separator=',' close=')' > #{item.id}</foreach>" +
             "</script>")
     int delChannelForGB(String platformId, List<ChannelReduce> channelReducesToDel);
 
@@ -50,14 +50,14 @@ public interface PlatformChannelMapper {
     int delChannelForDeviceId(String deviceId);
 
     @Delete("<script> "+
-            "DELETE FROM platform_gb_channel WHERE platformId='${platformId}'"  +
+            "DELETE FROM platform_gb_channel WHERE platformId=#{platformId}"  +
             "</script>")
     int cleanChannelForGB(String platformId);
 
-    @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId='${channelId}' and pgc.platformId='${platformId}'")
+    @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId=#{channelId} and pgc.platformId=#{platformId}")
     List<DeviceChannel> queryChannelInParentPlatform(String platformId, String channelId);
 
-    @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE pgc.platformId='${platformId}' and pgc.catalogId=#{catalogId}")
+    @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE pgc.platformId=#{platformId} and pgc.catalogId=#{catalogId}")
     List<DeviceChannel> queryAllChannelInCatalog(String platformId, String catalogId);
 
     @Select(" select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " +

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java

@@ -26,7 +26,7 @@ public interface PlatformGbStreamMapper {
             "(gbStreamId, platformId, catalogId) " +
             "values " +
             "<foreach collection='streamPushItems' index='index' item='item' separator=','> " +
-            "(${item.gbStreamId}, '${item.platformId}', '${item.catalogId}')" +
+            "(#{item.gbStreamId}, #{item.platformId}, #{item.catalogId})" +
             "</foreach> " +
             "</script>")
     int batchAdd(List<StreamPushItem> streamPushItems);

+ 2 - 2
src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java

@@ -14,10 +14,10 @@ import java.util.List;
 public interface RecordInfoDao {
 
     @Insert("INSERT INTO recordInfo (app, stream, mediaServerId, createTime, type, deviceId, channelId, name) VALUES" +
-            "('${app}', '${stream}', '${mediaServerId}', datetime('now','localtime')), '${type}', '${deviceId}', '${channelId}', '${name}'")
+            "(#{app}, #{stream}, #{mediaServerId}, datetime('now','localtime')), #{type}, #{deviceId}, #{channelId}, #{name}")
     int add(RecordInfo recordInfo);
 
-    @Delete("DELETE FROM user WHERE createTime < '${beforeTime}'")
+    @Delete("DELETE FROM user WHERE createTime < #{beforeTime}")
     int deleteBefore(String beforeTime);
 
     @Select("select * FROM recordInfo")

+ 4 - 4
src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java

@@ -12,14 +12,14 @@ import java.util.List;
 public interface RoleMapper {
 
     @Insert("INSERT INTO user_role (name, authority, createTime, updateTime) VALUES" +
-            "('${name}', '${authority}', '${createTime}', '${updateTime}')")
+            "(#{name}, #{authority}, #{createTime}, #{updateTime})")
     int add(Role role);
 
     @Update(value = {" <script>" +
             "UPDATE user_role " +
-            "SET updateTime='${updateTime}' " +
-            "<if test=\"name != null\">, name='${name}'</if>" +
-            "<if test=\"authority != null\">, authority='${authority}'</if>" +
+            "SET updateTime=#{updateTime} " +
+            "<if test=\"name != null\">, name=#{name}</if>" +
+            "<if test=\"authority != null\">, authority=#{authority}</if>" +
             "WHERE id != 1 and id=#{id}" +
             " </script>"})
     int update(Role role);

+ 7 - 7
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java

@@ -13,9 +13,9 @@ public interface StreamProxyMapper {
 
     @Insert("INSERT INTO stream_proxy (type, name, app, stream,mediaServerId, url, src_url, dst_url, " +
             "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_audio, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, createTime) VALUES" +
-            "('${type}','${name}', '${app}', '${stream}', '${mediaServerId}','${url}', '${src_url}', '${dst_url}', " +
-            "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_audio}, ${enable_mp4}, ${enable}, ${status}, " +
-            "${enable_remove_none_reader}, ${enable_disable_none_reader}, '${createTime}' )")
+            "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{src_url}, #{dst_url}, " +
+            "#{timeout_ms}, #{ffmpeg_cmd_key}, #{rtp_type}, #{enable_audio}, #{enable_mp4}, #{enable}, #{status}, " +
+            "#{enable_remove_none_reader}, #{enable_disable_none_reader}, #{createTime} )")
     int add(StreamProxyItem streamProxyDto);
 
     @Update("UPDATE stream_proxy " +
@@ -45,7 +45,7 @@ public interface StreamProxyMapper {
     @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.createTime desc")
     List<StreamProxyItem> selectAll();
 
-    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=${enable} order by st.createTime desc")
+    @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=#{enable} order by st.createTime desc")
     List<StreamProxyItem> selectForEnable(boolean enable);
 
     @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.createTime desc")
@@ -53,12 +53,12 @@ public interface StreamProxyMapper {
 
     @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " +
             "LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
-            "WHERE st.enable=${enable} and st.mediaServerId = #{id} order by st.createTime desc")
+            "WHERE st.enable=#{enable} and st.mediaServerId = #{id} order by st.createTime desc")
     List<StreamProxyItem> selectForEnableInMediaServer(String id, boolean enable);
 
     @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " +
             "LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
-            "WHERE st.mediaServerId = '${id}' order by st.createTime desc")
+            "WHERE st.mediaServerId = #{id} order by st.createTime desc")
     List<StreamProxyItem> selectInMediaServer(String id);
 
     @Update("UPDATE stream_proxy " +
@@ -67,7 +67,7 @@ public interface StreamProxyMapper {
     void updateStatusByMediaServerId(String mediaServerId, boolean status);
 
     @Update("UPDATE stream_proxy " +
-            "SET status=${status} " +
+            "SET status=#{status} " +
             "WHERE app=#{app} AND stream=#{stream}")
     int updateStatus(String app, String stream, boolean status);
 

+ 18 - 18
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java

@@ -17,23 +17,23 @@ public interface StreamPushMapper {
 
     @Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
             "pushTime, aliveSecond, mediaServerId, serverId, updateTime, createTime, pushIng, self) VALUES" +
-            "('${app}', '${stream}', '${totalReaderCount}', '${originType}', '${originTypeStr}', " +
-            "'${pushTime}', '${aliveSecond}', '${mediaServerId}' , '${serverId}' , '${updateTime}' , '${createTime}', " +
-            "${pushIng}, ${self} )")
+            "(#{app}, #{stream}, #{totalReaderCount}, #{originType}, #{originTypeStr}, " +
+            "#{pushTime}, #{aliveSecond}, #{mediaServerId} , #{serverId} , #{updateTime} , #{createTime}, " +
+            "#{pushIng}, #{self} )")
     int add(StreamPushItem streamPushItem);
 
 
     @Update(value = {" <script>" +
             "UPDATE stream_push " +
-            "SET updateTime='${updateTime}'" +
-            "<if test=\"mediaServerId != null\">, mediaServerId='${mediaServerId}'</if>" +
-            "<if test=\"totalReaderCount != null\">, totalReaderCount='${totalReaderCount}'</if>" +
-            "<if test=\"originType != null\">, originType=${originType}</if>" +
-            "<if test=\"originTypeStr != null\">, originTypeStr='${originTypeStr}'</if>" +
-            "<if test=\"pushTime != null\">, pushTime='${pushTime}'</if>" +
-            "<if test=\"aliveSecond != null\">, aliveSecond='${aliveSecond}'</if>" +
-            "<if test=\"pushIng != null\">, pushIng=${pushIng}</if>" +
-            "<if test=\"self != null\">, self=${self}</if>" +
+            "SET updateTime=#{updateTime}" +
+            "<if test=\"mediaServerId != null\">, mediaServerId=#{mediaServerId}</if>" +
+            "<if test=\"totalReaderCount != null\">, totalReaderCount=#{totalReaderCount}</if>" +
+            "<if test=\"originType != null\">, originType=#{originType}</if>" +
+            "<if test=\"originTypeStr != null\">, originTypeStr=#{originTypeStr}</if>" +
+            "<if test=\"pushTime != null\">, pushTime=#{pushTime}</if>" +
+            "<if test=\"aliveSecond != null\">, aliveSecond=#{aliveSecond}</if>" +
+            "<if test=\"pushIng != null\">, pushIng=#{pushIng}</if>" +
+            "<if test=\"self != null\">, self=#{self}</if>" +
             "WHERE app=#{app} AND stream=#{stream}"+
             " </script>"})
     int update(StreamPushItem streamPushItem);
@@ -76,7 +76,7 @@ public interface StreamPushMapper {
             "on st.app = gs.app AND st.stream = gs.stream " +
             "WHERE " +
             "1=1 " +
-            " <if test='query != null'> AND (st.app LIKE '%${query}%' OR st.stream LIKE '%${query}%' OR gs.gbId LIKE '%${query}%' OR gs.name LIKE '%${query}%')</if> " +
+            " <if test='query != null'> AND (st.app LIKE concat('%',#{query},'%') OR st.stream LIKE concat('%',#{query},'%') OR gs.gbId LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " +
             " <if test='pushing == true' > AND (gs.gbId is null OR st.pushIng=1)</if>" +
             " <if test='pushing == false' > AND (st.pushIng is null OR st.pushIng=0) </if>" +
             " <if test='mediaServerId != null' > AND st.mediaServerId=#{mediaServerId} </if>" +
@@ -94,9 +94,9 @@ public interface StreamPushMapper {
             "Insert IGNORE INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
             "createTime, aliveSecond, mediaServerId, status, pushIng) " +
             "VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" +
-            "( '${item.app}', '${item.stream}', '${item.totalReaderCount}', #{item.originType}, " +
-            "'${item.originTypeStr}',#{item.createTime}, #{item.aliveSecond}, '${item.mediaServerId}', ${item.status} ," +
-            " ${item.pushIng} )" +
+            "( #{item.app}, #{item.stream}, #{item.totalReaderCount}, #{item.originType}, " +
+            "#{item.originTypeStr},#{item.createTime}, #{item.aliveSecond}, #{item.mediaServerId}, #{item.status} ," +
+            " #{item.pushIng} )" +
             " </foreach>" +
             "</script>")
     @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
@@ -115,12 +115,12 @@ public interface StreamPushMapper {
     List<StreamPushItem> selectAllByMediaServerIdWithOutGbID(String mediaServerId);
 
     @Update("UPDATE stream_push " +
-            "SET status=${status} " +
+            "SET status=#{status} " +
             "WHERE app=#{app} AND stream=#{stream}")
     int updateStatus(String app, String stream, boolean status);
 
     @Update("UPDATE stream_push " +
-            "SET pushIng=${pushIng} " +
+            "SET pushIng=#{pushIng} " +
             "WHERE app=#{app} AND stream=#{stream}")
     int updatePushStatus(String app, String stream, boolean pushIng);
 

+ 8 - 8
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java

@@ -11,16 +11,16 @@ import java.util.List;
 public interface UserMapper {
 
     @Insert("INSERT INTO user (username, password, roleId, pushKey, createTime, updateTime) VALUES" +
-            "('${username}', '${password}', '${role.id}', '${pushKey}', '${createTime}', '${updateTime}')")
+            "(#{username}, #{password}, #{role.id}, #{pushKey}, #{createTime}, #{updateTime})")
     int add(User user);
 
     @Update(value = {" <script>" +
             "UPDATE user " +
-            "SET updateTime='${updateTime}' " +
-            "<if test=\"pushKey != null\">, pushKey='${pushKey}'</if>" +
-            "<if test=\"role != null\">, roleId='${role.id}'</if>" +
-            "<if test=\"password != null\">, password='${password}'</if>" +
-            "<if test=\"username != null\">, username='${username}'</if>" +
+            "SET updateTime=#{updateTime} " +
+            "<if test=\"pushKey != null\">, pushKey=#{pushKey}</if>" +
+            "<if test=\"role != null\">, roleId=#{role.id}</if>" +
+            "<if test=\"password != null\">, password=#{password}</if>" +
+            "<if test=\"username != null\">, username=#{username}</if>" +
             "WHERE id=#{id}" +
             " </script>"})
     int update(User user);
@@ -50,10 +50,10 @@ public interface UserMapper {
     @ResultMap(value="roleMap")
     List<User> selectAll();
 
-    @Select("select * from (select user.*, concat('${callId}_', pushKey) as str1 from user) as u where md5(u.str1) = '${sign}'")
+    @Select("select * from (select user.*, concat(concat(#{callId}, '_'), pushKey) as str1 from user) as u where md5(u.str1) = #{sign}")
     List<User> checkPushAuthorityByCallIdAndSign(String callId, String sign);
 
-    @Select("select * from user where md5(pushKey) = '${sign}'")
+    @Select("select * from user where md5(pushKey) = #{sign}")
     List<User> checkPushAuthorityByCallId(String sign);
 
     @Select("select u.id, u.username,u.pushKey,u.roleId, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u join user_role r on u.roleId=r.id")

+ 12 - 12
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java

@@ -224,31 +224,31 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 		PageHelper.startPage(page, count);
 		List<DeviceChannel> all;
 		if (catalogUnderDevice != null && catalogUnderDevice) {
-			all = deviceChannelMapper.queryChannels(deviceId, deviceId, query, hasSubChannel, online);
+			all = deviceChannelMapper.queryChannels(deviceId, deviceId, query, hasSubChannel, online,null);
 			// 海康设备的parentId是SIP id
-			List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, sipConfig.getId(), query, hasSubChannel, online);
+			List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, sipConfig.getId(), query, hasSubChannel, online,null);
 			all.addAll(deviceChannels);
 		}else {
-			all = deviceChannelMapper.queryChannels(deviceId, null, query, hasSubChannel, online);
+			all = deviceChannelMapper.queryChannels(deviceId, null, query, hasSubChannel, online,null);
 		}
 		return new PageInfo<>(all);
 	}
 
 	@Override
-	public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit) {
-		return deviceChannelMapper.queryChannelsByDeviceIdWithStartAndLimit(deviceId, null, query, hasSubChannel, online, start, limit);
+	public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit,List<String> channelIds) {
+		return deviceChannelMapper.queryChannelsByDeviceIdWithStartAndLimit(deviceId, null, query, hasSubChannel, online, start, limit,channelIds);
 	}
 
 
 	@Override
-	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
-		return deviceChannelMapper.queryChannels(deviceId, null,null, null, null);
+	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId,Boolean online,List<String> channelIds) {
+		return deviceChannelMapper.queryChannels(deviceId, null,null, null, online,channelIds);
 	}
 
 	@Override
 	public PageInfo<DeviceChannel> querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, int page, int count) {
 		PageHelper.startPage(page, count);
-		List<DeviceChannel> all = deviceChannelMapper.queryChannels(deviceId, parentChannelId, query, hasSubChannel, online);
+		List<DeviceChannel> all = deviceChannelMapper.queryChannels(deviceId, parentChannelId, query, hasSubChannel, online,null);
 		return new PageInfo<>(all);
 	}
 
@@ -271,9 +271,9 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 	 * @return PageInfo<Device> 分页设备对象数组
 	 */
 	@Override
-	public PageInfo<Device> queryVideoDeviceList(int page, int count) {
+	public PageInfo<Device> queryVideoDeviceList(int page, int count,Boolean online) {
 		PageHelper.startPage(page, count);
-		List<Device> all = deviceMapper.getDevices();
+		List<Device> all = deviceMapper.getDevices(online);
 		return new PageInfo<>(all);
 	}
 
@@ -283,9 +283,9 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 	 * @return List<Device> 设备对象数组
 	 */
 	@Override
-	public List<Device> queryVideoDeviceList() {
+	public List<Device> queryVideoDeviceList(Boolean online) {
 
-		List<Device> deviceList =  deviceMapper.getDevices();
+		List<Device> deviceList =  deviceMapper.getDevices(online);
 		return deviceList;
 	}
 

+ 3 - 4
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java

@@ -1,14 +1,13 @@
 package com.genersoft.iot.vmp.utils.redis;
 
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.utils.SpringBeanFactory;
-import gov.nist.javax.sip.stack.UDPMessageChannel;
 import org.springframework.data.redis.core.*;
 import org.springframework.util.CollectionUtils;
 
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
 /**    
  * Redis工具类
  * @author swwheihei

+ 1 - 2
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java

@@ -1,7 +1,5 @@
 package com.genersoft.iot.vmp.vmanager.bean;
 
-import io.swagger.v3.oas.annotations.media.Schema;
-
 /**
  * 全局错误码
  */
@@ -9,6 +7,7 @@ public enum ErrorCode {
     SUCCESS(0, "成功"),
     ERROR100(100, "失败"),
     ERROR400(400, "参数不全或者错误"),
+    ERROR404(404, "资源未找到"),
     ERROR403(403, "无权限操作"),
     ERROR401(401, "请登录后重新请求"),
     ERROR500(500, "系统异常");

+ 358 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java

@@ -0,0 +1,358 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import com.genersoft.iot.vmp.common.StreamInfo;
+
+public class StreamContent {
+
+    private String app;
+    private String stream;
+
+    private String ip;
+
+    private String flv;
+
+    private String https_flv;
+    private String ws_flv;
+    private String wss_flv;
+    private String fmp4;
+    private String https_fmp4;
+    private String ws_fmp4;
+    private String wss_fmp4;
+    private String hls;
+    private String https_hls;
+    private String ws_hls;
+    private String wss_hls;
+    private String ts;
+    private String https_ts;
+    private String ws_ts;
+    private String wss_ts;
+    private String rtmp;
+    private String rtmps;
+    private String rtsp;
+    private String rtsps;
+    private String rtc;
+
+    private String rtcs;
+    private String mediaServerId;
+    private Object tracks;
+
+    private String startTime;
+
+    private String endTime;
+
+    private double progress;
+
+    public StreamContent(StreamInfo streamInfo) {
+        if (streamInfo == null) {
+            return;
+        }
+        this.app = streamInfo.getApp();
+        this.stream = streamInfo.getStream();
+        if (streamInfo.getFlv() != null) {
+            this.flv = streamInfo.getFlv().getUrl();
+        }
+        if (streamInfo.getHttps_flv() != null) {
+            this.https_flv = streamInfo.getHttps_flv().getUrl();
+        }
+        if (streamInfo.getWs_flv() != null) {
+            this.ws_flv = streamInfo.getWs_flv().getUrl();
+        }
+        if (streamInfo.getWss_flv() != null) {
+            this.wss_flv = streamInfo.getWss_flv().getUrl();
+        }
+        if (streamInfo.getFmp4() != null) {
+            this.fmp4 = streamInfo.getFmp4().getUrl();
+        }
+        if (streamInfo.getWs_fmp4() != null) {
+            this.ws_fmp4 = streamInfo.getWs_fmp4().getUrl();
+        }
+        if (streamInfo.getWss_fmp4() != null) {
+            this.wss_fmp4 = streamInfo.getWss_fmp4().getUrl();
+        }
+        if (streamInfo.getHls() != null) {
+            this.hls = streamInfo.getHls().getUrl();
+        }
+        if (streamInfo.getHttps_hls() != null) {
+            this.https_hls = streamInfo.getHttps_hls().getUrl();
+        }
+        if (streamInfo.getWs_hls() != null) {
+            this.ws_hls = streamInfo.getWs_hls().getUrl();
+        }
+        if (streamInfo.getWss_hls() != null) {
+            this.wss_hls = streamInfo.getWss_hls().getUrl();
+        }
+        if (streamInfo.getTs() != null) {
+            this.ts = streamInfo.getTs().getUrl();
+        }
+        if (streamInfo.getHttps_ts() != null) {
+            this.https_ts = streamInfo.getHttps_ts().getUrl();
+        }
+        if (streamInfo.getWs_ts() != null) {
+            this.ws_ts = streamInfo.getWs_ts().getUrl();
+        }
+        if (streamInfo.getRtmp() != null) {
+            this.rtmp = streamInfo.getRtmp().getUrl();
+        }
+        if (streamInfo.getRtmps() != null) {
+            this.rtmps = streamInfo.getRtmps().getUrl();
+        }
+        if (streamInfo.getRtsp() != null) {
+            this.rtsp = streamInfo.getRtsp().getUrl();
+        }
+        if (streamInfo.getRtsps() != null) {
+            this.rtsps = streamInfo.getRtsps().getUrl();
+        }
+        if (streamInfo.getRtc() != null) {
+            this.rtc = streamInfo.getRtc().getUrl();
+        }
+        if (streamInfo.getRtcs() != null) {
+            this.rtcs = streamInfo.getRtcs().getUrl();
+        }
+
+        this.mediaServerId = streamInfo.getMediaServerId();
+        this.tracks = streamInfo.getTracks();
+        this.startTime = streamInfo.getStartTime();
+        this.endTime = streamInfo.getEndTime();
+        this.progress = streamInfo.getProgress();
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getFlv() {
+        return flv;
+    }
+
+    public void setFlv(String flv) {
+        this.flv = flv;
+    }
+
+    public String getHttps_flv() {
+        return https_flv;
+    }
+
+    public void setHttps_flv(String https_flv) {
+        this.https_flv = https_flv;
+    }
+
+    public String getWs_flv() {
+        return ws_flv;
+    }
+
+    public void setWs_flv(String ws_flv) {
+        this.ws_flv = ws_flv;
+    }
+
+    public String getWss_flv() {
+        return wss_flv;
+    }
+
+    public void setWss_flv(String wss_flv) {
+        this.wss_flv = wss_flv;
+    }
+
+    public String getFmp4() {
+        return fmp4;
+    }
+
+    public void setFmp4(String fmp4) {
+        this.fmp4 = fmp4;
+    }
+
+    public String getHttps_fmp4() {
+        return https_fmp4;
+    }
+
+    public void setHttps_fmp4(String https_fmp4) {
+        this.https_fmp4 = https_fmp4;
+    }
+
+    public String getWs_fmp4() {
+        return ws_fmp4;
+    }
+
+    public void setWs_fmp4(String ws_fmp4) {
+        this.ws_fmp4 = ws_fmp4;
+    }
+
+    public String getWss_fmp4() {
+        return wss_fmp4;
+    }
+
+    public void setWss_fmp4(String wss_fmp4) {
+        this.wss_fmp4 = wss_fmp4;
+    }
+
+    public String getHls() {
+        return hls;
+    }
+
+    public void setHls(String hls) {
+        this.hls = hls;
+    }
+
+    public String getHttps_hls() {
+        return https_hls;
+    }
+
+    public void setHttps_hls(String https_hls) {
+        this.https_hls = https_hls;
+    }
+
+    public String getWs_hls() {
+        return ws_hls;
+    }
+
+    public void setWs_hls(String ws_hls) {
+        this.ws_hls = ws_hls;
+    }
+
+    public String getWss_hls() {
+        return wss_hls;
+    }
+
+    public void setWss_hls(String wss_hls) {
+        this.wss_hls = wss_hls;
+    }
+
+    public String getTs() {
+        return ts;
+    }
+
+    public void setTs(String ts) {
+        this.ts = ts;
+    }
+
+    public String getHttps_ts() {
+        return https_ts;
+    }
+
+    public void setHttps_ts(String https_ts) {
+        this.https_ts = https_ts;
+    }
+
+    public String getWs_ts() {
+        return ws_ts;
+    }
+
+    public void setWs_ts(String ws_ts) {
+        this.ws_ts = ws_ts;
+    }
+
+    public String getWss_ts() {
+        return wss_ts;
+    }
+
+    public void setWss_ts(String wss_ts) {
+        this.wss_ts = wss_ts;
+    }
+
+    public String getRtmp() {
+        return rtmp;
+    }
+
+    public void setRtmp(String rtmp) {
+        this.rtmp = rtmp;
+    }
+
+    public String getRtmps() {
+        return rtmps;
+    }
+
+    public void setRtmps(String rtmps) {
+        this.rtmps = rtmps;
+    }
+
+    public String getRtsp() {
+        return rtsp;
+    }
+
+    public void setRtsp(String rtsp) {
+        this.rtsp = rtsp;
+    }
+
+    public String getRtsps() {
+        return rtsps;
+    }
+
+    public void setRtsps(String rtsps) {
+        this.rtsps = rtsps;
+    }
+
+    public String getRtc() {
+        return rtc;
+    }
+
+    public void setRtc(String rtc) {
+        this.rtc = rtc;
+    }
+
+    public String getRtcs() {
+        return rtcs;
+    }
+
+    public void setRtcs(String rtcs) {
+        this.rtcs = rtcs;
+    }
+
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
+    }
+
+    public Object getTracks() {
+        return tracks;
+    }
+
+    public void setTracks(Object tracks) {
+        this.tracks = tracks;
+    }
+
+    public String getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(String startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+
+    public double getProgress() {
+        return progress;
+    }
+
+    public void setProgress(double progress) {
+        this.progress = progress;
+    }
+}

+ 2 - 6
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java

@@ -14,7 +14,6 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
-
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -22,10 +21,8 @@ import io.swagger.v3.oas.annotations.tags.Tag;
 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.ObjectUtils;
-import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
@@ -130,15 +127,14 @@ public class DeviceControl {
 	 */
 	@Operation(summary = "布防/撤防命令")
 	@Parameter(name = "deviceId", description = "设备国标编号", required = true)
-	@Parameter(name = "channelId", description = "通道国标编号", required = true)
 	@Parameter(name = "guardCmdStr", description = "命令, 可选值:SetGuard(布防),ResetGuard(撤防)", required = true)
 	@GetMapping("/guard/{deviceId}/{guardCmdStr}")
-	public DeferredResult<String> guardApi(@PathVariable String deviceId, String channelId, @PathVariable String guardCmdStr) {
+	public DeferredResult<String> guardApi(@PathVariable String deviceId, @PathVariable String guardCmdStr) {
 		if (logger.isDebugEnabled()) {
 			logger.debug("布防/撤防API调用");
 		}
 		Device device = storager.queryVideoDevice(deviceId);
-		String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId;
+		String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + deviceId;
 		String uuid =UUID.randomUUID().toString();
 		try {
 			cmder.guardCmd(device, guardCmdStr, event -> {

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java

@@ -99,7 +99,7 @@ public class DeviceQuery {
 	@GetMapping("/devices")
 	public PageInfo<Device> devices(int page, int count){
 		
-		return storager.queryVideoDeviceList(page, count);
+		return storager.queryVideoDeviceList(page, count,null);
 	}
 
 	/**

+ 9 - 10
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java

@@ -5,11 +5,11 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.security.SecurityUtils;
 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
-import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.service.IMediaService;
+import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
-import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -53,11 +53,11 @@ public class MediaController {
     @Parameter(name = "useSourceIpAsStreamIp", description = "是否使用请求IP作为返回的地址IP")
     @GetMapping(value = "/stream_info_by_app_and_stream")
     @ResponseBody
-    public StreamInfo getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
-                                                             @RequestParam String stream,
-                                                             @RequestParam(required = false) String mediaServerId,
-                                                             @RequestParam(required = false) String callId,
-                                                             @RequestParam(required = false) Boolean useSourceIpAsStreamIp){
+    public StreamContent getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
+                                                     @RequestParam String stream,
+                                                     @RequestParam(required = false) String mediaServerId,
+                                                     @RequestParam(required = false) String callId,
+                                                     @RequestParam(required = false) Boolean useSourceIpAsStreamIp){
         boolean authority = false;
         if (callId != null) {
             // 权限校验
@@ -88,9 +88,8 @@ public class MediaController {
             streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
         }
 
-        WVPResult<StreamInfo> result = new WVPResult<>();
         if (streamInfo != null){
-            return  streamInfo;
+            return  new StreamContent(streamInfo);
         }else {
             //获取流失败,重启拉流后重试一次
             streamProxyService.stop(app,stream);
@@ -109,7 +108,7 @@ public class MediaController {
                 streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
             }
             if (streamInfo != null){
-                return  streamInfo;
+                return new StreamContent(streamInfo);
             }else {
                 throw new ControllerException(ErrorCode.ERROR100);
             }

+ 19 - 21
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java

@@ -22,6 +22,7 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx;
 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -85,8 +86,8 @@ public class PlayController {
 	@Parameter(name = "deviceId", description = "设备国标编号", required = true)
 	@Parameter(name = "channelId", description = "通道国标编号", required = true)
 	@GetMapping("/start/{deviceId}/{channelId}")
-	public DeferredResult<WVPResult<StreamInfo>> play(HttpServletRequest request, @PathVariable String deviceId,
-													  @PathVariable String channelId) {
+	public DeferredResult<WVPResult<StreamContent>> play(HttpServletRequest request, @PathVariable String deviceId,
+														 @PathVariable String channelId) {
 
 		// 获取可用的zlm
 		Device device = storager.queryVideoDevice(deviceId);
@@ -98,8 +99,8 @@ public class PlayController {
 		msg.setKey(key);
 		String uuid = UUID.randomUUID().toString();
 		msg.setId(uuid);
-		DeferredResult<WVPResult<StreamInfo>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
-		DeferredResultEx<WVPResult<StreamInfo>> deferredResultEx = new DeferredResultEx<>(result);
+		DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
+		DeferredResultEx<WVPResult<StreamContent>> deferredResultEx = new DeferredResultEx<>(result);
 
 		result.onTimeout(()->{
 			logger.info("点播接口等待超时");
@@ -110,25 +111,22 @@ public class PlayController {
 			msg.setData(wvpResult);
 			resultHolder.invokeResult(msg);
 		});
-
-		if (userSetting.getUseSourceIpAsStreamIp()) {
-			// TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误
-			deferredResultEx.setFilter(result1 -> {
-				WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1;
-				WVPResult<StreamInfo> clone = null;
-				try {
-					clone = (WVPResult<StreamInfo>)wvpResult1.clone();
-				} catch (CloneNotSupportedException e) {
-					throw new RuntimeException(e);
-				}
-				if (clone.getCode() == ErrorCode.SUCCESS.getCode()) {
-					StreamInfo data = clone.getData().clone();
+		// TODO 在点播未成功的情况下在此调用接口点播会导致返回的流地址ip错误
+		deferredResultEx.setFilter(result1 -> {
+			WVPResult<StreamInfo> wvpResult1 = (WVPResult<StreamInfo>)result1;
+			WVPResult<StreamContent> resultStream = new WVPResult<>();
+			resultStream.setCode(wvpResult1.getCode());
+			resultStream.setMsg(wvpResult1.getMsg());
+			if (wvpResult1.getCode() == ErrorCode.SUCCESS.getCode()) {
+				StreamInfo data = wvpResult1.getData().clone();
+				if (userSetting.getUseSourceIpAsStreamIp()) {
 					data.channgeStreamIp(request.getLocalName());
-					clone.setData(data);
 				}
-				return clone;
-			});
-		}
+				resultStream.setData(new StreamContent(wvpResult1.getData()));
+			}
+			return resultStream;
+		});
+
 
 		// 录像查询以channelId作为deviceId查询
 		resultHolder.put(key, uuid, deferredResultEx);

+ 24 - 9
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java

@@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -32,6 +33,7 @@ import org.springframework.web.context.request.async.DeferredResult;
 import javax.sip.InvalidArgumentException;
 import javax.sip.SipException;
 import java.text.ParseException;
+import java.util.UUID;
 
 /**
  * @author lin
@@ -68,24 +70,37 @@ public class PlaybackController {
 	@Parameter(name = "startTime", description = "开始时间", required = true)
 	@Parameter(name = "endTime", description = "结束时间", required = true)
 	@GetMapping("/start/{deviceId}/{channelId}")
-	public DeferredResult<WVPResult<StreamInfo>> play(@PathVariable String deviceId, @PathVariable String channelId,
-										  String startTime, String endTime) {
+	public DeferredResult<WVPResult<StreamContent>> 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));
 		}
 
+		String uuid = UUID.randomUUID().toString();
+		String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
+		DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(30000L);
+		resultHolder.put(key, uuid, result);
 
-		return playService.playBack(deviceId, channelId, startTime, endTime, null,
+		WVPResult<StreamContent> wvpResult = new WVPResult<>();
+
+		RequestMessage msg = new RequestMessage();
+		msg.setKey(key);
+		msg.setId(uuid);
+
+		playService.playBack(deviceId, channelId, startTime, endTime, null,
 				playBackResult->{
-					if (playBackResult.getCode() != ErrorCode.SUCCESS.getCode()) {
-						RequestMessage data = playBackResult.getData();
-						data.setData(WVPResult.fail(playBackResult.getCode(), playBackResult.getMsg()));
-						resultHolder.invokeResult(data);
-					}else {
-						resultHolder.invokeResult(playBackResult.getData());
+					wvpResult.setCode(playBackResult.getCode());
+					wvpResult.setMsg(playBackResult.getMsg());
+					if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {
+						StreamInfo streamInfo = (StreamInfo)playBackResult.getData();
+						wvpResult.setData(new StreamContent(streamInfo));
 					}
+					msg.setData(wvpResult);
+					resultHolder.invokeResult(msg);
 				});
+
+		return result;
 	}
 
 

+ 28 - 5
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java

@@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 
 import io.swagger.v3.oas.annotations.Operation;
@@ -121,15 +122,33 @@ public class GBRecordController {
 	@Parameter(name = "endTime", description = "结束时间", required = true)
 	@Parameter(name = "downloadSpeed", description = "下载倍速", required = true)
 	@GetMapping("/download/start/{deviceId}/{channelId}")
-	public DeferredResult<WVPResult<StreamInfo>> download(@PathVariable String deviceId, @PathVariable String channelId,
+	public DeferredResult<WVPResult<StreamContent>> download(@PathVariable String deviceId, @PathVariable String channelId,
 													   String startTime, String endTime, String downloadSpeed) {
 
 		if (logger.isDebugEnabled()) {
 			logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed));
 		}
 
-		DeferredResult<WVPResult<StreamInfo>> result = playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, hookCallBack->{
-			resultHolder.invokeResult(hookCallBack.getData());
+		String uuid = UUID.randomUUID().toString();
+		String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
+		DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(30000L);
+		resultHolder.put(key, uuid, result);
+		RequestMessage msg = new RequestMessage();
+		msg.setId(uuid);
+		msg.setKey(key);
+
+		WVPResult<StreamContent> wvpResult = new WVPResult<>();
+
+		playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, playBackResult->{
+
+			wvpResult.setCode(playBackResult.getCode());
+			wvpResult.setMsg(playBackResult.getMsg());
+			if (playBackResult.getCode() == ErrorCode.SUCCESS.getCode()) {
+				StreamInfo streamInfo = (StreamInfo)playBackResult.getData();
+				wvpResult.setData(new StreamContent(streamInfo));
+			}
+			msg.setData(wvpResult);
+			resultHolder.invokeResult(msg);
 		});
 
 		return result;
@@ -168,7 +187,11 @@ public class GBRecordController {
 	@Parameter(name = "channelId", description = "通道国标编号", required = true)
 	@Parameter(name = "stream", description = "流ID", required = true)
 	@GetMapping("/download/progress/{deviceId}/{channelId}/{stream}")
-	public StreamInfo getProgress(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
-		return playService.getDownLoadInfo(deviceId, channelId, stream);
+	public StreamContent getProgress(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
+		StreamInfo downLoadInfo = playService.getDownLoadInfo(deviceId, channelId, stream);
+		if (downLoadInfo == null) {
+			throw new ControllerException(ErrorCode.ERROR404);
+		}
+		return new StreamContent(downLoadInfo);
 	}
 }

+ 3 - 3
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java

@@ -1,13 +1,13 @@
 package com.genersoft.iot.vmp.vmanager.streamProxy;
 
 import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
 import com.github.pagehelper.PageInfo;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -58,7 +58,7 @@ public class StreamProxyController {
     })
     @PostMapping(value = "/save")
     @ResponseBody
-    public  StreamInfo save(@RequestBody StreamProxyItem param){
+    public StreamContent save(@RequestBody StreamProxyItem param){
         logger.info("添加代理: " + JSONObject.toJSONString(param));
         if (ObjectUtils.isEmpty(param.getMediaServerId())) {
             param.setMediaServerId("auto");
@@ -69,7 +69,7 @@ public class StreamProxyController {
         if (ObjectUtils.isEmpty(param.getGbId())) {
             param.setGbId(null);
         }
-        return streamProxyService.save(param);
+        return new StreamContent(streamProxyService.save(param));
     }
 
     @GetMapping(value = "/ffmpeg_cmd/list")

+ 4 - 12
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java

@@ -11,22 +11,16 @@ import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
 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.dto.StreamAuthorityInfo;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IMediaService;
 import com.genersoft.iot.vmp.service.IStreamPushService;
 import com.genersoft.iot.vmp.service.impl.StreamPushUploadFileHandler;
-import com.genersoft.iot.vmp.vmanager.bean.BatchGBStreamParam;
-import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
-import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
-import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+import com.genersoft.iot.vmp.vmanager.bean.*;
 import com.github.pagehelper.PageInfo;
-
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
-import org.apache.poi.sl.usermodel.Sheet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -34,12 +28,10 @@ import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
 import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 import org.springframework.web.multipart.MultipartFile;
 
-import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.HashMap;
@@ -243,8 +235,8 @@ public class StreamPushController {
     @Parameter(name = "app", description = "应用名", required = true)
     @Parameter(name = "stream", description = "流id", required = true)
     @Parameter(name = "mediaServerId", description = "媒体服务器id")
-    public StreamInfo getPlayUrl(@RequestParam String app,@RequestParam String stream,
-                                            @RequestParam(required = false) String mediaServerId){
+    public StreamContent getPlayUrl(@RequestParam String app, @RequestParam String stream,
+                                    @RequestParam(required = false) String mediaServerId){
         boolean authority = false;
         // 是否登陆用户, 登陆用户返回完整信息
         LoginUser userInfo = SecurityUtils.getUserInfo();
@@ -259,7 +251,7 @@ public class StreamPushController {
         if (streamInfo == null){
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取播放地址失败");
         }
-        return streamInfo;
+        return new StreamContent(streamInfo);
     }
 
     /**

+ 15 - 7
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java

@@ -10,8 +10,10 @@ import com.github.pagehelper.PageInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -59,10 +61,10 @@ public class ApiDeviceController {
         JSONObject result = new JSONObject();
         List<Device> devices;
         if (start == null || limit ==null) {
-            devices = storager.queryVideoDeviceList();
+            devices = storager.queryVideoDeviceList(online);
             result.put("DeviceCount", devices.size());
         }else {
-            PageInfo<Device> deviceList = storager.queryVideoDeviceList(start/limit, limit);
+            PageInfo<Device> deviceList = storager.queryVideoDeviceList(start/limit, limit,online);
             result.put("DeviceCount", deviceList.getTotal());
             devices = deviceList.getList();
         }
@@ -94,6 +96,7 @@ public class ApiDeviceController {
 
     @RequestMapping(value = "/channellist")
     public JSONObject channellist( String serial,
+                                   @RequestParam(required = false)String code,
                                    @RequestParam(required = false)String channel_type,
                                    @RequestParam(required = false)String dir_serial ,
                                    @RequestParam(required = false)Integer start,
@@ -113,12 +116,17 @@ public class ApiDeviceController {
             return result;
         }
         List<DeviceChannel> deviceChannels;
-        List<DeviceChannel> allDeviceChannelList = storager.queryChannelsByDeviceId(serial);
+        List<String> channelIds = null;
+        if (!StringUtils.isEmpty(code)) {
+            String[] split = code.trim().split(",");
+            channelIds = Arrays.asList(split);
+        }
+        List<DeviceChannel> allDeviceChannelList = storager.queryChannelsByDeviceId(serial,online,channelIds);
         if (start == null || limit ==null) {
             deviceChannels = allDeviceChannelList;
             result.put("ChannelCount", deviceChannels.size());
         }else {
-            deviceChannels = storager.queryChannelsByDeviceIdWithStartAndLimit(serial, null, null, null,start, limit);
+            deviceChannels = storager.queryChannelsByDeviceIdWithStartAndLimit(serial, null, null, online,start, limit,channelIds);
             int total = allDeviceChannelList.size();
             result.put("ChannelCount", total);
         }
@@ -148,9 +156,9 @@ public class ApiDeviceController {
                                                      // 1-IETF RFC3261,
                                                      // 2-基于口令的双向认证,
                                                      // 3-基于数字证书的双向认证
-            deviceJOSNChannel.put("Status", deviceChannel.getStatus());
-            deviceJOSNChannel.put("Longitude", deviceChannel.getLongitudeWgs84());
-            deviceJOSNChannel.put("Latitude", deviceChannel.getLatitudeWgs84());
+            deviceJOSNChannel.put("Status", deviceChannel.getStatus() == 1 ? "ON":"OFF");
+            deviceJOSNChannel.put("Longitude", deviceChannel.getLongitude());
+            deviceJOSNChannel.put("Latitude", deviceChannel.getLatitude());
             deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球,
                                                                             //   3 - 固定枪机, 4 - 遥控枪机
             deviceJOSNChannel.put("CustomPTZType", "");

+ 6 - 7
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java

@@ -12,7 +12,6 @@ import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.service.IPlayService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
-import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -120,12 +119,12 @@ public class ApiStreamController {
             result.put("ChannelID", code);
             result.put("ChannelName", deviceChannel.getName());
             result.put("ChannelCustomName", "");
-            result.put("FLV", streamInfo.getFlv());
-            result.put("WS_FLV", streamInfo.getWs_flv());
-            result.put("RTMP", streamInfo.getRtmp());
-            result.put("HLS", streamInfo.getHls());
-            result.put("RTSP", streamInfo.getRtsp());
-            result.put("WEBRTC", streamInfo.getRtc());
+            result.put("FLV", streamInfo.getFlv().getUrl());
+            result.put("WS_FLV", streamInfo.getWs_flv().getUrl());
+            result.put("RTMP", streamInfo.getRtmp().getUrl());
+            result.put("HLS", streamInfo.getHls().getUrl());
+            result.put("RTSP", streamInfo.getRtsp().getUrl());
+            result.put("WEBRTC", streamInfo.getRtc().getUrl());
             result.put("CDN", "");
             result.put("SnapURL", "");
             result.put("Transport", device.getTransport());

+ 6 - 2
src/main/resources/all-application.yml

@@ -168,7 +168,7 @@ user-settings:
     # 保存移动位置历史轨迹:true:保留历史数据,false:仅保留最后的位置(默认)
     save-position-history: false
     # 点播等待超时时间,单位:毫秒
-    play-timeout: 3000
+    play-timeout: 18000
     # 上级点播等待超时时间,单位:毫秒
     platform-play-timeout: 60000
     # 是否开启接口鉴权
@@ -186,7 +186,7 @@ user-settings:
     use-pushing-as-status: true
     # 使用来源请求ip作为streamIp,当且仅当你只有zlm节点它与wvp在一起的情况下开启
     use-source-ip-as-stream-ip: true
-    # 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放
+    # 国标点播 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放
     stream-on-demand: true
     # 推流鉴权, 默认开启
     push-authority: true
@@ -195,6 +195,10 @@ user-settings:
     gb-send-stream-strict: false
     # 设备上线时是否自动同步通道
     sync-channel-on-device-online: false
+    # 是否使用设备来源Ip作为回复IP, 不设置则为 false
+    sip-use-source-ip-as-remote-address: false
+    # 是否开启sip日志
+    sip-log: true
     # 收到ack消息后开始发流,默认false, 回复200ok后直接开始发流
     push-stream-after-ack: false
 

+ 15 - 2
web_src/src/components/CloudRecordDetail.vue

@@ -30,7 +30,7 @@
       </el-aside>
 			<el-main style="padding: 22px">
         <div class="playBox" :style="playerStyle">
-          <player ref="recordVideoPlayer" :videoUrl="videoUrl"  fluent autoplay :height="true" ></player>
+          <player ref="recordVideoPlayer" :videoUrl="videoUrl" :height="true" style="width: 100%" ></player>
         </div>
         <div class="player-option-box" >
           <el-slider
@@ -310,7 +310,20 @@
         let h = parseInt(val/3600);
         let m = parseInt((val - h*3600)/60);
         let s = parseInt(val - h*3600 - m*60);
-        return h + ":" + m + ":" + s
+
+        let hStr = h;
+        let mStr = m;
+        let sStr = s;
+        if (h < 10) {
+          hStr = "0" + hStr;
+        }
+        if (m < 10) {
+          mStr = "0" + mStr;s
+        }
+        if (s < 10) {
+          sStr = "0" + sStr;
+        }
+        return hStr + ":" + mStr + ":" + sStr
       },
       deleteRecord(){
 			  // TODO

+ 513 - 0
web_src/src/components/GBRecordDetail.vue

@@ -0,0 +1,513 @@
+<template>
+	<div style="width: 100%">
+    <div class="page-header" >
+      <div class="page-title">
+        <el-page-header @back="goBack" content="国标录像"></el-page-header>
+      </div>
+    </div>
+		<el-container>
+      <el-aside width="300px">
+        <div class="record-list-box-box">
+          <el-date-picker size="mini" v-model="chooseDate" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker>
+          <div class="record-list-box" v-loading="recordsLoading" :style="recordListStyle">
+            <ul v-if="detailFiles.length >0" class="infinite-list record-list" >
+              <li v-for="item in detailFiles" class="infinite-list-item record-list-item" >
+
+                <el-tag v-if="chooseFile != item" @click="checkedFile(item)">
+                  <i class="el-icon-video-camera"  ></i>
+                  {{ moment(item.startTime).format('HH:mm:ss')}}-{{ moment(item.endTime).format('HH:mm:ss')}}
+                </el-tag>
+                <el-tag v-if="chooseFile == item" type="danger" >
+                  <i class="el-icon-video-camera"  ></i>
+                  {{ moment(item.startTime).format('HH:mm:ss')}}-{{ moment(item.endTime).format('HH:mm:ss')}}
+                </el-tag>
+                <i style="color: #409EFF;margin-left: 5px;" class="el-icon-download" @click="downloadRecord(item)" ></i>
+              </li>
+            </ul>
+          </div>
+          <div size="mini" v-if="detailFiles.length ==0" class="record-list-no-val" >暂无数据</div>
+        </div>
+
+      </el-aside>
+			<el-main style="padding-bottom: 10px;">
+        <div class="playBox" :style="playerStyle">
+          <player ref="recordVideoPlayer"
+                  :videoUrl="videoUrl"
+                  :error="videoError"
+                  :message="videoError"
+                  :hasAudio="hasAudio"
+                  style="max-height: 100%"
+                  fluent autoplay live ></player>
+        </div>
+        <div class="player-option-box">
+          <div>
+            <el-button-group >
+              <el-time-picker
+                size="mini"
+                is-range
+                align="left"
+                v-model="timeRange"
+                value-format="yyyy-MM-dd HH:mm:ss"
+                range-separator="至"
+                start-placeholder="开始时间"
+                end-placeholder="结束时间"
+                @change="timePickerChange"
+                placeholder="选择时间范围">
+              </el-time-picker>
+            </el-button-group>
+
+            <el-button-group >
+              <el-button size="mini" class="iconfont icon-zanting" title="开始" @click="gbPause()"></el-button>
+              <el-button size="mini" class="iconfont icon-kaishi" title="暂停" @click="gbPlay()"></el-button>
+              <el-dropdown size="mini" title="播放倍速"  @command="gbScale">
+                <el-button size="mini">
+                  倍速 <i class="el-icon-arrow-down el-icon--right"></i>
+                </el-button>
+                <el-dropdown-menu  slot="dropdown">
+                  <el-dropdown-item command="0.25">0.25倍速</el-dropdown-item>
+                  <el-dropdown-item command="0.5">0.5倍速</el-dropdown-item>
+                  <el-dropdown-item command="1.0">1倍速</el-dropdown-item>
+                  <el-dropdown-item command="2.0">2倍速</el-dropdown-item>
+                  <el-dropdown-item command="4.0">4倍速</el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+              <el-button size="mini" class="iconfont icon-xiazai1" title="下载选定录像" @click="downloadRecord()"></el-button>
+              <el-button v-if="sliderMIn === 0 && sliderMax === 86400" size="mini" class="iconfont icon-slider" title="放大滑块" @click="setSliderFit()"></el-button>
+              <el-button v-if="sliderMIn !== 0 || sliderMax !== 86400" size="mini" class="iconfont icon-slider-right" title="恢复滑块" @click="setSliderFit()"></el-button>
+            </el-button-group>
+          </div>
+          <el-slider
+            class="playtime-slider"
+            v-model="playTime"
+            id="playtimeSlider"
+            :disabled="detailFiles.length === 0"
+            :min="sliderMIn"
+            :max="sliderMax"
+            :range="true"
+            :format-tooltip="playTimeFormat"
+            @change="playTimeChange"
+            :marks="playTimeSliderMarks">
+          </el-slider>
+          <div class="slider-val-box">
+            <div class="slider-val" v-for="item of detailFiles" :style="'width:' + getDataWidth(item) + '%; left:' + getDataLeft(item) + '%'"></div>
+          </div>
+        </div>
+
+			</el-main>
+		</el-container>
+    <recordDownload ref="recordDownload"></recordDownload>
+	</div>
+</template>
+
+
+<script>
+	import uiHeader from '../layout/UiHeader.vue'
+  import player from './common/jessibuca.vue'
+  import moment  from 'moment'
+  import recordDownload from './dialog/recordDownload.vue'
+	export default {
+		name: 'app',
+		components: {
+			uiHeader, player,recordDownload
+		},
+		data() {
+			return {
+        deviceId: this.$route.params.deviceId,
+        channelId: this.$route.params.channelId,
+        recordsLoading: false,
+        streamId: "",
+        hasAudio: false,
+			  detailFiles: [],
+        chooseDate: null,
+        videoUrl: null,
+        chooseFile: null,
+        streamInfo: null,
+        app: null,
+        mediaServerId: null,
+        ssrc: null,
+
+        sliderMIn: 0,
+        sliderMax: 86400,
+        autoPlay: true,
+        taskUpdate: null,
+        tabVal: "running",
+        recordListStyle: {
+			    height: this.winHeight + "px",
+          overflow: "auto",
+          margin: "10px auto 10px auto"
+        },
+        playerStyle: {
+			    "margin": "0 auto 20px auto",
+          "height": this.winHeight + "px",
+        },
+        winHeight: window.innerHeight - 240,
+        playTime: null,
+        timeRange: null,
+        startTime: null,
+        endTime: null,
+        playTimeSliderMarks: {
+			    0: "00:00",
+			    3600: "01:00",
+			    7200: "02:00",
+			    10800: "03:00",
+			    14400: "04:00",
+			    18000: "05:00",
+			    21600: "06:00",
+			    25200: "07:00",
+			    28800: "08:00",
+			    32400: "09:00",
+			    36000: "10:00",
+          39600: "11:00",
+			    43200: "12:00",
+			    46800: "13:00",
+			    50400: "14:00",
+			    54000: "15:00",
+			    57600: "16:00",
+			    61200: "17:00",
+			    64800: "18:00",
+			    68400: "19:00",
+          72000: "20:00",
+			    75600: "21:00",
+			    79200: "22:00",
+			    82800: "23:00",
+          86400: "24:00",
+        },
+			};
+		},
+		computed: {
+
+		},
+		mounted() {
+      this.recordListStyle.height = this.winHeight + "px";
+      this.playerStyle["height"] = this.winHeight + "px";
+      this.chooseDate = moment().format('YYYY-MM-DD')
+      this.dateChange();
+		},
+		destroyed() {
+			this.$destroy('recordVideoPlayer');
+		},
+		methods: {
+      dateChange(){
+        if (!this.chooseDate) {
+          return;
+        }
+
+        this.setTime(this.chooseDate + " 00:00:00", this.chooseDate + " 23:59:59");
+        this.recordsLoading = true;
+        this.detailFiles = [];
+        this.$axios({
+          method: 'get',
+          url: '/api/gb_record/query/' + this.deviceId + '/' + this.channelId + '?startTime=' + this.startTime + '&endTime=' + this.endTime
+        }).then((res)=>{
+          this.recordsLoading = false;
+          if(res.data.code === 0) {
+            // 处理时间信息
+            this.detailFiles = res.data.data.recordList;
+
+          }else {
+            this.$message({
+              showClose: true,
+              message: res.data.msg,
+              type: "error",
+            });
+          }
+
+        }).catch((e)=> {
+          this.recordsLoading = false;
+          // that.videoHistory.searchHistoryResult = falsificationData.recordData;
+        });
+      },
+      moment: function (v) {
+        return moment(v)
+      },
+      setTime: function (startTime, endTime){
+        this.startTime = startTime;
+        this.endTime = endTime;
+        let start = (new Date(this.startTime).getTime() - new Date(this.chooseDate + " 00:00:00").getTime())/1000;
+        let end = (new Date(this.endTime).getTime() - new Date(this.chooseDate + " 00:00:00").getTime())/1000;
+        console.log(start)
+        console.log(end)
+        this.playTime = [start, end];
+        this.timeRange = [startTime, endTime];
+      },
+      videoError: function (e) {
+        console.log("播放器错误:" + JSON.stringify(e));
+      },
+      checkedFile(file){
+        this.chooseFile = file;
+        this.setTime(file.startTime, file.endTime);
+			  // 开始回放
+        this.playRecord()
+      },
+      playRecord: function () {
+
+        if (this.streamId !== "") {
+          this.stopPlayRecord(()=> {
+            this.streamId = "";
+            this.playRecord();
+          })
+        } else {
+          this.$axios({
+            method: 'get',
+            url: '/api/playback/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + this.startTime + '&endTime=' +
+              this.endTime
+          }).then((res)=> {
+            if (res.data.code === 0) {
+              this.streamInfo = res.data.data;
+              this.app = this.streamInfo.app;
+              this.streamId = this.streamInfo.stream;
+              this.mediaServerId = this.streamInfo.mediaServerId;
+              this.ssrc = this.streamInfo.ssrc;
+              this.videoUrl = this.getUrlByStreamInfo();
+            }else {
+              this.$message({
+                showClose: true,
+                message: res.data.msg,
+                type: "error",
+              });
+            }
+          });
+        }
+      },
+      gbPlay(){
+        console.log('前端控制:播放');
+        this.$axios({
+          method: 'get',
+          url: '/api/playback/resume/' + this.streamId
+        }).then((res)=> {
+          this.$refs["recordVideoPlayer"].play(this.videoUrl)
+        });
+      },
+      gbPause(){
+        console.log('前端控制:暂停');
+        this.$axios({
+          method: 'get',
+          url: '/api/playback/pause/' + this.streamId
+        }).then(function (res) {});
+      },
+      gbScale(command){
+        console.log('前端控制:倍速 ' + command);
+        this.$axios({
+          method: 'get',
+          url: `/api/playback/speed/${this.streamId }/${command}`
+        }).then(function (res) {});
+      },
+      downloadRecord: function (row) {
+        if (!row) {
+          let startTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + this.playTime[0]*1000).format("YYYY-MM-DD HH:mm:ss");
+          let endTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + this.playTime[1]*1000).format("YYYY-MM-DD HH:mm:ss");
+          console.log(startTimeStr);
+          console.log(endTimeStr);
+          row = {
+            startTime: startTimeStr,
+            endTime: endTimeStr
+          }
+        }
+        if (this.streamId !== "") {
+          this.stopPlayRecord(()=> {
+            this.streamId = "";
+            this.downloadRecord(row);
+          })
+        }else {
+          this.$axios({
+            method: 'get',
+            url: '/api/gb_record/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' +
+              row.endTime + '&downloadSpeed=4'
+          }).then( (res)=> {
+            if (res.data.code === 0) {
+              let streamInfo = res.data.data;
+              this.$refs.recordDownload.openDialog(this.deviceId, this.channelId, streamInfo.app, streamInfo.stream, streamInfo.mediaServerId);
+            }else {
+              this.$message({
+                showClose: true,
+                message: res.data.msg,
+                type: "error",
+              });
+            }
+          });
+        }
+      },
+      stopDownloadRecord: function (callback) {
+        this.$refs["recordVideoPlayer"].pause();
+        this.videoUrl = '';
+        this.$axios({
+          method: 'get',
+          url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId
+        }).then((res)=> {
+          if (callback) callback(res)
+        });
+      },
+      stopPlayRecord: function (callback) {
+        this.$refs["recordVideoPlayer"].pause();
+        this.videoUrl = '';
+        this.$axios({
+          method: 'get',
+          url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId
+        }).then(function (res) {
+          if (callback) callback()
+        });
+      },
+      getDataWidth(item){
+        let timeForFile = this.getTimeForFile(item);
+        let result = (timeForFile[2])/((this.sliderMax - this.sliderMIn)*1000)
+        return result*100
+      },
+      getDataLeft(item){
+        let timeForFile = this.getTimeForFile(item);
+        let differenceTime = timeForFile[0].getTime() - new Date(this.chooseDate + " 00:00:00").getTime()
+        return parseFloat((differenceTime - this.sliderMIn * 1000)/((this.sliderMax - this.sliderMIn)*1000))*100   ;
+      },
+      getUrlByStreamInfo(){
+        if (location.protocol === "https:") {
+          this.videoUrl = this.streamInfo["wss_flv"]
+        }else {
+          this.videoUrl = this.streamInfo["ws_flv"]
+        }
+        return this.videoUrl;
+
+      },
+      timePickerChange: function (val){
+        this.setTime(val[0], val[1])
+      },
+      playTimeChange(val){
+        console.log(val)
+
+        let startTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + val[0]*1000).format("YYYY-MM-DD HH:mm:ss");
+        let endTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + val[1]*1000).format("YYYY-MM-DD HH:mm:ss");
+
+        this.setTime(startTimeStr, endTimeStr)
+
+        this.playRecord();
+      },
+      setSliderFit() {
+        if (this.sliderMIn === 0 && this.sliderMax === 86400) {
+          if (this.detailFiles.length > 0){
+            let timeForFile = this.getTimeForFile(this.detailFiles[0]);
+            let lastTimeForFile = this.getTimeForFile(this.detailFiles[this.detailFiles.length - 1]);
+            let timeNum = timeForFile[0].getTime() - new Date(this.chooseDate + " " + "00:00:00").getTime()
+            let lastTimeNum = lastTimeForFile[1].getTime() - new Date(this.chooseDate + " " + "00:00:00").getTime()
+
+            this.playTime = parseInt(timeNum/1000)
+            this.sliderMIn = parseInt(timeNum/1000 - timeNum/1000%(60*60))
+            this.sliderMax = parseInt(lastTimeNum/1000 - lastTimeNum/1000%(60*60)) + 60*60
+
+            this.playTime = [this.sliderMIn, this.sliderMax];
+          }
+        }else {
+          this.sliderMIn = 0;
+          this.sliderMax = 86400;
+        }
+      },
+      getTimeForFile(file){
+        let startTime = new Date(file.startTime);
+        let endTime = new Date(file.endTime);
+        return [startTime, endTime, endTime.getTime() - startTime.getTime()];
+      },
+      playTimeFormat(val){
+        let h = parseInt(val/3600);
+        let m = parseInt((val - h*3600)/60);
+        let s = parseInt(val - h*3600 - m*60);
+
+        let hStr = h;
+        let mStr = m;
+        let sStr = s;
+        if (h < 10) {
+          hStr = "0" + hStr;
+        }
+        if (m < 10) {
+          mStr = "0" + mStr;s
+        }
+        if (s < 10) {
+          sStr = "0" + sStr;
+        }
+        return hStr + ":" + mStr + ":" + sStr
+      },
+      goBack(){
+        window.history.go(-1);
+      }
+		}
+	};
+</script>
+
+<style>
+  .el-slider__runway {
+    background-color:rgba(206, 206, 206, 0.47) !important;
+  }
+  .el-slider__bar {
+    background-color: rgba(153, 153, 153, 0) !important;
+  }
+  .playtime-slider {
+    position: relative;
+    z-index: 100;
+  }
+  .data-picker-true{
+
+  }
+  .data-picker-true:after{
+    content: "";
+    position: absolute;
+    width: 4px;
+    height: 4px;
+    background-color: #606060;
+    border-radius: 4px;
+    left: 45%;
+    top: 74%;
+
+  }
+  .data-picker-false{
+
+  }
+  .slider-val-box{
+    height: 6px;
+    position: relative;
+    top: -22px;
+  }
+  .slider-val{
+    height: 6px;
+    background-color: #007CFF;
+    position: absolute;
+  }
+  .record-list-box-box{
+    width: 250px;
+    float: left;
+  }
+  .record-list-box{
+    overflow: auto;
+    width: 220px;
+    list-style: none;
+    padding: 0;
+    margin: 0;
+    margin-top: 0px;
+    padding: 1rem 0;
+    background-color: #FFF;
+    margin-top: 10px;
+  }
+  .record-list{
+    list-style: none;
+    padding: 0;
+    margin: 0;
+    background-color: #FFF;
+
+  }
+  .record-list-no-val {
+    position: absolute;
+    color: #9f9f9f;
+    top: 50%;
+    left: 110px;
+  }
+  .record-list-item{
+    padding: 0;
+    margin: 0;
+    margin: 0.5rem 0;
+    cursor: pointer;
+  }
+  .record-list-option {
+    width: 10px;
+    float: left;
+    margin-top: 39px;
+
+  }
+  .player-option-box{
+    padding: 0 20px;
+  }
+</style>

+ 2 - 2
web_src/src/components/channelList.vue

@@ -269,10 +269,10 @@ export default {
       });
     },
     queryRecords: function (itemData) {
-      var format = moment().format("yyyy-MM-DD");
       let deviceId = this.deviceId;
       let channelId = itemData.channelId;
-      this.$refs.devicePlayer.openDialog("record", deviceId, channelId, {date: format})
+
+      this.$router.push(`/gbRecordDetail/${deviceId}/${channelId}`)
     },
     stopDevicePush: function (itemData) {
       var that = this;

+ 8 - 5
web_src/src/components/console.vue

@@ -101,11 +101,14 @@ export default {
         window.clearTimeout(this.timer);
       }
       this.timer = setTimeout(()=>{
-        this.getSystemInfo();
-        this.getLoad();
-        this.timer = null;
-        this.loopForSystemInfo()
-        this.getResourceInfo()
+        if (this.$route.path === "/console") {
+          this.getSystemInfo();
+          this.getLoad();
+          this.timer = null;
+          this.loopForSystemInfo()
+          this.getResourceInfo()
+        }
+
       }, 2000)
     },
     getSystemInfo: function (){

+ 8 - 4
web_src/src/components/console/ConsoleResource.vue

@@ -1,28 +1,32 @@
 <template >
   <div id="consoleResource" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
     <div style="width: 50%;height: 50%; float:left; ">
-      <el-progress :width="100" :stroke-width="8" type="circle" :percentage="Math.floor(deviceInfo.online/deviceInfo.total*100)" style="margin-top: 20px; font-size: 18px"></el-progress>
+      <el-progress v-if="deviceInfo.total > 0" :width="100" :stroke-width="8" type="circle" :percentage="Math.floor(deviceInfo.online/deviceInfo.total*100)" style="margin-top: 20px; font-size: 18px"></el-progress>
+      <el-progress v-if="deviceInfo.total === 0" :width="100" :stroke-width="8" type="circle" :percentage="0" style="margin-top: 20px; font-size: 18px"></el-progress>
       <div class="resourceInfo">
         设备总数:{{deviceInfo.total}}<br/>
         在线数:{{deviceInfo.online}}
       </div>
     </div>
     <div style="width: 50%;height: 50%; float:left; ">
-      <el-progress :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(channelInfo.online/channelInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="channelInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(channelInfo.online/channelInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="channelInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
       <div class="resourceInfo">
         通道总数:{{channelInfo.total}}<br/>
         在线数:{{channelInfo.online}}
       </div>
     </div>
     <div style="width: 50%;height: 50%; float:left; ">
-      <el-progress :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(pushInfo.online/pushInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="pushInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(pushInfo.online/pushInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="pushInfo.total === 0"  :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
       <div class="resourceInfo">
         推流总数:{{pushInfo.total}}<br/>
         在线数:{{pushInfo.online}}
       </div>
     </div>
     <div style="width: 50%;height: 50%; float:left; ">
-      <el-progress :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(proxyInfo.online/proxyInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="proxyInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(proxyInfo.online/proxyInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="proxyInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
       <div class="resourceInfo">
         拉流代理总数:{{proxyInfo.total}}<br/>
         在线数:{{proxyInfo.online}}

+ 47 - 425
web_src/src/components/dialog/devicePlayer.vue

@@ -20,11 +20,6 @@
         <div id="shared" style="text-align: right; margin-top: 1rem;">
             <el-tabs v-model="tabActiveName" @tab-click="tabHandleClick" >
                 <el-tab-pane label="实时视频" name="media">
-                    <div style="margin-bottom: 0.5rem;">
-                        <!--		<el-button type="primary" size="small" @click="playRecord(true, '')">播放</el-button>-->
-                        <!--		 <el-button type="primary" size="small" @click="startRecord()">录制</el-button>-->
-                        <!--		 <el-button type="primary" size="small" @click="stopRecord()">停止录制</el-button>-->
-                    </div>
                     <div style="display: flex; margin-bottom: 0.5rem; height: 2.5rem;">
                         <span style="width: 5rem; line-height: 2.5rem; text-align: right;">播放地址:</span>
                         <el-input v-model="getPlayerShared.sharedUrl" :disabled="true" >
@@ -50,93 +45,93 @@
                                 更多地址<i class="el-icon-arrow-down el-icon--right"></i>
                               </el-button>
                               <el-dropdown-menu slot="dropdown" >
-                                <el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv.url">
+                                <el-dropdown-item v-if="streamInfo.flv" :command="streamInfo.flv">
                                   <el-tag >FLV:</el-tag>
-                                  <span>{{ streamInfo.flv.url }}</span>
+                                  <span>{{ streamInfo.flv }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.https_flv" :command="streamInfo.https_flv.url">
+                                <el-dropdown-item v-if="streamInfo.https_flv" :command="streamInfo.https_flv">
                                   <el-tag >FLV(https):</el-tag>
-                                  <span>{{ streamInfo.https_flv.url }}</span>
+                                  <span>{{ streamInfo.https_flv }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.ws_flv" :command="streamInfo.ws_flv.url">
+                                <el-dropdown-item v-if="streamInfo.ws_flv" :command="streamInfo.ws_flv">
                                   <el-tag  >FLV(ws):</el-tag>
-                                  <span >{{ streamInfo.ws_flv.url }}</span>
+                                  <span >{{ streamInfo.ws_flv }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.wss_flv" :command="streamInfo.wss_flv.url">
+                                <el-dropdown-item v-if="streamInfo.wss_flv" :command="streamInfo.wss_flv">
                                   <el-tag  >FLV(wss):</el-tag>
-                                  <span>{{ streamInfo.wss_flv.url }}</span>
+                                  <span>{{ streamInfo.wss_flv }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.fmp4" :command="streamInfo.fmp4.url">
+                                <el-dropdown-item v-if="streamInfo.fmp4" :command="streamInfo.fmp4">
                                   <el-tag >FMP4:</el-tag>
-                                  <span>{{ streamInfo.fmp4.url }}</span>
+                                  <span>{{ streamInfo.fmp4 }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.https_fmp4" :command="streamInfo.https_fmp4.url">
+                                <el-dropdown-item v-if="streamInfo.https_fmp4" :command="streamInfo.https_fmp4">
                                   <el-tag >FMP4(https):</el-tag>
-                                  <span>{{ streamInfo.https_fmp4.url }}</span>
+                                  <span>{{ streamInfo.https_fmp4 }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.ws_fmp4" :command="streamInfo.ws_fmp4.url">
+                                <el-dropdown-item v-if="streamInfo.ws_fmp4" :command="streamInfo.ws_fmp4">
                                   <el-tag >FMP4(ws):</el-tag>
-                                  <span>{{ streamInfo.ws_fmp4.url }}</span>
+                                  <span>{{ streamInfo.ws_fmp4 }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.wss_fmp4" :command="streamInfo.wss_fmp4.url">
+                                <el-dropdown-item v-if="streamInfo.wss_fmp4" :command="streamInfo.wss_fmp4">
                                   <el-tag >FMP4(wss):</el-tag>
-                                  <span>{{ streamInfo.wss_fmp4.url }}</span>
+                                  <span>{{ streamInfo.wss_fmp4 }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.hls" :command="streamInfo.hls.url">
+                                <el-dropdown-item v-if="streamInfo.hls" :command="streamInfo.hls">
                                   <el-tag>HLS:</el-tag>
-                                  <span>{{ streamInfo.hls.url }}</span>
+                                  <span>{{ streamInfo.hls }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.https_hls" :command="streamInfo.https_hls.url">
+                                <el-dropdown-item v-if="streamInfo.https_hls" :command="streamInfo.https_hls">
                                   <el-tag >HLS(https):</el-tag>
-                                  <span>{{ streamInfo.https_hls.url }}</span>
+                                  <span>{{ streamInfo.https_hls }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.ws_hls" :command="streamInfo.ws_hls.url">
+                                <el-dropdown-item v-if="streamInfo.ws_hls" :command="streamInfo.ws_hls">
                                   <el-tag >HLS(ws):</el-tag>
-                                  <span>{{ streamInfo.ws_hls.url }}</span>
+                                  <span>{{ streamInfo.ws_hls }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.wss_hls"  :command="streamInfo.wss_hls.url">
+                                <el-dropdown-item v-if="streamInfo.wss_hls"  :command="streamInfo.wss_hls">
                                   <el-tag >HLS(wss):</el-tag>
-                                  <span>{{ streamInfo.wss_hls.url }}</span>
+                                  <span>{{ streamInfo.wss_hls }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.ts"  :command="streamInfo.ts.url">
+                                <el-dropdown-item v-if="streamInfo.ts"  :command="streamInfo.ts">
                                   <el-tag>TS:</el-tag>
-                                  <span>{{ streamInfo.ts.url }}</span>
+                                  <span>{{ streamInfo.ts }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.https_ts" :command="streamInfo.https_ts.url">
+                                <el-dropdown-item v-if="streamInfo.https_ts" :command="streamInfo.https_ts">
                                   <el-tag>TS(https):</el-tag>
-                                  <span>{{ streamInfo.https_ts.url }}</span>
+                                  <span>{{ streamInfo.https_ts }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.ws_ts" :command="streamInfo.ws_ts.url">
+                                <el-dropdown-item v-if="streamInfo.ws_ts" :command="streamInfo.ws_ts">
                                   <el-tag>TS(ws):</el-tag>
-                                  <span>{{ streamInfo.ws_ts.url }}</span>
+                                  <span>{{ streamInfo.ws_ts }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.wss_ts" :command="streamInfo.wss_ts.url">
+                                <el-dropdown-item v-if="streamInfo.wss_ts" :command="streamInfo.wss_ts">
                                   <el-tag>TS(wss):</el-tag>
-                                  <span>{{ streamInfo.wss_ts.url }}</span>
+                                  <span>{{ streamInfo.wss_ts }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.rtc" :command="streamInfo.rtc.url">
+                                <el-dropdown-item v-if="streamInfo.rtc" :command="streamInfo.rtc">
                                   <el-tag >RTC:</el-tag>
-                                  <span>{{ streamInfo.rtc.url }}</span>
+                                  <span>{{ streamInfo.rtc }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.rtcs" :command="streamInfo.rtcs.url">
+                                <el-dropdown-item v-if="streamInfo.rtcs" :command="streamInfo.rtcs">
                                   <el-tag >RTCS:</el-tag>
                                   <span>{{ streamInfo.rtcs }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.rtmp" :command="streamInfo.rtmp.url">
+                                <el-dropdown-item v-if="streamInfo.rtmp" :command="streamInfo.rtmp">
                                   <el-tag >RTMP:</el-tag>
-                                  <span>{{ streamInfo.rtmp.url }}</span>
+                                  <span>{{ streamInfo.rtmp }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.rtmps" :command="streamInfo.rtmps.url">
+                                <el-dropdown-item v-if="streamInfo.rtmps" :command="streamInfo.rtmps">
                                   <el-tag >RTMPS:</el-tag>
-                                  <span>{{ streamInfo.rtmps.url }}</span>
+                                  <span>{{ streamInfo.rtmps }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.rtsp" :command="streamInfo.rtsp.url">
+                                <el-dropdown-item v-if="streamInfo.rtsp" :command="streamInfo.rtsp">
                                   <el-tag >RTSP:</el-tag>
-                                  <span>{{ streamInfo.rtsp.url }}</span>
+                                  <span>{{ streamInfo.rtsp }}</span>
                                 </el-dropdown-item>
-                                <el-dropdown-item v-if="streamInfo.rtsps" :command="streamInfo.rtsps.url">
+                                <el-dropdown-item v-if="streamInfo.rtsps" :command="streamInfo.rtsps">
                                   <el-tag >RTSPS:</el-tag>
-                                  <span>{{ streamInfo.rtsps.url }}</span>
+                                  <span>{{ streamInfo.rtsps }}</span>
                                 </el-dropdown-item>
                               </el-dropdown-menu>
                             </el-dropdown>
@@ -145,51 +140,6 @@
                     </div>
                 </el-tab-pane>
                 <!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}-->
-                <el-tab-pane label="录像查询" name="record" v-if="showRrecord">
-                    <div style="width: 100%;">
-                      <div style="width: 100%; text-align: left">
-                        <span>录像控制</span>
-                        <el-button-group style="margin-left: 1rem;">
-                          <el-button size="mini" class="iconfont icon-zanting" title="开始" @click="gbPause()"></el-button>
-                          <el-button size="mini" class="iconfont icon-kaishi" title="暂停" @click="gbPlay()"></el-button>
-                          <el-dropdown size="mini" title="播放倍速" style="margin-left: 1px;" @command="gbScale">
-                            <el-button size="mini">
-                              倍速 <i class="el-icon-arrow-down el-icon--right"></i>
-                            </el-button>
-                            <el-dropdown-menu  slot="dropdown">
-                              <el-dropdown-item command="0.25">0.25倍速</el-dropdown-item>
-                              <el-dropdown-item command="0.5">0.5倍速</el-dropdown-item>
-                              <el-dropdown-item command="1.0">1倍速</el-dropdown-item>
-                              <el-dropdown-item command="2.0">2倍速</el-dropdown-item>
-                              <el-dropdown-item command="4.0">4倍速</el-dropdown-item>
-                            </el-dropdown-menu>
-                          </el-dropdown>
-                        </el-button-group>
-                        <el-date-picker style="float: right;" size="mini" v-model="videoHistory.date" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="queryRecords()"></el-date-picker>
-                      </div>
-                      <div style="width: 100%; text-align: left">
-                        <span class="demonstration" style="padding: 12px 36px 12px 0;float: left;">{{showTimeText}}</span>
-                        <el-slider style="width: 80%; float:left;" v-model="sliderTime" @change="gbSeek" :show-tooltip="false"></el-slider>
-                      </div>
-                    </div>
-
-
-                    <el-table :data="videoHistory.searchHistoryResult" height="150" v-loading="recordsLoading">
-                        <el-table-column label="名称" prop="name"></el-table-column>
-                        <el-table-column label="文件" prop="filePath"></el-table-column>
-                        <el-table-column label="开始时间" prop="startTime" :formatter="timeFormatter"></el-table-column>
-                        <el-table-column label="结束时间" prop="endTime" :formatter="timeFormatter"></el-table-column>
-
-                        <el-table-column label="操作">
-                            <template slot-scope="scope">
-                                <el-button-group>
-                                    <el-button icon="el-icon-video-play" size="mini" @click="playRecord(scope.row)">播放</el-button>
-                                    <el-button icon="el-icon-download" size="mini" @click="downloadRecord(scope.row)">下载</el-button>
-                                </el-button-group>
-                            </template>
-                        </el-table-column>
-                    </el-table>
-                </el-tab-pane>
                 <!--遥控界面-->
                 <el-tab-pane label="云台控制" name="control" v-if="showPtz">
                     <div style="display: flex; justify-content: left;">
@@ -295,20 +245,19 @@
             </el-tabs>
         </div>
     </el-dialog>
-    <recordDownload ref="recordDownload"></recordDownload>
 </div>
 </template>
 
 <script>
 import rtcPlayer from '../dialog/rtcPlayer.vue'
+import LivePlayer from '@liveqing/liveplayer'
 import crypto from 'crypto'
 import jessibucaPlayer from '../common/jessibuca.vue'
-import recordDownload from '../dialog/recordDownload.vue'
 export default {
     name: 'devicePlayer',
     props: {},
     components: {
-      jessibucaPlayer, rtcPlayer, recordDownload,
+      LivePlayer, jessibucaPlayer, rtcPlayer,
     },
     computed: {
         getPlayerShared: function () {
@@ -337,10 +286,6 @@ export default {
               jessibuca : ["ws_flv", "wss_flv"],
               webRTC: ["rtc", "rtcs"],
             },
-            videoHistory: {
-                date: '',
-                searchHistoryResult: [] //媒体流历史记录搜索结果
-            },
             showVideoDialog: false,
             streamId: '',
             app : '',
@@ -366,7 +311,6 @@ export default {
             tracks: [],
             coverPlaying:false,
             tracksLoading: false,
-            recordPlay: "",
             showPtz: true,
             showRrecord: true,
             tracksNotLoaded: false,
@@ -429,11 +373,6 @@ export default {
                 case "media":
                     this.play(param.streamInfo, param.hasAudio)
                     break;
-                case "record":
-                    this.showVideoDialog = true;
-                    this.videoHistory.date = param.date;
-                    this.queryRecords()
-                    break;
                 case "streamPlay":
                     this.tabActiveName = "media";
                     this.showRrecord = false;
@@ -444,9 +383,6 @@ export default {
                     break;
             }
         },
-        timeAxisSelTime: function (val) {
-            console.log(val)
-        },
         play: function (streamInfo, hasAudio) {
             this.streamInfo = streamInfo;
             this.hasAudio = hasAudio;
@@ -461,9 +397,9 @@ export default {
         getUrlByStreamInfo(){
             console.log(this.streamInfo)
             if (location.protocol === "https:") {
-              this.videoUrl = this.streamInfo[this.player[this.activePlayer][1]].url
+              this.videoUrl = this.streamInfo[this.player[this.activePlayer][1]]
             }else {
-              this.videoUrl = this.streamInfo[this.player[this.activePlayer][0]].url
+              this.videoUrl = this.streamInfo[this.player[this.activePlayer][0]]
             }
             return this.videoUrl;
 
@@ -542,10 +478,6 @@ export default {
               this.convertStop();
             }
             this.convertKey = ''
-            if (this.recordPlay != '') {
-              this.stopPlayRecord();
-            }
-            this.recordPlay = ''
             this.stopBroadcast()
         },
 
@@ -571,137 +503,6 @@ export default {
                 }
             );
         },
-
-        queryRecords: function () {
-            if (!this.videoHistory.date) {
-                return;
-            }
-            this.recordsLoading = true;
-            this.videoHistory.searchHistoryResult = [];
-            let that = this;
-            var startTime = this.videoHistory.date + " 00:00:00";
-            var endTime = this.videoHistory.date + " 23:59:59";
-            this.$axios({
-                method: 'get',
-                url: '/api/gb_record/query/' + this.deviceId + '/' + this.channelId + '?startTime=' + startTime + '&endTime=' + endTime
-            }).then(function (res) {
-                console.log(res)
-                that.recordsLoading = false;
-                if(res.data.code === 0) {
-                  // 处理时间信息
-                  that.videoHistory.searchHistoryResult = res.data.data.recordList;
-                }else {
-                  this.$message({
-                    showClose: true,
-                    message: res.data.msg,
-                    type: "error",
-                  });
-                }
-
-            }).catch(function (e) {
-                console.log(e.message);
-                // that.videoHistory.searchHistoryResult = falsificationData.recordData;
-            });
-
-        },
-        onTimeChange: function (video) {
-            // this.queryRecords()
-        },
-        playRecord: function (row) {
-            let that = this;
-
-            let startTime = row.startTime
-            this.recordStartTime = row.startTime
-            this.showTimeText =  row.startTime.split(" ")[1]
-            let endtime = row.endTime
-            this.sliderTime = 0;
-            this.seekTime = new Date(endtime).getTime() - new Date(startTime).getTime();
-            console.log(this.seekTime)
-            if (that.streamId != "") {
-                that.stopPlayRecord(function () {
-                    that.streamId = "";
-                    that.playRecord(row);
-                })
-            } else {
-                this.$axios({
-                    method: 'get',
-                    url: '/api/playback/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' +
-                        row.endTime
-                }).then(function (res) {
-                  if (res.data.code === 0) {
-                    that.streamInfo = res.data.data;
-                    that.app = that.streamInfo.app;
-                    that.streamId = that.streamInfo.stream;
-                    that.mediaServerId = that.streamInfo.mediaServerId;
-                    that.ssrc = that.streamInfo.ssrc;
-                    that.videoUrl = that.getUrlByStreamInfo();
-                  }else {
-                    that.$message({
-                      showClose: true,
-                      message: res.data.msg,
-                      type: "error",
-                    });
-                  }
-                  that.recordPlay = true;
-                });
-            }
-        },
-        stopPlayRecord: function (callback) {
-          this.$refs[this.activePlayer].pause();
-            this.videoUrl = '';
-            this.$axios({
-                method: 'get',
-                url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId
-            }).then(function (res) {
-                if (callback) callback()
-            });
-        },
-        downloadRecord: function (row) {
-            let that = this;
-            if (that.streamId != "") {
-                that.stopDownloadRecord(function (res) {
-                  if (res.code == 0) {
-                    that.streamId = "";
-                    that.downloadRecord(row);
-                  }else {
-                    this.$message({
-                      showClose: true,
-                      message: res.data.msg,
-                      type: "error",
-                    });
-                  }
-
-                })
-            } else {
-                this.$axios({
-                    method: 'get',
-                    url: '/api/gb_record/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' +
-                        row.endTime + '&downloadSpeed=4'
-                }).then(function (res) {
-                  if (res.data.code == 0) {
-                    let streamInfo = res.data.data;
-                    that.recordPlay = false;
-                    that.$refs.recordDownload.openDialog(that.deviceId, that.channelId, streamInfo.app, streamInfo.stream, streamInfo.mediaServerId);
-                  }else {
-                    that.$message({
-                      showClose: true,
-                      message: res.data.msg,
-                      type: "error",
-                    });
-                  }
-                });
-            }
-        },
-        stopDownloadRecord: function (callback) {
-            this.$refs[this.activePlayer].pause();
-            this.videoUrl = '';
-            this.$axios({
-                method: 'get',
-                url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId
-            }).then((res)=> {
-                if (callback) callback(res)
-            });
-        },
         ptzCamera: function (command) {
             console.log('云台控制:' + command);
             let that = this;
@@ -740,52 +541,6 @@ export default {
                 url: '/api/ptz/front_end_command/' + this.deviceId + '/' + this.channelId + '?cmdCode=' + cmdCode + '&parameter1=' + groupNum + '&parameter2=' + parameter + '&combindCode2=0'
             }).then(function (res) {});
         },
-        formatTooltip: function (val) {
-            var h = parseInt(val / 60);
-            var hStr = h < 10 ? ("0" + h) : h;
-            var s = val % 60;
-            var sStr = s < 10 ? ("0" + s) : s;
-            return h + ":" + sStr;
-        },
-        timeFormatter: function (row, column, cellValue, index) {
-            return cellValue.split(" ")[1];
-        },
-        mergeTime: function (timeArray) {
-            var resultArray = [];
-            for (let i = 0; i < timeArray.length; i++) {
-                var startTime = new Date(timeArray[i].startTime);
-                var endTime = new Date(timeArray[i].endTime);
-                if (i == 0) {
-                    resultArray[0] = {
-                        startTime: startTime,
-                        endTime: endTime
-                    }
-                }
-                for (let j = 0; j < resultArray.length; j++) {
-                    if (startTime > resultArray[j].endTime) { // 合并
-                        if (startTime - resultArray[j].endTime <= 1000) {
-                            resultArray[j].endTime = endTime;
-                        } else {
-                            resultArray[resultArray.length] = {
-                                startTime: startTime,
-                                endTime: endTime
-                            }
-                        }
-                    } else if (resultArray[j].startTime > endTime) { // 合并
-                        if (resultArray[j].startTime - endTime <= 1000) {
-                            resultArray[j].startTime = startTime;
-                        } else {
-                            resultArray[resultArray.length] = {
-                                startTime: startTime,
-                                endTime: endTime
-                            }
-                        }
-                    }
-                }
-            }
-            console.log(resultArray)
-            return resultArray;
-        },
         copyUrl: function (dropdownItem){
             console.log(dropdownItem)
             this.$copyText(dropdownItem).then((e)=> {
@@ -794,140 +549,7 @@ export default {
 
             })
         },
-        gbPlay(){
-          console.log('前端控制:播放');
-          this.$axios({
-            method: 'get',
-            url: '/api/playback/resume/' + this.streamId
-          }).then((res)=> {
-            this.$refs[this.activePlayer].play(this.videoUrl)
-          });
-        },
-        gbPause(){
-          console.log('前端控制:暂停');
-          this.$axios({
-            method: 'get',
-            url: '/api/playback/pause/' + this.streamId
-          }).then(function (res) {});
-        },
-        gbScale(command){
-          console.log('前端控制:倍速 ' + command);
-          this.$axios({
-            method: 'get',
-            url: `/api/playback/speed/${this.streamId }/${command}`
-          }).then(function (res) {});
-        },
-        gbSeek(val){
-          console.log('前端控制:seek ');
-          console.log(this.seekTime);
-          console.log(this.sliderTime);
-          let showTime = new Date(new Date(this.recordStartTime).getTime() + this.seekTime * val / 100)
-          let hour = showTime.getHours();
-          let minutes = showTime.getMinutes();
-          let seconds = showTime.getSeconds();
-          this.showTimeText = (hour < 10?("0" + hour):hour) + ":" + (minutes<10?("0" + minutes):minutes) + ":" + (seconds<10?("0" + seconds):seconds)
-          this.$axios({
-            method: 'get',
-            url: `/api/playback/seek/${this.streamId }/` + Math.floor(this.seekTime * val / 100000)
-          }).then( (res)=> {
-            setTimeout(()=>{
-              this.$refs[this.activePlayer].play(this.videoUrl)
-            }, 600)
-          });
-        },
-        getBroadcastStatus() {
-            if (this.broadcastStatus == -2) {
-              return "primary"
-            }
-            if (this.broadcastStatus == -1) {
-              return "primary"
-            }
-            if (this.broadcastStatus == 0) {
-              return "warning"
-            }
-            if (this.broadcastStatus == 1) {
-              return "danger"
-            }
-
-        },
-        broadcastStatusClick() {
-            if (this.broadcastStatus == -1) {
-              // 默认状态, 开始
-              this.broadcastStatus = 0
-              // 发起语音对讲
-              this.$axios({
-                method: 'get',
-                url: '/api/play/broadcast/' + this.deviceId + '/' + this.channelId + "?timeout=30"
-              }).then( (res)=> {
-                if (res.data.code == 0) {
-                  let streamInfo = res.data.data.streamInfo;
-                  if (document.location.protocol.includes("https")) {
-                    this.startBroadcast(streamInfo.rtcs.url)
-                  }else {
-                    this.startBroadcast(streamInfo.rtc.url)
-                  }
 
-                }else {
-                  this.$message({
-                    showClose: true,
-                    message: res.data.msg,
-                    type: "error",
-                  });
-                }
-              });
-            }else if (this.broadcastStatus === 1) {
-                this.broadcastStatus = -1;
-                this.broadcastRtc.close()
-            }
-        },
-        startBroadcast(url){
-          // 获取推流鉴权Key
-          this.$axios({
-            method: 'post',
-            url: '/api/user/userInfo',
-          }).then( (res)=> {
-            if (res.data.code !== 0) {
-              this.$message({
-                showClose: true,
-                message: "获取推流鉴权Key失败",
-                type: "error",
-              });
-              this.broadcastStatus = -1;
-            }else {
-              let pushKey = res.data.data.pushKey;
-              // 获取推流鉴权KEY
-              url += "&sign=" + crypto.createHash('md5').update(pushKey, "utf8").digest('hex')
-              console.log("开始语音对讲: " + url)
-              this.broadcastRtc = new ZLMRTCClient.Endpoint({
-                debug: true, // 是否打印日志
-                zlmsdpUrl: url, //流地址
-                simulecast: false,
-                useCamera: false,
-                audioEnable: true,
-                videoEnable: false,
-                recvOnly: false,
-              })
-
-              // webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS,(e)=>{//获取到了远端流,可以播放
-              //   console.error('播放成功',e.streams)
-              //   this.broadcastStatus = 1;
-              // });
-              //
-              // webrtcPlayer.on(ZLMRTCClient.Events.WEBRTC_ON_LOCAL_STREAM,(s)=>{// 获取到了本地流
-              //   this.broadcastStatus = 1;
-              //   // document.getElementById('selfVideo').srcObject=s;
-              //   // this.eventcallbacK("LOCAL STREAM", "获取到了本地流")
-              // });
-
-              this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_NOT_SUPPORT,(e)=>{// 获取到了本地流
-                console.error('不支持webrtc',e)
-                this.$message({
-                  showClose: true,
-                  message: '不支持webrtc, 无法进行语音对讲',
-                  type: 'error'
-                });
-                this.broadcastStatus = -1;
-              });
 
               this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE 协商出错
                 console.error('ICE 协商出错')

+ 14 - 16
web_src/src/components/dialog/recordDownload.vue

@@ -6,18 +6,6 @@
         <el-progress :percentage="percentage"></el-progress>
       </el-col>
       <el-col :span="6" >
-<!--       <el-dropdown size="mini" title="播放倍速" style="margin-left: 1px;" @command="gbScale">-->
-<!--         <el-button-group>-->
-<!--           <el-button size="mini" style="width: 100%">-->
-<!--             {{scale}}倍速 <i class="el-icon-arrow-down el-icon&#45;&#45;right"></i>-->
-<!--           </el-button>-->
-<!--         </el-button-group>-->
-<!--        <el-dropdown-menu  slot="dropdown">-->
-<!--          <el-dropdown-item command="1">1倍速</el-dropdown-item>-->
-<!--          <el-dropdown-item command="2">2倍速</el-dropdown-item>-->
-<!--          <el-dropdown-item command="4">4倍速</el-dropdown-item>-->
-<!--        </el-dropdown-menu>-->
-<!--      </el-dropdown>-->
         <el-button icon="el-icon-download" v-if="percentage < 100" size="mini" title="点击下载可将以缓存部分下载到本地" @click="download()">停止缓存并下载</el-button>
       </el-col>
     </el-row>
@@ -51,6 +39,7 @@ export default {
           taskId: null,
           getProgressRun: false,
           getProgressForFileRun: false,
+          timer: null
 
         };
     },
@@ -66,7 +55,7 @@ export default {
             this.percentage = 0.0;
             this.getProgressTimer()
         },
-        getProgressTimer(){
+        getProgressTimer: function (){
           if (!this.getProgressRun) {
             return;
           }
@@ -93,15 +82,24 @@ export default {
                   this.percentage = (parseFloat(res.data.data.progress)*100).toFixed(1);
                 }
                 if (callback)callback();
+              }else {
+                this.$message({
+                  showClose: true,
+                  message: res.data.msg,
+                  type: "error",
+                });
+                this.close();
               }
 
           }).catch((e) =>{
-
+            console.log(e)
           });
         },
         close: function (){
-          if (this.streamInfo.progress < 100) {
-            this.stopDownloadRecord();
+          this.stopDownloadRecord();
+          if (this.timer !== null) {
+            window.clearTimeout(this.timer);
+            this.timer = null;
           }
           this.showDialog=false;
           this.getProgressRun = false;

+ 2 - 2
web_src/src/components/live.vue

@@ -140,9 +140,9 @@ export default {
         if (res.data.code === 0 && res.data.data) {
           let videoUrl;
           if (location.protocol === "https:") {
-            videoUrl = res.data.data.wss_flv.url;
+            videoUrl = res.data.data.wss_flv;
           } else {
-            videoUrl = res.data.data.ws_flv.url;
+            videoUrl = res.data.data.ws_flv;
           }
           itemData.playUrl = videoUrl;
           that.setPlayUrl(videoUrl, idxTmp);

+ 6 - 0
web_src/src/router/index.js

@@ -5,6 +5,7 @@ import Layout from "../layout/index.vue"
 import console from '../components/console.vue'
 import deviceList from '../components/DeviceList.vue'
 import channelList from '../components/channelList.vue'
+import gbRecordDetail from '../components/GBRecordDetail.vue'
 import pushVideoList from '../components/PushVideoList.vue'
 import streamProxyList from '../components/StreamProxyList.vue'
 import map from '../components/map.vue'
@@ -64,6 +65,11 @@ export default new VueRouter({
           name: 'channelList',
           component: channelList,
         },
+        {
+          path: '/gbRecordDetail/:deviceId/:channelId/',
+          name: 'gbRecordDetail',
+          component: gbRecordDetail,
+        },
         {
           path: '/parentPlatformList/:count/:page',
           name: 'parentPlatformList',

+ 11 - 3
web_src/static/css/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 1291092 */
-  src: url('iconfont.woff2?t=1655453611360') format('woff2'),
-       url('iconfont.woff?t=1655453611360') format('woff'),
-       url('iconfont.ttf?t=1655453611360') format('truetype');
+  src: url('iconfont.woff2?t=1673251105600') format('woff2'),
+       url('iconfont.woff?t=1673251105600') format('woff'),
+       url('iconfont.ttf?t=1673251105600') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,14 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-slider:before {
+  content: "\e7e0";
+}
+
+.icon-slider-right:before {
+  content: "\ea19";
+}
+
 .icon-list:before {
   content: "\e7de";
 }

BIN
web_src/static/css/iconfont.woff2