From bb50a243145dba2b3bf5f3bf225c63a092697a16 Mon Sep 17 00:00:00 2001
From: mrjackwang <30337754+mrjackwang@users.noreply.github.com>
Date: 星期五, 04 三月 2022 20:37:17 +0800
Subject: [PATCH] Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0

---
 src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformCycleRegisterEventLister.java                        |   13 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java                                                             |    9 
 src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java                                                        |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java                                                               |   11 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java                                                        |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java                                                              |   13 
 src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java                                                   |    7 
 src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java                                                       |   32 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java                              |    3 
 src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java                                                                       |   29 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java                                   |   25 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java                                             |    9 
 src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java                                 |    5 
 src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java                                                             |    3 
 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java                                                       |   10 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java                                                                      |   14 
 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java                                                              |   43 +
 src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java                                                    |    6 
 README.md                                                                                                                          |   19 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java                                |  262 +++++++----
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java                                              |    5 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java       |  157 ++++++
 src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java                                                             |    1 
 src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java                                                                       |   32 +
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java                                              |    4 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java                                                                       |   13 
 src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java                                               |   49 ++
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java                                                                  |   26 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                                                    |   45 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java |    8 
 pom.xml                                                                                                                            |    4 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java                                                            |   31 
 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java                                                       |    1 
 src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java                                                        |   22 
 src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java                                                               |   55 ++
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java                                                                   |   12 
 src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java                                                                   |   38 +
 src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java                                                                |    1 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java                                                     |    2 
 src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java                                                               |    2 
 src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java                                                         |    6 
 src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java                                                       |   44 +
 src/main/resources/all-application.yml                                                                                             |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java                                   |   84 ++-
 src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java                                                            |    3 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                                                             |    2 
 src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java                                                                     |   11 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java                                         |   54 ++
 web_src/src/components/control.vue                                                                                                 |   26 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java                                                      |    1 
 src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java                                                           |   64 ++
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java                                                |    2 
 52 files changed, 1,032 insertions(+), 292 deletions(-)

