From dea44dcd78418ed3e7f191a73cee2b81a7a0019f Mon Sep 17 00:00:00 2001
From: 648540858 <648540858@qq.com>
Date: 星期五, 13 一月 2023 16:21:17 +0800
Subject: [PATCH] Merge branch 'wvp-28181-2.0'

---
 src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java                                                               |    8 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java                                                |   19 
 src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java                                                         |   36 
 src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java                                                    |   16 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java                                                   |    2 
 src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java                                                           |  358 ++++++
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java                                               |    2 
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java                                                             |   74 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java                   |    3 
 web_src/src/components/GBRecordDetail.vue                                                                                      |  513 +++++++++
 sql/mysql.sql                                                                                                                  |   30 
 src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java                                                                      |   20 
 src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java                                                               |   16 
 doc/_media/3.png                                                                                                               |    0 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java                                         |    2 
 src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java                                                         |    7 
 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java                                                   |   28 
 src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java                                                               |    3 
 src/main/java/com/genersoft/iot/vmp/service/IPlayService.java                                                                  |   13 
 src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java                                               |   13 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java                                                        |   27 
 src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java                                                      |   31 
 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java                                                          |  137 +-
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java                                                 |    8 
 src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java                                              |   16 
 web_src/src/components/live.vue                                                                                                |    4 
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java                                                        |   20 
 doc/_media/3-3.png                                                                                                             |    0 
 src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java                                            |    6 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java                          |   24 
 src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java                                                                 |    7 
 README.md                                                                                                                      |  155 +-
 doc/_media/2.png                                                                                                               |    0 
 src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java                                                          |    2 
 src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java                                                         |    8 
 src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java                                             |    3 
 src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java                                                                |   29 
 src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java                                                        |   14 
 web_src/src/router/index.js                                                                                                    |    6 
 src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java                                                           |   18 
 sql/update.sql                                                                                                                 |   44 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java                                          |   33 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java                                                                   |   15 
 web_src/src/components/console.vue                                                                                             |   13 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                                                |    5 
 src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java                                                 |    2 
 web_src/src/components/console/ConsoleResource.vue                                                                             |   12 
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java                                           |    8 
 src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java                                                       |   13 
 pom.xml                                                                                                                        |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java                                                        |   38 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java  |   53 
 src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java                                                            |    4 
 src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java                                                 |   24 
 web_src/src/components/dialog/devicePlayer.vue                                                                                 |  472 --------
 src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java                                                                |   10 
 doc/_media/3-2.png                                                                                                             |    0 
 web_src/src/components/CloudRecordDetail.vue                                                                                   |   17 
 src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java                                                        |   25 
 doc/_media/index.png                                                                                                           |    0 
 src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java                                                                  |    4 
 web_src/static/css/iconfont.css                                                                                                |   14 
 src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java                                                           |    2 
 src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java                                                     |    8 
 src/main/resources/all-application.yml                                                                                         |    8 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java |   13 
 src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java                                                   |    2 
 doc/_media/3-1.png                                                                                                             |    0 
 /dev/null                                                                                                                      |  107 --
 web_src/static/css/iconfont.woff2                                                                                              |    0 
 src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java                                                                      |    6 
 src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java                                                       |   22 
 web_src/src/components/channelList.vue                                                                                         |    4 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                                                         |   11 
 src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java                                                        |  124 +-
 web_src/src/components/dialog/recordDownload.vue                                                                               |   30 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java                                     |    8 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java                                                  |   40 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java                                            |   33 
 src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java                                                   |    2 
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java                                                      |  182 +-
 81 files changed, 1,830 insertions(+), 1,258 deletions(-)

diff --git a/README.md b/README.md
index 4634113..64ec409 100644
--- a/README.md
+++ b/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 @@
 # 搴旂敤鍦烘櫙锛�
 鏀寔娴忚鍣ㄦ棤鎻掍欢鎾斁鎽勫儚澶磋棰戙��  
 鏀寔鎽勫儚鏈恒�佸钩鍙般�丯VR绛夎澶囨帴鍏ャ�� 
-鏀寔鍥芥爣绾ц仈銆�  
+鏀寔鍥芥爣绾ц仈銆傚骞冲彴绾ц仈銆傝法缃戣棰戦瑙堛��
 鏀寔rtsp/rtmp绛夎棰戞祦杞彂鍒板浗鏍囧钩鍙般��  
 鏀寔rtsp/rtmp绛夋帹娴佽浆鍙戝埌鍥芥爣骞冲彴銆�  
 
@@ -31,62 +31,49 @@
 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")