diff --git a/README.md b/README.md
index 93b3ffb..564b197 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-yellow.svg)](https://github.com/xia-chu/ZLMediaKit/pulls)
 
 
-WEB VIDEO PLATFORM鏄竴涓熀浜嶨B28181-2016鏍囧噯瀹炵幇鐨勫紑绠卞嵆鐢ㄧ殑缃戠粶瑙嗛骞冲彴锛岃礋璐e疄鐜版牳蹇冧俊浠や笌璁惧绠$悊鍚庡彴閮ㄥ垎锛屾敮鎸丯AT绌块�忥紝鏀寔娴峰悍銆佸ぇ鍗庛�佸畤瑙嗙瓑鍝佺墝鐨処PC銆丯VR銆丏VR鎺ュ叆銆傛敮鎸佸浗鏍囩骇鑱旓紝鏀寔rtsp/rtmp绛夎棰戞祦杞彂鍒板浗鏍囧钩鍙帮紝鏀寔rtsp/rtmp绛夋帹娴佽浆鍙戝埌鍥芥爣骞冲彴銆�   
+WEB VIDEO PLATFORM鏄竴涓熀浜嶨B28181-2016鏍囧噯瀹炵幇鐨勫紑绠卞嵆鐢ㄧ殑缃戠粶瑙嗛骞冲彴锛岃礋璐e疄鐜版牳蹇冧俊浠や笌璁惧绠$悊鍚庡彴閮ㄥ垎锛屾敮鎸丯AT绌块�忥紝鏀寔娴峰悍銆佸ぇ鍗庛�佸畤瑙嗙瓑鍝佺墝鐨処PC銆丯VR鎺ュ叆銆傛敮鎸佸浗鏍囩骇鑱旓紝鏀寔灏嗕笉甯﹀浗鏍囧姛鑳界殑鎽勫儚鏈�/鐩存挱娴�/鐩存挱鎺ㄦ祦杞彂鍒板叾浠栧浗鏍囧钩鍙般��   
 
 娴佸獟浣撴湇鍔″熀浜嶼LMediaKit-https://github.com/xiongziliang/ZLMediaKit
 
@@ -31,11 +31,13 @@
 https://gitee.com/pan648540858/wvp-GB28181-pro.git
 
 # 鎴浘
-![build_1.png](https://github.com/648540858/wiki/blob/master/images/Screenshot_1.png)
-![build_1.png](https://github.com/648540858/wiki/blob/master/images/Screenshot_2.png)
-![build_1.png](https://github.com/648540858/wiki/blob/master/images/Screenshot_20201012_151459.png)
-![build_1.png](https://github.com/648540858/wiki/blob/master/images/Screenshot_20201012_152643.png)
-![build_1.png](https://github.com/648540858/wiki/blob/master/images/Screenshot_20201012_151606.png)
+![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101513_79632720_1018729.png "2022-03-04_09-51.png")
+![build_1.png](https://images.gitee.com/uploads/images/2022/0304/103025_5df016f9_1018729.png "2022-03-04_10-27.png")
+![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101706_088fbafa_1018729.png "2022-03-04_09-52_1.png")
+![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101756_3d662828_1018729.png "2022-03-04_10-00_1.png")
+![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101823_19050c66_1018729.png "2022-03-04_10-12_1.png")
+![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101848_e5a39557_1018729.png "2022-03-04_10-12_2.png")
+![build_1.png](https://images.gitee.com/uploads/images/2022/0304/101919_ee5b8c79_1018729.png "2022-03-04_10-13.png")
 
 # 1.0 鍩虹鐗规��  
 1. 瑙嗛棰勮;  
@@ -79,7 +81,7 @@
    -  [X] 绉诲姩浣嶇疆閫氱煡澶勭悊
    -  [X] 鎶ヨ浜嬩欢璁㈤槄
    -  [X] 鎶ヨ浜嬩欢閫氱煡澶勭悊
-   -  [ ] 璁惧鐩綍璁㈤槄
+   -  [X] 璁惧鐩綍璁㈤槄
    -  [X] 璁惧鐩綍閫氱煡澶勭悊
 16. 绉诲姩浣嶇疆鏌ヨ鍜屾樉绀猴紝鍙�氳繃閰嶇疆鏂囦欢璁剧疆绉诲姩浣嶇疆鍘嗗彶鏄惁瀛樺偍
 
@@ -96,6 +98,9 @@
     - [X] 骞冲彴淇℃伅鏌ヨ
     - [X] 骞冲彴杩滅▼鍚姩
     - [X] 姣忎釜绾ц仈骞冲彴鍙嚜瀹氫箟鐨勮櫄鎷熺洰褰�
+    - [X] 鐩綍璁㈤槄涓庨�氱煡
+    - [X] 褰曞儚鏌ョ湅涓庢挱鏀�
+    - [X] GPS璁㈤槄涓庨�氱煡锛堢洿鎾帹娴侊級
 - [X] 娣诲姞RTSP瑙嗛
 - [X] 娣诲姞鎺ュ彛閴存潈
 - [X] 娣诲姞RTMP瑙嗛
diff --git a/pom.xml b/pom.xml
index 9d31f72..2dde4da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -253,10 +253,6 @@
 			<artifactId>spring-boot-starter-test</artifactId>
 <!--			<scope>test</scope>-->
 		</dependency>
-		<dependency>
-			<groupId>org.projectlombok</groupId>
-			<artifactId>lombok</artifactId>
-		</dependency>
 	</dependencies>
 
 
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 aff1671..761437f 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
@@ -4,11 +4,6 @@
 public class Device {
 
 	/**
-	 * Id
-	 */
-	private int id;
-
-	/**
 	 * 璁惧Id
 	 */
 	private String deviceId;
@@ -119,13 +114,7 @@
 	 */
 	private int subscribeCycleForCatalog ;
 
-	public int getId() {
-		return id;
-	}
 
-	public void setId(int id) {
-		this.id = id;
-	}
 
 	public String getDeviceId() {
 		return deviceId;
@@ -294,6 +283,4 @@
 	public void setSubscribeCycleForCatalog(int subscribeCycleForCatalog) {
 		this.subscribeCycleForCatalog = subscribeCycleForCatalog;
 	}
-
-
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java
index 7c1f0ad..c6cf782 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java
@@ -8,10 +8,6 @@
 
 public class MobilePosition {
     /**
-     * Id
-     */
-    private int id;
-    /**
      * 璁惧Id
      */
     private String deviceId;
@@ -76,13 +72,6 @@
      */
     private String cnLat;
 
-    public int getId() {
-        return id;
-    }
-
-    public void setId(int id) {
-        this.id = id;
-    }
 
     public String getDeviceId() {
         return deviceId;
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
index 39f894c..ca7fd54 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
@@ -19,7 +19,9 @@
 	private String name;
 	
 	private String filePath;
-	
+
+	private String fileSize;
+
 	private String address;
 	
 	private String startTime;
@@ -104,6 +106,14 @@
 		this.recorderId = recorderId;
 	}
 
+	public String getFileSize() {
+		return fileSize;
+	}
+
+	public void setFileSize(String fileSize) {
+		this.fileSize = fileSize;
+	}
+
 	@Override
 	public int compareTo(@NotNull RecordItem recordItem) {
 		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java
new file mode 100644
index 0000000..39225b5
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java
@@ -0,0 +1,14 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import javax.sdp.SessionDescription;
+
+public class SDPInfo {
+    private byte[] source;
+    private SessionDescription sdpSource;
+    private String sessionName;
+    private Long startTime;
+    private Long stopTime;
+    private String username;
+    private String address;
+    private String ssrc;
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
index 2c9c494..3e5d222 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
@@ -71,6 +71,16 @@
      */
     private String mediaServerId;
 
+    /**
+     *  invite鐨刢allId
+     */
+    private String CallId;
+
+    /**
+     * 鏄惁鏄痯lay锛� false鏄痯layback
+     */
+    private boolean isPlay;
+
     public String getIp() {
         return ip;
     }
@@ -174,4 +184,20 @@
     public void setMediaServerId(String mediaServerId) {
         this.mediaServerId = mediaServerId;
     }
+
+    public String getCallId() {
+        return CallId;
+    }
+
+    public void setCallId(String callId) {
+        CallId = callId;
+    }
+
+    public boolean isPlay() {
+        return isPlay;
+    }
+
+    public void setPlay(boolean play) {
+        isPlay = play;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
index 746467d..a9464b7 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
@@ -1,12 +1,11 @@
 package com.genersoft.iot.vmp.gb28181.event;
 
-import com.genersoft.iot.vmp.gb28181.bean.Device;
-import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.gb28181.bean.GbStream;
+import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent;
 import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent;
 import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformCycleRegisterEvent;
 import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent;
+import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
 import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
 import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent;
@@ -15,7 +14,6 @@
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Component;
 
-import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
 import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
 import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
 
@@ -145,4 +143,11 @@
 		gbStreamList.add(gbStream);
 		catalogEventPublishForStream(platformId, gbStreamList, type);
 	}
+
+	public void recordEndEventPush(RecordInfo recordInfo) {
+		RecordEndEvent outEvent = new RecordEndEvent(this);
+		outEvent.setRecordInfo(recordInfo);
+		applicationEventPublisher.publishEvent(outEvent);
+	}
+
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java
index aaf5b5d..9ba0c05 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java
@@ -76,10 +76,7 @@
             eventResult.callId = callid;
             eventResult.msg = "娉ㄥ唽瓒呮椂";
             eventResult.type = "register timeout";
-            if (sipSubscribe.getErrorSubscribe(callid) != null) {
-                sipSubscribe.getErrorSubscribe(callid).response(eventResult);
-            }
-
+            sipSubscribe.getErrorSubscribe(callid).response(eventResult);
         }
 
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformCycleRegisterEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformCycleRegisterEventLister.java
index 996f65d..4df77a0 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformCycleRegisterEventLister.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformCycleRegisterEventLister.java
@@ -4,7 +4,8 @@
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
-import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationListener;
 import org.springframework.stereotype.Component;
@@ -12,9 +13,11 @@
 import java.util.Timer;
 import java.util.TimerTask;
 
-@Slf4j
 @Component
 public class PlatformCycleRegisterEventLister implements ApplicationListener<PlatformCycleRegisterEvent> {
+
+    private final static Logger logger = LoggerFactory.getLogger(PlatformCycleRegisterEventLister.class);
+
     @Autowired
     private IVideoManagerStorager storager;
     @Autowired
@@ -22,10 +25,10 @@
 
     @Override
     public void onApplicationEvent(PlatformCycleRegisterEvent event) {
-        log.info("涓婄骇骞冲彴鍛ㄦ湡娉ㄥ唽浜嬩欢");
+        logger.info("涓婄骇骞冲彴鍛ㄦ湡娉ㄥ唽浜嬩欢");
         ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformGbID());
         if (parentPlatform == null) {
-            log.info("[ 骞冲彴鏈敞鍐屼簨浠� ] 骞冲彴宸茬粡鍒犻櫎!!! 骞冲彴鍥芥爣ID锛�" + event.getPlatformGbID());
+            logger.info("[ 骞冲彴鏈敞鍐屼簨浠� ] 骞冲彴宸茬粡鍒犻櫎!!! 骞冲彴鍥芥爣ID锛�" + event.getPlatformGbID());
             return;
         }
         Timer timer = new Timer();
@@ -36,7 +39,7 @@
         timer.schedule(new TimerTask() {
             @Override
             public void run() {
-                log.info("[骞冲彴娉ㄥ唽]鍐嶆鍚戝钩鍙版敞鍐岋紝骞冲彴鍥芥爣ID锛�" + event.getPlatformGbID());
+                logger.info("[骞冲彴娉ㄥ唽]鍐嶆鍚戝钩鍙版敞鍐岋紝骞冲彴鍥芥爣ID锛�" + event.getPlatformGbID());
                 sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
             }
         }, 15*1000 ,Long.parseLong(parentPlatform.getExpires())* 1000);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java
new file mode 100644
index 0000000..cfd2985
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java
@@ -0,0 +1,32 @@
+package com.genersoft.iot.vmp.gb28181.event.record;
+
+import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
+import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * @description: 褰曞儚鏌ヨ缁撴潫鏃堕棿
+ * @author: pan
+ * @data: 2022-02-23
+ */
+
+public class RecordEndEvent extends ApplicationEvent {
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    public RecordEndEvent(Object source) {
+        super(source);
+    }
+
+    private RecordInfo recordInfo;
+
+    public RecordInfo getRecordInfo() {
+        return recordInfo;
+    }
+
+    public void setRecordInfo(RecordInfo recordInfo) {
+        this.recordInfo = recordInfo;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
new file mode 100644
index 0000000..95ffbfa
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
@@ -0,0 +1,49 @@
+package com.genersoft.iot.vmp.gb28181.event.record;
+
+import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
+import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @description: 褰曞儚鏌ヨ缁撴潫鏃堕棿
+ * @author: pan
+ * @data: 2022-02-23
+ */
+
+@Component
+public class RecordEndEventListener implements ApplicationListener<RecordEndEvent> {
+
+    private final static Logger logger = LoggerFactory.getLogger(RecordEndEventListener.class);
+
+    private static Map<String, SseEmitter> sseEmitters = new Hashtable<>();
+
+    public interface RecordEndEventHandler{
+        void  handler(RecordInfo recordInfo);
+    }
+
+    private Map<String, RecordEndEventHandler> handlerMap = new HashMap<>();
+    @Override
+    public void onApplicationEvent(RecordEndEvent event) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("褰曞儚鏌ヨ瀹屾垚浜嬩欢瑙﹀彂锛宒eviceId锛歿}, channelId: {}, 褰曞儚鏁伴噺{}鏉�", event.getRecordInfo().getDeviceId(),
+                    event.getRecordInfo().getChannelId(), event.getRecordInfo().getRecordList().size() );
+        }
+        if (handlerMap.size() > 0) {
+            for (RecordEndEventHandler recordEndEventHandler : handlerMap.values()) {
+                recordEndEventHandler.handler(event.getRecordInfo());
+            }
+        }
+
+    }
+
+    public void addEndEventHandler(String device, String channelId, RecordEndEventHandler recordEndEventHandler) {
+        handlerMap.put(device + channelId, recordEndEventHandler);
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java
index e96e6a5..ac54c2d 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java
@@ -81,7 +81,6 @@
             isUsed.remove(sn);
             notUsed.add(sn);
         }catch (NullPointerException e){
-            System.out.printf("11111");
         }
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java
index 0d56bd5..f0d9033 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java
@@ -36,7 +36,6 @@
 
         SubscribeInfo subscribe = redisCatchStorage.getSubscribe(key);
         if (subscribe != null) {
-            System.out.println("鍙戦�丟PS娑堟伅");
             ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
             if (parentPlatform == null || parentPlatform.isStatus()) {
                 // TODO 鏆傛椂鍙鐞嗚棰戞祦鐨勫洖澶�,鍚庣画澧炲姞瀵瑰浗鏍囪澶囩殑鏀寔
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
index 4732cc1..3cc4456 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
@@ -141,7 +141,6 @@
      */
     @Override
     public void processTimeout(TimeoutEvent timeoutEvent) {
-        System.out.println("processTimeout");
         if(timeoutProcessor != null) {
             timeoutProcessor.process(timeoutEvent);
         }
@@ -173,7 +172,6 @@
 
     @Override
     public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
-        System.out.println("processDialogTerminated");
         CallIdHeader callId = dialogTerminatedEvent.getDialog().getCallId();
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
index 5859d65..67be247 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -258,7 +258,7 @@
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 * @param sn
 	 */
-	boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent);
+	boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn,  Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
 	
 	/**
 	 * 鏌ヨ鎶ヨ淇℃伅
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 d6294fa..cd2d627 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
@@ -2,6 +2,7 @@
 
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
 import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
@@ -87,4 +88,12 @@
      */
     boolean sendNotifyForCatalogOther(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index);
 
+    /**
+     * 鍥炲recordInfo
+     * @param deviceChannel 閫氶亾淇℃伅
+     * @param parentPlatform 骞冲彴淇℃伅
+     * @param fromTag fromTag
+     * @param recordInfo 褰曞儚淇℃伅
+     */
+    boolean recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo);
 }
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 734fe23..437c69d 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
@@ -346,8 +346,11 @@
 			subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
 					(MediaServerItem mediaServerItemInUse, JSONObject json)->{
 				if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
-				event.response(mediaServerItemInUse, json);
-				subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
+				if (event != null) {
+					event.response(mediaServerItemInUse, json);
+				}
+
+//				subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
 			});
 			//
 			StringBuffer content = new StringBuffer(200);
@@ -450,13 +453,16 @@
 			subscribeKey.put("app", "rtp");
 			subscribeKey.put("stream", ssrcInfo.getStream());
 			subscribeKey.put("regist", true);
+			subscribeKey.put("schema", "rtmp");
 			subscribeKey.put("mediaServerId", mediaServerItem.getId());
 			logger.debug("褰曞儚鍥炴斁娣诲姞璁㈤槄锛岃闃呭唴瀹癸細" + subscribeKey.toString());
 			subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
 					(MediaServerItem mediaServerItemInUse, JSONObject json)->{
+						System.out.println(344444);
 				if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
-				event.response(mediaServerItemInUse, json);
-				subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
+				if (event != null) {
+					event.response(mediaServerItemInUse, json);
+				}
 			});
 
 			StringBuffer content = new StringBuffer(200);
@@ -713,6 +719,7 @@
 			if (ssrcTransaction != null) {
 				MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
 				mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc());
+				mediaServerService.closeRTPServer(deviceId, channelId, ssrcTransaction.getStream());
 				streamSession.remove(deviceId, channelId, ssrcTransaction.getStream());
 			}
 		} catch (SipException | ParseException e) {
@@ -1196,9 +1203,13 @@
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */  
 	@Override
-	public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent) {
-
-
+	public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
+		if (secrecy == null) {
+			secrecy = 0;
+		}
+		if (type == null) {
+			type = "all";
+		}
 		try {
 			StringBuffer recordInfoXml = new StringBuffer(200);
 			recordInfoXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
@@ -1206,11 +1217,19 @@
 			recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
 			recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
 			recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
-			recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
-			recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
-			recordInfoXml.append("<Secrecy>0</Secrecy>\r\n");
-			// 澶у崕NVR瑕佹眰蹇呴』澧炲姞涓�涓�间负all鐨勬枃鏈厓绱犺妭鐐筎ype
-			recordInfoXml.append("<Type>all</Type>\r\n");
+			if (startTime != null) {
+				recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
+			}
+			if (endTime != null) {
+				recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
+			}
+			if (secrecy != null) {
+				recordInfoXml.append("<Secrecy> "+ secrecy + " </Secrecy>\r\n");
+			}
+			if (type != null) {
+				// 澶у崕NVR瑕佹眰蹇呴』澧炲姞涓�涓�间负all鐨勬枃鏈厓绱犺妭鐐筎ype
+				recordInfoXml.append("<Type>" + type+"</Type>\r\n");
+			}
 			recordInfoXml.append("</Query>\r\n");
 			
 			String tm = Long.toString(System.currentTimeMillis());
@@ -1221,7 +1240,7 @@
 			Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
 					"z9hG4bK-ViaRecordInfo-" + tm, "fromRec" + tm, null, callIdHeader);
 
-			transmitRequest(device, request, errorEvent);
+			transmitRequest(device, request, errorEvent, okEvent);
 		} catch (SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();
 			return false;
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 5dcffe7..b57a5e4 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
@@ -1,12 +1,10 @@
 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
 
-import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
-import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
+import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
+import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import org.slf4j.Logger;
@@ -17,6 +15,7 @@
 import org.springframework.context.annotation.Lazy;
 import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
 
 import javax.sip.*;
 import javax.sip.header.CallIdHeader;
@@ -496,5 +495,52 @@
         catalogXml.append("</Notify>\r\n");
         return catalogXml.toString();
     }
+    @Override
+    public boolean recordInfo(DeviceChannel deviceChannel, ParentPlatform parentPlatform, String fromTag, RecordInfo recordInfo) {
+        if ( parentPlatform ==null) {
+            return false;
+        }
+        try {
+            StringBuffer recordXml = new StringBuffer(600);
+            recordXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
+            recordXml.append("<Response>\r\n");
+            recordXml.append("<CmdType>RecordInfo</CmdType>\r\n");
+            recordXml.append("<SN>" +recordInfo.getSn() + "</SN>\r\n");
+            recordXml.append("<DeviceID>" + recordInfo.getDeviceId() + "</DeviceID>\r\n");
+            recordXml.append("<SumNum>" + recordInfo.getSumNum() + "</SumNum>\r\n");
+            recordXml.append("<RecordList Num=\"" + recordInfo.getRecordList().size()+"\">\r\n");
+            for (RecordItem recordItem : recordInfo.getRecordList()) {
+                recordXml.append("<Item>\r\n");
+                if (deviceChannel != null) {
+                    recordXml.append("<DeviceID>" + recordItem.getDeviceId() + "</DeviceID>\r\n");
+                    recordXml.append("<Name>" + recordItem.getName() + "</Name>\r\n");
+                    recordXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getStartTime()) + "</StartTime>\r\n");
+                    recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n");
+                    recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n");
+                    recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n");
+                    if (!StringUtils.isEmpty(recordItem.getFileSize())) {
+                        recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n");
+                    }
+                    if (!StringUtils.isEmpty(recordItem.getFilePath())) {
+                        recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n");
+                    }
+                }
+                recordXml.append("</Item>\r\n");
+            }
 
+            recordXml.append("</RecordList>\r\n");
+            recordXml.append("</Response>\r\n");
+
+            // callid
+            CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
+                    : udpSipProvider.getNewCallId();
+            Request request = headerProviderPlarformProvider.createMessageRequest(parentPlatform, recordXml.toString(), fromTag, callIdHeader);
+            transmitRequest(parentPlatform, request);
+
+        } catch (SipException | ParseException | InvalidArgumentException e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
index 98ae86f..d5bc99b 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -1,10 +1,13 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
+import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.service.IMediaServerService;
@@ -24,6 +27,8 @@
 import javax.sip.header.ToHeader;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
 
 /**
  * SIP鍛戒护绫诲瀷锛� ACK璇锋眰
@@ -52,6 +57,9 @@
 	@Autowired
 	private IMediaServerService mediaServerService;
 
+	@Autowired
+	private ZLMHttpHookSubscribe subscribe;
+
 
 	/**   
 	 * 澶勭悊  ACK璇锋眰
@@ -60,6 +68,7 @@
 	 */
 	@Override
 	public void process(RequestEvent evt) {
+		logger.info("ACK璇锋眰锛� {}", ((System.currentTimeMillis())));
 		Dialog dialog = evt.getDialog();
 		if (dialog == null) return;
 		if (dialog.getState()== DialogState.CONFIRMED) {
@@ -69,16 +78,17 @@
 			String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
 			String deviceId = sendRtpItem.getDeviceId();
 			StreamInfo streamInfo = null;
-			if (deviceId == null) {
+			if (sendRtpItem.isPlay()) {
+				streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
+			}else {
+				streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId);
+			}
+			System.out.println(JSON.toJSON(streamInfo));
+			if (streamInfo == null) {
 				streamInfo = new StreamInfo();
 				streamInfo.setApp(sendRtpItem.getApp());
 				streamInfo.setStream(sendRtpItem.getStreamId());
-			}else {
-				streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
-				sendRtpItem.setStreamId(streamInfo.getStream());
-				streamInfo.setApp("rtp");
 			}
-
 			redisCatchStorage.updateSendRTPSever(sendRtpItem);
 			logger.info(platformGbId);
 			logger.info(channelId);
@@ -90,34 +100,42 @@
 			param.put("dst_url",sendRtpItem.getIp());
 			param.put("dst_port", sendRtpItem.getPort());
 			param.put("is_udp", is_Udp);
-			//param.put ("src_port", sendRtpItem.getLocalPort());
 			// 璁惧鎺ㄦ祦鏌ヨ锛屾垚鍔熷悗鎵嶈兘杞帹
-			boolean rtpPushed = false;
-			long startTime = System.currentTimeMillis();
-			while (!rtpPushed) {
-				try {
-					if (System.currentTimeMillis() - startTime < 30 * 1000) {
-						MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-						if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStream())) {
-							rtpPushed = true;
-							logger.info("宸茶幏鍙栬澶囨帹娴乕{}/{}]锛屽紑濮嬪悜涓婄骇鎺ㄦ祦[{}:{}]",
-									streamInfo.getApp() ,streamInfo.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort());
-							zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
-						} else {
-							logger.info("绛夊緟璁惧鎺ㄦ祦[{}/{}].......",
-									streamInfo.getApp() ,streamInfo.getStream());
-							Thread.sleep(1000);
-							continue;
-						}
-					} else {
-						rtpPushed = true;
-						logger.info("璁惧鎺ㄦ祦[{}/{}]瓒呮椂锛岀粓姝㈠悜涓婄骇鎺ㄦ祦",
-								streamInfo.getApp() ,streamInfo.getStream());
-					}
-				} catch (InterruptedException e) {
-					e.printStackTrace();
-				}
-			}
+			MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+			zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
+//			if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) {
+//				logger.info("宸茶幏鍙栬澶囨帹娴乕{}/{}]锛屽紑濮嬪悜涓婄骇鎺ㄦ祦[{}:{}]",
+//						streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort());
+//				zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
+//			} else {
+//				// 瀵筯ook杩涜璁㈤槄
+//				logger.info("绛夊緟璁惧鎺ㄦ祦[{}/{}].......",
+//						streamInfo.getApp(), streamInfo.getStreamId());
+//				Timer timer = new Timer();
+//				timer.schedule(new TimerTask() {
+//					@Override
+//					public void run() {
+//						logger.info("璁惧鎺ㄦ祦[{}/{}]瓒呮椂锛岀粓姝㈠悜涓婄骇鎺ㄦ祦",
+//								finalStreamInfo.getApp() , finalStreamInfo.getStreamId());
+//
+//					}
+//				}, 30*1000L);
+//				// 娣诲姞璁㈤槄
+//				JSONObject subscribeKey = new JSONObject();
+//				subscribeKey.put("app", "rtp");
+//				subscribeKey.put("stream", streamInfo.getStreamId());
+//				subscribeKey.put("mediaServerId", streamInfo.getMediaServerId());
+//				subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, subscribeKey,
+//						(MediaServerItem mediaServerItemInUse, JSONObject json) -> {
+//							logger.info("宸茶幏鍙栬澶囨帹娴乕{}/{}]锛屽紑濮嬪悜涓婄骇鎺ㄦ祦[{}:{}]",
+//									finalStreamInfo.getApp(), finalStreamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort());
+//							timer.cancel();
+//							zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
+//							subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
+//						});
+//			}
+
+
 		}
 	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
index eb25cde..deda783 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
@@ -2,6 +2,7 @@
 
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
@@ -87,22 +88,34 @@
 					MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
 					zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
 					redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
-					if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) {
+					int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
+					if (totalReaderCount == 0) {
 						logger.info(streamId + "鏃犲叾瀹冭鐪嬭�咃紝閫氱煡璁惧鍋滄鎺ㄦ祦");
 						cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId, streamId);
+					}else if (totalReaderCount == -1){
+						logger.warn(streamId + " 鏌ユ壘鍏跺畠瑙傜湅鑰呭け璐�");
 					}
 				}
 				// 鍙兘鏄澶囦富鍔ㄥ仠姝�
 				Device device = storager.queryVideoDeviceByChannelId(platformGbId);
-				if (device != null) {
+                if (device != null) {
 					StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
+					if (sendRtpItem != null) {
+						if (sendRtpItem.isPlay()) {
+							if (streamInfo != null) {
+								redisCatchStorage.stopPlay(streamInfo);
+							}
+						}else {
+							if (streamInfo != null) {
+								redisCatchStorage.stopPlayback(streamInfo);
+							}
+						}
 
-					if (streamInfo != null) {
-						redisCatchStorage.stopPlay(streamInfo);
+						storager.stopPlay(device.getDeviceId(), channelId);
+						mediaServerService.closeRTPServer(device.getDeviceId(), channelId, streamInfo.getStream());
 					}
-					storager.stopPlay(device.getDeviceId(), channelId);
-					mediaServerService.closeRTPServer(device, channelId, streamInfo.getStream());
 				}
+
 			}
 		} catch (SipException e) {
 			e.printStackTrace();
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
index 0c228c7..f861da4 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -1,18 +1,29 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
+import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
+import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
+import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.IPlayService;
+import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
+import gov.nist.javax.sdp.TimeDescriptionImpl;
+import gov.nist.javax.sdp.fields.TimeField;
 import gov.nist.javax.sip.address.AddressImpl;
 import gov.nist.javax.sip.address.SipUri;
 import org.slf4j.Logger;
@@ -27,10 +38,13 @@
 import javax.sip.ServerTransaction;
 import javax.sip.SipException;
 import javax.sip.address.SipURI;
+import javax.sip.header.CallIdHeader;
 import javax.sip.header.FromHeader;
 import javax.sip.message.Request;
 import javax.sip.message.Response;
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.List;
 import java.util.Vector;
 
@@ -61,6 +75,9 @@
 	private IPlayService playService;
 
 	@Autowired
+	private ISIPCommander commander;
+
+	@Autowired
 	private ZLMRTPServerFactory zlmrtpServerFactory;
 
 	@Autowired
@@ -68,6 +85,7 @@
 
 	@Autowired
 	private SIPProcessorObserver sipProcessorObserver;
+
 
 	@Override
 	public void afterPropertiesSet() throws Exception {
@@ -88,22 +106,19 @@
 			Request request = evt.getRequest();
 			SipURI sipURI = (SipURI) request.getRequestURI();
 			String channelId = sipURI.getUser();
-			String requesterId = null;
-
-			FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
-			AddressImpl address = (AddressImpl) fromHeader.getAddress();
-			SipUri uri = (SipUri) address.getURI();
-			requesterId = uri.getUser();
-
+			String requesterId = SipUtils.getUserIdFromFromHeader(request);
+			CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
 			if (requesterId == null || channelId == null) {
 				logger.info("鏃犳硶浠嶧romHeader鐨凙ddress涓幏鍙栧埌骞冲彴id锛岃繑鍥�400");
 				responseAck(evt, Response.BAD_REQUEST); // 鍙傛暟涓嶅叏锛� 鍙�400锛岃姹傞敊璇�
 				return;
 			}
 
-			// 鏌ヨ璇锋眰鏂规槸鍚︿笂绾у钩鍙�
+			// 鏌ヨ璇锋眰鏄惁鏉ヨ嚜涓婄骇骞冲彴\璁惧
 			ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
-			if (platform != null) {
+			if (platform == null) {
+				inviteFromDeviceHandle(evt, requesterId);
+			}else {
 				// 鏌ヨ骞冲彴涓嬫槸鍚︽湁璇ラ�氶亾
 				DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
 				GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
@@ -122,7 +137,7 @@
 					mediaServerItem = mediaServerService.getOne(mediaServerId);
 					if (mediaServerItem == null) {
 						logger.info("[ app={}, stream={} ]鎵句笉鍒皕lm {}锛岃繑鍥�410",gbStream.getApp(), gbStream.getStream(), mediaServerId);
-						responseAck(evt, Response.GONE, "media server not found");
+						responseAck(evt, Response.GONE);
 						return;
 					}
 					Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
@@ -158,13 +173,26 @@
 					ssrc = ssrcDefault;
 					sdp = SdpFactory.getInstance().createSessionDescription(contentString);
 				}
+				String sessionName = sdp.getSessionName().getValue();
 
+				Long startTime = null;
+				Long stopTime = null;
+				Date start = null;
+				Date end = null;
+				if (sdp.getTimeDescriptions(false) != null && sdp.getTimeDescriptions(false).size() > 0) {
+					TimeDescriptionImpl timeDescription = (TimeDescriptionImpl)(sdp.getTimeDescriptions(false).get(0));
+					TimeField startTimeFiled = (TimeField)timeDescription.getTime();
+					startTime = startTimeFiled.getStartTime();
+					stopTime = startTimeFiled.getStopTime();
+
+					start = new Date(startTime*1000);
+					end = new Date(stopTime*1000);
+				}
 				//  鑾峰彇鏀寔鐨勬牸寮�
 				Vector mediaDescriptions = sdp.getMediaDescriptions(true);
 				// 鏌ョ湅鏄惁鏀寔PS 璐熻浇96
 				//String ip = null;
 				int port = -1;
-				//boolean recvonly = false;
 				boolean mediaTransmissionTCP = false;
 				Boolean tcpActive = null;
 				for (Object description : mediaDescriptions) {
@@ -200,7 +228,6 @@
 				}
 				String username = sdp.getOrigin().getUsername();
 				String addressStr = sdp.getOrigin().getAddress();
-				//String sessionName = sdp.getSessionName().getValue();
 				logger.info("[涓婄骇鐐规挱]鐢ㄦ埛锛歿}锛� 鍦板潃锛歿}:{}锛� ssrc锛歿}", username, addressStr, port, ssrc);
 				Device device  = null;
 				// 閫氳繃 channel 鍜� gbStream 鏄惁涓簄ull 鍊煎垽鏂潵婧愭槸鐩存挱娴佸悎閫傚浗鏍�
@@ -228,23 +255,33 @@
 						responseAck(evt, Response.BUSY_HERE);
 						return;
 					}
-
+					sendRtpItem.setCallId(callIdHeader.getCallId());
+					sendRtpItem.setPlay("Play".equals(sessionName));
 					// 鍐欏叆redis锛� 瓒呮椂鏃跺洖澶�
 					redisCatchStorage.updateSendRTPSever(sendRtpItem);
-					// 閫氱煡涓嬬骇鎺ㄦ祦锛�
-					PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{
-						// 鏀跺埌鎺ㄦ祦锛� 鍥炲200OK, 绛夊緟ack
-						// if (sendRtpItem == null) return;
+
+					Device finalDevice = device;
+					MediaServerItem finalMediaServerItem = mediaServerItem;
+					Long finalStartTime = startTime;
+					Long finalStopTime = stopTime;
+					ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON)->{
+						logger.info("[涓婄骇鐐规挱]涓嬬骇宸茬粡寮�濮嬫帹娴併�� 鍥炲200OK(SDP)锛� {}/{}", sendRtpItem.getApp(), sendRtpItem.getStreamId());
+						//     * 0 绛夊緟璁惧鎺ㄦ祦涓婃潵
+						//     * 1 涓嬬骇宸茬粡鎺ㄦ祦锛岀瓑寰呬笂绾у钩鍙板洖澶峚ck
+						//     * 2 鎺ㄦ祦涓�
 						sendRtpItem.setStatus(1);
 						redisCatchStorage.updateSendRTPSever(sendRtpItem);
-						// TODO 娣诲姞瀵箃cp鐨勬敮鎸�
 
 						StringBuffer content = new StringBuffer(200);
 						content.append("v=0\r\n");
 						content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
-						content.append("s=Play\r\n");
+						content.append("s=" + sessionName+"\r\n");
 						content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
-						content.append("t=0 0\r\n");
+						if ("Playback".equals(sessionName)) {
+							content.append("t=" + finalStartTime + " " + finalStopTime + "\r\n");
+						}else {
+							content.append("t=0 0\r\n");
+						}
 						content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
 						content.append("a=sendonly\r\n");
 						content.append("a=rtpmap:96 PS/90000\r\n");
@@ -260,7 +297,8 @@
 						} catch (ParseException e) {
 							e.printStackTrace();
 						}
-					} ,((event) -> {
+					};
+					SipSubscribe.Event errorEvent = ((event) -> {
 						// 鏈煡閿欒銆傜洿鎺ヨ浆鍙戣澶囩偣鎾殑閿欒
 						Response response = null;
 						try {
@@ -271,11 +309,46 @@
 						} catch (ParseException | SipException | InvalidArgumentException e) {
 							e.printStackTrace();
 						}
-					}));
-					if (logger.isDebugEnabled()) {
-						logger.debug(playResult.getResult().toString());
+					});
+					if ("Playback".equals(sessionName)) {
+						sendRtpItem.setPlay(false);
+						sendRtpItem.setStreamId(ssrc);
+						SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+						playService.playBack(device.getDeviceId(), channelId, format.format(start), format.format(end),result -> {
+							if (result.getCode() != 0){
+								logger.warn("褰曞儚鍥炴斁澶辫触");
+								if (result.getEvent() != null) {
+									errorEvent.response(result.getEvent());
+								}
+								try {
+									responseAck(evt, Response.REQUEST_TIMEOUT);
+								} catch (SipException e) {
+									e.printStackTrace();
+								} catch (InvalidArgumentException e) {
+									e.printStackTrace();
+								} catch (ParseException e) {
+									e.printStackTrace();
+								}
+							}else {
+								if (result.getMediaServerItem() != null) {
+									hookEvent.response(result.getMediaServerItem(), result.getResponse());
+								}
+							}
+						});
+					}else {
+						sendRtpItem.setPlay(true);
+						StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
+						if (streamInfo == null) {
+							if (mediaServerItem.isRtpEnable()) {
+								sendRtpItem.setStreamId(String.format("%s_%s", device.getDeviceId(), channelId));
+							}
+							sendRtpItem.setPlay(false);
+							playService.play(mediaServerItem,device.getDeviceId(), channelId, hookEvent,errorEvent);
+						}else {
+							sendRtpItem.setStreamId(streamInfo.getStream());
+							hookEvent.response(mediaServerItem, null);
+						}
 					}
-
 				}else if (gbStream != null) {
 					SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
 							gbStream.getApp(), gbStream.getStream(), channelId,
@@ -291,11 +364,8 @@
 					}
 
 					// 鍐欏叆redis锛� 瓒呮椂鏃跺洖澶�
-					redisCatchStorage.updateSendRTPSever(sendRtpItem);
-
 					sendRtpItem.setStatus(1);
 					redisCatchStorage.updateSendRTPSever(sendRtpItem);
-					// TODO 娣诲姞瀵箃cp鐨勬敮鎸�
 					StringBuffer content = new StringBuffer(200);
 					content.append("v=0\r\n");
 					content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
@@ -319,72 +389,6 @@
 					}
 				}
 
-			} else {
-				// 闈炰笂绾у钩鍙拌姹傦紝鏌ヨ鏄惁璁惧璇锋眰锛堥�氬父涓烘帴鏀惰闊冲箍鎾殑璁惧锛�
-				Device device = redisCatchStorage.getDevice(requesterId);
-				if (device != null) {
-					logger.info("鏀跺埌璁惧" + requesterId + "鐨勮闊冲箍鎾璉nvite璇锋眰");
-					responseAck(evt, Response.TRYING);
-
-					String contentString = new String(request.getRawContent());
-					// jainSip涓嶆敮鎸亂=瀛楁锛� 绉婚櫎绉婚櫎浠ヨВ鏋愩��
-					String substring = contentString;
-					String ssrc = "0000000404";
-					int ssrcIndex = contentString.indexOf("y=");
-					if (ssrcIndex > 0) {
-						substring = contentString.substring(0, ssrcIndex);
-						ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
-					}
-					ssrcIndex = substring.indexOf("f=");
-					if (ssrcIndex > 0) {
-						substring = contentString.substring(0, ssrcIndex);
-					}
-					SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
-
-					//  鑾峰彇鏀寔鐨勬牸寮�
-					Vector mediaDescriptions = sdp.getMediaDescriptions(true);
-					// 鏌ョ湅鏄惁鏀寔PS 璐熻浇96
-					int port = -1;
-					//boolean recvonly = false;
-					boolean mediaTransmissionTCP = false;
-					Boolean tcpActive = null;
-					for (int i = 0; i < mediaDescriptions.size(); i++) {
-						MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
-						Media media = mediaDescription.getMedia();
-
-						Vector mediaFormats = media.getMediaFormats(false);
-						if (mediaFormats.contains("8")) {
-							port = media.getMediaPort();
-							String protocol = media.getProtocol();
-							// 鍖哄垎TCP鍙戞祦杩樻槸udp锛� 褰撳墠榛樿udp
-							if ("TCP/RTP/AVP".equals(protocol)) {
-								String setup = mediaDescription.getAttribute("setup");
-								if (setup != null) {
-									mediaTransmissionTCP = true;
-									if ("active".equals(setup)) {
-										tcpActive = true;
-									} else if ("passive".equals(setup)) {
-										tcpActive = false;
-									}
-								}
-							}
-							break;
-						}
-					}
-					if (port == -1) {
-						logger.info("涓嶆敮鎸佺殑濯掍綋鏍煎紡锛岃繑鍥�415");
-						// 鍥炲涓嶆敮鎸佺殑鏍煎紡
-						responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 涓嶆敮鎸佺殑鏍煎紡锛屽彂415
-						return;
-					}
-					String username = sdp.getOrigin().getUsername();
-					String addressStr = sdp.getOrigin().getAddress();
-					logger.info("璁惧{}璇锋眰璇煶娴侊紝鍦板潃锛歿}:{}锛宻src锛歿}", username, addressStr, port, ssrc);
-
-				} else {
-					logger.warn("鏉ヨ嚜鏃犳晥璁惧/骞冲彴鐨勮姹�");
-					responseAck(evt, Response.BAD_REQUEST);
-				}
 			}
 
 		} catch (SipException | InvalidArgumentException | ParseException e) {
@@ -397,4 +401,74 @@
 			e.printStackTrace();
 		}
 	}
+
+	public void inviteFromDeviceHandle(RequestEvent evt, String requesterId) throws InvalidArgumentException, ParseException, SipException, SdpException {
+
+		// 闈炰笂绾у钩鍙拌姹傦紝鏌ヨ鏄惁璁惧璇锋眰锛堥�氬父涓烘帴鏀惰闊冲箍鎾殑璁惧锛�
+		Device device = redisCatchStorage.getDevice(requesterId);
+		Request request = evt.getRequest();
+		if (device != null) {
+			logger.info("鏀跺埌璁惧" + requesterId + "鐨勮闊冲箍鎾璉nvite璇锋眰");
+			responseAck(evt, Response.TRYING);
+
+			String contentString = new String(request.getRawContent());
+			// jainSip涓嶆敮鎸亂=瀛楁锛� 绉婚櫎绉婚櫎浠ヨВ鏋愩��
+			String substring = contentString;
+			String ssrc = "0000000404";
+			int ssrcIndex = contentString.indexOf("y=");
+			if (ssrcIndex > 0) {
+				substring = contentString.substring(0, ssrcIndex);
+				ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
+			}
+			ssrcIndex = substring.indexOf("f=");
+			if (ssrcIndex > 0) {
+				substring = contentString.substring(0, ssrcIndex);
+			}
+			SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
+
+			//  鑾峰彇鏀寔鐨勬牸寮�
+			Vector mediaDescriptions = sdp.getMediaDescriptions(true);
+			// 鏌ョ湅鏄惁鏀寔PS 璐熻浇96
+			int port = -1;
+			//boolean recvonly = false;
+			boolean mediaTransmissionTCP = false;
+			Boolean tcpActive = null;
+			for (int i = 0; i < mediaDescriptions.size(); i++) {
+				MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
+				Media media = mediaDescription.getMedia();
+
+				Vector mediaFormats = media.getMediaFormats(false);
+				if (mediaFormats.contains("8")) {
+					port = media.getMediaPort();
+					String protocol = media.getProtocol();
+					// 鍖哄垎TCP鍙戞祦杩樻槸udp锛� 褰撳墠榛樿udp
+					if ("TCP/RTP/AVP".equals(protocol)) {
+						String setup = mediaDescription.getAttribute("setup");
+						if (setup != null) {
+							mediaTransmissionTCP = true;
+							if ("active".equals(setup)) {
+								tcpActive = true;
+							} else if ("passive".equals(setup)) {
+								tcpActive = false;
+							}
+						}
+					}
+					break;
+				}
+			}
+			if (port == -1) {
+				logger.info("涓嶆敮鎸佺殑濯掍綋鏍煎紡锛岃繑鍥�415");
+				// 鍥炲涓嶆敮鎸佺殑鏍煎紡
+				responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 涓嶆敮鎸佺殑鏍煎紡锛屽彂415
+				return;
+			}
+			String username = sdp.getOrigin().getUsername();
+			String addressStr = sdp.getOrigin().getAddress();
+			logger.info("璁惧{}璇锋眰璇煶娴侊紝鍦板潃锛歿}:{}锛宻src锛歿}", username, addressStr, port, ssrc);
+
+		} else {
+			logger.warn("鏉ヨ嚜鏃犳晥璁惧/骞冲彴鐨勮姹�");
+			responseAck(evt, Response.BAD_REQUEST);
+		}
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java
new file mode 100644
index 0000000..a273314
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java
@@ -0,0 +1,157 @@
+package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
+
+import com.genersoft.iot.vmp.conf.SipConfig;
+import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
+import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEventListener;
+import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
+import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
+import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
+import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
+import org.dom4j.Element;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.sip.InvalidArgumentException;
+import javax.sip.RequestEvent;
+import javax.sip.SipException;
+import javax.sip.header.FromHeader;
+import javax.sip.message.Response;
+import java.text.ParseException;
+import java.util.List;
+
+@Component
+public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
+
+    private Logger logger = LoggerFactory.getLogger(RecordInfoQueryMessageHandler.class);
+    private final String cmdType = "RecordInfo";
+
+    @Autowired
+    private QueryMessageHandler queryMessageHandler;
+
+    @Autowired
+    private IVideoManagerStorager storager;
+
+    @Autowired
+    private SIPCommanderFroPlatform cmderFroPlatform;
+
+    @Autowired
+    private SIPCommander commander;
+
+    @Autowired
+    private RecordEndEventListener recordEndEventListener;
+
+    @Autowired
+    private SipConfig config;
+
+    @Autowired
+    private EventPublisher publisher;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        queryMessageHandler.addHandler(cmdType, this);
+    }
+
+    @Override
+    public void handForDevice(RequestEvent evt, Device device, Element element) {
+
+    }
+
+    @Override
+    public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
+
+        FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
+
+        Element snElement = rootElement.element("SN");
+        int sn = Integer.parseInt(snElement.getText());
+        Element deviceIDElement = rootElement.element("DeviceID");
+        String channelId = deviceIDElement.getText();
+        Element startTimeElement = rootElement.element("StartTime");
+        String startTime = null;
+        if (startTimeElement != null) {
+            startTime = startTimeElement.getText();
+        }
+        Element endTimeElement = rootElement.element("EndTime");
+        String endTime = null;
+        if (endTimeElement != null) {
+            endTime = endTimeElement.getText();
+        }
+        Element secrecyElement = rootElement.element("Secrecy");
+        int secrecy = 0;
+        if (secrecyElement != null) {
+            secrecy = Integer.parseInt(secrecyElement.getText());
+        }
+        String type = "all";
+        Element typeElement = rootElement.element("Type");
+        if (typeElement != null) {
+            type =  typeElement.getText();
+        }
+        // 纭鏄洿鎾繕鏄浗鏍囷紝 鍥芥爣鐩存帴璇锋眰涓嬬骇锛岀洿鎾姹傚綍鍍忕鐞嗘湇鍔�
+        List<ChannelSourceInfo> channelSources = storager.getChannelSource(parentPlatform.getServerGBId(), channelId);
+
+        if (channelSources.get(0).getCount() > 0) { // 鍥芥爣
+            // 鍚戝浗鏍囪澶囪姹傚綍鍍忔暟鎹�
+            Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
+            DeviceChannel deviceChannel = storager.queryChannelInParentPlatform(parentPlatform.getServerGBId(), channelId);
+            // 鎺ユ敹褰曞儚鏁版嵁
+            recordEndEventListener.addEndEventHandler(deviceChannel.getDeviceId(), channelId, (recordInfo)->{
+                cmderFroPlatform.recordInfo(deviceChannel, parentPlatform, fromHeader.getTag(), recordInfo);
+            });
+            commander.recordInfoQuery(device, channelId, DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTime),
+                    DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTime), sn, secrecy, type, (eventResult -> {
+                        // 鍥炲200 OK
+                        try {
+                            responseAck(evt, Response.OK);
+                        } catch (SipException e) {
+                            e.printStackTrace();
+                        } catch (InvalidArgumentException e) {
+                            e.printStackTrace();
+                        } catch (ParseException e) {
+                            e.printStackTrace();
+                        }
+                    }),(eventResult -> {
+                        // 鏌ヨ澶辫触
+                        try {
+                            responseAck(evt, eventResult.statusCode, eventResult.msg);
+                        } catch (SipException e) {
+                            e.printStackTrace();
+                        } catch (InvalidArgumentException e) {
+                            e.printStackTrace();
+                        } catch (ParseException e) {
+                            e.printStackTrace();
+                        }
+                    }));
+
+        }else if (channelSources.get(1).getCount() > 0) { // 鐩存挱娴�
+            // TODO
+            try {
+                responseAck(evt, Response.NOT_IMPLEMENTED); // 鍥炲鏈疄鐜�
+            } catch (SipException e) {
+                e.printStackTrace();
+            } catch (InvalidArgumentException e) {
+                e.printStackTrace();
+            } catch (ParseException e) {
+                e.printStackTrace();
+            }
+        }else { // 閿欒鐨勮姹�
+            try {
+                responseAck(evt, Response.BAD_REQUEST);
+            } catch (SipException e) {
+                e.printStackTrace();
+            } catch (InvalidArgumentException e) {
+                e.printStackTrace();
+            } catch (ParseException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
index f0f8421..45b7e56 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
@@ -4,6 +4,7 @@
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
 import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
+import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
@@ -49,6 +50,9 @@
     @Autowired
     private DeferredResultHolder deferredResultHolder;
 
+    @Autowired
+    private EventPublisher eventPublisher;
+
     @Override
     public void afterPropertiesSet() throws Exception {
         responseMessageHandler.addHandler(cmdType, this);
@@ -77,6 +81,7 @@
             Element recordListElement = rootElement.element("RecordList");
             if (recordListElement == null || recordInfo.getSumNum() == 0) {
                 logger.info("鏃犲綍鍍忔暟鎹�");
+                eventPublisher.recordEndEventPush(recordInfo);
                 RequestMessage msg = new RequestMessage();
                 msg.setKey(key);
                 msg.setData(recordInfo);
@@ -99,6 +104,7 @@
                         record.setDeviceId(getText(itemRecord, "DeviceID"));
                         record.setName(getText(itemRecord, "Name"));
                         record.setFilePath(getText(itemRecord, "FilePath"));
+                        record.setFileSize(getText(itemRecord, "FileSize"));
                         record.setAddress(getText(itemRecord, "Address"));
                         record.setStartTime(
                                 DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "StartTime")));
@@ -112,7 +118,7 @@
                     }
                     recordInfo.setRecordList(recordList);
                 }