+![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")
 
-# 1.0 鍩虹鐗规��  
-1. 瑙嗛棰勮;  
-2. 浜戝彴鎺у埗锛堟柟鍚戙�佺缉鏀炬帶鍒讹級;  
-3. 瑙嗛璁惧淇℃伅鍚屾;   
-4. 绂诲湪绾跨洃鎺�;  
-5. 褰曞儚鏌ヨ涓庡洖鏀撅紙鍩轰簬NVR\DVR锛屾殏涓嶆敮鎸佸揩杩涖�乻eek鎿嶄綔锛�;  
-6. 鏃犱汉瑙傜湅鑷姩鏂祦;    
-7. 鏀寔UDP鍜孴CP涓ょ鍥芥爣淇′护浼犺緭妯″紡; 
-8. 闆嗘垚web鐣岄潰, 涓嶉渶瑕佸崟鐙儴缃插墠绔湇鍔�, 鐩存帴鍒╃敤wvp鍐呯疆鏂囦欢鏈嶅姟閮ㄧ讲, 闅弚vp涓�璧烽儴缃�;   
-9. 鏀寔骞冲彴鎺ュ叆, 閽堝澶у钩鍙板ぇ閲忚澶囩殑鎯呭喌杩涜浼樺寲;  
-10. 鏀寔妫�绱�,閫氶亾绛涢��;  
-11. 鏀寔鑷姩閰嶇疆ZLM濯掍綋鏈嶅姟, 鍑忓皯鍥犻厤缃棶棰樻墍鍑虹幇鐨勯棶棰�;  
-12. 鏀寔鍚敤udp澶氱鍙fā寮�, 鎻愰珮udp妯″紡涓嬪獟浣撲紶杈撴�ц兘;  
-13. 鏀寔閫氶亾鏄惁鍚湁闊抽鐨勮缃�;  
-14. 鏀寔閫氶亾瀛愮洰褰曟煡璇�;  
-15. 鏀寔udp/tcp鍥芥爣娴佷紶杈撴ā寮�;  
-16. 鏀寔鐩存帴杈撳嚭RTSP銆丷TMP銆丠TTP-FLV銆乄ebsocket-FLV銆丠LS澶氱鍗忚娴佸湴鍧�  
-17. 鏀寔鍥芥爣缃戠粶鏍℃椂  
-18. 鏀寔鍏綉閮ㄧ讲, 鏀寔wvp涓巣lm鍒嗗紑閮ㄧ讲   
-19. 鏀寔鎾斁h265, g.711鏍煎紡鐨勬祦(闇�瑕佸皢closeWaitRTPInfo璁句负false)
-20. 鎶ヨ淇℃伅澶勭悊锛屾敮鎸佸悜鍓嶇鎺ㄩ�佹姤璀︿俊鎭�
-
-# 1.0 鏂版敮鎸佺壒鎬�  
-1. 闆嗘垚web鐣岄潰, 涓嶉渶瑕佸崟鐙儴缃插墠绔湇鍔�, 鐩存帴鍒╃敤wvp鍐呯疆鏂囦欢鏈嶅姟閮ㄧ讲, 闅弚vp涓�璧烽儴缃�;   
-2. 鏀寔骞冲彴鎺ュ叆, 閽堝澶у钩鍙板ぇ閲忚澶囩殑鎯呭喌杩涜浼樺寲;  
-3. 鏀寔妫�绱�,閫氶亾绛涢��;  
-4. 鏀寔鑷姩閰嶇疆ZLM濯掍綋鏈嶅姟, 鍑忓皯鍥犻厤缃棶棰樻墍鍑虹幇鐨勯棶棰�;  
-5. 鏀寔鍚敤udp澶氱鍙fā寮�, 鎻愰珮udp妯″紡涓嬪獟浣撲紶杈撴�ц兘;  
-6. 鏀寔閫氶亾鏄惁鍚湁闊抽鐨勮缃�;  
-7. 鏀寔閫氶亾瀛愮洰褰曟煡璇�;  
-8. 鏀寔udp/tcp鍥芥爣娴佷紶杈撴ā寮�;  
-9. 鏀寔鐩存帴杈撳嚭RTSP銆丷TMP銆丠TTP-FLV銆乄ebsocket-FLV銆丠LS澶氱鍗忚娴佸湴鍧�  
-10. 鏀寔鍥芥爣缃戠粶鏍℃椂  
-11. 鏀寔鍏綉閮ㄧ讲, 鏀寔wvp涓巣lm鍒嗗紑閮ㄧ讲   
-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] 鍥芥爣閫氶亾鍚戜笂绾ц仈
+# 鍔熻兘鐗规�� 
+- [X] 闆嗘垚web鐣岄潰
+- [X] 鍏煎鎬ц壇濂�
+- [X] 鏀寔鐢靛瓙鍦板浘锛屾敮鎸佹帴鍏GS84鍜孏CJ02涓ょ鍧愭爣绯伙紝骞朵笖鑷姩杞寲涓哄悎閫傜殑鍧愭爣绯昏繘琛屽睍绀哄拰鍒嗗彂
+- [X] 鎺ュ叆璁惧
+  - [X] 瑙嗛棰勮
+  - [X] 鏃犻檺鍒舵帴鍏ヨ矾鏁帮紝鑳芥帴鍏ュ灏戣澶囧彧鍙栧喅浜庝綘鐨勬湇鍔″櫒鎬ц兘
+  - [X] 浜戝彴鎺у埗锛屾帶鍒惰澶囪浆鍚戯紝鎷夎繎锛屾媺杩�
+  - [X] 棰勭疆浣嶆煡璇紝浣跨敤涓庤缃�
+  - [X] 鏌ヨNVR/IPC涓婄殑褰曞儚涓庢挱鏀撅紝鏀寔鎸囧畾鏃堕棿鎾斁涓庝笅杞�
+  - [X] 鏃犱汉瑙傜湅鑷姩鏂祦锛岃妭鐪佹祦閲�
+  - [X] 瑙嗛璁惧淇℃伅鍚屾
+  - [X] 绂诲湪绾跨洃鎺�
+  - [X] 鏀寔鐩存帴杈撳嚭RTSP銆丷TMP銆丠TTP-FLV銆乄ebsocket-FLV銆丠LS澶氱鍗忚娴佸湴鍧�
+  - [X] 鏀寔閫氳繃涓�涓祦鍦板潃鐩存帴瑙傜湅鎽勫儚澶达紝鏃犻渶鐧诲綍浠ュ強璋冪敤浠讳綍鎺ュ彛
+  - [X] 鏀寔UDP鍜孴CP涓ょ鍥芥爣淇′护浼犺緭妯″紡
+  - [X] 鏀寔UDP鍜孴CP涓ょ鍥芥爣娴佷紶杈撴ā寮�
+  - [X] 鏀寔妫�绱�,閫氶亾绛涢��
+  - [X] 鏀寔閫氶亾瀛愮洰褰曟煡璇�
+  - [X] 鏀寔杩囨护闊抽锛岄槻姝㈡潅闊冲奖鍝嶈鐪�
+  - [X] 鏀寔鍥芥爣缃戠粶鏍℃椂
+  - [X] 鏀寔鎾斁H264鍜孒265
+  - [X] 鎶ヨ淇℃伅澶勭悊锛屾敮鎸佸悜鍓嶇鎺ㄩ�佹姤璀︿俊鎭�
+  - [X] 鏀寔璁㈤槄涓庨�氱煡鏂规硶
+    - [X] 绉诲姩浣嶇疆璁㈤槄
+    - [X] 绉诲姩浣嶇疆閫氱煡澶勭悊
+    - [X] 鎶ヨ浜嬩欢璁㈤槄
+    - [X] 鎶ヨ浜嬩欢閫氱煡澶勭悊
+    - [X] 璁惧鐩綍璁㈤槄
+    - [X] 璁惧鐩綍閫氱煡澶勭悊
+  -  [X] 绉诲姩浣嶇疆鏌ヨ鍜屾樉绀�
+  - [X] 鏀寔鎵嬪姩娣诲姞璁惧鍜岀粰璁惧璁剧疆鍗曠嫭鐨勫瘑鐮�
+-  [X] 鏀寔骞冲彴瀵规帴鎺ュ叆
+-  [X] 鏀寔鍥芥爣绾ц仈
+  - [X] 鍥芥爣閫氶亾鍚戜笂绾ц仈
     - [X] WEB娣诲姞涓婄骇骞冲彴
     - [X] 娉ㄥ唽
     - [X] 蹇冭烦淇濇椿