-
+                eventPublisher.recordEndEventPush(recordInfo);
                 // 鏀圭敤鍗曠嫭绾跨▼缁熻宸茶幏鍙栧綍鍍忔枃浠舵暟閲忥紝閬垮厤澶氬寘骞惰鍒嗗埆缁熻涓嶅畬鏁寸殑闂
                 String cacheKey = CACHE_RECORDINFO_KEY + device.getDeviceId() + sn;
                 redis.set(cacheKey + "_" + uuid, recordList, 90);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
index 5446a90..1b5081b 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
@@ -82,9 +82,6 @@
 				requestURI.setPort(event.getRemotePort());
 				reqAck.setRequestURI(requestURI);
 				logger.info("鍚� " + event.getRemoteIpAddress() + ":" + event.getRemotePort() + "鍥炲ack");
-				SipURI sipURI = (SipURI)dialog.getRemoteParty().getURI();
-				String deviceId = requestURI.getUser();
-				String channelId = sipURI.getUser();
 
 				dialog.sendAck(reqAck);
 
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 75b0dea..e7d098f 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
@@ -184,7 +184,7 @@
 	@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
 	public ResponseEntity<String> onPublish(@RequestBody JSONObject json) {
 
-		logger.debug("[ ZLM HOOK ]on_publish API璋冪敤锛屽弬鏁帮細" + json.toString());
+		logger.info("[ ZLM HOOK ]on_publish API璋冪敤锛屽弬鏁帮細" + json.toString());
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("msg", "success");
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
index ff8204c..84b36e3 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
@@ -77,22 +77,23 @@
         if (eventMap == null) {
             return;
         }
-        Iterator<Map.Entry<JSONObject, Event>> iterator = eventMap.entrySet().iterator();
-        while (iterator.hasNext()){
-            Map.Entry<JSONObject, Event> next = iterator.next();
-            JSONObject key = next.getKey();
-            Boolean result = null;
-            for (String s : key.keySet()) {
-                if (result == null) {
-                    result = key.getString(s).equals(hookResponse.getString(s));
-                }else {
-                    if (key.getString(s) == null) continue;
-                    result = result && key.getString(s).equals(hookResponse.getString(s));
+
+        Set<Map.Entry<JSONObject, Event>> entries = eventMap.entrySet();
+        if (entries.size() > 0) {
+            for (Map.Entry<JSONObject, Event> entry : entries) {
+                JSONObject key = entry.getKey();
+                Boolean result = null;
+                for (String s : key.keySet()) {
+                    if (result == null) {
+                        result = key.getString(s).equals(hookResponse.getString(s));
+                    }else {
+                        if (key.getString(s) == null) continue;
+                        result = result && key.getString(s).equals(hookResponse.getString(s));
+                    }
                 }
-            }
-            if (null != result && result){
-                // TODO 鎶ラ敊鏈鐞�
-                iterator.remove();
+                if (null != result && result){
+                    entries.remove(entry);
+                }
             }
         }
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
index 30a1509..76bab9c 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -242,9 +242,18 @@
      */
     public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) {
         JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
+        Integer code = mediaInfo.getInteger("code");
         if (mediaInfo == null) {
             return 0;
         }
+        if ( code < 0) {
+            logger.warn("鏌ヨ娴�({}/{})鏄惁鏈夊叾瀹冭鐪嬭�呮椂寰楀埌锛� {}", app, streamId, mediaInfo.getString("msg"));
+            return -1;
+        }
+        if ( code == 0 && ! mediaInfo.getBoolean("online")) {
+            logger.warn("鏌ヨ娴�({}/{})鏄惁鏈夊叾瀹冭鐪嬭�呮椂寰楀埌锛� {}", app, streamId, mediaInfo.getString("msg"));
+            return -1;
+        }
         return mediaInfo.getInteger("totalReaderCount");
     }
 
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 2e8a68e..8c12c78 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -48,7 +48,7 @@
 
     SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean isPlayback);
 
-    void closeRTPServer(Device device, String channelId, String ssrc);
+    void closeRTPServer(String deviceId, String channelId, String ssrc);
 
     void clearRTPServer(MediaServerItem mediaServerItem);
 
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 089523f..5ed6cf3 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,9 +1,10 @@
 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 {
 
-    void call(RequestMessage msg);
+    void call(PlayBackResult<RequestMessage> msg);
 
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java b/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
new file mode 100644
index 0000000..10a2759
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java
@@ -0,0 +1,55 @@
+package com.genersoft.iot.vmp.service.bean;
+
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+
+import javax.sip.RequestEvent;
+
+public class PlayBackResult<T> {
+     private int code;
+     private T data;
+     private MediaServerItem mediaServerItem;
+    private JSONObject response;
+    private SipSubscribe.EventResult event;
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public MediaServerItem getMediaServerItem() {
+        return mediaServerItem;
+    }
+
+    public void setMediaServerItem(MediaServerItem mediaServerItem) {
+        this.mediaServerItem = mediaServerItem;
+    }
+
+    public JSONObject getResponse() {
+        return response;
+    }
+
+    public void setResponse(JSONObject response) {
+        this.response = response;
+    }
+
+    public SipSubscribe.EventResult getEvent() {
+        return event;
+    }
+
+    public void setEvent(SipSubscribe.EventResult event) {
+        this.event = event;
+    }
+}
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 4f08c99..f226a37 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
@@ -160,16 +160,16 @@
     }
 
     @Override
-    public void closeRTPServer(Device device, String channelId, String stream) {
-        String mediaServerId = streamSession.getMediaServerId(device.getDeviceId(), channelId, stream);
-        String ssrc = streamSession.getSSRC(device.getDeviceId(), channelId, stream);
+    public void closeRTPServer(String deviceId, String channelId, String stream) {
+        String mediaServerId = streamSession.getMediaServerId(deviceId, channelId, stream);
+        String ssrc = streamSession.getSSRC(deviceId, channelId, stream);
         MediaServerItem mediaServerItem = this.getOne(mediaServerId);
         if (mediaServerItem != null) {
-            String streamId = String.format("%s_%s", device.getDeviceId(), channelId);
+            String streamId = String.format("%s_%s", deviceId, channelId);
             zlmrtpServerFactory.closeRTPServer(mediaServerItem, streamId);
             releaseSsrc(mediaServerItem, ssrc);
         }
-        streamSession.remove(device.getDeviceId(), channelId, stream);
+        streamSession.remove(deviceId, channelId, stream);
     }
 
     @Override
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 9c87a0a..778bd67 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
@@ -17,9 +17,11 @@
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.service.IMediaServerService;
 import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
+import com.genersoft.iot.vmp.service.bean.PlayBackResult;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
 import com.genersoft.iot.vmp.service.IMediaService;
@@ -52,6 +54,9 @@
 
     @Autowired
     private IRedisCatchStorage redisCatchStorage;
+
+    @Autowired
+    private RedisUtil redis;
 
     @Autowired
     private DeferredResultHolder resultHolder;
@@ -112,7 +117,7 @@
             // 鐐规挱瓒呮椂鍥炲BYE
             cmder.streamByeCmd(device.getDeviceId(), channelId, streamInfo.getStream());
             // 閲婃斁rtpserver
-            mediaServerService.closeRTPServer(playResult.getDevice(), channelId, streamInfo.getStream());
+            mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, streamInfo.getStream());
             // 鍥炲涔嬪墠鎵�鏈夌殑鐐规挱璇锋眰
             resultHolder.invokeAllResult(msg);
             // TODO 閲婃斁ssrc
@@ -121,7 +126,6 @@
             // 鐐规挱缁撴潫鏃惰皟鐢ㄦ埅鍥炬帴鍙�
             try {
                 String classPath = ResourceUtils.getURL("classpath:").getPath();
-                // System.out.println(classPath);
                 // 鍏煎鎵撳寘涓簀ar鐨刢lass璺緞
                 if(classPath.contains("jar")) {
                     classPath = classPath.substring(0, classPath.lastIndexOf("."));
@@ -170,7 +174,10 @@
                 WVPResult wvpResult = new WVPResult();
                 wvpResult.setCode(-1);
                 // 鐐规挱杩斿洖sip閿欒
-                mediaServerService.closeRTPServer(playResult.getDevice(), channelId, ssrcInfo.getStream());
+                mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream());
+                // 閲婃斁ssrc
+                mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
+                streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
                 wvpResult.setMsg(String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg));
                 msg.setData(wvpResult);
                 resultHolder.invokeAllResult(msg);
@@ -219,7 +226,10 @@
                     logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
                     onPublishHandlerForPlay(mediaServerItemInuse, response, deviceId, channelId, uuid);
                 }, (event) -> {
-                    mediaServerService.closeRTPServer(playResult.getDevice(), channelId, ssrcInfo.getStream());
+                    mediaServerService.closeRTPServer(playResult.getDevice().getDeviceId(), channelId, ssrcInfo.getStream());
+                    // 閲婃斁ssrc
+                    mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
+                    streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
                     WVPResult wvpResult = new WVPResult();
                     wvpResult.setCode(-1);
                     wvpResult.setMsg(String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg));
@@ -233,11 +243,11 @@
     }
 
     @Override
-    public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid) {
+    public void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String uuid) {
         RequestMessage msg = new RequestMessage();
         msg.setId(uuid);
         msg.setKey(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId);
-        StreamInfo streamInfo = onPublishHandler(mediaServerItem, resonse, deviceId, channelId);
+        StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
         if (streamInfo != null) {
             DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
             if (deviceChannel != null) {
@@ -295,9 +305,12 @@
         RequestMessage msg = new RequestMessage();
         msg.setId(uuid);
         msg.setKey(key);
+        PlayBackResult<RequestMessage> playBackResult = new PlayBackResult<>();
         result.onTimeout(()->{
             msg.setData("鍥炴斁瓒呮椂");
-            callback.call(msg);
+            playBackResult.setCode(-1);
+            playBackResult.setData(msg);
+            callback.call(playBackResult);
         });
         cmder.playbackStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, (MediaServerItem mediaServerItem, JSONObject response) -> {
             logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
@@ -305,15 +318,25 @@
             if (streamInfo == null) {
                 logger.warn("璁惧鍥炴斁API璋冪敤澶辫触锛�");
                 msg.setData("璁惧鍥炴斁API璋冪敤澶辫触锛�");
-                callback.call(msg);
+                playBackResult.setCode(-1);
+                playBackResult.setData(msg);
+                callback.call(playBackResult);
                 return;
             }
             redisCatchStorage.startPlayback(streamInfo);
             msg.setData(JSON.toJSONString(streamInfo));
-            callback.call(msg);
+            playBackResult.setCode(0);
+            playBackResult.setData(msg);
+            playBackResult.setMediaServerItem(mediaServerItem);
+            playBackResult.setResponse(response);
+            callback.call(playBackResult);
         }, event -> {
             msg.setData(String.format("鍥炴斁澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg));
-            callback.call(msg);
+            playBackResult.setCode(-1);
+            playBackResult.setData(msg);
+            playBackResult.setEvent(event);
+            callback.call(playBackResult);
+            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
         });
         return result;
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
index 723e9f1..710219e 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -5,6 +5,7 @@
 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
+import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
 import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
 import com.github.pagehelper.PageInfo;
@@ -475,4 +476,6 @@
 	void delRelationByPlatformId(String serverGBId);
 
     PlatformCatalog queryDefaultCatalogInPlatform(String platformId);
+
+	List<ChannelSourceInfo> getChannelSource(String platformId, String gbId);
 }
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 ca8a72b..f74b6d4 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
@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.storager.dao;
 
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
 import org.apache.ibatis.annotations.*;
 import org.springframework.stereotype.Repository;
 
@@ -86,4 +87,9 @@
             "WHERE serverGBId=#{platformId}"+
             "</script>"})
     int setDefaultCatalog(String platformId, String catalogId);
+
+    @Select("select 'channel' as name, count(pgc.platformId) count from platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId where  pgc.platformId=#{platformId} and dc.channelId =#{gbId} " +
+            "union " +
+            "select 'stream' as name, count(pgs.platformId) count from platform_gb_stream pgs left join gb_stream gs on pgs.gbStreamId = gs.gbStreamId where  pgs.platformId=#{platformId} and gs.gbId = #{gbId}")
+    List<ChannelSourceInfo> getChannelSource(String platformId, String gbId);
 }
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 0836001..f1d23f1 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
@@ -75,7 +75,7 @@
     int delByCatalogId(String id);
 
     @Delete("<script> "+
-           "DELETE FROM platform_gb_channel WHERE catalogId=#{parentId} AND platformId=#{platformId} AND channelId=#{id}"  +
+           "DELETE FROM platform_gb_channel  WHERE catalogId=#{parentId} AND platformId=#{platformId} AND channelId=#{id}"  +
            "</script>")
     int delByCatalogIdAndChannelIdAndPlatformId(PlatformCatalog platformCatalog);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java