@@ -101,54 +88,25 @@
     - [X] 鐩綍璁㈤槄涓庨�氱煡
     - [X] 褰曞儚鏌ョ湅涓庢挱鏀�
     - [X] GPS璁㈤槄涓庨�氱煡锛堢洿鎾帹娴侊級
-- [X] 鏀寔鎵嬪姩娣诲姞璁惧鍜岀粰璁惧璁剧疆鍗曠嫭鐨勫瘑鐮�
-- [X] 娣诲姞RTSP瑙嗛
-- [X] 娣诲姞鎺ュ彛閴存潈
-- [X] 娣诲姞RTMP瑙嗛
-- [X] 浜戠褰曞儚锛堥渶瑕侀儴缃插崟鐙湇鍔¢厤鍚堜娇鐢級
+- [X] 鏀寔鑷姩閰嶇疆ZLM濯掍綋鏈嶅姟, 鍑忓皯鍥犻厤缃棶棰樻墍鍑虹幇鐨勯棶棰�;  
 - [X] 澶氭祦濯掍綋鑺傜偣锛岃嚜鍔ㄩ�夋嫨璐熻浇鏈�浣庣殑鑺傜偣浣跨敤銆�
-- [X] WEB绔敮鎸佹挱鏀綡264涓嶩265锛岄煶棰戞敮鎸丟.711A/G.711U/AAC,瑕嗙洊鍥芥爣甯哥敤缂栫爜鏍煎紡銆�
-- [X] 鏀寔鐢靛瓙鍦板浘銆�
-- [X] 鏀寔鎺ュ叆WGS84鍜孏CJ02涓ょ鍧愭爣绯汇��
+- [X] 鏀寔鍚敤udp澶氱鍙fā寮�, 鎻愰珮udp妯″紡涓嬪獟浣撲紶杈撴�ц兘;
+- [X] 鏀寔鍏綉閮ㄧ讲锛� 
+- [X] 鏀寔wvp涓巣lm鍒嗗紑閮ㄧ讲锛屾彁鍗囧钩鍙板苟鍙戣兘鍔�
+- [X] 鏀寔鎷夋祦RTSP/RTMP锛屽垎鍙戜负鍚勭娴佹牸寮忥紝鎴栬�呮帹閫佸埌鍏朵粬鍥芥爣骞冲彴
+- [X] 鏀寔鎺ㄦ祦RTSP/RTMP锛屽垎鍙戜负鍚勭娴佹牸寮忥紝鎴栬�呮帹閫佸埌鍏朵粬鍥芥爣骞冲彴
+- [X] 鏀寔鎺ㄦ祦閴存潈
+- [X] 鏀寔鎺ュ彛閴存潈
+- [X] 浜戠褰曞儚锛屾帹娴�/浠g悊/鍥芥爣瑙嗛鍧囧彲浠ュ綍鍒跺湪浜戠鏈嶅姟鍣紝鏀寔棰勮鍜屼笅杞�
+ 
 