new file mode 100644
index 0000000..e8b91e7
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java
@@ -0,0 +1,22 @@
+package com.genersoft.iot.vmp.storager.dao.dto;
+
+public class ChannelSourceInfo {
+    private String name;
+    private int count;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    public void setCount(int count) {
+        this.count = count;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
index 0a78a53..b5a3aba 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -141,7 +141,6 @@
 
     @Override
     public StreamInfo queryPlayByDevice(String deviceId, String channelId) {
-//		List<Object> playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
         List<Object> playLeys = redis.scan(String.format("%S_%s_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
                 userSetup.getServerId(),
                 deviceId,
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
index 0e0a8e3..3266e6a 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
@@ -14,6 +14,7 @@
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.storager.dao.*;
+import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
 import com.genersoft.iot.vmp.utils.node.ForestNodeMerger;
 import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
@@ -1104,4 +1105,9 @@
 	public PlatformCatalog queryDefaultCatalogInPlatform(String platformId) {
 		return catalogMapper.selectDefaultByPlatFormId(platformId);
 	}
+
+	@Override
+	public List<ChannelSourceInfo> getChannelSource(String platformId, String gbId) {
+		return platformMapper.getChannelSource(platformId, gbId);
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
index 6b95508..7835feb 100644
--- a/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
@@ -1,7 +1,6 @@
 package com.genersoft.iot.vmp.utils.node;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
-import lombok.Data;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -10,7 +9,6 @@
  * 鑺傜偣鍩虹被
  *
  */
-@Data
 public class BaseNode<T> implements INode<T> {
 
 	private static final long serialVersionUID = 1L;
@@ -51,4 +49,34 @@
 		}
 	}
 
+	@Override
+	public int getId() {
+		return id;
+	}
+
+	public void setId(int id) {
+		this.id = id;
+	}
+
+	@Override
+	public String getParentId() {
+		return parentId;
+	}
+
+	public void setParentId(String parentId) {
+		this.parentId = parentId;
+	}
+
+	@Override
+	public List<T> getChildren() {
+		return children;
+	}
+
+	public void setChildren(List<T> children) {
+		this.children = children;
+	}
+
+	public void setHasChildren(Boolean hasChildren) {
+		this.hasChildren = hasChildren;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java
index d0500a1..21a48df 100644
--- a/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/ForestNode.java
@@ -1,15 +1,11 @@
 package com.genersoft.iot.vmp.utils.node;
 
-import lombok.Data;
-import lombok.EqualsAndHashCode;
 
 
 /**
  * 妫灄鑺傜偣绫�
  *
  */
-@Data
-@EqualsAndHashCode(callSuper = false)
 public class ForestNode extends BaseNode<ForestNode> {
 
 	private static final long serialVersionUID = 1L;
@@ -25,4 +21,11 @@
 		this.content = content;
 	}
 
+	public Object getContent() {
+		return content;
+	}
+
+	public void setContent(Object content) {
+		this.content = content;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java b/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
index 9df6f11..71f1b2b 100644
--- a/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
+++ b/src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
@@ -1,14 +1,11 @@
 package com.genersoft.iot.vmp.utils.node;
 
-import lombok.Data;
-import lombok.EqualsAndHashCode;
+
 
 /**
  * 鏍戝瀷鑺傜偣绫�
  *
  */
-@Data
-@EqualsAndHashCode(callSuper = false)
 public class TreeNode extends BaseNode<TreeNode> {
 
 	private static final long serialVersionUID = 1L;
@@ -18,4 +15,28 @@
 	private String key;
 
 	private String value;
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getKey() {
+		return key;
+	}
+
+	public void setKey(String key) {
+		this.key = key;
+	}
+
+	public String getValue() {
+		return value;
+	}
+
+	public void setValue(String value) {
+		this.value = value;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java
index 4eaf598..73928a4 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTree.java
@@ -4,14 +4,10 @@
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.utils.node.INode;
 import io.swagger.annotations.ApiModel;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@Data
-@EqualsAndHashCode(callSuper = true)
 @ApiModel(value = "DeviceChannelTree瀵硅薄", description = "DeviceChannelTree瀵硅薄")
 public class DeviceChannelTree extends DeviceChannel implements INode<DeviceChannelTree> {
     private static final long serialVersionUID = 1L;
@@ -62,4 +58,64 @@
             return this.hasChildren;
         }
     }
+
+    @Override
+    public int getId() {
+        return id;
+    }
+
+    @Override
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getParentId() {
+        return parentId;
+    }
+
+    @Override
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public void setChildren(List<DeviceChannelTree> children) {
+        this.children = children;
+    }
+
+    public void setHasChildren(Boolean hasChildren) {
+        this.hasChildren = hasChildren;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java
index 29d82be..96577d1 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeviceChannelTreeNode.java
@@ -1,11 +1,7 @@
 package com.genersoft.iot.vmp.vmanager.bean;
 
 import com.genersoft.iot.vmp.utils.node.TreeNode;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
 
-@Data
-@EqualsAndHashCode(callSuper = true)
 public class DeviceChannelTreeNode extends TreeNode {
 
 	private Integer status;
@@ -17,4 +13,44 @@
 	private Double lng;
 
 	private Double lat;
+
+	public Integer getStatus() {
+		return status;
+	}
+
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+
+	public String getDeviceId() {
+		return deviceId;
+	}
+
+	public void setDeviceId(String deviceId) {
+		this.deviceId = deviceId;
+	}
+
+	public String getChannelId() {
+		return channelId;
+	}
+
+	public void setChannelId(String channelId) {
+		this.channelId = channelId;
+	}
+
+	public Double getLng() {
+		return lng;
+	}
+
+	public void setLng(Double lng) {
+		this.lng = lng;
+	}
+
+	public Double getLat() {
+		return lat;
+	}
+
+	public void setLat(Double lat) {
+		this.lat = lat;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
index b4e3eb4..91ed22c 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
@@ -1,13 +1,16 @@
 package com.genersoft.iot.vmp.vmanager.bean;
 
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
 
-@Data
-@NoArgsConstructor
-@AllArgsConstructor
 public class WVPResult<T> {
+
+    public WVPResult() {
+    }
+
+    public WVPResult(int code, String msg, T data) {
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
 
     private int code;
     private String msg;
@@ -32,4 +35,27 @@
         return fail(FAILED, msg);
     }
 
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
index 78b5d53..8fed6dd 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
@@ -137,6 +137,11 @@
             wvpResult.setMsg("missing parameters");
             return new ResponseEntity<>(wvpResult, HttpStatus.BAD_REQUEST);
         }
+        if (parentPlatform.getServerPort()< 0 || parentPlatform.getServerPort() > 65535){
+            wvpResult.setCode(-1);
+            wvpResult.setMsg("error severPort");
+            return new ResponseEntity<>(wvpResult, HttpStatus.BAD_REQUEST);
+        }
 
         ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());
         if (parentPlatformOld != null) {
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 8350d29..fd70690 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
@@ -129,7 +129,6 @@
 			//Response response = event.getResponse();
 			msg.setData(String.format("success"));
 			resultHolder.invokeAllResult(msg);
-			mediaServerService.closeRTPServer(device, channelId, streamInfo.getStream());
 		});
 
 		if (deviceId != null || channelId != null) {
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 3607a8d..b864f46 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
@@ -77,8 +77,8 @@
 			logger.debug(String.format("璁惧鍥炴斁 API璋冪敤锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId));
 		}
 
-		DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, msg->{
-			resultHolder.invokeResult(msg);
+		DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, wvpResult->{
+			resultHolder.invokeResult(wvpResult.getData());
 		});
 
 		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 a8675e8..e565981 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
@@ -64,7 +64,7 @@
 		RequestMessage msg = new RequestMessage();
 		msg.setId(uuid);
 		msg.setKey(key);
-		cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, (eventResult -> {
+		cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> {
 			msg.setData("鏌ヨ褰曞儚澶辫触, status: " +  eventResult.statusCode + ", message: " + eventResult.msg );
 			resultHolder.invokeResult(msg);
 		}));
diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml
index f383629..f3f1fb3 100644
--- a/src/main/resources/all-application.yml
+++ b/src/main/resources/all-application.yml
@@ -1,7 +1,7 @@
 
 
 
-# 姝ら厤缃枃浠跺彧鏄敤浣滃睍绀烘墍鏈夐厤缃」锛� 涓嶅彲涓嶇洿鎺ヤ娇鐢�
+# 姝ら厤缃枃浠跺彧鏄敤浣滃睍绀烘墍鏈夐厤缃」锛� 涓嶅彲鐩存帴浣跨敤
 
 
 spring:
diff --git a/src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java b/src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java
index 3cb9aa5..23b9f6b 100644
--- a/src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java
+++ b/src/test/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImplTest.java
@@ -50,14 +50,7 @@
 //        System.out.println(deviceAlarmService.getAllAlarm(0, 10000, "11111111111111111111", null, "1", null,
 //                null, null).getSize());
 
-        System.out.println(deviceAlarmService.getAllAlarm(0, 10000, "11111111111111111111", null, null, null,
-                "2021-01-01 00:00:00", null).getSize());
 
-        System.out.println(deviceAlarmService.getAllAlarm(0, 10000, "11111111111111111111", null, null, null,
-                null, "2021-04-01 09:00:00").getSize());
-
-        System.out.println(deviceAlarmService.getAllAlarm(0, 10000, "11111111111111111111", null, null, null,
-                "2021-02-01 01:00:00", "2021-04-01 04:00:00").getSize());
     }
 
 
diff --git a/web_src/src/components/control.vue b/web_src/src/components/control.vue
index 4928077..3651593 100644
--- a/web_src/src/components/control.vue
+++ b/web_src/src/components/control.vue
@@ -37,8 +37,20 @@
                     </el-popover>
                     <el-popover placement="bottom" width="900" height="300" trigger="click">
                         <div style="height: 600px;overflow:auto; padding: 20px">
+                          <el-descriptions title="鍥芥爣閰嶇疆" border column="1">
+                            <template slot="extra">
+                              <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy"  title="鐐瑰嚮鎷疯礉" v-clipboard="JSON.stringify(wvpServerConfig.sip)" @success="$message({type:'success', message:'鎴愬姛鎷疯礉鍒扮矘璐存澘'})"></el-button>
+                            </template>
+                            <el-descriptions-item v-for="(value, key, index) in wvpServerConfig.sip">
+                              <template slot="label">
+                                {{ getNameFromKey(key) }}
+                              </template>
+                              {{ value }}
+                            </el-descriptions-item>
+                          </el-descriptions>
 
-                          <el-descriptions title="鍩虹閰嶇疆" border column="1">
+                          <div style="margin-top: 1rem">
+                            <el-descriptions title="鍩虹閰嶇疆" border column="1">
                               <template slot="extra">
                                 <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy"  title="鐐瑰嚮鎷疯礉" v-clipboard="JSON.stringify(wvpServerConfig.base)" @success="$message({type:'success', message:'鎴愬姛鎷疯礉鍒扮矘璐存澘'})"></el-button>
                               </template>
@@ -68,18 +80,6 @@
                                   </div>
                                 </div>
 
-                              </el-descriptions-item>
-                            </el-descriptions>
-                          <div style="margin-top: 1rem">
-                            <el-descriptions title="鍥芥爣閰嶇疆" border column="1">
-                              <template slot="extra">
-                                <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy"  title="鐐瑰嚮鎷疯礉" v-clipboard="JSON.stringify(wvpServerConfig.sip)" @success="$message({type:'success', message:'鎴愬姛鎷疯礉鍒扮矘璐存澘'})"></el-button>
-                              </template>
-                              <el-descriptions-item v-for="(value, key, index) in wvpServerConfig.sip" :key="key">
-                                <template slot="label">
-                                  {{ getNameFromKey(key) }}
-                                </template>
-                                {{ value }}
                               </el-descriptions-item>
                             </el-descriptions>
                           </div>

--
Gitblit v1.8.0