-[//]: # (# docker蹇�熶綋楠�)
-
-[//]: # (鐩墠浣滆�呯殑docker-compose鍥犱负鏃堕棿鏈夐檺缁存姢涓嶅強鏃讹紝杩欓噷鎻愪緵绗笁鏂规彁渚涚殑渚涘ぇ瀹朵娇鐢紝缁存姢涓嶆槗锛屽ぇ瀹惰寰楃粰杩欎綅灏忎紮浼寸偣涓猻tar銆�  )
-
-[//]: # (https://github.com/SaltFish001/wvp_pro_compose)
-
-[//]: # ([https://github.com/SaltFish001/wvp_pro_compose]&#40;https://github.com/SaltFish001/wvp_pro_compose&#41;)
-
-[//]: # (杩欐槸浣滆�呯淮鎶ょ殑涓�涓暅鍍忥紝鍙兘瀛樺湪涓嶅強鏃剁殑闂銆�)
-
-[//]: # (```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]&#40;https://hub.docker.com/r/648540858/wvp_pro&#41;)
-
-# gitee鍚屾浠撳簱
-https://gitee.com/pan648540858/wvp-GB28181-pro.git  
-
-# 閬囧埌闂
+# 閬囧埌闂濡備綍瑙e喅
 鍥芥爣鏈�楹荤儲鐨勫湴鏂瑰湪浜庤澶囩殑鍏煎鎬э紝鎵�浠ラ渶瑕佸ぇ閲忕殑璁惧鏉ユ祴璇曪紝鐩墠浣滆�呮墜閲岀殑璁惧鏈夐檺锛屽啀鍔犱笂浣滆�呮按骞虫湁闄愶紝鎵�浠ラ亣鍒伴棶棰樺湪鎵�闅惧厤锛�
 1. 鏌ョ湅wiki锛屼粩缁嗙殑闃呰鍙互甯綘閬垮厤鍑犱箮鎵�鏈夌殑闂
 2. 鎼滅储issues锛岃繖閲屾湁澶ч儴鍒嗙殑绛旀
-3. 鍔燪Q缇わ紝杩欓噷鏈夊ぇ閲忕儹蹇冪殑灏忎紮浼达紝浣嗘槸鍓嶆彁鏂板笇鏈涗綘宸茬粡浠旂粏闃呰浜唚iki鍜屾悳绱簡issues銆�
+3. 鍔燪Q缇わ紙901799015锛夛紝杩欓噷鏈夊ぇ閲忕儹蹇冪殑灏忎紮浼达紝浣嗘槸鍓嶆彁鏂板笇鏈涗綘宸茬粡浠旂粏闃呰浜唚iki鍜屾悳绱簡issues銆�
 4. 浣犲彲浠ヨ浣滆�呬负浣犺В绛旓紝浣嗘槸鎴戜笉鏄厤璐圭殑銆�
 5. 浣犲彲浠ユ妸閬囧埌闂鐨勮澶囧瘎缁欐垜锛屽彲浠ユ洿瀹规槗鐨勫鐜伴棶棰樸��
-
-
-# 鍚堜綔
-鐩墠寰堝鎵撶潃鍚堜綔鐨勫箤瀛愭潵绉佽亰鐨勶紝鍏跺疄澶у澶у彲涓嶅繀锛岀洰鍓嶄綔鑰呮病鏈夌簿鍔涳紝浣犳湁闂鍙互浠樿垂鎵炬垜瑙g瓟锛屼篃鍙互鎻怭R
-锛屽鏋滃浠g爜鏈夊缓璁彲浠ユ彁ISSUE锛涗篃鍙互鍔犵兢涓�璧疯亰鑱娿�傛垜浠杩庢墍鏈夋湁鍏磋叮鍙備笌鍒伴」鐩腑鏉ョ殑浜恒��
-
-
 
 # 浣跨敤甯姪
 QQ缇�: 901799015, ZLM浣跨敤鏂囨。[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)  
@@ -156,6 +114,7 @@
 
 # 鎺堟潈鍗忚
 鏈」鐩嚜鏈変唬鐮佷娇鐢ㄥ鏉剧殑MIT鍗忚锛屽湪淇濈暀鐗堟潈淇℃伅鐨勬儏鍐典笅鍙互鑷敱搴旂敤浜庡悇鑷晢鐢ㄣ�侀潪鍟嗕笟鐨勯」鐩�� 浣嗘槸鏈」鐩篃闆剁鐨勪娇鐢ㄤ簡涓�浜涘叾浠栫殑寮�婧愪唬鐮侊紝鍦ㄥ晢鐢ㄧ殑鎯呭喌涓嬭鑷鏇夸唬鎴栧墧闄わ紱 鐢变簬浣跨敤鏈」鐩�屼骇鐢熺殑鍟嗕笟绾犵悍鎴栦镜鏉冭涓轰竴姒備笌鏈」鐩強寮�鍙戣�呮棤鍏筹紝璇疯嚜琛屾壙鎷呮硶寰嬮闄┿�� 鍦ㄤ娇鐢ㄦ湰椤圭洰浠g爜鏃讹紝涔熷簲璇ュ湪鎺堟潈鍗忚涓悓鏃惰〃鏄庢湰椤圭洰渚濊禆鐨勭涓夋柟搴撶殑鍗忚
+
 # 鑷磋阿
 鎰熻阿浣滆�匸澶忔](https://github.com/xia-chu) 鎻愪緵杩欎箞妫掔殑寮�婧愭祦濯掍綋鏈嶅姟妗嗘灦,骞跺湪寮�鍙戣繃绋嬩腑缁欎簣鏀寔涓庡府鍔┿��     
 鎰熻阿浣滆�匸dexter langhuihui](https://github.com/langhuihui) 寮�婧愯繖涔堝ソ鐢ㄧ殑WEB鎾斁鍣ㄣ��     
diff --git a/doc/_media/2.png b/doc/_media/2.png
new file mode 100644
index 0000000..dd982e1
--- /dev/null
+++ b/doc/_media/2.png
Binary files differ
diff --git a/doc/_media/3-1.png b/doc/_media/3-1.png
new file mode 100644
index 0000000..a52620f
--- /dev/null
+++ b/doc/_media/3-1.png
Binary files differ
diff --git a/doc/_media/3-2.png b/doc/_media/3-2.png
new file mode 100644
index 0000000..bef780e
--- /dev/null
+++ b/doc/_media/3-2.png
Binary files differ
diff --git a/doc/_media/3-3.png b/doc/_media/3-3.png
new file mode 100644
index 0000000..3943a52
--- /dev/null
+++ b/doc/_media/3-3.png
Binary files differ
diff --git a/doc/_media/3.png b/doc/_media/3.png
new file mode 100644
index 0000000..913d294
--- /dev/null
+++ b/doc/_media/3.png
Binary files differ
diff --git a/doc/_media/index.png b/doc/_media/index.png
new file mode 100644
index 0000000..15200e6
--- /dev/null
+++ b/doc/_media/index.png
Binary files differ
diff --git a/pom.xml b/pom.xml
index 7ed0304..efc311a 100644
--- a/pom.xml
+++ b/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>
 
diff --git a/sql/mysql.sql b/sql/mysql.sql
index 27c6da1..d9010e2 100644
--- a/sql/mysql.sql
+++ b/sql/mysql.sql
@@ -54,7 +54,7 @@
                           `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 @@
                                 `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 @@
                                   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 @@
                                           `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 @@
                              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 @@
                        `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 @@
                                    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 @@
                                        `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 @@
 /*!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 @@
                                 `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 @@
                                `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 @@
                         `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 @@
 
 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 @@
                              `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 */;
 
 --
diff --git a/sql/update.sql b/sql/update.sql
index 877e247..2e5d569 100644
--- a/sql/update.sql
+++ b/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;
\ No newline at end of file
diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
index 3db903b..45cd57b 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -71,6 +71,8 @@
 	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_";
+
 
 
 
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java b/src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
index 5f4ac22..d1e61c0 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
@@ -10,6 +10,7 @@
 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 @@
 
             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());
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
index 57f3245..83eace5 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -35,6 +35,8 @@
 
     private Boolean useSourceIpAsStreamIp = Boolean.FALSE;
 
+    private Boolean sipUseSourceIpAsRemoteAddress = Boolean.FALSE;
+
     private Boolean streamOnDemand = Boolean.TRUE;
 
     private Boolean pushAuthority = Boolean.TRUE;
@@ -44,6 +46,8 @@
     private Boolean syncChannelOnDeviceOnline = Boolean.FALSE;
 
     private Boolean pushStreamAfterAck = Boolean.FALSE;
+
+    private Boolean sipLog = Boolean.FALSE;
 
     private String serverId = "000000";
 
@@ -206,4 +210,20 @@
     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;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
index 24b88e5..605e7cf 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
+++ b/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;
@@ -28,6 +29,9 @@
 
 	@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 @@
 	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鏈嶅姟鍚姩澶辫触锛� 鐩戝惉鍦板潃{}澶辫触,璇锋鏌p鏄惁姝g‘", monitorIp);
 			return;
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
index 280d35a..99b46a1 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -94,6 +94,13 @@
 	@Schema(description = "蹇冭烦鏃堕棿")
 	private String keepaliveTime;
 
+
+	/**
+	 * 蹇冭烦闂撮殧
+	 */
+	@Schema(description = "蹇冭烦闂撮殧")
+	private int keepaliveIntervalTime;
+
 	/**
 	 * 閫氶亾涓暟
 	 */
@@ -414,4 +421,12 @@
 	public void setLocalIp(String localIp) {
 		this.localIp = localIp;
 	}
+
+	public int getKeepaliveIntervalTime() {
+		return keepaliveIntervalTime;
+	}
+
+	public void setKeepaliveIntervalTime(int keepaliveIntervalTime) {
+		this.keepaliveIntervalTime = keepaliveIntervalTime;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java
new file mode 100644
index 0000000..4107593
--- /dev/null
+++ b/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;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java b/src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java
index e0691e5..3cdf48d 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java
+++ b/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 @@
  */
 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 @@
         // 鎺ユ敹鎵�鏈塶otify璇锋眰锛屽嵆浣挎病鏈夎闃�
         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 @@
         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 鍫嗘爤锛屼簡瑙e叾鍐呴儴绾跨▼鐨勫仴搴风姸鍐碉紙璇ュ睘鎬ф寚瀹氳繛缁璁′箣闂寸殑鏃堕棿锛堜互姣涓哄崟浣嶏級锛�
+        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;
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/conf/SipLoggerPass.java b/src/main/java/com/genersoft/iot/vmp/gb28181/conf/SipLoggerPass.java
deleted file mode 100644
index 18dd151..0000000
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/conf/SipLoggerPass.java
+++ /dev/null
@@ -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;
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
index e2cd84f..ea2760d 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
@@ -13,7 +13,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-/**    
+/**
  * @description:瑙嗛娴乻ession绠$悊鍣紝绠$悊瑙嗛棰勮銆侀瑙堝洖鏀剧殑閫氫俊鍙ユ焺 
  * @author: swwheihei
  * @date:   2020骞�5鏈�13鏃� 涓嬪崍4:03:02     
@@ -51,6 +51,7 @@
 		ssrcTransaction.setSsrc(ssrc);
 		ssrcTransaction.setMediaServerId(mediaServerId);
 		ssrcTransaction.setType(type);
+
 		RedisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId()
 				+ "_" +  deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
 	}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
index 13a36d7..0d6da64 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
@@ -64,7 +64,7 @@
      * @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;
 
     /**
      * 鍚戜笂绾у洖澶嶇Щ鍔ㄤ綅缃闃呮秷鎭�
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
index 3181ee2..729f9b8 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -574,10 +574,11 @@
         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 @@
         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);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
index 08cc3c3..5a3faac 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -287,19 +287,20 @@
      * @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 @@
 
         Request request = headerProviderPlatformProvider.createMessageRequest(parentPlatform, deviceStatusXml.toString(), fromTag, SipUtils.getNewViaTag(), callIdHeader);
         sipSender.transmitRequest(parentPlatform.getDeviceIp(), request);
-
     }
 
     @Override
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
index b4f5d8f..3ed223e 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -1,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;
@@ -58,6 +61,9 @@
 
     @Autowired
     private SIPSender sipSender;
+
+    @Autowired
+    private UserSetting userSetting;
 
     @Override
     public void afterPropertiesSet() throws Exception {
@@ -128,15 +134,9 @@
             // 娣诲姞Expires澶�
             response.addHeader(request.getExpires());
 
-            // 鑾峰彇鍒伴�氫俊鍦板潃绛変俊鎭�
-            ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
-            String received = viaHeader.getReceived();
-            int rPort = viaHeader.getRPort();
-            // 瑙f瀽鏈湴鍦板潃鏇夸唬
-            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 @@
                 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) {
                 // 娉ㄩ攢鎴愬姛
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
index 1f4513e..527b5d0 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
@@ -67,6 +67,7 @@
     @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 @@
             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());
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
index 2846903..98c1a96 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -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.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 @@
 @Component
 public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
 
+
     private Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class);
     private final static String cmdType = "Keepalive";
 
@@ -41,6 +41,12 @@
 
     @Autowired
     private IDeviceService deviceService;
+
+    @Autowired
+    private UserSetting userSetting;
+
+    @Autowired
+    private DynamicTask dynamicTask;
 
     @Override
     public void afterPropertiesSet() throws Exception {
@@ -53,26 +59,27 @@
             // 鏈敞鍐岀殑璁惧涓嶅仛澶勭悊
             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();
-        // 瑙f瀽鏈湴鍦板潃鏇夸唬
-        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 @@
         }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
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
index 7f0e6af..e9d44d5 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
@@ -2,6 +2,7 @@
 
 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;
@@ -23,6 +24,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 @@
         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());
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
index bbce087..45c5a90 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
+++ b/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 @@
         int typeCodeFromGbCode = getTypeCodeFromGbCode(deviceId);
         return typeCodeFromGbCode > 130 && typeCodeFromGbCode < 199;
     }
+    /**
+     * 浠庤姹備腑鑾峰彇璁惧ip鍦板潃鍜岀鍙e彿
+     * @param request 璇锋眰
+     * @param sipUseSourceIpAsRemoteAddress  false 浠巚ia涓幏鍙栧湴鍧�锛� 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();
+            // 瑙f瀽鏈湴鍦板潃鏇夸唬
+            if (ObjectUtils.isEmpty(remoteAddress) || remotePort == -1) {
+                remoteAddress = request.getTopmostViaHeader().getHost();
+                remotePort = request.getTopmostViaHeader().getPort();
+            }
+        }
+
+        return new RemoteAddressInfo(remoteAddress, remotePort);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
index 20946ea..ba95972 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -19,6 +19,7 @@
 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 @@
 								}
 								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 @@
 								}
 								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 @@
 		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 @@
 	@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 @@
 	@PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8")
 	public JSONObject onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param){
 
-		logger.info("[ZLM HOOK] 鍙戦�乺tp琚姩鍏抽棴锛歿}->{}/{}", 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);
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
index 29f91c8..07c09e6 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
+++ b/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 @@
         }
     }
 
-    private StreamInfo streamInfo;
+    private StreamContent streamInfo;
 
     public String getApp() {
         return app;
@@ -407,11 +407,11 @@
         this.docker = docker;
     }
 
-    public StreamInfo getStreamInfo() {
+    public StreamContent getStreamInfo() {
         return streamInfo;
     }
 
-    public void setStreamInfo(StreamInfo streamInfo) {
+    public void setStreamInfo(StreamContent streamInfo) {
         this.streamInfo = streamInfo;
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
index 21375e0..1233455 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -37,7 +37,7 @@
      */
     void zlmServerOffline(String mediaServerId);
 
-    MediaServerItem getMediaServerForMinimumLoad();
+    MediaServerItem getMediaServerForMinimumLoad(Boolean hasAssist);
 
     void setZLMConfig(MediaServerItem mediaServerItem, boolean restart);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
index 39c5ffa..ffdaef3 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -40,15 +40,20 @@
 
     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);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java b/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java
index 5ed6cf3..33a09bd 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java
+++ b/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);
 
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
index 9db2d68..880b697 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
@@ -99,7 +99,7 @@
         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);
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
index eb208d3..1c57d0b 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -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.*;
@@ -45,8 +46,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 @@
             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 @@
             }
             sync(device);
         }else {
-
             if(device.getOnline() == 0){
                 device.setOnline(1);
                 device.setCreateTime(now);
@@ -160,18 +161,19 @@
             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 @@
         device.setUpdateTime(DateUtil.getNow());
         if (deviceMapper.update(device) > 0) {
             redisCatchStorage.updateDevice(device);
-
         }
     }
 
@@ -432,7 +433,7 @@
             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 @@
             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 @@
                 }
             }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);
                     }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
index ccb5564..28b5405 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -501,7 +501,7 @@
      * @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 @@
         // 鑾峰彇鍒嗘暟鏈�浣庣殑锛屽強骞跺彂鏈�浣庣殑
         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;
     }
 
     /**
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
index fbc507a..136689c 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
@@ -135,14 +135,7 @@
             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 @@
         }
     }
 
+    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());
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
index 616aaad..d198882 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -45,11 +45,8 @@
 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 @@
                     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 @@
             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 @@
                 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 @@
         }
     }
 
-    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 @@
             }
             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 @@
         }
         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 @@
     }
 
     @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("[鑾峰彇鍙敤鐨刏LM鑺傜偣]鏈壘鍒板彲浣跨敤鐨刏LM...");
+        }
+        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("璁惧鍥炴斁瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%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 @@
                 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 @@
                 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 @@
                                             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 @@
             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 = getNewMediaServerItem(device);
+        MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device);
+        if (newMediaServerItem == null) {
+            PlayBackResult<StreamInfo> downloadResult = new PlayBackResult<>();
+            downloadResult.setCode(ErrorCode.ERROR100.getCode());
+            downloadResult.setMsg("鏈壘鍒癮ssist鏈嶅姟");
+            playBackCallback.call(downloadResult);
+            return;
+        }
         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("褰曞儚涓嬭浇璇锋眰瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId));
-            wvpResult.setCode(ErrorCode.ERROR100.getCode());
-            wvpResult.setMsg("褰曞儚涓嬭浇璇锋眰瓒呮椂");
             downloadResult.setCode(ErrorCode.ERROR100.getCode());
             downloadResult.setMsg("褰曞儚涓嬭浇璇锋眰瓒呮椂");
             hookCallBack.call(downloadResult);
@@ -846,16 +839,12 @@
                 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 @@
                         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 @@
             eventResult.msg = "鍛戒护鍙戦�佸け璐�";
             errorEvent.response(eventResult);
         }
-        return result;
     }
 
     @Override
@@ -906,7 +892,10 @@
             }
             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) {
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
index b9693a0..ad37a61 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -90,7 +90,7 @@
     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());
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
index 42cbec5..35ed99e 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
@@ -117,7 +117,7 @@
                     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 @@
 
                             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 @@
                             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 @@
                                     }
                                     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 @@
                                 default:
                                     break;
                             }
+
                         }
                     }catch (Exception e) {
                         logger.warn("[RedisGbPlayMsg] 鍙戠幇鏈鐞嗙殑寮傚父, {}",e.getMessage());
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
index ab43746..b4644bf 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
@@ -59,7 +59,7 @@
 	 */
 	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 @@
 	 * @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 @@
 	 * @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);
 
 
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java
index bc651ce..f67e152 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java
@@ -16,19 +16,19 @@
 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 @@
     @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);
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
index 53072b2..8da1a09 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -20,46 +20,46 @@
             "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 @@
             "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 @@
             " 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 @@
             "  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 @@
             "<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 @@
             "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 @@
     @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 @@
             "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);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
index 0e61692..8143d35 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
@@ -61,6 +61,7 @@
                 "expires," +
                 "registerTime," +
                 "keepaliveTime," +
+                "keepaliveIntervalTime," +
                 "createTime," +
                 "updateTime," +
                 "charset," +
@@ -88,6 +89,7 @@
                 "#{expires}," +
                 "#{registerTime}," +
                 "#{keepaliveTime}," +
+                "#{keepaliveIntervalTime}," +
                 "#{createTime}," +
                 "#{updateTime}," +
                 "#{charset}," +
@@ -104,25 +106,28 @@
 
     @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 @@
             "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 @@
             "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);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
index 616b1b7..358836c 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
@@ -9,7 +9,7 @@
 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>" +
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
index 6ea852e..49101bd 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
@@ -16,9 +16,9 @@
 
     @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 @@
             "(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 @@
 
     @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 @@
             "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 @@
             "<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>"})
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java
index 9716c75..fb1b4e3 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java
@@ -18,16 +18,16 @@
 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);
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
index e9254a5..97e74ae 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
@@ -35,92 +35,92 @@
             "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")
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
index 554354a..52025eb 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
@@ -17,9 +17,9 @@
     @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 @@
             "ptz=#{ptz}, " +
             "rtcp=#{rtcp}, " +
             "status=#{status}, " +
-            "startOfflinePush=${startOfflinePush}, " +
+            "startOfflinePush=#{startOfflinePush}, " +
             "catalogGroup=#{catalogGroup}, " +
             "administrativeDivision=#{administrativeDivision}, " +
             "createTime=#{createTime}, " +
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
index 120ecb3..b98b948 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
@@ -21,22 +21,22 @@
      * 鏌ヨ鍒楄〃閲屽凡缁忓叧鑱旂殑
      */
     @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 @@
     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 " +
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
index 13094b9..91a4a5f 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
@@ -26,7 +26,7 @@
             "(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);
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java
index 2d73982..a784472 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java
@@ -14,10 +14,10 @@
 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")
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java
index 66a60b9..425f5e4 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java
@@ -12,14 +12,14 @@
 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);
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
index 4ed214d..5dbd8f0 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
@@ -13,9 +13,9 @@
 
     @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 @@
     @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 @@
 
     @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 @@
     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);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
index ec51f11..492dfe3 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
@@ -17,23 +17,23 @@
 
     @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 @@
             "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 @@
             "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 @@
     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);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
index c7a44fd..ecaa165 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
@@ -11,16 +11,16 @@
 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 @@
     @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")
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
index e8997cb..139f018 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -224,31 +224,31 @@
 		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);
 			// 娴峰悍璁惧鐨刾arentId鏄疭IP 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 @@
 	 * @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 @@
 	 * @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;
 	}
 
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java b/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
index 3b4bec4..50152cd 100644
--- a/src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
+++ b/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
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java
index b5fe8fb..7e2b512 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java
+++ b/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 @@
     SUCCESS(0, "鎴愬姛"),
     ERROR100(100, "澶辫触"),
     ERROR400(400, "鍙傛暟涓嶅叏鎴栬�呴敊璇�"),
+    ERROR404(404, "璧勬簮鏈壘鍒�"),
     ERROR403(403, "鏃犳潈闄愭搷浣�"),
     ERROR401(401, "璇风櫥褰曞悗閲嶆柊璇锋眰"),
     ERROR500(500, "绯荤粺寮傚父");
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
new file mode 100644
index 0000000..e7c24aa
--- /dev/null
+++ b/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;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
index 5dc0f03..18618e7 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
@@ -14,7 +14,6 @@
 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 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 @@
 	 */
 	@Operation(summary = "甯冮槻/鎾ら槻鍛戒护")
 	@Parameter(name = "deviceId", description = "璁惧鍥芥爣缂栧彿", required = true)
-	@Parameter(name = "channelId", description = "閫氶亾鍥芥爣缂栧彿", required = true)
 	@Parameter(name = "guardCmdStr", description = "鍛戒护锛� 鍙�夊�硷細SetGuard锛堝竷闃诧級锛孯esetGuard锛堟挙闃诧級", 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 -> {
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
index d4694c5..11bc621 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -99,7 +99,7 @@
 	@GetMapping("/devices")
 	public PageInfo<Device> devices(int page, int count){
 		
-		return storager.queryVideoDeviceList(page, count);
+		return storager.queryVideoDeviceList(page, count,null);
 	}
 
 	/**
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
index 7e73e05..d135fa2 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
@@ -5,11 +5,11 @@
 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 @@
     @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 @@
             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 @@
                 streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
             }
             if (streamInfo != null){
-                return  streamInfo;
+                return new StreamContent(streamInfo);
             }else {
                 throw new ControllerException(ErrorCode.ERROR100);
             }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
index 19b2adc..99fa4c1 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -22,6 +22,7 @@
 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 @@
 	@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) {
 
 		// 鑾峰彇鍙敤鐨剒lm
 		Device device = storager.queryVideoDevice(deviceId);
@@ -98,8 +99,8 @@
 		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 @@
 			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;
+		});
+
 
 		// 褰曞儚鏌ヨ浠hannelId浣滀负deviceId鏌ヨ
 		resultHolder.put(key, uuid, deferredResultEx);
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
index 696fae0..511b98d 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
@@ -10,6 +10,7 @@
 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 javax.sip.InvalidArgumentException;
 import javax.sip.SipException;
 import java.text.ParseException;
+import java.util.UUID;
 
 /**
  * @author lin
@@ -68,24 +70,37 @@
 	@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璋冪敤锛宒eviceId锛�%s 锛宑hannelId锛�%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;
 	}
 
 
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
index 6625ba4..c3b9c78 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
@@ -8,6 +8,7 @@
 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 @@
 	@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璋冪敤锛宒eviceId锛�%s锛宑hannelId锛�%s锛宒ownloadSpeed锛�%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 @@
 	@Parameter(name = "channelId", description = "閫氶亾鍥芥爣缂栧彿", required = true)
 	@Parameter(name = "stream", description = "娴両D", 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);
 	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
index d1368d8..65ec3d3 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
+++ b/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 @@
     })
     @PostMapping(value = "/save")
     @ResponseBody
-    public  StreamInfo save(@RequestBody StreamProxyItem param){
+    public StreamContent save(@RequestBody StreamProxyItem param){
         logger.info("娣诲姞浠g悊锛� " + JSONObject.toJSONString(param));
         if (ObjectUtils.isEmpty(param.getMediaServerId())) {
             param.setMediaServerId("auto");
@@ -69,7 +69,7 @@
         if (ObjectUtils.isEmpty(param.getGbId())) {
             param.setGbId(null);
         }
-        return streamProxyService.save(param);
+        return new StreamContent(streamProxyService.save(param));
     }
 
     @GetMapping(value = "/ffmpeg_cmd/list")
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
index d0aff58..7506433 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
@@ -11,22 +11,16 @@
 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.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 @@
     @Parameter(name = "app", description = "搴旂敤鍚�", required = true)
     @Parameter(name = "stream", description = "娴乮d", required = true)
     @Parameter(name = "mediaServerId", description = "濯掍綋鏈嶅姟鍣╥d")
-    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 @@
         if (streamInfo == null){
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "鑾峰彇鎾斁鍦板潃澶辫触");
         }
-        return streamInfo;
+        return new StreamContent(streamInfo);
     }
 
     /**
diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java
index 48dbbc4..e5f4227 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java
@@ -10,8 +10,10 @@
 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 @@
         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 @@
 
     @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 @@
             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 @@
                                                      // 1-IETF RFC3261,
                                                      // 2-鍩轰簬鍙d护鐨勫弻鍚戣璇�,
                                                      // 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", "");
diff --git a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
index ab769f5..5381a3a 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
@@ -12,7 +12,6 @@
 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 @@
             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());
diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml
index bd2038d..052fa74 100644
--- a/src/main/resources/all-application.yml
+++ b/src/main/resources/all-application.yml
@@ -168,7 +168,7 @@
     # 淇濆瓨绉诲姩浣嶇疆鍘嗗彶杞ㄨ抗锛歵rue:淇濈暀鍘嗗彶鏁版嵁锛宖alse:浠呬繚鐣欐渶鍚庣殑浣嶇疆(榛樿)
     save-position-history: false
     # 鐐规挱绛夊緟瓒呮椂鏃堕棿,鍗曚綅锛氭绉�
-    play-timeout: 3000
+    play-timeout: 18000
     # 涓婄骇鐐规挱绛夊緟瓒呮椂鏃堕棿,鍗曚綅锛氭绉�
     platform-play-timeout: 60000
     # 鏄惁寮�鍚帴鍙i壌鏉�
@@ -186,7 +186,7 @@
     use-pushing-as-status: true
     # 浣跨敤鏉ユ簮璇锋眰ip浣滀负streamIp,褰撲笖浠呭綋浣犲彧鏈墇lm鑺傜偣瀹冧笌wvp鍦ㄤ竴璧风殑鎯呭喌涓嬪紑鍚�
     use-source-ip-as-stream-ip: true
-    # 鎸夐渶鎷夋祦, true锛氭湁浜鸿鐪嬫媺娴侊紝鏃犱汉瑙傜湅閲婃斁锛� false锛氭媺璧峰悗涓嶈嚜鍔ㄩ噴鏀�
+    # 鍥芥爣鐐规挱 鎸夐渶鎷夋祦, true锛氭湁浜鸿鐪嬫媺娴侊紝鏃犱汉瑙傜湅閲婃斁锛� false锛氭媺璧峰悗涓嶈嚜鍔ㄩ噴鏀�
     stream-on-demand: true
     # 鎺ㄦ祦閴存潈锛� 榛樿寮�鍚�
     push-authority: true
@@ -195,6 +195,10 @@
     gb-send-stream-strict: false
     # 璁惧涓婄嚎鏃舵槸鍚﹁嚜鍔ㄥ悓姝ラ�氶亾
     sync-channel-on-device-online: false
+    # 鏄惁浣跨敤璁惧鏉ユ簮Ip浣滀负鍥炲IP锛� 涓嶈缃垯涓� false
+    sip-use-source-ip-as-remote-address: false
+    # 鏄惁寮�鍚痵ip鏃ュ織
+    sip-log: true
     # 鏀跺埌ack娑堟伅鍚庡紑濮嬪彂娴侊紝榛樿false锛� 鍥炲200ok鍚庣洿鎺ュ紑濮嬪彂娴�
     push-stream-after-ack: false
 
diff --git a/web_src/src/components/CloudRecordDetail.vue b/web_src/src/components/CloudRecordDetail.vue
index 143448e..8d04eb0 100644
--- a/web_src/src/components/CloudRecordDetail.vue
+++ b/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
diff --git a/web_src/src/components/GBRecordDetail.vue b/web_src/src/components/GBRecordDetail.vue
new file mode 100644
index 0000000..6fe29a8
--- /dev/null
+++ b/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>
diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue
index 136ddfe..f020f34 100644
--- a/web_src/src/components/channelList.vue
+++ b/web_src/src/components/channelList.vue
@@ -269,10 +269,10 @@
       });
     },
     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;
diff --git a/web_src/src/components/console.vue b/web_src/src/components/console.vue
index 6e2dd83..e192fb1 100644
--- a/web_src/src/components/console.vue
+++ b/web_src/src/components/console.vue
@@ -101,11 +101,14 @@
         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 (){
diff --git a/web_src/src/components/console/ConsoleResource.vue b/web_src/src/components/console/ConsoleResource.vue
index bc307b9..3aa7771 100644
--- a/web_src/src/components/console/ConsoleResource.vue
+++ b/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">
         鎷夋祦浠g悊鎬绘暟:{{proxyInfo.total}}<br/>
         鍦ㄧ嚎鏁�:{{proxyInfo.online}}
diff --git a/web_src/src/components/dialog/devicePlayer.vue b/web_src/src/components/dialog/devicePlayer.vue
index 89b3e07..b49a188 100644
--- a/web_src/src/components/dialog/devicePlayer.vue
+++ b/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 @@
               jessibuca : ["ws_flv", "wss_flv"],
               webRTC: ["rtc", "rtcs"],
             },
-            videoHistory: {
-                date: '',
-                searchHistoryResult: [] //濯掍綋娴佸巻鍙茶褰曟悳绱㈢粨鏋�
-            },
             showVideoDialog: false,
             streamId: '',
             app : '',
@@ -366,7 +311,6 @@
             tracks: [],
             coverPlaying:false,
             tracksLoading: false,
-            recordPlay: "",
             showPtz: true,
             showRrecord: true,
             tracksNotLoaded: false,
@@ -429,11 +373,6 @@
                 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;
@@ -443,9 +382,6 @@
                 case "control":
                     break;
             }
-        },
-        timeAxisSelTime: function (val) {
-            console.log(val)
         },
         play: function (streamInfo, hasAudio) {
             this.streamInfo = streamInfo;
@@ -461,9 +397,9 @@
         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 @@
               this.convertStop();
             }
             this.convertKey = ''
-            if (this.recordPlay != '') {
-              this.stopPlayRecord();
-            }
-            this.recordPlay = ''
             this.stopBroadcast()
         },
 
@@ -570,137 +502,6 @@
                     });
                 }
             );
-        },
-
-        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);
@@ -740,52 +541,6 @@
                 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 @@
 
             })
         },
-        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('鍓嶇鎺у埗锛歴eek ');
-          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('涓嶆敮鎸亀ebrtc',e)
-                this.$message({
-                  showClose: true,
-                  message: '涓嶆敮鎸亀ebrtc, 鏃犳硶杩涜璇煶瀵硅',
-                  type: 'error'
-                });
-                this.broadcastStatus = -1;
-              });
 
               this.broadcastRtc.on(ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR,(e)=>{// ICE 鍗忓晢鍑洪敊
                 console.error('ICE 鍗忓晢鍑洪敊')
diff --git a/web_src/src/components/dialog/recordDownload.vue b/web_src/src/components/dialog/recordDownload.vue
index b0b8fea..3e8c427 100644
--- a/web_src/src/components/dialog/recordDownload.vue
+++ b/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 @@
           taskId: null,
           getProgressRun: false,
           getProgressForFileRun: false,
+          timer: null
 
         };
     },
@@ -66,7 +55,7 @@
             this.percentage = 0.0;
             this.getProgressTimer()
         },
-        getProgressTimer(){
+        getProgressTimer: function (){
           if (!this.getProgressRun) {
             return;
           }
@@ -93,15 +82,24 @@
                   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;
diff --git a/web_src/src/components/live.vue b/web_src/src/components/live.vue
index fcf1d59..4a7af49 100644
--- a/web_src/src/components/live.vue
+++ b/web_src/src/components/live.vue
@@ -140,9 +140,9 @@
         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);
diff --git a/web_src/src/router/index.js b/web_src/src/router/index.js
index 4844d64..23c0a82 100644
--- a/web_src/src/router/index.js
+++ b/web_src/src/router/index.js
@@ -5,6 +5,7 @@
 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'
@@ -65,6 +66,11 @@
           component: channelList,
         },
         {
+          path: '/gbRecordDetail/:deviceId/:channelId/',
+          name: 'gbRecordDetail',
+          component: gbRecordDetail,
+        },
+        {
           path: '/parentPlatformList/:count/:page',
           name: 'parentPlatformList',
           component: parentPlatformList,
diff --git a/web_src/static/css/iconfont.css b/web_src/static/css/iconfont.css
index a09b98e..4636a73 100644
--- a/web_src/static/css/iconfont.css
+++ b/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";
 }
diff --git a/web_src/static/css/iconfont.woff2 b/web_src/static/css/iconfont.woff2
index c2fdf69..f1cb24c 100644
--- a/web_src/static/css/iconfont.woff2
+++ b/web_src/static/css/iconfont.woff2
Binary files differ

--
Gitblit v1.8.0