From 34135cce5d59f6ad7653737dd035bb1d441e185f Mon Sep 17 00:00:00 2001
From: panlinlin <648540858@qq.com>
Date: 星期二, 05 一月 2021 15:56:19 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into wvp-28181-2.0

---
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java |   41 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java                                    |   57 
 src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java                           |  120 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                 |  251 ++++-
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java                          |   95 ++
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java                              |    4 
 src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java                                      |    9 
 pom.xml                                                                                         |   88 +-
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java                     |   18 
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java                              |   66 +
 src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java                      |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java          |   24 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java                             |   37 
 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java                    |  166 +++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java |   16 
 src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java                  |   19 
 src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java                            |   58 +
 src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java                                |   23 
 src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java          |   98 ++
 src/main/resources/application-dev.yml                                                          |   34 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java                                    |    6 
 src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java                             |   50 +
 web_src/src/components/videoList.vue                                                            |   42 
 src/main/resources/wvp.sqlite                                                                   |    0 
 web_src/src/components/gb28181/devicePlayer.vue                                                 |   21 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java         |    7 
 src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java                 |  202 ++++
 src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java                   |   15 
 src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java                            |   63 +
 src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java                         |  102 --
 src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java                             |   17 
 src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java                                |  152 --
 /dev/null                                                                                       |  385 --------
 src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java                                       |   28 
 web_src/src/components/channelList.vue                                                          |   40 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                          |   95 +-
 src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java                       |   63 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java                   |   14 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java                       |    8 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java  |   32 
 src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java                                |    1 
 src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java                       |   13 
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java                       |   51 +
 43 files changed, 1,616 insertions(+), 1,017 deletions(-)

diff --git a/pom.xml b/pom.xml
index 86b4c17..2f45a6d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,13 +13,38 @@
 	<artifactId>wvp</artifactId>
 	<name>web video platform</name>
 
+	<repositories>
+		<repository>
+			<id>nexus-aliyun</id>
+			<name>Nexus aliyun</name>
+			<url>https://maven.aliyun.com/repository/public</url>
+			<layout>default</layout>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+			<releases>
+				<enabled>true</enabled>
+			</releases>
+		</repository>
+	</repositories>
+	<pluginRepositories>
+		<pluginRepository>
+			<id>nexus-aliyun</id>
+			<name>Nexus aliyun</name>
+			<url>https://maven.aliyun.com/repository/public</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+			<releases>
+				<enabled>true</enabled>
+			</releases>
+		</pluginRepository>
+	</pluginRepositories>
+
 	<properties>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 
 		<!-- 渚濊禆鐗堟湰 -->
-		<mapper.version>4.1.5</mapper.version>
-		<mybatis.version>3.5.5</mybatis.version>
-		<mybatis.spring.version>2.0.5</mybatis.spring.version>
 		<pagehelper.version>5.2.0</pagehelper.version>
 		<snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
 		<asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory>
@@ -31,30 +56,16 @@
 	<dependencies>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-jdbc</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.springframework.boot</groupId>
-			<artifactId>spring-boot-starter-tomcat</artifactId>
+			<artifactId>spring-boot-starter-data-redis</artifactId>
 		</dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-web</artifactId>
 		</dependency>
 		<dependency>
-			<groupId>org.springframework</groupId>
-			<artifactId>spring-context</artifactId>
-		</dependency>
-
-		<!-- redis -->
-		<dependency>
-			<groupId>org.springframework.data</groupId>
-			<artifactId>spring-data-redis</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>redis.clients</groupId>
-			<artifactId>jedis</artifactId>
-			<version>3.3.0</version>
+			<groupId>org.mybatis.spring.boot</groupId>
+			<artifactId>mybatis-spring-boot-starter</artifactId>
+			<version>2.1.4</version>
 		</dependency>
 
 		<!-- druid鏁版嵁搴撹繛鎺ユ睜 -->
@@ -71,36 +82,25 @@
 			<version>8.0.22</version>
 		</dependency>
 
-		<!--Mybatis -->
+		<!-- 娣诲姞sqlite-jdbc鏁版嵁搴撻┍鍔� -->
 		<dependency>
-			<groupId>org.mybatis</groupId>
-			<artifactId>mybatis</artifactId>
-			<version>${mybatis.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.mybatis</groupId>
-			<artifactId>mybatis-spring</artifactId>
-			<version>${mybatis.spring.version}</version>
+			<groupId>org.xerial</groupId>
+			<artifactId>sqlite-jdbc</artifactId>
+			<version>3.32.3.2</version>
 		</dependency>
 
-		<!--鍒嗛〉鎻掍欢 -->
+		<!--Mybatis鍒嗛〉鎻掍欢 -->
 		<dependency>
 			<groupId>com.github.pagehelper</groupId>
-			<artifactId>pagehelper</artifactId>
-			<version>${pagehelper.version}</version>
+			<artifactId>pagehelper-spring-boot-starter</artifactId>
+			<version>1.2.10</version>
 		</dependency>
 
-		<!--閫氱敤Mapper -->
-		<dependency>
-			<groupId>tk.mybatis</groupId>
-			<artifactId>mapper</artifactId>
-			<version>${mapper.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.commons</groupId>
-			<artifactId>commons-lang3</artifactId>
-			<version>3.11</version>
-		</dependency>
+<!--		<dependency>-->
+<!--			<groupId>org.apache.commons</groupId>-->
+<!--			<artifactId>commons-lang3</artifactId>-->
+<!--			<version>3.11</version>-->
+<!--		</dependency>-->
 
 		<!--Swagger2 -->
 		<!--鍦ㄧ嚎鏂囨。 -->
diff --git a/src/main/java/com/genersoft/iot/vmp/common/PageResult.java b/src/main/java/com/genersoft/iot/vmp/common/PageResult.java
deleted file mode 100644
index 6d7c89e..0000000
--- a/src/main/java/com/genersoft/iot/vmp/common/PageResult.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.genersoft.iot.vmp.common;
-
-
-import java.util.List;
-
-public class PageResult<T> {
-
-    private int page;
-    private int count;
-    private int total;
-
-    private List<T> data;
-
-    public List<T> getData() {
-        return data;
-    }
-
-    public int getPage() {
-        return page;
-    }
-
-    public void setPage(int page) {
-        this.page = page;
-    }
-
-    public int getCount() {
-        return count;
-    }
-
-    public void setCount(int count) {
-        this.count = count;
-    }
-
-    public int getTotal() {
-        return total;
-    }
-
-    public void setTotal(int total) {
-        this.total = total;
-    }
-
-    public void setData(List<T> data) {
-        this.data = data;
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
index 53bda91..0fb76b9 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -4,7 +4,6 @@
 
 public class StreamInfo {
 
-    private String ssrc;
     private String streamId;
     private String deviceID;
     private String cahnnelId;
@@ -19,14 +18,6 @@
     private String rtmp;
     private String rtsp;
     private JSONArray tracks;
-
-    public String getSsrc() {
-        return ssrc;
-    }
-
-    public void setSsrc(String ssrc) {
-        this.ssrc = ssrc;
-    }
 
     public String getDeviceID() {
         return deviceID;
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java b/src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java
new file mode 100644
index 0000000..faa9ef1
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java
@@ -0,0 +1,63 @@
+package com.genersoft.iot.vmp.conf;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+
+/**
+ *  瀵归厤缃枃浠惰繘琛屾牎楠�
+ */
+@Component
+@Order(value=2)
+public class ApplicationCheckRunner implements CommandLineRunner {
+
+    private Logger logger = LoggerFactory.getLogger("ApplicationCheckRunner");
+
+    @Value("${sip.ip}")
+    private String sipIp;
+
+    @Value("${media.ip}")
+    private String mediaIp;
+
+    @Value("${media.wanIp}")
+    private String mediaWanIp;
+
+    @Value("${media.hookIp}")
+    private String mediaHookIp;
+
+    @Value("${media.port}")
+    private int mediaPort;
+
+    @Value("${media.secret}")
+    private String mediaSecret;
+
+    @Value("${media.streamNoneReaderDelayMS}")
+    private String streamNoneReaderDelayMS;
+
+    @Value("${sip.ip}")
+    private String sipIP;
+
+    @Value("${server.port}")
+    private String serverPort;
+
+    @Value("${media.autoConfig}")
+    private boolean autoConfig;
+
+
+    @Override
+    public void run(String... args) throws Exception {
+        if (sipIP.equals("localhost") || sipIP.equals("127.0.0.1")) {
+            logger.error("sip.ip涓嶈兘浣跨敤 {} ,璇蜂娇鐢ㄧ被浼�192.168.1.44杩欐牱鐨勬潵鑷綉鍗$殑IP!!!", sipIP );
+            System.exit(1);
+        }
+
+        if (mediaIp.equals("localhost") || mediaIp.equals("127.0.0.1")) {
+            logger.warn("mediaIp.ip浣跨敤 {} ,灏嗘棤娉曟敹鍒扮綉缁滃唴鍏朵粬璁惧鐨勬帹娴�!!!", mediaIp );
+        }
+
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
index 54c0711..0b4ecbb 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -8,8 +8,10 @@
 import java.util.concurrent.TimeUnit;
 
 import javax.sip.*;
+import javax.sip.header.CallIdHeader;
 import javax.sip.message.Response;
 
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -33,6 +35,9 @@
 
 	@Autowired
 	private SIPProcessorFactory processorFactory;
+
+	@Autowired
+	private SipSubscribe sipSubscribe;
 
 	private SipStack sipStack;
 
@@ -133,17 +138,34 @@
 				// TODO Auto-generated catch block
 				e.printStackTrace();
 			}
+			if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
+				CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
+				if (callIdHeader != null) {
+					SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
+					if (subscribe != null) {
+						subscribe.response(evt);
+					}
+				}
+			}
 		// } else if (status == Response.TRYING) {
 			// trying涓嶄細鍥炲
 		} else if ((status >= 100) && (status < 200)) {
 			// 澧炲姞鍏跺畠鏃犻渶鍥炲鐨勫搷搴旓紝濡�101銆�180绛�
 		} else {
 			logger.warn("鎺ユ敹鍒板け璐ョ殑response鍝嶅簲锛乻tatus锛�" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
+			if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) {
+				CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
+				if (callIdHeader != null) {
+					SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId());
+					if (subscribe != null) {
+						subscribe.response(evt);
+					}
+				}
+			}
 		}
-		// trying涓嶄細鍥炲
-		// if (status == Response.TRYING) {
 
-		// }
+
+
 	}
 
 	/**
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
index 637ee9a..16ed56a 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
@@ -27,6 +27,7 @@
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.text.DecimalFormat;
 import java.util.Date;
 import java.util.Random;
 
@@ -103,9 +104,12 @@
                     .createWWWAuthenticateHeader(DEFAULT_SCHEME);
             proxyAuthenticate.setParameter("realm", realm);
             proxyAuthenticate.setParameter("nonce", generateNonce());
+
             proxyAuthenticate.setParameter("opaque", "");
             proxyAuthenticate.setParameter("stale", "FALSE");
             proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM);
+
+//            proxyAuthenticate.setParameter("qop", "auth");
             response.setHeader(proxyAuthenticate);
         } catch (Exception ex) {
             InternalErrorHandler.handleException(ex);
@@ -170,42 +174,116 @@
     public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
     	AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
         if ( authHeader == null ) return false;
-        String realm = authHeader.getRealm();
-        String username = authHeader.getUsername();
-      
-   
+        String realm = authHeader.getRealm().trim();
+        String username = authHeader.getUsername().trim();
+
         if ( username == null || realm == null ) {
             return false;
         }
-        
 
         String nonce = authHeader.getNonce();
         URI uri = authHeader.getURI();
         if (uri == null) {
            return false;
         }
-        
+        // qop 淇濇姢璐ㄩ噺 鍖呭惈auth锛堥粯璁ょ殑锛夊拰auth-int锛堝鍔犱簡鎶ユ枃瀹屾暣鎬ф娴嬶級涓ょ绛栫暐
+        String qop = authHeader.getQop();
+
+        // 瀹㈡埛绔殢鏈烘暟锛岃繖鏄竴涓笉閫忔槑鐨勫瓧绗︿覆鍊硷紝鐢卞鎴风鎻愪緵锛屽苟涓斿鎴风鍜屾湇鍔″櫒閮戒細浣跨敤锛屼互閬垮厤鐢ㄦ槑鏂囨枃鏈��
+        // 杩欎娇寰楀弻鏂归兘鍙互鏌ラ獙瀵规柟鐨勮韩浠斤紝骞跺娑堟伅鐨勫畬鏁存�ф彁渚涗竴浜涗繚鎶�
+        String cNonce = authHeader.getCNonce();
+
+        // nonce璁℃暟鍣紝鏄竴涓�16杩涘埗鐨勬暟鍊硷紝琛ㄧず鍚屼竴nonce涓嬪鎴风鍙戦�佸嚭璇锋眰鐨勬暟閲�
+        int nc = authHeader.getNonceCount();
+        String ncStr = new DecimalFormat("00000000").format(nc);
+//        String ncStr = new DecimalFormat("00000000").format(Integer.parseInt(nc + "", 16));
 
         String A1 = username + ":" + realm + ":" + pass;
         String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
         byte mdbytes[] = messageDigest.digest(A1.getBytes());
         String HA1 = toHexString(mdbytes);
+        System.out.println("A1: " + A1);
+        System.out.println("A2: " + A2);
 
-       
         mdbytes = messageDigest.digest(A2.getBytes());
         String HA2 = toHexString(mdbytes);
-      
+        System.out.println("HA1: " + HA1);
+        System.out.println("HA2: " + HA2);
         String cnonce = authHeader.getCNonce();
+        System.out.println("nonce: " + nonce);
+        System.out.println("nc: " + ncStr);
+        System.out.println("cnonce: " + cnonce);
+        System.out.println("qop: " + qop);
         String KD = HA1 + ":" + nonce;
-        if (cnonce != null) {
-            KD += ":" + cnonce;
+
+        if (qop != null && qop.equals("auth") ) {
+            if (nc != -1) {
+                KD += ":" + ncStr;
+            }
+            if (cnonce != null) {
+                KD += ":" + cnonce;
+            }
+            KD += ":" + qop;
         }
         KD += ":" + HA2;
+        System.out.println("KD: " + KD);
         mdbytes = messageDigest.digest(KD.getBytes());
         String mdString = toHexString(mdbytes);
+        System.out.println("mdString: " + mdString);
         String response = authHeader.getResponse();
+        System.out.println("response: " + response);
         return mdString.equals(response);
         
     }
 
+
+    public static void main(String[] args) throws NoSuchAlgorithmException {
+        MessageDigest  messageDigest2 = MessageDigest.getInstance(DEFAULT_ALGORITHM);
+        String realm = "DS-2CD2520F";
+        String username = "admin";
+        String passwd = "12345";
+
+        String nonce = "4d6a553452444d30525441364e6d4d304e6a68684e47553d";
+
+        String uri = "/ISAPI/Streaming/channels/101/picture";
+        // qop 淇濇姢璐ㄩ噺 鍖呭惈auth锛堥粯璁ょ殑锛夊拰auth-int锛堝鍔犱簡鎶ユ枃瀹屾暣鎬ф娴嬶級涓ょ绛栫暐
+        String qop = "auth";
+
+        // 瀹㈡埛绔殢鏈烘暟锛岃繖鏄竴涓笉閫忔槑鐨勫瓧绗︿覆鍊硷紝鐢卞鎴风鎻愪緵锛屽苟涓斿鎴风鍜屾湇鍔″櫒閮戒細浣跨敤锛屼互閬垮厤鐢ㄦ槑鏂囨枃鏈��
+        // 杩欎娇寰楀弻鏂归兘鍙互鏌ラ獙瀵规柟鐨勮韩浠斤紝骞跺娑堟伅鐨勫畬鏁存�ф彁渚涗竴浜涗繚鎶�
+        String cNonce = "C1A5298F939E87E8F962A5EDFC206918";
+
+        // nonce璁℃暟鍣紝鏄竴涓�16杩涘埗鐨勬暟鍊硷紝琛ㄧず鍚屼竴nonce涓嬪鎴风鍙戦�佸嚭璇锋眰鐨勬暟閲�
+        int nc = 1;
+
+        String A1 = username + ":" + realm + ":" + passwd;
+        System.out.println("A1: " + A1);
+        String A2 = "GET" + ":" + uri.toString();
+        System.out.println("A2: " + A2);
+        byte mdbytes[] = messageDigest2.digest(A1.getBytes());
+        String HA1 = toHexString(mdbytes);
+        System.out.println("HA1: " + HA1);
+
+        mdbytes = messageDigest2.digest(A2.getBytes());
+        String HA2 = toHexString(mdbytes);
+        System.out.println("HA2: " + HA2);
+        String cnonce = "93d4d37df32e1a85";
+        String KD = HA1 + ":" + nonce;
+
+        if (nc != -1) {
+            KD += ":" + "00000001";
+        }
+        if (cnonce != null) {
+            KD += ":" + cnonce;
+        }
+        if (qop != null) {
+            KD += ":" + qop;
+        }
+        KD += ":" + HA2;
+        System.out.println("KD: " + KD);
+        mdbytes = messageDigest2.digest(KD.getBytes());
+        String mdString = toHexString(mdbytes);
+        String response = "3993a815e5cdaf4470e9b4f9bd41cf4a";
+        System.out.println(mdString);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java
index 6e4588d..6fe63cc 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java
@@ -21,6 +21,6 @@
 		// TODO 鍚庣画澶勭悊锛屽彧鏈夌涓�娆℃敞鍐屾椂璋冪敤鏌ヨ璁惧淇℃伅锛屽闇�鏇存柊璋冪敤鏇存柊API鎺ュ彛
 		cmder.deviceInfoQuery(device);
 		
-		cmder.catalogQuery(device);
+		cmder.catalogQuery(device, null);
 	}
 }
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 de52ac6..9393106 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -1,9 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
 
-import java.util.List;
-import java.util.Map;
-
 public class Device {
 
 	/**
@@ -46,23 +43,35 @@
 	private String streamMode;
 
 	/**
+	 * wan鍦板潃_ip
+	 */
+	private String  ip;
+
+	/**
+	 * wan鍦板潃_port
+	 */
+	private int port;
+
+	/**
 	 * wan鍦板潃
 	 */
-	private Host host;
+	private String  hostAddress;
 	
 	/**
 	 * 鍦ㄧ嚎
 	 */
 	private int online;
 
+
 	/**
-	 * 閫氶亾鍒楄〃
+	 * 娉ㄥ唽鏃堕棿
 	 */
-//	private Map<String,DeviceChannel> channelMap;
+	private Long registerTimeMillis;
 
+	/**
+	 * 閫氶亾涓暟
+	 */
 	private int channelCount;
-
-	private List<String> channelList;
 
 	public String getDeviceId() {
 		return deviceId;
@@ -120,12 +129,28 @@
 		this.streamMode = streamMode;
 	}
 
-	public Host getHost() {
-		return host;
+	public String getIp() {
+		return ip;
 	}
 
-	public void setHost(Host host) {
-		this.host = host;
+	public void setIp(String ip) {
+		this.ip = ip;
+	}
+
+	public int getPort() {
+		return port;
+	}
+
+	public void setPort(int port) {
+		this.port = port;
+	}
+
+	public String getHostAddress() {
+		return hostAddress;
+	}
+
+	public void setHostAddress(String hostAddress) {
+		this.hostAddress = hostAddress;
 	}
 
 	public int getOnline() {
@@ -144,11 +169,11 @@
 		this.channelCount = channelCount;
 	}
 
-	public List<String> getChannelList() {
-		return channelList;
+	public Long getRegisterTimeMillis() {
+		return registerTimeMillis;
 	}
 
-	public void setChannelList(List<String> channelList) {
-		this.channelList = channelList;
+	public void setRegisterTimeMillis(Long registerTimeMillis) {
+		this.registerTimeMillis = registerTimeMillis;
 	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
index 810feab..ca6ef60 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
@@ -2,10 +2,17 @@
 
 public class DeviceChannel {
 
+
+
 	/**
 	 * 閫氶亾id
 	 */
 	private String channelId;
+
+	/**
+	 * 璁惧id
+	 */
+	private String deviceId;
 	
 	/**
 	 * 閫氶亾鍚�
@@ -141,18 +148,20 @@
 	/**
 	 * 娴佸敮涓�缂栧彿锛屽瓨鍦ㄨ〃绀烘鍦ㄧ洿鎾�
 	 */
-	private String  ssrc;
+	private String  streamId;
 
 	/**
 	 *  鏄惁鍚湁闊抽
 	 */
-	private  boolean hasAudio;
+	private boolean hasAudio;
 
-	/**
-	 *  鏄惁姝e湪鎾斁
-	 */
-	private  boolean play;
+	public String getDeviceId() {
+		return deviceId;
+	}
 
+	public void setDeviceId(String deviceId) {
+		this.deviceId = deviceId;
+	}
 
 	public void setPTZType(int PTZType) {
 		this.PTZType = PTZType;
@@ -379,14 +388,6 @@
 		this.subCount = subCount;
 	}
 
-	public String getSsrc() {
-		return ssrc;
-	}
-
-	public void setSsrc(String ssrc) {
-		this.ssrc = ssrc;
-	}
-
 	public boolean isHasAudio() {
 		return hasAudio;
 	}
@@ -395,11 +396,11 @@
 		this.hasAudio = hasAudio;
 	}
 
-	public boolean isPlay() {
-		return play;
+	public String getStreamId() {
+		return streamId;
 	}
 
-	public void setPlay(boolean play) {
-		this.play = play;
+	public void setStreamId(String streamId) {
+		this.streamId = streamId;
 	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
new file mode 100644
index 0000000..176a435
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
@@ -0,0 +1,50 @@
+package com.genersoft.iot.vmp.gb28181.event;
+
+import com.alibaba.fastjson.JSONObject;
+import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.sip.ResponseEvent;
+import javax.sip.message.Request;
+import java.util.EventObject;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class SipSubscribe {
+
+    private final static Logger logger = LoggerFactory.getLogger(SipSubscribe.class);
+
+    private Map<String, SipSubscribe.Event> errorSubscribes = new ConcurrentHashMap<>();
+
+    private Map<String, SipSubscribe.Event> okSubscribes = new ConcurrentHashMap<>();
+
+    public interface Event {
+        void response(ResponseEvent event);
+    }
+
+    public void addErrorSubscribe(String key, SipSubscribe.Event event) {
+        errorSubscribes.put(key, event);
+    }
+
+    public void addOkSubscribe(String key, SipSubscribe.Event event) {
+        okSubscribes.put(key, event);
+    }
+
+    public SipSubscribe.Event getErrorSubscribe(String key) {
+        return errorSubscribes.get(key);
+    }
+
+    public SipSubscribe.Event getOkSubscribe(String key) {
+        return okSubscribes.get(key);
+    }
+
+    public int getErrorSubscribesSize(){
+        return errorSubscribes.size();
+    }
+    public int getOkSubscribesSize(){
+        return okSubscribes.size();
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
index f063b49..1e374ad 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
@@ -7,7 +7,9 @@
 import javax.sip.message.Request;
 import javax.sip.message.Response;
 
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.alibaba.fastjson.JSON;
+import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
 import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,7 +56,10 @@
 	
 	@Autowired
 	private IVideoManagerStorager storager;
-	
+
+	@Autowired
+	private IRedisCatchStorage redisCatchStorage;
+
 	@Autowired
 	private EventPublisher publisher;
 	
@@ -82,10 +87,11 @@
 	@Autowired
 	@Lazy
 	private RegisterResponseProcessor registerResponseProcessor;
-	
+
 	@Autowired
 	private OtherResponseProcessor otherResponseProcessor;
-	
+
+
 	// 娉細杩欓噷浣跨敤娉ㄨВ浼氬鑷村惊鐜緷璧栨敞鍏ワ紝鏆傜敤springBean
 	private SipProvider tcpSipProvider;
 		
@@ -140,6 +146,7 @@
 			processor.setOffLineDetector(offLineDetector);
 			processor.setCmder(cmder);
 			processor.setStorager(storager);
+			processor.setRedisCatchStorage(redisCatchStorage);
 			return processor;
 		} else {
 			return new OtherRequestProcessor();
@@ -147,6 +154,7 @@
 	}
 	
 	public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) {
+
 		Response response = evt.getResponse();
 		CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
 		String method = cseqHeader.getMethod();
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
index 0c1e63d..0759d7f 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
@@ -2,6 +2,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
@@ -24,8 +25,10 @@
 
 	public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY";
 
-	private Map<String, DeferredResult> map = new HashMap<String, DeferredResult>();
-	
+	public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
+
+	private Map<String, DeferredResult> map = new ConcurrentHashMap<String, DeferredResult>();
+
 	public void put(String key, DeferredResult result) {
 		map.put(key, result);
 	}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
index d3f36cd..67fd996 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -2,8 +2,8 @@
 
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 
 /**    
  * @Description:璁惧鑳藉姏鎺ュ彛锛岀敤浜庡畾涔夎澶囩殑鎺у埗銆佹煡璇㈣兘鍔�   
@@ -84,7 +84,7 @@
 	 * @param device  瑙嗛璁惧
 	 * @param channelId  棰勮閫氶亾
 	 */
-	void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event);
+	void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
 	
 	/**
 	 * 璇锋眰鍥炴斁瑙嗛娴�
@@ -94,15 +94,16 @@
 	 * @param startTime 寮�濮嬫椂闂�,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */
-	void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event);
+	void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
 	
 	/**
 	 * 瑙嗛娴佸仠姝�
 	 * 
 	 * @param ssrc  ssrc
 	 */
+	void streamByeCmd(String ssrc, SipSubscribe.Event okEvent);
 	void streamByeCmd(String ssrc);
-	
+
 	/**
 	 * 璇煶骞挎挱
 	 * 
@@ -176,7 +177,7 @@
 	 * 
 	 * @param device 瑙嗛璁惧
 	 */
-	boolean catalogQuery(Device device);
+	boolean catalogQuery(Device device, SipSubscribe.Event errorEvent);
 	
 	/**
 	 * 鏌ヨ褰曞儚淇℃伅
@@ -214,4 +215,11 @@
 	 * @param device 瑙嗛璁惧
 	 */
 	boolean mobilePostitionQuery(Device device);
+
+	/**
+	 * 閲婃斁rtpserver
+	 * @param device
+	 * @param channelId
+	 */
+    void closeRTPServer(Device device, String channelId);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
index 6982144..739d5a9 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
@@ -47,9 +47,8 @@
 	
 	public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
 		Request request = null;
-		Host host = device.getHost();
 		// sipuri
-		SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
+		SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
 		// via
 		ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
 		ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
@@ -75,22 +74,21 @@
 
 		request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
 				toHeader, viaHeaders, maxForwards);
-		ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
+		ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
 		request.setContent(content, contentTypeHeader);
 		return request;
 	}
 	
 	public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
 		Request request = null;
-		Host host = device.getHost();
 		//璇锋眰琛�
-		SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, host.getAddress());
+		SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
 		//via
 		ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
-		// ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
-		ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag);
+		ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
 		viaHeader.setRPort();
 		viaHeaders.add(viaHeader);
+
 		//from
 		SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain());
 		Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
@@ -122,20 +120,18 @@
 		// Subject
 		SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0));
 		request.addHeader(subjectHeader);
-		ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "SDP");
+		ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
 		request.setContent(content, contentTypeHeader);
 		return request;
 	}
 	
 	public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
 		Request request = null;
-		Host host = device.getHost();
 		//璇锋眰琛�
-		SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
-		//via
+		SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
+		// via
 		ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
-		// ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
-		ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag);
+		ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
 		viaHeader.setRPort();
 		viaHeaders.add(viaHeader);
 		//from
@@ -167,7 +163,7 @@
 		// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
 		request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
 		
-		ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "SDP");
+		ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
 		request.setContent(content, contentTypeHeader);
 		return request;
 	}
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 3d5aacc..e1d474f 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -1,17 +1,14 @@
 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
 
 import java.text.ParseException;
+import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.sip.ClientTransaction;
-import javax.sip.Dialog;
-import javax.sip.InvalidArgumentException;
-import javax.sip.SipException;
-import javax.sip.SipFactory;
-import javax.sip.SipProvider;
-import javax.sip.TransactionDoesNotExistException;
+import javax.sip.*;
 import javax.sip.address.SipURI;
+import javax.sip.header.CallIdHeader;
+import javax.sip.header.Header;
 import javax.sip.header.ViaHeader;
 import javax.sip.message.Request;
 
@@ -19,9 +16,13 @@
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
-import com.genersoft.iot.vmp.media.zlm.ZLMUtils;
+import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
@@ -41,6 +42,8 @@
  */
 @Component
 public class SIPCommander implements ISIPCommander {
+
+	private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
 	
 	@Autowired
 	private SipConfig sipConfig;
@@ -53,6 +56,9 @@
 
 	@Autowired
 	private IVideoManagerStorager storager;
+
+	@Autowired
+	private IRedisCatchStorage redisCatchStorage;
 	
 	@Autowired
 	@Qualifier(value="tcpSipProvider")
@@ -63,13 +69,19 @@
 	private SipProvider udpSipProvider;
 
 	@Autowired
-	private ZLMUtils zlmUtils;
+	private ZLMRTPServerFactory zlmrtpServerFactory;
 
 	@Value("${media.rtp.enable}")
 	private boolean rtpEnable;
 
+	@Value("${media.seniorSdp}")
+	private boolean seniorSdp;
+
 	@Autowired
 	private ZLMHttpHookSubscribe subscribe;
+
+	@Autowired
+	private SipSubscribe sipSubscribe;
 
 
 
@@ -176,19 +188,29 @@
     * @param moveSpeed  闀滃ご绉诲姩閫熷害 榛樿 0XFF (0-255)
     * @param zoomSpeed  闀滃ご缂╂斁閫熷害 榛樿 0X1 (0-255)
     */
-    public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {
+
+	/**
+	 * 浜戝彴鎸囦护鐮佽绠�
+	 *
+	 * @param cmdCode 鎸囦护鐮�
+	 * @param horizonSpeed	姘村钩绉诲姩閫熷害
+	 * @param verticalSpeed	鍨傜洿绉诲姩閫熷害
+	 * @param zoomSpeed	    缂╂斁閫熷害
+	 * @return
+	 */
+    public static String frontEndCmdString(int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed) {
 		StringBuilder builder = new StringBuilder("A50F01");
 		String strTmp;
 		strTmp = String.format("%02X", cmdCode);
 		builder.append(strTmp, 0, 2);
-		strTmp = String.format("%02X", parameter1);
+		strTmp = String.format("%02X", horizonSpeed);
 		builder.append(strTmp, 0, 2);
-		strTmp = String.format("%02X", parameter2);
+		strTmp = String.format("%02X", verticalSpeed);
 		builder.append(strTmp, 0, 2);
-		strTmp = String.format("%X", combineCode2);
+		strTmp = String.format("%X", zoomSpeed);
 		builder.append(strTmp, 0, 1).append("0");
 		//璁$畻鏍¢獙鐮�
-		int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
+		int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + horizonSpeed + verticalSpeed + (zoomSpeed & 0XF0)) % 0X100;
 		strTmp = String.format("%02X", checkCode);
 		builder.append(strTmp, 0, 2);
 		return builder.toString();
@@ -237,14 +259,14 @@
 	 * @param device  		鎺у埗璁惧
 	 * @param channelId		棰勮閫氶亾
 	 * @param cmdCode		鎸囦护鐮�
-     * @param parameter1	鏁版嵁1
-     * @param parameter2	鏁版嵁2
-     * @param combineCode2	缁勫悎鐮�2
+     * @param horizonSpeed	姘村钩绉诲姩閫熷害
+     * @param verticalSpeed	鍨傜洿绉诲姩閫熷害
+     * @param zoomSpeed	    缂╂斁閫熷害
 	 */
 	@Override
-	public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) {
+	public boolean frontEndCmd(Device device, String channelId, int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed) {
 		try {
-			String cmdStr= frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);
+			String cmdStr= frontEndCmdString(cmdCode, horizonSpeed, verticalSpeed, zoomSpeed);
 			System.out.println("鎺у埗瀛楃涓诧細" + cmdStr);
 			StringBuffer ptzXml = new StringBuffer(200);
 			ptzXml.append("<?xml version=\"1.0\" ?>\r\n");
@@ -258,7 +280,6 @@
 			ptzXml.append("</Control>\r\n");
 			
 			Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag");
-			
 			transmitRequest(device, request);
 			return true;
 		} catch (SipException | ParseException | InvalidArgumentException e) {
@@ -266,28 +287,39 @@
 		} 
 		return false;
 	}
+
 	/**
-	 * 璇锋眰棰勮瑙嗛娴�
-	 *
+	 * 	璇锋眰棰勮瑙嗛娴�
 	 * @param device  瑙嗛璁惧
 	 * @param channelId  棰勮閫氶亾
+	 * @param event hook璁㈤槄
+	 * @param errorEvent sip閿欒璁㈤槄
 	 */
 	@Override
-	public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event) {
+	public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
 		try {
 
 			String ssrc = streamSession.createPlaySsrc();
+			String streamId = null;
+			if (rtpEnable) {
+				streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
+			}else {
+				streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
+			}
 			String streamMode = device.getStreamMode().toUpperCase();
-			MediaServerConfig mediaInfo = storager.getMediaInfo();
+			MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
+			if (mediaInfo == null) {
+				logger.warn("鐐规挱鏃跺彂鐜癦LM灏氭湭杩炴帴...");
+				return;
+			}
 			String mediaPort = null;
 			// 浣跨敤鍔ㄦ�乽dp绔彛
 			if (rtpEnable) {
-				mediaPort = zlmUtils.getNewRTPPort(ssrc) + "";
+				mediaPort = zlmrtpServerFactory.createRTPServer(streamId) + "";
 			}else {
 				mediaPort = mediaInfo.getRtpProxyPort();
 			}
 
-			String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
 			// 娣诲姞璁㈤槄
 			JSONObject subscribeKey = new JSONObject();
 			subscribeKey.put("app", "rtp");
@@ -297,7 +329,8 @@
 			//
 			StringBuffer content = new StringBuffer(200);
 			content.append("v=0\r\n");
-			content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
+//			content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
+			content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
 			content.append("s=Play\r\n");
 			content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
 			content.append("t=0 0\r\n");
@@ -327,17 +360,14 @@
 			}
 			content.append("y="+ssrc+"\r\n");//ssrc
 
+//			String fromTag = UUID.randomUUID().toString();
+//			Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, fromTag, null, ssrc);
+
 			Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc);
 
-			ClientTransaction transaction = transmitRequest(device, request);
-			streamSession.put(ssrc, transaction);
-			DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
-			if (deviceChannel != null) {
-				deviceChannel.setSsrc(ssrc);
-				storager.updateChannel(device.getDeviceId(), deviceChannel);
-			}
+			ClientTransaction transaction = transmitRequest(device, request, errorEvent);
+			streamSession.put(streamId, transaction);
 
-			// TODO 璁㈤槄SIP response锛屽鐞嗗鏂圭殑閿欒杩斿洖
 
 
 		} catch ( SipException | ParseException | InvalidArgumentException e) {
@@ -354,9 +384,10 @@
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */ 
 	@Override
-	public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event) {
+	public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
+			, SipSubscribe.Event errorEvent) {
 		try {
-			MediaServerConfig mediaInfo = storager.getMediaInfo();
+			MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
 			String ssrc = streamSession.createPlayBackSsrc();
 			String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
 			// 娣诲姞璁㈤槄
@@ -378,57 +409,91 @@
 			String mediaPort = null;
 			// 浣跨敤鍔ㄦ�乽dp绔彛
 			if (rtpEnable) {
-				mediaPort = zlmUtils.getNewRTPPort(ssrc) + "";
+				mediaPort = zlmrtpServerFactory.createRTPServer(streamId) + "";
 			}else {
 				mediaPort = mediaInfo.getRtpProxyPort();
 			}
 			String streamMode = device.getStreamMode().toUpperCase();
-			if("TCP-PASSIVE".equals(streamMode)) {
-				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
-			}else if ("TCP-ACTIVE".equals(streamMode)) {
-				content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
-			}else if("UDP".equals(streamMode)) {
-				content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n");
+
+			if (seniorSdp) {
+				if("TCP-PASSIVE".equals(streamMode)) {
+					content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
+				}else if ("TCP-ACTIVE".equals(streamMode)) {
+					content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
+				}else if("UDP".equals(streamMode)) {
+					content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n");
+				}
+				content.append("a=recvonly\r\n");
+				content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
+				content.append("a=rtpmap:126 H264/90000\r\n");
+				content.append("a=rtpmap:125 H264S/90000\r\n");
+				content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
+				content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
+				content.append("a=fmtp:99 profile-level-id=3\r\n");
+				content.append("a=rtpmap:98 H264/90000\r\n");
+				content.append("a=rtpmap:97 MPEG4/90000\r\n");
+				content.append("a=rtpmap:96 PS/90000\r\n");
+				if("TCP-PASSIVE".equals(streamMode)){ // tcp琚姩妯″紡
+					content.append("a=setup:passive\r\n");
+					content.append("a=connection:new\r\n");
+				}else if ("TCP-ACTIVE".equals(streamMode)) { // tcp涓诲姩妯″紡
+					content.append("a=setup:active\r\n");
+					content.append("a=connection:new\r\n");
+				}
+			}else {
+				if("TCP-PASSIVE".equals(streamMode)) {
+					content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
+				}else if ("TCP-ACTIVE".equals(streamMode)) {
+					content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
+				}else if("UDP".equals(streamMode)) {
+					content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
+				}
+				content.append("a=recvonly\r\n");
+				content.append("a=rtpmap:96 PS/90000\r\n");
+				content.append("a=rtpmap:98 H264/90000\r\n");
+				content.append("a=rtpmap:97 MPEG4/90000\r\n");
+				if("TCP-PASSIVE".equals(streamMode)){ // tcp琚姩妯″紡
+					content.append("a=setup:passive\r\n");
+					content.append("a=connection:new\r\n");
+				}else if ("TCP-ACTIVE".equals(streamMode)) { // tcp涓诲姩妯″紡
+					content.append("a=setup:active\r\n");
+					content.append("a=connection:new\r\n");
+				}
 			}
-			content.append("a=recvonly\r\n");
-			content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
-			content.append("a=rtpmap:126 H264/90000\r\n");
-			content.append("a=rtpmap:125 H264S/90000\r\n");
-			content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
-			content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
-			content.append("a=fmtp:99 profile-level-id=3\r\n");
-			content.append("a=rtpmap:98 H264/90000\r\n");
-			content.append("a=rtpmap:97 MPEG4/90000\r\n");
-			content.append("a=rtpmap:96 PS/90000\r\n");
-			if("TCP-PASSIVE".equals(streamMode)){ // tcp琚姩妯″紡
-				content.append("a=setup:passive\r\n");
-				content.append("a=connection:new\r\n");
-			}else if ("TCP-ACTIVE".equals(streamMode)) { // tcp涓诲姩妯″紡
-				content.append("a=setup:active\r\n");
-				content.append("a=connection:new\r\n");
-			}
+
 	        content.append("y="+ssrc+"\r\n");//ssrc
 	        
 	        Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null);
-	
-	        ClientTransaction transaction = transmitRequest(device, request);
-	        streamSession.put(ssrc, transaction);
+
+	        ClientTransaction transaction = transmitRequest(device, request, errorEvent);
+	        streamSession.put(streamId, transaction);
 
 		} catch ( SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();
 		}
 	}
-	
+
+
+
 	/**
 	 * 瑙嗛娴佸仠姝�
 	 * 
 	 */
 	@Override
 	public void streamByeCmd(String ssrc) {
+		streamByeCmd(ssrc, null);
+	}
+	@Override
+	public void streamByeCmd(String streamId, SipSubscribe.Event okEvent) {
 		
 		try {
-			ClientTransaction transaction = streamSession.get(ssrc);
+			ClientTransaction transaction = streamSession.get(streamId);
+			// 鏈嶅姟閲嶅惎鍚�
 			if (transaction == null) {
+				StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
+				if (streamInfo != null) {
+
+				}
 				return;
 			}
 			
@@ -436,6 +501,9 @@
 			if (dialog == null) {
 				return;
 			}
+
+
+
 			Request byeRequest = dialog.createRequest(Request.BYE);
 			SipURI byeURI = (SipURI) byeRequest.getRequestURI();
 			String vh = transaction.getRequest().getHeader(ViaHeader.NAME).toString();
@@ -452,8 +520,16 @@
 			} else if("UDP".equals(protocol)) {
 				clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
 			}
+
+			CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME);
+			if (okEvent != null) {
+				sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
+			}
+
 			dialog.sendRequest(clientTransaction);
-			streamSession.remove(ssrc);
+
+			streamSession.remove(streamId);
+			zlmrtpServerFactory.closeRTPServer(streamId);
 		} catch (TransactionDoesNotExistException e) {
 			e.printStackTrace();
 		} catch (SipException e) {
@@ -571,6 +647,7 @@
 			catalogXml.append("</Query>\r\n");
 			
 			Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag");
+
 			transmitRequest(device, request);
 			
 		} catch (SipException | ParseException | InvalidArgumentException e) {
@@ -586,7 +663,7 @@
 	 * @param device 瑙嗛璁惧
 	 */ 
 	@Override
-	public boolean catalogQuery(Device device) {
+	public boolean catalogQuery(Device device, SipSubscribe.Event errorEvent) {
 		// 娓呯┖閫氶亾
 		storager.cleanChannelsForDevice(device.getDeviceId());
 		try {
@@ -598,8 +675,9 @@
 			catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
 			catalogXml.append("</Query>\r\n");
 			
-			Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", "ToCatalogTag");
-			transmitRequest(device, request);
+			Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", null);
+
+			transmitRequest(device, request, errorEvent);
 		} catch (SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();
 			return false;
@@ -631,7 +709,8 @@
 			recordInfoXml.append("<Type>all</Type>\r\n");
 			recordInfoXml.append("</Query>\r\n");
 			
-			Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag");
+			Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", null);
+
 			transmitRequest(device, request);
 		} catch (SipException | ParseException | InvalidArgumentException e) {
 			e.printStackTrace();
@@ -683,17 +762,45 @@
 		// TODO Auto-generated method stub
 		return false;
 	}
-	
+
 	private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
+		return transmitRequest(device, request, null, null);
+	}
+
+	private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException {
+		return transmitRequest(device, request, errorEvent, null);
+	}
+
+	private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException {
 		ClientTransaction clientTransaction = null;
 		if("TCP".equals(device.getTransport())) {
 			clientTransaction = tcpSipProvider.getNewClientTransaction(request);
 		} else if("UDP".equals(device.getTransport())) {
 			clientTransaction = udpSipProvider.getNewClientTransaction(request);
 		}
+
+		CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
+		// 娣诲姞閿欒璁㈤槄
+		if (errorEvent != null) {
+			sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), errorEvent);
+		}
+		// 娣诲姞璁㈤槄
+		if (okEvent != null) {
+			sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
+		}
+
 		clientTransaction.sendRequest();
 		return clientTransaction;
 	}
 
 
+
+
+	@Override
+	public void closeRTPServer(Device device, String channelId) {
+		if (rtpEnable) {
+			String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
+			zlmrtpServerFactory.closeRTPServer(streamId);
+		}
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
index c987f5e..cab4a9b 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
@@ -10,6 +10,7 @@
 import javax.sip.message.Request;
 import javax.sip.message.Response;
 
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import org.dom4j.Document;
 import org.dom4j.DocumentException;
 import org.dom4j.Element;
@@ -47,6 +48,8 @@
 	private SIPCommander cmder;
 
 	private IVideoManagerStorager storager;
+
+	private IRedisCatchStorage redisCatchStorage;
 
 	private EventPublisher publisher;
 
@@ -294,7 +297,7 @@
 				device.setStreamMode("UDP");
 			}
 			storager.updateDevice(device);
-			cmder.catalogQuery(device);
+			cmder.catalogQuery(device, null);
 			// 鍥炲200 OK
 			responseAck(evt);
 			if (offLineDetector.isOnline(deviceId)) {
@@ -315,12 +318,16 @@
 		try {
 			Element rootElement = getRootElement(evt);
 			String deviceId = XmlUtil.getText(rootElement, "DeviceID");
-			// 鍥炲200 OK
-			responseAck(evt);
-			if (offLineDetector.isOnline(deviceId)) {
-				publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
-			} else {
+			// 妫�鏌ヨ澶囨槸鍚﹀瓨鍦紝 涓嶅瓨鍦ㄥ垯涓嶅洖澶�
+			if (storager.exists(deviceId)) {
+				// 鍥炲200 OK
+				responseAck(evt);
+				if (offLineDetector.isOnline(deviceId)) {
+					publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
+				} else {
+				}
 			}
+
 		} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
 			e.printStackTrace();
 		}
@@ -447,10 +454,10 @@
 			String NotifyType =XmlUtil.getText(rootElement, "NotifyType");
 			if (NotifyType.equals("121")){
 				logger.info("濯掍綋鎾斁瀹屾瘯锛岄�氱煡鍏虫祦");
-				StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, "*");
+				StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, "*");
 				if (streamInfo != null) {
-					storager.stopPlayback(streamInfo);
-					cmder.streamByeCmd(streamInfo.getSsrc());
+					redisCatchStorage.stopPlayback(streamInfo);
+					cmder.streamByeCmd(streamInfo.getStreamId());
 				}
 			}
 		} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
@@ -503,4 +510,11 @@
 		this.offLineDetector = offLineDetector;
 	}
 
+	public IRedisCatchStorage getRedisCatchStorage() {
+		return redisCatchStorage;
+	}
+
+	public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
+		this.redisCatchStorage = redisCatchStorage;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
index be076bd..4faab0e 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
@@ -107,17 +107,15 @@
 					rPort = viaHeader.getPort();
 				}
 				//
-				Host host = new Host();
-				host.setIp(received);
-				host.setPort(rPort);
-				host.setAddress(received.concat(":").concat(String.valueOf(rPort)));
 				AddressImpl address = (AddressImpl) fromHeader.getAddress();
 				SipUri uri = (SipUri) address.getURI();
 				String deviceId = uri.getUser();
 				device = new Device();
 				device.setStreamMode("UDP");
 				device.setDeviceId(deviceId);
-				device.setHost(host);
+				device.setIp(received);
+				device.setPort(rPort);
+				device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
 				// 娉ㄩ攢鎴愬姛
 				if (expiresHeader != null && expiresHeader.getExpires() == 0) {
 					registerFlag = 2;
@@ -141,9 +139,15 @@
 			// 涓嬪彂catelog鏌ヨ鐩綍
 			if (registerFlag == 1 && device != null) {
 				logger.info("娉ㄥ唽鎴愬姛! deviceId:" + device.getDeviceId());
+				boolean exists = storager.exists(device.getDeviceId());
+				device.setRegisterTimeMillis(System.currentTimeMillis());
 				storager.updateDevice(device);
 				publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER);
-				handler.onRegister(device);
+
+				// 鍙湁绗竴娆℃敞鍐屾墠鏇存柊閫氶亾
+				if (!exists) {
+					handler.onRegister(device);
+				}
 			} else if (registerFlag == 2) {
 				logger.info("娉ㄩ攢鎴愬姛! deviceId:" + device.getDeviceId());
 				publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java
index ae7182d..93f533f 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java
@@ -12,6 +12,7 @@
 import javax.sip.message.Request;
 import javax.sip.message.Response;
 
+import gov.nist.javax.sip.header.CSeq;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
@@ -23,14 +24,14 @@
 
 
 /**
- * @Description:澶勭悊INVITE鍝嶅簲
+ * @Description:澶勭悊INVITE鍝嶅簲
  * @author: swwheihei
- * @date: 2020骞�5鏈�3鏃� 涓嬪崍4:43:52
+ * @date: 2020骞�5鏈�3鏃� 涓嬪崍4:43:52
  */
 @Component
 public class InviteResponseProcessor implements ISIPResponseProcessor {
 
-	private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class);
+	private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
 
 	/**
 	 * 澶勭悊invite鍝嶅簲
@@ -49,48 +50,16 @@
 			// 鎴愬姛鍝嶅簲
 			// 涓嬪彂ack
 			if (statusCode == Response.OK) {
-				// ClientTransaction clientTransaction = evt.getClientTransaction();
-				// if(clientTransaction == null){
-				// logger.error("鍥炲ACK鏃讹紝clientTransaction涓簄ull >>> {}",response);
-				// return;
-				// }
-				// Dialog clientDialog = clientTransaction.getDialog();
-
-				// CSeqHeader clientCSeqHeader = (CSeqHeader)
-				// response.getHeader(CSeqHeader.NAME);
-				// long cseqId = clientCSeqHeader.getSeqNumber();
-				// /*
-				// createAck鍑芥暟锛屽垱寤虹殑ackRequest锛屼細閲囩敤Invite鍝嶅簲鐨�200OK锛屼腑鐨刢ontact瀛楁涓殑鍦板潃锛屼綔涓虹洰鏍囧湴鍧�銆�
-				// 鏈夌殑缁堢浼犱笂鏉ョ殑鍙兘杩樻槸鍐呯綉鍦板潃锛屼細閫犳垚ack鍙戦�佷笉鍑哄幓銆傛帴鍙椾笉鍒伴煶瑙嗛娴�
-				// 鎵�浠ュ湪姝ゅ缁熶竴鏇挎崲鍦板潃銆傚拰鍝嶅簲娑堟伅鐨刅ia澶翠腑鐨勫湴鍧�淇濇寔涓�鑷淬��
-				// */
-				// Request ackRequest = clientDialog.createAck(cseqId);
-				// SipURI requestURI = (SipURI) ackRequest.getRequestURI();
-				// ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME);
-				// try {
-				// requestURI.setHost(viaHeader.getHost());
-				// } catch (Exception e) {
-				// e.printStackTrace();
-				// }
-				// requestURI.setPort(viaHeader.getPort());
-				// clientDialog.sendAck(ackRequest);
-
 				Dialog dialog = evt.getDialog();
 				CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
 				Request reqAck = dialog.createAck(cseq.getSeqNumber());
 
 				SipURI requestURI = (SipURI) reqAck.getRequestURI();
 				ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME);
-				// String viaHost =viaHeader.getHost();
-				//getHost()鍑芥暟鍙栧洖鐨処P鍦板潃鏄�淸xxx.xxx.xxx.xxx:yyyy]鈥濈殑鏍煎紡锛岄渶鐢ㄦ鍒欒〃杈惧紡鎴彇涓衡�渪xx.xxx.xxx.xxx"鏍煎紡
-				// Pattern p = Pattern.compile("(?<=//|)((\\w)+\\.)+\\w+");
-				// Matcher matcher = p.matcher(viaHeader.getHost());
-				// if (matcher.find()) {
-				// 	requestURI.setHost(matcher.group());
-				// }
 				requestURI.setHost(viaHeader.getHost());
 				requestURI.setPort(viaHeader.getPort());
 				reqAck.setRequestURI(requestURI);
+
 				dialog.sendAck(reqAck);
 			}
 		} catch (InvalidArgumentException | SipException e) {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
index f76cdd9..9daef23 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
@@ -2,6 +2,7 @@
 
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -29,6 +30,9 @@
     @Autowired
     private IVideoManagerStorager storager;
 
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
     @Value("${media.port}")
     private int mediaHttpPort;
 
@@ -36,10 +40,10 @@
     @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
     public Object proxy(HttpServletRequest request, HttpServletResponse response){
 
-        if (storager.getMediaInfo() == null) {
+        if (redisCatchStorage.getMediaInfo() == null) {
             return "鏈帴鍏ユ祦濯掍綋";
         }
-        MediaServerConfig mediaInfo = storager.getMediaInfo();
+        MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
         String requestURI = String.format("http://%s:%s%s?%s&%s",
                 mediaInfo.getLocalIP(),
                 mediaHttpPort,
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
index 99da624..cb8ad05 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
@@ -4,13 +4,17 @@
 import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.UUID;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.utils.IpUtil;
+import com.genersoft.iot.vmp.vmanager.service.IPlayService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -44,13 +48,22 @@
 	private SIPCommander cmder;
 
 	@Autowired
+	private IPlayService playService;
+
+	@Autowired
 	private IVideoManagerStorager storager;
+
+	@Autowired
+	private IRedisCatchStorage redisCatchStorage;
 
 	@Autowired
 	private ZLMRESTfulUtils zlmresTfulUtils;
 
 	@Autowired
 	private ZLMHttpHookSubscribe subscribe;
+
+	@Value("${media.autoApplyPlay}")
+	private boolean autoApplyPlay;
 
 	@Value("${media.ip}")
 	private String mediaIp;
@@ -135,34 +148,6 @@
 		ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
 		if (subscribe != null) subscribe.response(json);
 
-//		if ("rtp".equals(app)) {
-//			String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
-//			StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc);
-//			if ("rtp".equals(app) && streamInfoForPlay != null ) {
-//				MediaServerConfig mediaInfo = storager.getMediaInfo();
-//				streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
-//				streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
-//				storager.startPlay(streamInfoForPlay);
-//			}
-//
-//			StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc);
-//			if ("rtp".equals(app) && streamInfoForPlayBack != null ) {
-//				MediaServerConfig mediaInfo = storager.getMediaInfo();
-//				streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
-//				streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
-//				streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
-//				storager.startPlayback(streamInfoForPlayBack);
-//			}
-//		}
 
 		// TODO Auto-generated method stub
 		
@@ -268,15 +253,13 @@
 		String app = json.getString("app");
 		String streamId = json.getString("stream");
 		boolean regist = json.getBoolean("regist");
-//		String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 瑕佹眰澶у啓涓旈浣嶈ˉ闆�
-		String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
-		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+		StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
 		if ("rtp".equals(app) && !regist ) {
 			if (streamInfo!=null){
-				storager.stopPlay(streamInfo);
+				redisCatchStorage.stopPlay(streamInfo);
 			}else{
-				streamInfo = storager.queryPlaybackBySSRC(ssrc);
-				storager.stopPlayback(streamInfo);
+				streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
+				redisCatchStorage.stopPlayback(streamInfo);
 			}
 		}
 
@@ -299,17 +282,15 @@
 			logger.debug("ZLM HOOK on_stream_none_reader API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
 		
-		BigInteger bigint=new BigInteger(json.getString("stream"), 16);
-		int numb=bigint.intValue();
-		String ssrc = String.format("%010d", numb); 
-		
-		cmder.streamByeCmd(ssrc);
-		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+		String streamId = json.getString("stream");
+
+		cmder.streamByeCmd(streamId);
+		StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
 		if (streamInfo!=null){
-			storager.stopPlay(streamInfo);
+			redisCatchStorage.stopPlay(streamInfo);
 		}else{
-			streamInfo = storager.queryPlaybackBySSRC(ssrc);
-			storager.stopPlayback(streamInfo);
+			streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
+			redisCatchStorage.stopPlayback(streamInfo);
 		}
 		
 		JSONObject ret = new JSONObject();
@@ -330,7 +311,31 @@
 			logger.debug("ZLM HOOK on_stream_not_found API璋冪敤锛屽弬鏁帮細" + json.toString());
 		}
 		// TODO Auto-generated method stub
-		
+
+		if (autoApplyPlay) {
+			String app = json.getString("app");
+			String streamId = json.getString("stream");
+				StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
+			if ("rtp".equals(app) && streamId.indexOf("gb_play") > -1 && streamInfo == null) {
+				String[] s = streamId.split("_");
+				if (s.length == 4) {
+					String deviceId = s[2];
+					String channelId = s[3];
+					Device device = storager.queryVideoDevice(deviceId);
+					if (device != null) {
+						UUID uuid = UUID.randomUUID();
+						cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
+							logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
+							playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
+						}, null);
+					}
+
+				}
+
+			}
+
+		}
+
 		JSONObject ret = new JSONObject();
 		ret.put("code", 0);
 		ret.put("msg", "success");
@@ -354,7 +359,7 @@
 //		MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0);
 		MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class);
 		mediaServerConfig.setLocalIP(mediaIp);
-		storager.updateMediaInfo(mediaServerConfig);
+		redisCatchStorage.updateMediaInfo(mediaServerConfig);
 		// TODO Auto-generated method stub
 		
 		JSONObject ret = new JSONObject();
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
index 1e38bdc..ac1f51a 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -116,4 +116,8 @@
     public JSONObject openRtpServer(Map<String, Object> param){
         return sendPost("openRtpServer",param);
     }
+
+    public JSONObject closeRtpServer(Map<String, Object> param) {
+        return sendPost("closeRtpServer",param);
+    }
 }
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
new file mode 100644
index 0000000..f69ff0f
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -0,0 +1,95 @@
+package com.genersoft.iot.vmp.media.zlm;
+
+import com.alibaba.fastjson.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class ZLMRTPServerFactory {
+
+    private Logger logger = LoggerFactory.getLogger("ZLMRTPServerFactory");
+
+    @Value("${media.rtp.udpPortRange}")
+    private String udpPortRange;
+
+    @Autowired
+    private ZLMRESTfulUtils zlmresTfulUtils;
+
+    private int[] udpPortRangeArray = new int[2];
+
+    private int currentPort = 0;
+
+    public int createRTPServer(String streamId) {
+        Map<String, Object> param = new HashMap<>();
+        int result = -1;
+        int newPort = getPortFromUdpPortRange();
+        param.put("port", newPort);
+        param.put("enable_tcp", 1);
+        param.put("stream_id", streamId);
+        JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param);
+        System.out.println(jsonObject);
+
+        if (jsonObject != null) {
+            switch (jsonObject.getInteger("code")){
+                case 0:
+                    result= newPort;
+                    break;
+                case -300: // id宸茬粡瀛樺湪
+                    result = newPort;
+                    break;
+                case -400: // 绔彛鍗犵敤
+                    result= createRTPServer(streamId);
+                    break;
+                default:
+                    logger.error("鍒涘缓RTP Server 澶辫触: " + jsonObject.getString("msg"));
+                    break;
+            }
+        }else {
+            //  妫�鏌LM鐘舵��
+            logger.error("鍒涘缓RTP Server 澶辫触: 璇锋鏌LM鏈嶅姟");
+        }
+        return result;
+    }
+
+    public boolean closeRTPServer(String streamId) {
+        boolean result = false;
+        Map<String, Object> param = new HashMap<>();
+        param.put("stream_id", streamId);
+        JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(param);
+        if (jsonObject != null ) {
+            if (jsonObject.getInteger("code") == 0) {
+                result = jsonObject.getInteger("hit") == 1;
+            }else {
+                logger.error("鍏抽棴RTP Server 澶辫触: " + jsonObject.getString("msg"));
+            }
+        }else {
+            //  妫�鏌LM鐘舵��
+            logger.error("鍏抽棴RTP Server 澶辫触: 璇锋鏌LM鏈嶅姟");
+        }
+        return result;
+    }
+
+    private int getPortFromUdpPortRange() {
+        if (currentPort == 0) {
+            String[] udpPortRangeStrArray = udpPortRange.split(",");
+            udpPortRangeArray[0] = Integer.parseInt(udpPortRangeStrArray[0]);
+            udpPortRangeArray[1] = Integer.parseInt(udpPortRangeStrArray[1]);
+        }
+
+        if (currentPort == 0 || currentPort++ > udpPortRangeArray[1]) {
+            currentPort = udpPortRangeArray[0];
+            return udpPortRangeArray[0];
+        } else {
+            if (currentPort % 2 == 1) {
+                currentPort++;
+            }
+            return currentPort++;
+        }
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
index 3f88b2a..282699f 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -4,6 +4,7 @@
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import okhttp3.*;
 import org.slf4j.Logger;
@@ -29,6 +30,9 @@
 
     @Autowired
     private IVideoManagerStorager storager;
+
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
 
     @Value("${media.ip}")
     private String mediaIp;
@@ -69,7 +73,7 @@
             logger.info("zlm鎺ュ叆鎴愬姛...");
             if (autoConfig) saveZLMConfig();
             mediaServerConfig = getMediaServerConfig();
-            storager.updateMediaInfo(mediaServerConfig);
+            redisCatchStorage.updateMediaInfo(mediaServerConfig);
         }
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
deleted file mode 100644
index 8195b65..0000000
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.genersoft.iot.vmp.media.zlm;
-
-import com.alibaba.fastjson.JSONObject;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@Component
-public class ZLMUtils {
-
-    @Value("${media.rtp.udpPortRange}")
-    private String udpPortRange;
-
-    @Autowired
-    private ZLMRESTfulUtils zlmresTfulUtils;
-
-    private int[] udpPortRangeArray = new int[2];
-
-    private int currentPort = 0;
-
-    public int getNewRTPPort(String ssrc) {
-        String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
-        Map<String, Object> param = new HashMap<>();
-        int newPort = getPortFromUdpPortRange();
-        param.put("port", newPort);
-        param.put("enable_tcp", 1);
-        param.put("stream_id", streamId);
-        JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param);
-        if (jsonObject != null && jsonObject.getInteger("code") == 0) {
-            return newPort;
-        } else {
-            return getNewRTPPort(ssrc);
-        }
-    }
-
-    private int getPortFromUdpPortRange() {
-        if (currentPort == 0) {
-            String[] udpPortRangeStrArray = udpPortRange.split(",");
-            udpPortRangeArray[0] = Integer.parseInt(udpPortRangeStrArray[0]);
-            udpPortRangeArray[1] = Integer.parseInt(udpPortRangeStrArray[1]);
-        }
-
-        if (currentPort == 0 || currentPort++ > udpPortRangeArray[1]) {
-            currentPort = udpPortRangeArray[0];
-            return udpPortRangeArray[0];
-        } else {
-            if (currentPort % 2 == 1) {
-                currentPort++;
-            }
-            return currentPort++;
-        }
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
new file mode 100644
index 0000000..8bc78b9
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -0,0 +1,58 @@
+package com.genersoft.iot.vmp.storager;
+
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
+
+import java.util.Map;
+
+public interface IRedisCatchStorage {
+
+    /**
+     * 寮�濮嬫挱鏀炬椂灏嗘祦瀛樺叆
+     *
+     * @param stream 娴佷俊鎭�
+     * @return
+     */
+    boolean startPlay(StreamInfo stream);
+
+
+    /**
+     * 鍋滄鎾斁鏃跺垹闄�
+     *
+     * @return
+     */
+    boolean stopPlay(StreamInfo streamInfo);
+
+    /**
+     * 鏌ヨ鎾斁鍒楄〃
+     * @return
+     */
+    StreamInfo queryPlay(StreamInfo streamInfo);
+
+    StreamInfo queryPlayByStreamId(String steamId);
+
+    StreamInfo queryPlaybackByStreamId(String steamId);
+
+    StreamInfo queryPlayByDevice(String deviceId, String code);
+
+    /**
+     * 鏇存柊娴佸獟浣撲俊鎭�
+     * @param mediaServerConfig
+     * @return
+     */
+    boolean updateMediaInfo(MediaServerConfig mediaServerConfig);
+
+    /**
+     * 鑾峰彇娴佸獟浣撲俊鎭�
+     * @return
+     */
+    MediaServerConfig getMediaInfo();
+
+    Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);
+
+    boolean startPlayback(StreamInfo stream);
+
+    boolean stopPlayback(StreamInfo streamInfo);
+
+    StreamInfo queryPlaybackByDevice(String deviceId, String code);
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
index b58caae..c601f7e 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -1,15 +1,10 @@
 package com.genersoft.iot.vmp.storager;
 
 import java.util.List;
-import java.util.Map;
 
-import com.alibaba.fastjson.JSONObject;
-import com.genersoft.iot.vmp.common.PageResult;
-import com.genersoft.iot.vmp.common.StreamInfo;
-import com.genersoft.iot.vmp.conf.MediaServerConfig;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.github.pagehelper.PageInfo;
 
 /**    
  * @Description:瑙嗛璁惧鏁版嵁瀛樺偍鎺ュ彛
@@ -17,19 +12,6 @@
  * @date:   2020骞�5鏈�6鏃� 涓嬪崍2:14:31     
  */
 public interface IVideoManagerStorager {
-
-	/**
-	 * 鏇存柊娴佸獟浣撲俊鎭�
-	 * @param mediaServerConfig
-	 * @return
-	 */
-	public boolean updateMediaInfo(MediaServerConfig mediaServerConfig);
-
-	/**
-	 * 鑾峰彇娴佸獟浣撲俊鎭�
-	 * @return
-	 */
-	public MediaServerConfig getMediaInfo();
 
 	/**   
 	 * 鏍规嵁璁惧ID鍒ゆ柇璁惧鏄惁瀛樺湪
@@ -79,7 +61,7 @@
 	 * @param count 姣忛〉鏁伴噺
 	 * @return
 	 */
-	public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count);
+	public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count);
 
 	/**
 	 * 鑾峰彇鏌愪釜璁惧鐨勯�氶亾鍒楄〃
@@ -88,6 +70,7 @@
 	 * @return
 	 */
 	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId);
+
 	/**
 	 * 鑾峰彇鏌愪釜璁惧鐨勯�氶亾
 	 * @param deviceId 璁惧ID
@@ -95,21 +78,20 @@
 	 */
 	public DeviceChannel queryChannel(String deviceId, String channelId);
 
-	/**   
+	/**
 	 * 鑾峰彇澶氫釜璁惧
-	 * 
-	 * @param deviceIds 璁惧ID鏁扮粍
+	 * @param page 褰撳墠椤垫暟
+	 * @param count 姣忛〉鏁伴噺
 	 * @return List<Device> 璁惧瀵硅薄鏁扮粍
 	 */
-	public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count);
+	public PageInfo<Device> queryVideoDeviceList(int page, int count);
 
 	/**
 	 * 鑾峰彇澶氫釜璁惧
 	 *
-	 * @param deviceIds 璁惧ID鏁扮粍
 	 * @return List<Device> 璁惧瀵硅薄鏁扮粍
 	 */
-	public List<Device> queryVideoDeviceList(String[] deviceIds);
+	public List<Device> queryVideoDeviceList();
 
 	/**   
 	 * 鍒犻櫎璁惧
@@ -135,27 +117,6 @@
 	 */
 	public boolean outline(String deviceId);
 
-	/**
-	 * 寮�濮嬫挱鏀炬椂灏嗘祦瀛樺叆
-	 *
-	 * @param stream 娴佷俊鎭�
-	 * @return
-	 */
-	public boolean startPlay(StreamInfo stream);
-
-	/**
-	 * 鍋滄鎾斁鏃跺垹闄�
-	 *
-	 * @return
-	 */
-	public boolean stopPlay(StreamInfo streamInfo);
-
-	/**
-	 * 鏌ユ壘瑙嗛娴�
-	 *
-	 * @return
-	 */
-	public StreamInfo queryPlay(StreamInfo streamInfo);
 
 	/**
 	 * 鏌ヨ瀛愯澶�
@@ -166,12 +127,8 @@
 	 * @param count
 	 * @return
 	 */
-    PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count);
+	PageInfo querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count);
 
-	/**
-	 * 鏇存柊缂撳瓨
-	 */
-	public void updateCatch();
 
 	/**
 	 * 娓呯┖閫氶亾
@@ -179,45 +136,4 @@
 	 */
 	void cleanChannelsForDevice(String deviceId);
 
-	StreamInfo queryPlayBySSRC(String ssrc);
-
-	StreamInfo queryPlayByDevice(String deviceId, String code);
-
-	Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);
-
-	boolean startPlayback(StreamInfo streamInfo);
-
-	boolean stopPlayback(StreamInfo streamInfo);
-
-	StreamInfo queryPlaybackByDevice(String deviceId, String channelId);
-
-	StreamInfo queryPlaybackBySSRC(String ssrc);
-
-	/**
-	 * 鏇存柊鎴栨坊鍔犱笂绾у钩鍙�
-	 * @param parentPlatform
-	 */
-	boolean updateParentPlatform(ParentPlatform parentPlatform);
-
-	/**
-	 * 鍒犻櫎涓婄骇骞冲彴
-	 * @param parentPlatform
-	 */
-	boolean deleteParentPlatform(ParentPlatform parentPlatform);
-
-
-	/**
-	 * 鍒嗛〉鑾峰彇涓婄骇骞冲彴
-	 * @param page
-	 * @param count
-	 * @return
-	 */
-	public PageResult<ParentPlatform> queryParentPlatformList(int page, int count);
-
-	/**
-	 * 鑾峰彇涓婄骇骞冲彴
-	 * @param platformGbId
-	 * @return
-	 */
-	public ParentPlatform queryParentPlatById(String platformGbId);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java b/src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java
deleted file mode 100644
index 70bdad7..0000000
--- a/src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.genersoft.iot.vmp.storager;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.stereotype.Component;
-
-import com.genersoft.iot.vmp.conf.VManagerConfig;
-
-/**    
- * @Description:瑙嗛璁惧鏁版嵁瀛樺偍宸ュ巶锛屾牴鎹瓨鍌ㄧ瓥鐣ワ紝杩斿洖瀵瑰簲鐨勫瓨鍌ㄥ櫒
- * @author: swwheihei
- * @date:   2020骞�5鏈�6鏃� 涓嬪崍2:15:16     
- */
-@Component
-public class VideoManagerStoragerFactory {
-	
-	@Autowired
-	private VManagerConfig vmConfig;
-
-	@Autowired
-	private IVideoManagerStorager jdbcStorager;
-	
-	@Autowired
-	private IVideoManagerStorager redisStorager;
-	
-	@Bean("storager")
-	public IVideoManagerStorager getStorager() {
-		if ("redis".equals(vmConfig.getDatabase().toLowerCase())) {
-			return redisStorager;
-		} else  if ("jdbc".equals(vmConfig.getDatabase().toLowerCase())) {
-			return jdbcStorager;
-		}
-		return redisStorager;
-	}
-	
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java b/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java
deleted file mode 100644
index c96e4bb..0000000
--- a/src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.genersoft.iot.vmp.storager;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.CommandLineRunner;
-import org.springframework.stereotype.Component;
-
-@Component
-public class VodeoMannagerTask implements CommandLineRunner {
-
-    @Autowired
-    private IVideoManagerStorager storager;
-
-    @Override
-    public void run(String... strings) throws Exception {
-        storager.updateCatch();
-    }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
new file mode 100644
index 0000000..eecc0bb
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -0,0 +1,51 @@
+package com.genersoft.iot.vmp.storager.dao;
+
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * 鐢ㄤ簬瀛樺偍璁惧閫氶亾淇℃伅
+ */
+@Mapper
+public interface DeviceChannelMapper {
+
+    @Insert("INSERT INTO device_channel (channelId, deviceId, name, manufacture, model, owner, civilCode, block, " +
+            "address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
+            "ipAddress, port, password, PTZType, status) " +
+            "VALUES ('${channelId}', '${deviceId}', '${name}', '${manufacture}', '${model}', '${owner}', '${civilCode}', '${block}'," +
+            "'${address}', ${parental}, '${parentId}', ${safetyWay}, ${registerWay}, '${certNum}', ${certifiable}, ${errCode}, '${secrecy}', " +
+            "'${ipAddress}', ${port}, '${password}', ${PTZType}, ${status})")
+    int add(DeviceChannel channel);
+
+    @Update("UPDATE device_channel " +
+            "SET name=#{name}, manufacture=#{manufacture}, model=#{model}, owner=#{owner}, civilCode=#{civilCode}, " +
+            "block=#{block}, address=#{address}, parental=#{parental}, parentId=#{parentId}, safetyWay=#{safetyWay}, " +
+            "registerWay=#{registerWay}, certNum=#{certNum}, certifiable=#{certifiable}, errCode=#{errCode}, secrecy=#{secrecy}, " +
+            "ipAddress=#{ipAddress}, port=#{port}, password=#{password}, PTZType=#{PTZType}, status=#{status}, streamId=#{streamId}, " +
+            "hasAudio=#{hasAudio}" +
+            "WHERE deviceId=#{deviceId} AND channelId=#{channelId}")
+    int update(DeviceChannel channel);
+
+    @Select(value = {" <script>" +
+            "SELECT * FROM ( "+
+            " SELECT * , (SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount FROM device_channel dc " +
+            " WHERE dc.deviceId=#{deviceId} " +
+            " <if test=\"query != null\"> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
+            " <if test=\"parentChannelId != null\"> AND dc.parentId=#{parentChannelId} </if> " +
+            " <if test=\"online == true\" > AND dc.status=1</if>" +
+            " <if test=\"online == false\" > AND dc.status=0</if>) dcr" +
+            " WHERE 1=1 " +
+            " <if test=\"hasSubChannel == true\" >  AND subCount >0</if>" +
+            " <if test=\"hasSubChannel == false\" >  AND subCount=0</if>" +
+            " </script>"})
+    List<DeviceChannel> queryChannelsByDeviceId(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online);
+
+    @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}")
+    DeviceChannel queryChannel(String deviceId, String channelId);
+
+    @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}")
+    int cleanChannelsByDeviceId(String deviceId);
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
new file mode 100644
index 0000000..3c10618
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
@@ -0,0 +1,66 @@
+package com.genersoft.iot.vmp.storager.dao;
+
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import org.apache.ibatis.annotations.*;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 鐢ㄤ簬瀛樺偍璁惧淇℃伅
+ */
+@Mapper
+@Repository
+public interface DeviceMapper {
+
+    @Select("SELECT * FROM device WHERE deviceId = #{deviceId}")
+    Device getDeviceByDeviceId(String deviceId);
+
+    @Insert("INSERT INTO device (" +
+                "deviceId, " +
+                "name, " +
+                "manufacturer, " +
+                "model, " +
+                "firmware, " +
+                "transport," +
+                "streamMode," +
+                "ip," +
+                "port," +
+                "hostAddress," +
+                "online" +
+            ") VALUES (" +
+                "#{deviceId}," +
+                "#{name}," +
+                "#{manufacturer}," +
+                "#{model}," +
+                "#{firmware}," +
+                "#{transport}," +
+                "#{streamMode}," +
+                "#{ip}," +
+                "#{port}," +
+                "#{hostAddress}," +
+                "#{online}" +
+            ")")
+    int add(Device device);
+
+
+    @Update("UPDATE device " +
+            "SET name=#{name}, " +
+            "manufacturer=#{manufacturer}," +
+            "model=#{model}," +
+            "firmware=#{firmware}, " +
+            "transport=#{transport}," +
+            "streamMode=#{streamMode}, " +
+            "ip=#{ip}, " +
+            "port=#{port}, " +
+            "hostAddress=#{hostAddress}, " +
+            "online=#{online} " +
+            "WHERE deviceId=#{deviceId}")
+    int update(Device device);
+
+    @Select("SELECT *, (SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount  FROM device de")
+    List<Device> getDevices();
+
+    @Delete("DELETE FROM device WHERE deviceId=#{deviceId}")
+    int del(String deviceId);
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
new file mode 100644
index 0000000..cebb30b
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -0,0 +1,166 @@
+package com.genersoft.iot.vmp.storager.impl;
+
+import com.genersoft.iot.vmp.common.StreamInfo;
+import com.genersoft.iot.vmp.common.VideoManagerConstants;
+import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
+import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
+import com.genersoft.iot.vmp.utils.redis.RedisUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+@Component
+public class RedisCatchStorageImpl implements IRedisCatchStorage {
+
+    @Autowired
+	private RedisUtil redis;
+
+    @Autowired
+    private DeviceChannelMapper deviceChannelMapper;
+
+
+    /**
+     * 寮�濮嬫挱鏀炬椂灏嗘祦瀛樺叆redis
+     *
+     * @return
+     */
+    @Override
+    public boolean startPlay(StreamInfo stream) {
+        return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()),
+                stream);
+    }
+
+    /**
+     * 鍋滄鎾斁鏃朵粠redis鍒犻櫎
+     *
+     * @return
+     */
+    @Override
+    public boolean stopPlay(StreamInfo streamInfo) {
+        if (streamInfo == null) return false;
+        DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
+        if (deviceChannel != null) {
+            deviceChannel.setStreamId(null);
+            deviceChannel.setDeviceId(streamInfo.getDeviceID());
+            deviceChannelMapper.update(deviceChannel);
+        }
+        return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
+                streamInfo.getStreamId(),
+                streamInfo.getDeviceID(),
+                streamInfo.getCahnnelId()));
+    }
+
+    /**
+     * 鏌ヨ鎾斁鍒楄〃
+     * @return
+     */
+    @Override
+    public StreamInfo queryPlay(StreamInfo streamInfo) {
+        return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
+                VideoManagerConstants.PLAYER_PREFIX,
+                streamInfo.getStreamId(),
+                streamInfo.getDeviceID(),
+                streamInfo.getCahnnelId()));
+    }
+    @Override
+    public StreamInfo queryPlayByStreamId(String steamId) {
+        List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, steamId));
+        if (playLeys == null || playLeys.size() == 0) return null;
+        return (StreamInfo)redis.get(playLeys.get(0).toString());
+    }
+
+    @Override
+    public StreamInfo queryPlaybackByStreamId(String steamId) {
+        List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, steamId));
+        if (playLeys == null || playLeys.size() == 0) return null;
+        return (StreamInfo)redis.get(playLeys.get(0).toString());
+    }
+
+    @Override
+    public StreamInfo queryPlayByDevice(String deviceId, String code) {
+//		List<Object> playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
+        List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
+                deviceId,
+                code));
+        if (playLeys == null || playLeys.size() == 0) return null;
+        return (StreamInfo)redis.get(playLeys.get(0).toString());
+    }
+
+    /**
+     * 鏇存柊娴佸獟浣撲俊鎭�
+     * @param mediaServerConfig
+     * @return
+     */
+    @Override
+    public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
+        return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig);
+    }
+
+    /**
+     * 鑾峰彇娴佸獟浣撲俊鎭�
+     * @return
+     */
+    @Override
+    public MediaServerConfig getMediaInfo() {
+        return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
+    }
+
+    @Override
+    public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {
+        Map<String, StreamInfo> streamInfos = new HashMap<>();
+//		List<Object> playLeys = redis.keys(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
+        List<Object> players = redis.scan(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
+        if (players.size() == 0) return streamInfos;
+        for (int i = 0; i < players.size(); i++) {
+            String key = (String) players.get(i);
+            StreamInfo streamInfo = (StreamInfo)redis.get(key);
+            streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getCahnnelId(), streamInfo);
+        }
+        return streamInfos;
+    }
+
+
+    @Override
+    public boolean startPlayback(StreamInfo stream) {
+        return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()),
+                stream);
+    }
+
+
+    @Override
+    public boolean stopPlayback(StreamInfo streamInfo) {
+        if (streamInfo == null) return false;
+        DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
+        if (deviceChannel != null) {
+            deviceChannel.setStreamId(null);
+            deviceChannel.setDeviceId(streamInfo.getDeviceID());
+            deviceChannelMapper.update(deviceChannel);
+        }
+        return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
+                streamInfo.getStreamId(),
+                streamInfo.getDeviceID(),
+                streamInfo.getCahnnelId()));
+    }
+
+    @Override
+    public StreamInfo queryPlaybackByDevice(String deviceId, String code) {
+        String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
+                deviceId,
+                code);
+        List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
+                deviceId,
+                code));
+        if (playLeys == null || playLeys.size() == 0) {
+            playLeys = redis.scan(String.format("%S_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
+                    deviceId));
+        }
+        if (playLeys == null || playLeys.size() == 0) return null;
+        return (StreamInfo)redis.get(playLeys.get(0).toString());
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
new file mode 100644
index 0000000..01ed247
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
@@ -0,0 +1,202 @@
+package com.genersoft.iot.vmp.storager.impl;
+
+import java.util.*;
+
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
+import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.models.auth.In;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import org.springframework.util.StringUtils;
+
+/**    
+ * @Description:瑙嗛璁惧鏁版嵁瀛樺偍-jdbc瀹炵幇
+ * @author: swwheihei
+ * @date:   2020骞�5鏈�6鏃� 涓嬪崍2:31:42
+ */
+@Component
+public class VideoManagerStoragerImpl implements IVideoManagerStorager {
+
+	@Autowired
+    private DeviceMapper deviceMapper;
+
+	@Autowired
+    private DeviceChannelMapper deviceChannelMapper;
+
+
+	/**
+	 * 鏍规嵁璁惧ID鍒ゆ柇璁惧鏄惁瀛樺湪
+	 *
+	 * @param deviceId 璁惧ID
+	 * @return true:瀛樺湪  false锛氫笉瀛樺湪
+	 */
+	@Override
+	public boolean exists(String deviceId) {
+		return deviceMapper.getDeviceByDeviceId(deviceId) != null;
+	}
+
+	/**
+	 * 瑙嗛璁惧鍒涘缓
+	 *
+	 * @param device 璁惧瀵硅薄
+	 * @return true锛氬垱寤烘垚鍔�  false锛氬垱寤哄け璐�
+	 */
+	@Override
+	public synchronized boolean create(Device device) {
+		return deviceMapper.add(device) > 0;
+	}
+
+
+
+	/**
+	 * 瑙嗛璁惧鏇存柊
+	 *
+	 * @param device 璁惧瀵硅薄
+	 * @return true锛氭洿鏂版垚鍔�  false锛氭洿鏂板け璐�
+	 */
+	@Override
+	public synchronized boolean updateDevice(Device device) {
+		Device deviceByDeviceId = deviceMapper.getDeviceByDeviceId(device.getDeviceId());
+		if (deviceByDeviceId == null) {
+			return deviceMapper.add(device) > 0;
+		}else {
+			return deviceMapper.update(device) > 0;
+		}
+
+	}
+
+	@Override
+	public synchronized void updateChannel(String deviceId, DeviceChannel channel) {
+		String channelId = channel.getChannelId();
+		channel.setDeviceId(deviceId);
+		DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
+		if (deviceChannel == null) {
+			deviceChannelMapper.add(channel);
+		}else {
+			deviceChannelMapper.update(channel);
+		}
+	}
+
+	/**
+	 * 鑾峰彇璁惧
+	 *
+	 * @param deviceId 璁惧ID
+	 * @return Device 璁惧瀵硅薄
+	 */
+	@Override
+	public Device queryVideoDevice(String deviceId) {
+		return deviceMapper.getDeviceByDeviceId(deviceId);
+	}
+
+	@Override
+	public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count) {
+		// 鑾峰彇鍒版墍鏈夋鍦ㄦ挱鏀剧殑娴�
+		PageHelper.startPage(page, count);
+		List<DeviceChannel> all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, null, query, hasSubChannel, online);
+		return new PageInfo<>(all);
+	}
+
+
+
+	@Override
+	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
+		return deviceChannelMapper.queryChannelsByDeviceId(deviceId, null,null, null, null);
+	}
+
+	@Override
+	public PageInfo<DeviceChannel> querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) {
+		PageHelper.startPage(page, count);
+		List<DeviceChannel> all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, parentChannelId, null, null, null);
+		return new PageInfo<>(all);
+	}
+
+	@Override
+	public DeviceChannel queryChannel(String deviceId, String channelId) {
+		return deviceChannelMapper.queryChannel(deviceId, channelId);
+	}
+
+
+	/**
+	 * 鑾峰彇澶氫釜璁惧
+	 *
+	 * @param page 褰撳墠椤垫暟
+	 * @param count 姣忛〉鏁伴噺
+	 * @return PageInfo<Device> 鍒嗛〉璁惧瀵硅薄鏁扮粍
+	 */
+	@Override
+	public PageInfo<Device> queryVideoDeviceList(int page, int count) {
+		PageHelper.startPage(page, count);
+		List<Device> all = deviceMapper.getDevices();
+		return new PageInfo<>(all);
+	}
+
+	/**
+	 * 鑾峰彇澶氫釜璁惧
+	 *
+	 * @return List<Device> 璁惧瀵硅薄鏁扮粍
+	 */
+	@Override
+	public List<Device> queryVideoDeviceList() {
+
+		List<Device> deviceList =  deviceMapper.getDevices();
+		return deviceList;
+	}
+
+	/**
+	 * 鍒犻櫎璁惧
+	 *
+	 * @param deviceId 璁惧ID
+	 * @return true锛氬垹闄ゆ垚鍔�  false锛氬垹闄ゅけ璐�
+	 */
+	@Override
+	public boolean delete(String deviceId) {
+		int result = deviceMapper.del(deviceId);
+
+		return result > 0;
+	}
+
+	/**
+	 * 鏇存柊璁惧鍦ㄧ嚎
+	 *
+	 * @param deviceId 璁惧ID
+	 * @return true锛氭洿鏂版垚鍔�  false锛氭洿鏂板け璐�
+	 */
+	@Override
+	public synchronized boolean online(String deviceId) {
+		Device device = deviceMapper.getDeviceByDeviceId(deviceId);
+		device.setOnline(1);
+		System.out.println("鏇存柊璁惧鍦ㄧ嚎");
+		if (device == null) {
+			return false;
+		}
+		return deviceMapper.update(device) > 0;
+	}
+
+	/**
+	 * 鏇存柊璁惧绂荤嚎
+	 *
+	 * @param deviceId 璁惧ID
+	 * @return true锛氭洿鏂版垚鍔�  false锛氭洿鏂板け璐�
+	 */
+	@Override
+	public synchronized boolean outline(String deviceId) {
+		Device device = deviceMapper.getDeviceByDeviceId(deviceId);
+		device.setOnline(0);
+		System.out.println("鏇存柊璁惧绂荤嚎");
+		return deviceMapper.update(device) > 0;
+	}
+
+
+	@Override
+	public void cleanChannelsForDevice(String deviceId) {
+		int result = deviceChannelMapper.cleanChannelsByDeviceId(deviceId);
+	}
+
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
deleted file mode 100644
index 5e8ba1a..0000000
--- a/src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
+++ /dev/null
@@ -1,237 +0,0 @@
-package com.genersoft.iot.vmp.storager.jdbc;
-
-import java.util.List;
-import java.util.Map;
-
-import com.genersoft.iot.vmp.common.PageResult;
-import com.genersoft.iot.vmp.common.StreamInfo;
-import com.genersoft.iot.vmp.conf.MediaServerConfig;
-import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
-import org.springframework.stereotype.Component;
-import org.springframework.stereotype.Service;
-
-import com.genersoft.iot.vmp.common.VideoManagerConstants;
-import com.genersoft.iot.vmp.gb28181.bean.Device;
-import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
-
-/**    
- * @Description:瑙嗛璁惧鏁版嵁瀛樺偍-jdbc瀹炵幇  
- * @author: swwheihei
- * @date:   2020骞�5鏈�6鏃� 涓嬪崍2:28:12     
- */
-@Component("jdbcStorager")
-public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
-
-	@Override
-	public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
-		return false;
-	}
-
-	@Override
-	public MediaServerConfig getMediaInfo() {
-		return null;
-	}
-
-	/**
-	 * 鏍规嵁璁惧ID鍒ゆ柇璁惧鏄惁瀛樺湪
-	 * 
-	 * @param deviceId 璁惧ID
-	 * @return true:瀛樺湪  false锛氫笉瀛樺湪
-	 */ 
-	@Override
-	public boolean exists(String deviceId) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	/**   
-	 * 瑙嗛璁惧鍒涘缓
-	 * 
-	 * @param device 璁惧瀵硅薄
-	 * @return true锛氬垱寤烘垚鍔�  false锛氬垱寤哄け璐�
-	 */ 
-	@Override
-	public boolean create(Device device) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	@Override
-	public boolean updateDevice(Device device) {
-		return false;
-	}
-
-	@Override
-	public void updateChannel(String deviceId, DeviceChannel channel) {
-
-	}
-
-
-	/**   
-	 * 鑾峰彇璁惧
-	 * 
-	 * @param deviceId 璁惧ID
-	 * @return Device 璁惧瀵硅薄
-	 */  
-	@Override
-	public Device queryVideoDevice(String deviceId) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	@Override
-	public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) {
-		return null;
-	}
-
-
-	@Override
-	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
-		return null;
-	}
-
-	@Override
-	public DeviceChannel queryChannel(String deviceId, String channelId) {
-		return null;
-	}
-
-	@Override
-	public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count) {
-		return null;
-	}
-
-	/**   
-	 * 鑾峰彇澶氫釜璁惧
-	 * 
-	 * @param deviceIds 璁惧ID鏁扮粍
-	 * @return List<Device> 璁惧瀵硅薄鏁扮粍
-	 */  
-	@Override
-	public List<Device> queryVideoDeviceList(String[] deviceIds) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	/**   
-	 * 鍒犻櫎璁惧
-	 * 
-	 * @param deviceId 璁惧ID
-	 * @return true锛氬垹闄ゆ垚鍔�  false锛氬垹闄ゅけ璐�
-	 */  
-	@Override
-	public boolean delete(String deviceId) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	/**   
-	 * 鏇存柊璁惧鍦ㄧ嚎
-	 * 
-	 * @param deviceId 璁惧ID
-	 * @return true锛氭洿鏂版垚鍔�  false锛氭洿鏂板け璐�
-	 */ 
-	@Override
-	public boolean online(String deviceId) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	/**   
-	 * 鏇存柊璁惧绂荤嚎
-	 * 
-	 * @param deviceId 璁惧ID
-	 * @return true锛氭洿鏂版垚鍔�  false锛氭洿鏂板け璐�
-	 */ 
-	@Override
-	public boolean outline(String deviceId) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-	@Override
-	public boolean stopPlay(StreamInfo streamInfo) {
-		return false;
-	}
-
-	@Override
-	public StreamInfo queryPlay(StreamInfo streamInfo) {
-		return null;
-	}
-
-	@Override
-	public PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count) {
-		return null;
-	}
-
-	@Override
-	public void updateCatch() {
-		System.out.println("##################");
-	}
-
-	@Override
-	public void cleanChannelsForDevice(String deviceId) {
-
-	}
-
-	@Override
-	public boolean startPlay(StreamInfo stream) {
-		return false;
-	}
-
-	@Override
-	public StreamInfo queryPlayBySSRC(String ssrc) {
-		return null;
-	}
-
-	@Override
-	public StreamInfo queryPlayByDevice(String deviceId, String code) {
-		return null;
-	}
-
-	@Override
-	public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {
-
-		return null;
-	}
-
-	@Override
-	public boolean startPlayback(StreamInfo streamInfo) {
-		return false;
-	}
-
-	@Override
-	public boolean stopPlayback(StreamInfo streamInfo) {
-		return false;
-	}
-
-	@Override
-	public StreamInfo queryPlaybackByDevice(String deviceId, String channelId) {
-		return null;
-	}
-
-	@Override
-	public StreamInfo queryPlaybackBySSRC(String ssrc) {
-		return null;
-	}
-
-	@Override
-	public boolean updateParentPlatform(ParentPlatform parentPlatform) {
-		return false;
-	}
-
-	@Override
-	public boolean deleteParentPlatform(ParentPlatform parentPlatform) {
-		return false;
-	}
-
-	@Override
-	public PageResult<ParentPlatform> queryParentPlatformList(int page, int count) {
-		return null;
-	}
-
-	@Override
-	public ParentPlatform queryParentPlatById(String platformGbId) {
-		return null;
-	}
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
deleted file mode 100644
index 99c7f06..0000000
--- a/src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
+++ /dev/null
@@ -1,600 +0,0 @@
-package com.genersoft.iot.vmp.storager.redis;
-
-import java.util.*;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.genersoft.iot.vmp.common.PageResult;
-import com.genersoft.iot.vmp.common.StreamInfo;
-import com.genersoft.iot.vmp.conf.MediaServerConfig;
-import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import com.genersoft.iot.vmp.common.VideoManagerConstants;
-import com.genersoft.iot.vmp.gb28181.bean.Device;
-import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
-import com.genersoft.iot.vmp.utils.redis.RedisUtil;
-import org.springframework.util.StringUtils;
-
-/**    
- * @Description:瑙嗛璁惧鏁版嵁瀛樺偍-redis瀹炵幇
- * @author: swwheihei
- * @date:   2020骞�5鏈�6鏃� 涓嬪崍2:31:42
- */
-@Component("redisStorager")
-public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
-
-	@Autowired
-    private RedisUtil redis;
-
-	private HashMap<String, HashMap<String, HashSet<String>>> deviceMap = new HashMap<>();
-
-
-	/**
-	 * 鏍规嵁璁惧ID鍒ゆ柇璁惧鏄惁瀛樺湪
-	 *
-	 * @param deviceId 璁惧ID
-	 * @return true:瀛樺湪  false锛氫笉瀛樺湪
-	 */
-	@Override
-	public boolean exists(String deviceId) {
-		return redis.hasKey(VideoManagerConstants.DEVICE_PREFIX+deviceId);
-	}
-
-	/**
-	 * 瑙嗛璁惧鍒涘缓
-	 *
-	 * @param device 璁惧瀵硅薄
-	 * @return true锛氬垱寤烘垚鍔�  false锛氬垱寤哄け璐�
-	 */
-	@Override
-	public boolean create(Device device) {
-		return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
-	}
-
-
-
-	/**
-	 * 瑙嗛璁惧鏇存柊
-	 *
-	 * @param device 璁惧瀵硅薄
-	 * @return true锛氭洿鏂版垚鍔�  false锛氭洿鏂板け璐�
-	 */
-	@Override
-	public boolean updateDevice(Device device) {
-		if (deviceMap.get(device.getDeviceId()) == null) {
-			deviceMap.put(device.getDeviceId(), new HashMap<String, HashSet<String>>());
-		}
-		// 鏇存柊device涓殑閫氶亾鏁伴噺
-		device.setChannelCount(deviceMap.get(device.getDeviceId()).size());
-		// 瀛樺偍device
-		return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
-
-
-	}
-
-	@Override
-	public void updateChannel(String deviceId, DeviceChannel channel) {
-		String channelId = channel.getChannelId();
-		HashMap<String, HashSet<String>> channelMap = deviceMap.get(deviceId);
-		if (channelMap == null) return;
-		// 浣滀负鐖惰澶�, 纭畾鑷繁鐨勫瓙鑺傜偣鏁�
-		if (channelMap.get(channelId) == null) {
-			channelMap.put(channelId, new HashSet<String>());
-		}else if (channelMap.get(channelId).size() > 0) {
-			channel.setSubCount(channelMap.get(channelId).size());
-		}
-
-		// 瀛樺偍閫氶亾
-		redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
-						"_" + channel.getChannelId() +
-						"_" + (channel.getStatus() == 1 ? "on":"off") +
-						"_" + (channelMap.get(channelId).size() > 0)+
-						"_" + (StringUtils.isEmpty(channel.getParentId())?null:channel.getParentId()),
-				channel);
-		// 鏇存柊device涓殑閫氶亾鏁伴噺
-		Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
-		device.setChannelCount(deviceMap.get(deviceId).size());
-		redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
-
-
-		// 濡傛灉鏈夌埗璁惧,鏇存柊鐖惰澶囧唴瀛愯妭鐐规暟
-		String parentId = channel.getParentId();
-		if (!StringUtils.isEmpty(parentId) && !parentId.equals(deviceId)) {
-
-			if (channelMap.get(parentId) == null) {
-				channelMap.put(parentId, new HashSet<String>());
-			}
-			channelMap.get(parentId).add(channelId);
-
-			DeviceChannel deviceChannel = queryChannel(deviceId, parentId);
-			if (deviceChannel != null) {
-				deviceChannel.setSubCount(channelMap.get(parentId).size());
-				redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
-								"_" + deviceChannel.getChannelId() +
-								"_" + (deviceChannel.getStatus() == 1 ? "on":"off") +
-								"_" + (channelMap.get(deviceChannel.getChannelId()).size() > 0)+
-								"_" + (StringUtils.isEmpty(deviceChannel.getParentId())?null:deviceChannel.getParentId()),
-						deviceChannel);
-
-			}
-		}
-
-	}
-
-	/**
-	 * 鑾峰彇璁惧
-	 *
-	 * @param deviceId 璁惧ID
-	 * @return Device 璁惧瀵硅薄
-	 */
-	@Override
-	public Device queryVideoDevice(String deviceId) {
-		return (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
-	}
-
-	@Override
-	public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) {
-		// 鑾峰彇鍒版墍鏈夋鍦ㄦ挱鏀剧殑娴�
-		Map<String, StreamInfo> stringStreamInfoMap = queryPlayByDeviceId(deviceId);
-		List<DeviceChannel> result = new ArrayList<>();
-		PageResult pageResult = new PageResult<DeviceChannel>();
-		String queryContent = "*";
-		if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query);
-		String queryHasSubChannel = "*";
-		if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false";
-		String queryOnline = "*";
-		if (!StringUtils.isEmpty(online)) queryOnline = online;
-		String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
-				"_" + queryContent + // 鎼滅储缂栧彿鍜屽悕绉�
-				"_" + queryOnline + // 鎼滅储鏄惁鍦ㄧ嚎
-				"_" + queryHasSubChannel + // 鎼滅储鏄惁鍚湁瀛愯妭鐐�
-				"_" + "*";
-//		List<Object> deviceChannelList = redis.keys(queryStr);
-		List<Object> deviceChannelList = redis.scan(queryStr);
-		//瀵规煡璇㈢粨鏋滄帓搴忥紝閬垮厤鍑虹幇閫氶亾鎺掑垪椤哄簭涔卞簭鐨勬儏鍐�
-		Collections.sort(deviceChannelList,new Comparator<Object>(){
-			@Override
-			public int compare(Object o1, Object o2) {
-				return o1.toString().compareToIgnoreCase(o2.toString());
-			}
-		});
-		pageResult.setPage(page);
-		pageResult.setCount(count);
-		pageResult.setTotal(deviceChannelList.size());
-		int maxCount = (page + 1 ) * count;
-		if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
-			for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) {
-				DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i));
-				StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId());
-				deviceChannel.setPlay(streamInfo != null);
-				if (streamInfo != null) deviceChannel.setSsrc(streamInfo.getSsrc());
-				result.add(deviceChannel);
-			}
-			pageResult.setData(result);
-		}
-
-		return pageResult;
-	}
-
-
-
-	@Override
-	public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
-		List<DeviceChannel> result = new ArrayList<>();
-//		List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
-		List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
-
-		if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
-			for (int i = 0; i < deviceChannelList.size(); i++) {
-				result.add((DeviceChannel)redis.get((String) deviceChannelList.get(i)));
-			}
-		}
-		return result;
-	}
-
-	@Override
-	public PageResult querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) {
-		List<DeviceChannel> allDeviceChannels = new ArrayList<>();
-		String queryContent = "*";
-		if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query);
-		String queryHasSubChannel = "*";
-		if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false";
-		String queryOnline = "*";
-		if (!StringUtils.isEmpty(online)) queryOnline = online;
-		String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
-				"_" + queryContent + // 鎼滅储缂栧彿鍜屽悕绉�
-				"_" + queryOnline + // 鎼滅储鏄惁鍦ㄧ嚎
-				"_" + queryHasSubChannel + // 鎼滅储鏄惁鍚湁瀛愯妭鐐�
-				"_" + parentChannelId;
-
-//		List<Object> deviceChannelList = redis.keys(queryStr);
-		List<Object> deviceChannelList = redis.scan(queryStr);
-
-		if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
-			for (int i = 0; i < deviceChannelList.size(); i++) {
-				DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i));
-				if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) {
-					allDeviceChannels.add(deviceChannel);
-				}
-			}
-		}
-		int maxCount = (page + 1 ) * count;
-		PageResult pageResult = new PageResult<DeviceChannel>();
-		pageResult.setPage(page);
-		pageResult.setCount(count);
-		pageResult.setTotal(allDeviceChannels.size());
-
-		if (allDeviceChannels.size() > 0) {
-			pageResult.setData(allDeviceChannels.subList(
-					page * count, pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal()
-			));
-		}
-		return pageResult;
-	}
-
-	public List<DeviceChannel> querySubChannels(String deviceId, String parentChannelId) {
-		List<DeviceChannel> allDeviceChannels = new ArrayList<>();
-//		List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
-		List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
-
-		if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
-			for (int i = 0; i < deviceChannelList.size(); i++) {
-				DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i));
-				if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) {
-					allDeviceChannels.add(deviceChannel);
-				}
-			}
-		}
-
-		return allDeviceChannels;
-	}
-
-	@Override
-	public DeviceChannel queryChannel(String deviceId, String channelId) {
-		DeviceChannel deviceChannel = null;
-//		List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
-		List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
-				"_" + channelId  + "*");
-		if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
-			deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(0));
-		}
-		return deviceChannel;
-	}
-
-
-	/**
-	 * 鑾峰彇澶氫釜璁惧
-	 *
-	 * @param deviceIds 璁惧ID鏁扮粍
-	 * @return List<Device> 璁惧瀵硅薄鏁扮粍
-	 */
-	@Override
-	public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count) {
-		List<Device> devices = new ArrayList<>();
-		PageResult pageResult = new PageResult<Device>();
-		pageResult.setPage(page);
-		pageResult.setCount(count);
-		Device device = null;
-
-		if (deviceIds == null || deviceIds.length == 0) {
-
-//			List<Object> deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*");
-			List<Object> deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*");
-			pageResult.setTotal(deviceIdList.size());
-			int maxCount = (page + 1)* count;
-			for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) {
-				// devices.add((Device)redis.get((String)deviceIdList.get(i)));
-				device =(Device)redis.get((String)deviceIdList.get(i));
-				if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){
-					// outline(device.getDeviceId());
-				}
-				devices.add(device);
-			}
-		} else {
-			for (int i = 0; i < deviceIds.length; i++) {
-				// devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]));
-				device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]);
-				if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){
-					// outline(device.getDeviceId());
-				}
-				devices.add(device);
-			}
-		}
-		pageResult.setData(devices);
-		return pageResult;
-	}
-
-	/**
-	 * 鑾峰彇澶氫釜璁惧
-	 *
-	 * @param deviceIds 璁惧ID鏁扮粍
-	 * @return List<Device> 璁惧瀵硅薄鏁扮粍
-	 */
-	@Override
-	public List<Device> queryVideoDeviceList(String[] deviceIds) {
-		List<Device> devices = new ArrayList<>();
-		Device device = null;
-
-		if (deviceIds == null || deviceIds.length == 0) {
-//			List<Object> deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*");
-			List<Object> deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*");
-			for (int i = 0; i < deviceIdList.size(); i++) {
-				device =(Device)redis.get((String)deviceIdList.get(i));
-				if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){
-					outline(device.getDeviceId());
-				}
-				devices.add(device);
-			}
-		} else {
-			for (int i = 0; i < deviceIds.length; i++) {
-				device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]);
-				if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){
-					outline(device.getDeviceId());
-				}
-				devices.add(device);
-			}
-		}
-		return devices;
-	}
-
-	/**
-	 * 鍒犻櫎璁惧
-	 *
-	 * @param deviceId 璁惧ID
-	 * @return true锛氬垹闄ゆ垚鍔�  false锛氬垹闄ゅけ璐�
-	 */
-	@Override
-	public boolean delete(String deviceId) {
-		return redis.del(VideoManagerConstants.DEVICE_PREFIX+deviceId);
-	}
-
-	/**
-	 * 鏇存柊璁惧鍦ㄧ嚎
-	 *
-	 * @param deviceId 璁惧ID
-	 * @return true锛氭洿鏂版垚鍔�  false锛氭洿鏂板け璐�
-	 */
-	@Override
-	public boolean online(String deviceId) {
-		Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
-		device.setOnline(1);
-		return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
-	}
-
-	/**
-	 * 鏇存柊璁惧绂荤嚎
-	 *
-	 * @param deviceId 璁惧ID
-	 * @return true锛氭洿鏂版垚鍔�  false锛氭洿鏂板け璐�
-	 */
-	@Override
-	public boolean outline(String deviceId) {
-		Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
-		if (device == null) return false;
-		device.setOnline(0);
-		return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
-	}
-
-	/**
-	 * 寮�濮嬫挱鏀炬椂灏嗘祦瀛樺叆redis
-	 *
-	 * @return
-	 */
-	@Override
-	public boolean startPlay(StreamInfo stream) {
-		return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
-				stream);
-	}
-
-	/**
-	 * 鍋滄鎾斁鏃朵粠redis鍒犻櫎
-	 *
-	 * @return
-	 */
-	@Override
-	public boolean stopPlay(StreamInfo streamInfo) {
-		if (streamInfo == null) return false;
-		DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
-		if (deviceChannel != null) {
-			deviceChannel.setSsrc(null);
-			deviceChannel.setPlay(false);
-			updateChannel(streamInfo.getDeviceID(), deviceChannel);
-		}
-		return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
-				streamInfo.getSsrc(),
-				streamInfo.getDeviceID(),
-				streamInfo.getCahnnelId()));
-	}
-
-	/**
-	 * 鏌ヨ鎾斁鍒楄〃
-	 * @return
-	 */
-	@Override
-	public StreamInfo queryPlay(StreamInfo streamInfo) {
-		return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
-				VideoManagerConstants.PLAYER_PREFIX,
-				streamInfo.getSsrc(),
-				streamInfo.getDeviceID(),
-				streamInfo.getCahnnelId()));
-	}
-	@Override
-	public StreamInfo queryPlayBySSRC(String ssrc) {
-//		List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
-		List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
-		if (playLeys == null || playLeys.size() == 0) return null;
-		return (StreamInfo)redis.get(playLeys.get(0).toString());
-	}
-
-	@Override
-	public StreamInfo queryPlaybackBySSRC(String ssrc) {
-//		List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
-		List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, ssrc));
-		if (playLeys == null || playLeys.size() == 0) return null;
-		return (StreamInfo)redis.get(playLeys.get(0).toString());
-	}
-
-	@Override
-	public StreamInfo queryPlayByDevice(String deviceId, String code) {
-//		List<Object> playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
-		List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
-				deviceId,
-				code));
-		if (playLeys == null || playLeys.size() == 0) return null;
-		return (StreamInfo)redis.get(playLeys.get(0).toString());
-	}
-
-	/**
-	 * 鏇存柊娴佸獟浣撲俊鎭�
-	 * @param mediaServerConfig
-	 * @return
-	 */
-	@Override
-	public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
-		return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig);
-	}
-
-	/**
-	 * 鑾峰彇娴佸獟浣撲俊鎭�
-	 * @return
-	 */
-	@Override
-	public MediaServerConfig getMediaInfo() {
-		return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
-	}
-
-	@Override
-	public void updateCatch() {
-		deviceMap = new HashMap<>();
-		// 鏇存柊璁惧
-		List<Device> devices = queryVideoDeviceList(null);
-		if (devices == null && devices.size() == 0) return;
-		for (Device device : devices) {
-			// 鏇存柊璁惧涓嬬殑閫氶亾
-			HashMap<String, HashSet<String>> channelMap = new HashMap<String, HashSet<String>>();
-			List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX +
-					device.getDeviceId() + "_" + "*");
-			if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
-				for (int i = 0; i < deviceChannelList.size(); i++) {
-					String key = (String)deviceChannelList.get(i);
-					String[] s = key.split("_");
-					String channelId = s[3];
-					HashSet<String> subChannel = channelMap.get(channelId);
-					if (subChannel == null) {
-						subChannel = new HashSet<>();
-					}
-					System.out.println(key);
-					if (s.length == 6 && !"null".equals(s[5])) {
-						subChannel.add(s[5]);
-					}
-					channelMap.put(channelId, subChannel);
-				}
-			}
-			deviceMap.put(device.getDeviceId(),channelMap);
-		}
-		System.out.println();
-	}
-
-	@Override
-	public void cleanChannelsForDevice(String deviceId) {
-		List<DeviceChannel> result = new ArrayList<>();
-//		List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
-		List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
-		if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
-			for (int i = 0; i < deviceChannelList.size(); i++) {
-				redis.del((String)deviceChannelList.get(i));
-			}
-		}
-	}
-
-	@Override
-	public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {
-		Map<String, StreamInfo> streamInfos = new HashMap<>();
-//		List<Object> playLeys = redis.keys(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
-		List<Object> playLeys = redis.scan(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
-		if (playLeys.size() == 0) return streamInfos;
-		for (int i = 0; i < playLeys.size(); i++) {
-			String key = (String) playLeys.get(i);
-			StreamInfo streamInfo = (StreamInfo)redis.get(key);
-			streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getCahnnelId(), streamInfo);
-		}
-		return streamInfos;
-	}
-
-
-	@Override
-	public boolean startPlayback(StreamInfo stream) {
-		return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
-				stream);
-	}
-
-
-	@Override
-	public boolean stopPlayback(StreamInfo streamInfo) {
-		if (streamInfo == null) return false;
-		DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
-		if (deviceChannel != null) {
-			deviceChannel.setSsrc(null);
-			deviceChannel.setPlay(false);
-			updateChannel(streamInfo.getDeviceID(), deviceChannel);
-		}
-		return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
-				streamInfo.getSsrc(),
-				streamInfo.getDeviceID(),
-				streamInfo.getCahnnelId()));
-	}
-
-	@Override
-	public StreamInfo queryPlaybackByDevice(String deviceId, String code) {
-		String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
-				deviceId,
-				code);
-		List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
-				deviceId,
-				code));
-		if (playLeys == null || playLeys.size() == 0) {
-			playLeys = redis.scan(String.format("%S_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
-				deviceId));
-		}
-		if (playLeys == null || playLeys.size() == 0) return null;
-		return (StreamInfo)redis.get(playLeys.get(0).toString());
-	}
-
-	@Override
-	public boolean updateParentPlatform(ParentPlatform parentPlatform) {
-
-		// 瀛樺偍device
-		return redis.set(VideoManagerConstants.PLATFORM_PREFIX + parentPlatform.getDeviceGBId(), parentPlatform);
-	}
-
-	@Override
-	public boolean deleteParentPlatform(ParentPlatform parentPlatform) {
-		return redis.del(VideoManagerConstants.PLATFORM_PREFIX + parentPlatform.getDeviceGBId());
-	}
-
-	@Override
-	public PageResult<ParentPlatform> queryParentPlatformList(int page, int count) {
-		PageResult pageResult = new PageResult<Device>();
-		pageResult.setPage(page);
-		pageResult.setCount(count);
-		List<ParentPlatform> resultData = new ArrayList<>();
-		List<Object> parentPlatformList = redis.scan(VideoManagerConstants.PLATFORM_PREFIX + "*");
-		pageResult.setTotal(parentPlatformList.size());
-		int maxCount = (page + 1)* count;
-		for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) {
-			ParentPlatform parentPlatform =(ParentPlatform)redis.get((String)parentPlatformList.get(i));
-			resultData.add(parentPlatform);
-
-		}
-		pageResult.setData(resultData);
-		return pageResult;
-	}
-
-	@Override
-	public ParentPlatform queryParentPlatById(String platformGbId) {
-		return (ParentPlatform)redis.get(VideoManagerConstants.PLATFORM_PREFIX + platformGbId);
-	}
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java
index 3fe7dcc..ccbe94d 100644
--- a/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java
+++ b/src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java
@@ -34,6 +34,7 @@
      * 鑾峰彇瀵硅薄 杩欓噷閲嶅啓浜哹ean鏂规硶锛岃捣涓昏浣滅敤
      */
     public static Object getBean(String beanId) throws BeansException {
+        if (applicationContext == null) return null;
         return applicationContext.getBean(beanId);
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
index 34a02ee..d64b632 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
@@ -1,14 +1,14 @@
 package com.genersoft.iot.vmp.vmanager.device;
 
-import java.util.List;
-
-import com.genersoft.iot.vmp.common.PageResult;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
+import com.github.pagehelper.PageInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
@@ -18,6 +18,8 @@
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+
+import javax.sip.message.Response;
 
 @CrossOrigin
 @RestController
@@ -50,13 +52,13 @@
 	}
 	
 	@GetMapping("/devices")
-	public PageResult<Device> devices(int page, int count){
+	public PageInfo<Device> devices(int page, int count){
 		
 		if (logger.isDebugEnabled()) {
 			logger.debug("鏌ヨ鎵�鏈夎棰戣澶嘇PI璋冪敤");
 		}
 		
-		return storager.queryVideoDeviceList(null, page, count);
+		return storager.queryVideoDeviceList(page, count);
 	}
 
 	/**
@@ -66,18 +68,33 @@
 	 * @param count 姣忛〉鏉℃暟
 	 * @return 閫氶亾鍒楄〃
 	 */
+	/**
+	 * 鍒嗛〉鏌ヨ閫氶亾鏁�
+	 *
+	 * @param deviceId 璁惧id
+	 * @param page 褰撳墠椤�
+	 * @param count 姣忛〉鏉℃暟
+	 * @param query 鏌ヨ鍐呭
+	 * @param online 鏄惁鍦ㄧ嚎  鍦ㄧ嚎 true / 绂荤嚎 false
+	 * @param channelType 璁惧 false/瀛愮洰褰� true
+	 * @return 閫氶亾鍒楄〃
+	 */
 	@GetMapping("/devices/{deviceId}/channels")
-	public ResponseEntity<PageResult> channels(@PathVariable String deviceId,
+	public ResponseEntity<PageInfo> channels(@PathVariable String deviceId,
 											   int page, int count,
 											   @RequestParam(required = false) String query,
-											   @RequestParam(required = false) String online,
+											   @RequestParam(required = false) Boolean online,
 											   @RequestParam(required = false) Boolean channelType
 	){
 
 		if (logger.isDebugEnabled()) {
 			logger.debug("鏌ヨ鎵�鏈夎棰戣澶嘇PI璋冪敤");
 		}
-		PageResult pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count);
+		if (StringUtils.isEmpty(query)) {
+			query = null;
+		}
+
+		PageInfo pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count);
 		return new ResponseEntity<>(pageResult,HttpStatus.OK);
 	}
 	
@@ -86,11 +103,25 @@
 		
 		if (logger.isDebugEnabled()) {
 		}
-			logger.debug("璁惧淇℃伅鍚屾API璋冪敤锛宒eviceId锛�" + deviceId);
+			logger.debug("璁惧閫氶亾淇℃伅鍚屾API璋冪敤锛宒eviceId锛�" + deviceId);
 
 		Device device = storager.queryVideoDevice(deviceId);
-        cmder.catalogQuery(device);
-        DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>();
+        cmder.catalogQuery(device, event -> {
+			Response response = event.getResponse();
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId);
+			msg.setData(String.format("鍚屾閫氶亾澶辫触锛岄敊璇爜锛� %s, %s", response.getStatusCode(), response.getReasonPhrase()));
+			resultHolder.invokeResult(msg);
+		});
+        DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(2*1000L);
+		result.onTimeout(()->{
+			logger.warn(String.format("璁惧閫氶亾淇℃伅鍚屾瓒呮椂"));
+			// 閲婃斁rtpserver
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId);
+			msg.setData("Timeout");
+			resultHolder.invokeResult(msg);
+		});
         resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result);
         return result;
 	}
@@ -124,7 +155,7 @@
 	 * @return 瀛愰�氶亾鍒楄〃
 	 */
 	@GetMapping("/subChannels/{deviceId}/{channelId}/channels")
-	public ResponseEntity<PageResult> subChannels(@PathVariable String deviceId,
+	public ResponseEntity<PageInfo> subChannels(@PathVariable String deviceId,
 												  @PathVariable String channelId,
 												  int page,
 												  int count,
@@ -137,23 +168,23 @@
 		}
 		DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId);
 		if (deviceChannel == null) {
-			PageResult<DeviceChannel> deviceChannelPageResult = new PageResult<>();
+			PageInfo<DeviceChannel> deviceChannelPageResult = new PageInfo<>();
 			return new ResponseEntity<>(deviceChannelPageResult,HttpStatus.OK);
 		}
 
-		PageResult pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
+		PageInfo pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
 		return new ResponseEntity<>(pageResult,HttpStatus.OK);
 	}
 
 	@PostMapping("/channel/update/{deviceId}")
-	public ResponseEntity<PageResult> updateChannel(@PathVariable String deviceId,DeviceChannel channel){
+	public ResponseEntity<PageInfo> updateChannel(@PathVariable String deviceId,DeviceChannel channel){
 		storager.updateChannel(deviceId, channel);
 		return new ResponseEntity<>(null,HttpStatus.OK);
 	}
 
 	@GetMapping("/devices/{deviceId}/transport/{streamMode}")
 	@PostMapping("/devices/{deviceId}/transport/{streamMode}")
-	public ResponseEntity<PageResult> updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){
+	public ResponseEntity<PageInfo> updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){
 		Device device = storager.queryVideoDevice(deviceId);
 		device.setStreamMode(streamMode);
 		storager.updateDevice(device);
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/Device.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/Device.java
deleted file mode 100644
index e47f796..0000000
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/Device.java
+++ /dev/null
@@ -1,401 +0,0 @@
-package com.genersoft.iot.vmp.vmanager.device.entity;
-
-import java.util.List;
-
-import javax.persistence.Column;
-import javax.persistence.Id;
-import javax.persistence.Table;
-import javax.persistence.Transient;
-import javax.validation.constraints.Max;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-
-/**
- * @Description:瑙嗛璁惧淇℃伅
- * @author: songww
- * @date:   2020骞�5鏈�8鏃� 涓嬪崍2:05:56
- */
-@ApiModel(value = "瑙嗛璁惧淇℃伅", description = "瑙嗛璁惧淇℃伅")
-@Table(name="VMP_VIDEODEVICES")
-public class Device {
-
-	/**
-	 * 璁惧Id
-	 */
-	@ApiModelProperty("璁惧缂栧彿")
-	@Id
-	@Column(name="DEVICE_ID")
-	@NotNull(message = "deviceId 涓嶈兘涓� null")
-	@Size(min = 4, max = 32, message = "deviceId 蹇呴』澶т簬 4 浣嶅苟涓斿皬浜� 32 浣�")
-	private String deviceId;
-
-	/**
-	 * 璁惧鍚嶇О
-	 */
-	@ApiModelProperty("璁惧鍚嶇О")
-	@Column(name="DEVICE_NAME")
-	@Size(max = 32, message = "deviceName 蹇呴』灏忎簬 32 浣�")
-	private String deviceName;
-
-	/**
-	 * 鐢熶骇鍘傚晢
-	 */
-	@ApiModelProperty("鐢熶骇鍘傚晢")
-	@Column(name="MANUFACTURER")
-	@Size(max = 64, message = "manufacturer 蹇呴』灏忎簬 64 浣�")
-	private String manufacturer;
-
-	/**
-	 * 鍨嬪彿
-	 */
-	@ApiModelProperty("鍨嬪彿")
-	@Column(name="MODEL")
-	@Size(max = 64, message = "manufacturer 蹇呴』灏忎簬 64 浣�")
-	private String model;
-
-	/**
-	 * 鍥轰欢鐗堟湰
-	 */
-	@ApiModelProperty("鍥轰欢鐗堟湰")
-	@Column(name="FIRMWARE")
-	@Size(max = 64, message = "firmware 蹇呴』灏忎簬 64 浣�")
-	private String firmware;
-
-	/**
-	 * 閫氫俊鍗忚
-	 * GB28181 ONVIF
-	 */
-	@ApiModelProperty("閫氫俊鍗忚")
-	@Column(name="PROTOCOL")
-	@NotNull(message = "protocol 涓嶈兘涓� null")
-	@Size(max = 16, message = "protocol 蹇呴』灏忎簬 16 浣�")
-	private String protocol;
-
-	/**
-	 * SIP 浼犺緭鍗忚
-	 * UDP/TCP
-	 */
-	@ApiModelProperty("SIP 浼犺緭鍗忚")
-	@Column(name="TRANSPORT")
-	@Size(min = 3,max = 3 ,message = "transport 蹇呴』涓� 3 浣�")
-	private String transport;
-
-	/**
-	 * 鏁版嵁娴佷紶杈撴ā寮�
-	 * UDP:udp浼犺緭
-	 * TCP-ACTIVE锛歵cp涓诲姩妯″紡
-	 * TCP-PASSIVE锛歵cp琚姩妯″紡
-	 */
-	@ApiModelProperty("鏁版嵁娴佷紶杈撴ā寮�")
-	@Column(name="STREAM_MODE")
-	@Size(max = 64, message = "streamMode 蹇呴』灏忎簬 16 浣�")
-	private String streamMode;
-
-	/**
-	 * IP鍦板潃
-	 */
-	@ApiModelProperty("IP鍦板潃")
-	@Column(name="IP")
-	@Size(max = 15, message = "streamMode 蹇呴』灏忎簬 15 浣�")
-	private String ip;
-
-	/**
-	 * 绔彛鍙�
-	 */
-	@ApiModelProperty("绔彛鍙�")
-	@Column(name="PORT")
-	@Max(value = 65535,message = "port 鏈�澶у�间负 65535")
-	private Integer port;
-
-	/**
-	 * 鍦ㄧ嚎鐘舵�� 1鍦ㄧ嚎, 0绂荤嚎
-	 */
-	@ApiModelProperty("鍦ㄧ嚎鐘舵��")
-	@Size(min = 1,max = 1 ,message = "online 蹇呴』涓� 1 浣�")
-	@Column(name="ONLINE")
-	private String online;
-
-	/**
-	 * 閫氶亾鏁伴噺
-	 */
-	@ApiModelProperty("閫氶亾鏁伴噺")
-	@Column(name="CHANNEL_SUM")
-	@Max(value = 1000000000,message = "channelSum 鏈�澶у�间负 1000000000")
-	private Integer channelSum;
-
-	@Override
-	public String toString() {
-		return "Device{" +
-				"deviceId='" + deviceId + '\'' +
-				", deviceName='" + deviceName + '\'' +
-				", manufacturer='" + manufacturer + '\'' +
-				", model='" + model + '\'' +
-				", firmware='" + firmware + '\'' +
-				", protocol='" + protocol + '\'' +
-				", transport='" + transport + '\'' +
-				", streamMode='" + streamMode + '\'' +
-				", ip='" + ip + '\'' +
-				", port=" + port +
-				", online='" + online + '\'' +
-				", channelSum=" + channelSum +
-				", createTime='" + createTime + '\'' +
-				", registerTime='" + registerTime + '\'' +
-				", heartbeatTime='" + heartbeatTime + '\'' +
-				", updateTime='" + updateTime + '\'' +
-				", updatePerson='" + updatePerson + '\'' +
-				", syncTime='" + syncTime + '\'' +
-				", syncPerson='" + syncPerson + '\'' +
-				", username='" + username + '\'' +
-				", password='" + password + '\'' +
-				", channelList=" + channelList +
-				'}';
-	}
-
-	/**
-	 * 鍒涘缓鏃堕棿
-	 */
-	@ApiModelProperty("鍒涘缓鏃堕棿")
-	@Column(name="CREATE_TIME")
-	private String createTime;
-
-	/**
-	 * 娉ㄥ唽鏃堕棿
-	 */
-	@ApiModelProperty("娉ㄥ唽鏃堕棿")
-	@Column(name="REGISTER_TIME")
-	private String registerTime;
-
-	/**
-	 * 蹇冭烦鏃堕棿
-	 */
-	@ApiModelProperty("蹇冭烦鏃堕棿")
-	@Column(name="HEARTBEAT_TIME")
-	private String heartbeatTime;
-
-	/**
-	 * 淇敼鏃堕棿
-	 */
-	@ApiModelProperty("鏇存柊鏃堕棿")
-	@Column(name="UPDATE_TIME")
-	private String updateTime;
-
-	/**
-	 * 淇敼浜�
-	 */
-	@ApiModelProperty("淇敼浜�")
-	@Column(name="UPDATE_PERSON")
-	private String updatePerson;
-
-	/**
-	 * 鍚屾鏃堕棿
-	 */
-	@ApiModelProperty("鍚屾鏃堕棿")
-	@Column(name="SYNC_TIME")
-	private String syncTime;
-
-	/**
-	 * 鍚屾浜�
-	 */
-	@ApiModelProperty("鍚屾浜�")
-	@Column(name="SYNC_PERSON")
-	private String syncPerson;
-
-	/**
-	 * ONVIF鍗忚-鐢ㄦ埛鍚�
-	 */
-	@ApiModelProperty("鐢ㄦ埛鍚�")
-	@Column(name="USERNAME")
-	@Size(max = 32, message = "username 蹇呴』灏忎簬 32 浣�")
-	private String username;
-
-	/**
-	 * ONVIF鍗忚-瀵嗙爜
-	 */
-	@ApiModelProperty("瀵嗙爜")
-	@Size(max = 32, message = "password 蹇呴』灏忎簬 32 浣�")
-	@Column(name="PASSWORD")
-	private String password;
-
-	@Transient
-	private List<DeviceChannel> channelList;
-
-
-	public String getDeviceId() {
-		return deviceId;
-	}
-
-	public void setDeviceId(String deviceId) {
-		this.deviceId = deviceId;
-	}
-
-	public String getDeviceName() {
-		return deviceName;
-	}
-
-	public void setDeviceName(String deviceName) {
-		this.deviceName = deviceName;
-	}
-
-	public String getManufacturer() {
-		return manufacturer;
-	}
-
-	public void setManufacturer(String manufacturer) {
-		this.manufacturer = manufacturer;
-	}
-
-	public String getModel() {
-		return model;
-	}
-
-	public void setModel(String model) {
-		this.model = model;
-	}
-
-	public String getFirmware() {
-		return firmware;
-	}
-
-	public void setFirmware(String firmware) {
-		this.firmware = firmware;
-	}
-
-	public String getProtocol() {
-		return protocol;
-	}
-
-	public void setProtocol(String protocol) {
-		this.protocol = protocol;
-	}
-
-	public String getTransport() {
-		return transport;
-	}
-
-	public void setTransport(String transport) {
-		this.transport = transport;
-	}
-
-	public String getStreamMode() {
-		return streamMode;
-	}
-
-	public void setStreamMode(String streamMode) {
-		this.streamMode = streamMode;
-	}
-
-	public String getIp() {
-		return ip;
-	}
-
-	public void setIp(String ip) {
-		this.ip = ip;
-	}
-
-	public Integer getPort() {
-		return port;
-	}
-
-	public void setPort(Integer port) {
-		this.port = port;
-	}
-
-	public String getOnline() {
-		return online;
-	}
-
-	public void setOnline(String online) {
-		this.online = online;
-	}
-
-	public Integer getChannelSum() {
-		return channelSum;
-	}
-
-	public void setChannelSum(Integer channelSum) {
-		this.channelSum = channelSum;
-	}
-
-	public String getCreateTime() {
-		return createTime;
-	}
-
-	public void setCreateTime(String createTime) {
-		this.createTime = createTime;
-	}
-
-	public String getRegisterTime() {
-		return registerTime;
-	}
-
-	public void setRegisterTime(String registerTime) {
-		this.registerTime = registerTime;
-	}
-
-	public String getHeartbeatTime() {
-		return heartbeatTime;
-	}
-
-	public void setHeartbeatTime(String heartbeatTime) {
-		this.heartbeatTime = heartbeatTime;
-	}
-
-	public String getUpdateTime() {
-		return updateTime;
-	}
-
-	public void setUpdateTime(String updateTime) {
-		this.updateTime = updateTime;
-	}
-
-	public String getUpdatePerson() {
-		return updatePerson;
-	}
-
-	public void setUpdatePerson(String updatePerson) {
-		this.updatePerson = updatePerson;
-	}
-
-	public String getSyncTime() {
-		return syncTime;
-	}
-
-	public void setSyncTime(String syncTime) {
-		this.syncTime = syncTime;
-	}
-
-	public String getSyncPerson() {
-		return syncPerson;
-	}
-
-	public void setSyncPerson(String syncPerson) {
-		this.syncPerson = syncPerson;
-	}
-
-	public String getUsername() {
-		return username;
-	}
-
-	public void setUsername(String username) {
-		this.username = username;
-	}
-
-	public String getPassword() {
-		return password;
-	}
-
-	public void setPassword(String password) {
-		this.password = password;
-	}
-
-	public List<DeviceChannel> getChannelList() {
-		return channelList;
-	}
-
-	public void setChannelList(List<DeviceChannel> channelList) {
-		this.channelList = channelList;
-	}
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/DeviceChannel.java
deleted file mode 100644
index bedd075..0000000
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/DeviceChannel.java
+++ /dev/null
@@ -1,385 +0,0 @@
-package com.genersoft.iot.vmp.vmanager.device.entity;
-
-import javax.persistence.Column;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-
-/**
- * @Description:璁惧閫氶亾淇℃伅
- * @author: songww
- * @date:   2020骞�5鏈�20鏃� 涓嬪崍9:00:46     
- */
-@ApiModel(value = "璁惧閫氶亾淇℃伅", description = "璁惧閫氶亾淇℃伅")
-@Table(name="VMP_VIDEOCHANNELS")
-public class DeviceChannel {
-
-	/**
-	 * 閫氶亾缂栧彿
-	 */
-	@ApiModelProperty("閫氶亾缂栧彿")
-	@Id
-	@Column(name="CHANNEL_ID")
-	private String channelId;
-	
-	/**
-	 * 璁惧缂栧彿
-	 */
-	@ApiModelProperty("璁惧缂栧彿")
-	@Column(name="DEVICE_ID")
-	private String deviceId;
-	
-	/**
-	 * 閫氶亾鍚�
-	 */
-	@ApiModelProperty("閫氶亾鍚�")
-	@Column(name="CHANNEL_NAME")
-	private String channelName;
-	
-	/**
-	 * 鐢熶骇鍘傚晢
-	 */
-	@ApiModelProperty("鐢熶骇鍘傚晢")
-	@Column(name="MANUFACTURER")
-	private String manufacture;
-	
-	/**
-	 * 鍨嬪彿
-	 */
-	@ApiModelProperty("鍨嬪彿")
-	@Column(name="MODEL")
-	private String model;
-	
-	/**
-	 * 璁惧褰掑睘
-	 */
-	@ApiModelProperty("璁惧褰掑睘")
-	@Column(name="OWNER")
-	private String owner;
-	
-	/**
-	 * 琛屾斂鍖哄煙
-	 */
-	@ApiModelProperty("琛屾斂鍖哄煙")
-	@Column(name="CIVIL_CODE")
-	private String civilCode;
-	
-	/**
-	 * 璀﹀尯
-	 */
-	@ApiModelProperty("璀﹀尯")
-	@Column(name="BLOCK")
-	private String block;
-
-	/**
-	 * 瀹夎鍦板潃
-	 */
-	@ApiModelProperty("瀹夎鍦板潃")
-	@Column(name="ADDRESS")
-	private String address;
-	
-	/**
-	 * 鏄惁鏈夊瓙璁惧 1鏈�, 0娌℃湁
-	 */
-	@ApiModelProperty("鏄惁鏈夊瓙璁惧")
-	@Column(name="PARENTAL")
-	private String parental;
-	
-	/**
-	 * 鐖剁骇id
-	 */
-	@ApiModelProperty("鐖剁骇缂栫爜")
-	@Column(name="PARENT_ID")
-	private String parentId;
-	
-	/**
-	 * 淇′护瀹夊叏妯″紡  缂虹渷涓�0; 0:涓嶉噰鐢�; 2: S/MIME绛惧悕鏂瑰紡; 3: S/ MIME鍔犲瘑绛惧悕鍚屾椂閲囩敤鏂瑰紡; 4:鏁板瓧鎽樿鏂瑰紡
-	 */
-	@ApiModelProperty("淇′护瀹夊叏妯″紡")
-	@Column(name="SAFETY_WAY")
-	private String safetyWay;
-	
-	/**
-	 * 娉ㄥ唽鏂瑰紡 缂虹渷涓�1;1:绗﹀悎IETFRFC3261鏍囧噯鐨勮璇佹敞鍐屾ā 寮�; 2:鍩轰簬鍙d护鐨勫弻鍚戣璇佹敞鍐屾ā寮�; 3:鍩轰簬鏁板瓧璇佷功鐨勫弻鍚戣璇佹敞鍐屾ā寮�
-	 */
-	@ApiModelProperty("娉ㄥ唽鏂瑰紡")
-	@Column(name="REGISTER_WAY")
-	private String registerWay;
-	
-	/**
-	 * 璇佷功搴忓垪鍙�
-	 */
-	@ApiModelProperty("璇佷功搴忓垪鍙�")
-	@Column(name="CERT_NUM")
-	private String certNum;
-	
-	/**
-	 * 璇佷功鏈夋晥鏍囪瘑 缂虹渷涓�0;璇佷功鏈夋晥鏍囪瘑:0:鏃犳晥1: 鏈夋晥
-	 */
-	@ApiModelProperty("璇佷功鏈夋晥鏍囪瘑")
-	@Column(name="CERT_VALID")
-	private String certValid;
-	
-	/**
-	 * 璇佷功鏃犳晥鍘熷洜鐮�
-	 */
-	@ApiModelProperty("璇佷功鏃犳晥鍘熷洜鐮�")
-	@Column(name="CERT_ERRCODE")
-	private String certErrCode;
-	
-	/**
-	 * 璇佷功缁堟鏈夋晥鏈�
-	 */
-	@ApiModelProperty("璇佷功缁堟鏈夋晥鏈�")
-	@Column(name="CERT_ENDTIME")
-	private String certEndTime;
-	
-	/**
-	 * 淇濆瘑灞炴�� 缂虹渷涓�0; 0:涓嶆秹瀵�, 1:娑夊瘑
-	 */
-	@ApiModelProperty("淇濆瘑灞炴��")
-	@Column(name="SECRECY")
-	private String secrecy;
-	
-	/**
-	 * IP鍦板潃
-	 */
-	@ApiModelProperty("IP鍦板潃")
-	@Column(name="IP")
-	private String ip;
-	
-	/**
-	 * 绔彛鍙�
-	 */
-	@ApiModelProperty("绔彛鍙�")
-	@Column(name="PORT")
-	private Integer port;
-	
-	/**
-	 * 瀵嗙爜
-	 */
-	@ApiModelProperty("瀵嗙爜")
-	@Column(name="PASSWORD")
-	private String password;	 
-	
-	/**
-	 * 鍦ㄧ嚎/绂荤嚎
-	 * 1鍦ㄧ嚎,0绂荤嚎
-	 * 榛樿鍦ㄧ嚎
-	 * 淇′护:
-	 * <Status>ON</Status>
-	 * <Status>OFF</Status>
-	 * 閬囧埌杩嘚VR涓嬬殑IPC涓嬪彂淇′护鍙互鎺ㄦ祦锛� 浣嗘槸 Status 鍝嶅簲 OFF
-	 */
-	@ApiModelProperty("鐘舵��")
-	@Column(name="ONLINE")
-	private String online;
-
-	/**
-	 * 缁忓害
-	 */
-	@ApiModelProperty("缁忓害")
-	@Column(name="LONGITUDE")
-	private double longitude;
-	
-	/**
-	 * 绾害
-	 */
-	@ApiModelProperty("绾害")
-	@Column(name="LATITUDE")
-	private double latitude;
-
-	public String getChannelId() {
-		return channelId;
-	}
-
-	public void setChannelId(String channelId) {
-		this.channelId = channelId;
-	}
-
-	public String getDeviceId() {
-		return deviceId;
-	}
-
-	public void setDeviceId(String deviceId) {
-		this.deviceId = deviceId;
-	}
-
-	public String getChannelName() {
-		return channelName;
-	}
-
-	public void setChannelName(String channelName) {
-		this.channelName = channelName;
-	}
-
-	public String getManufacture() {
-		return manufacture;
-	}
-
-	public void setManufacture(String manufacture) {
-		this.manufacture = manufacture;
-	}
-
-	public String getModel() {
-		return model;
-	}
-
-	public void setModel(String model) {
-		this.model = model;
-	}
-
-	public String getOwner() {
-		return owner;
-	}
-
-	public void setOwner(String owner) {
-		this.owner = owner;
-	}
-
-	public String getCivilCode() {
-		return civilCode;
-	}
-
-	public void setCivilCode(String civilCode) {
-		this.civilCode = civilCode;
-	}
-
-	public String getBlock() {
-		return block;
-	}
-
-	public void setBlock(String block) {
-		this.block = block;
-	}
-
-	public String getAddress() {
-		return address;
-	}
-
-	public void setAddress(String address) {
-		this.address = address;
-	}
-
-	public String getParental() {
-		return parental;
-	}
-
-	public void setParental(String parental) {
-		this.parental = parental;
-	}
-
-	public String getParentId() {
-		return parentId;
-	}
-
-	public void setParentId(String parentId) {
-		this.parentId = parentId;
-	}
-
-	public String getSafetyWay() {
-		return safetyWay;
-	}
-
-	public void setSafetyWay(String safetyWay) {
-		this.safetyWay = safetyWay;
-	}
-
-	public String getRegisterWay() {
-		return registerWay;
-	}
-
-	public void setRegisterWay(String registerWay) {
-		this.registerWay = registerWay;
-	}
-
-	public String getCertNum() {
-		return certNum;
-	}
-
-	public void setCertNum(String certNum) {
-		this.certNum = certNum;
-	}
-
-	public String getCertValid() {
-		return certValid;
-	}
-
-	public void setCertValid(String certValid) {
-		this.certValid = certValid;
-	}
-
-	public String getCertErrCode() {
-		return certErrCode;
-	}
-
-	public void setCertErrCode(String certErrCode) {
-		this.certErrCode = certErrCode;
-	}
-
-	public String getCertEndTime() {
-		return certEndTime;
-	}
-
-	public void setCertEndTime(String certEndTime) {
-		this.certEndTime = certEndTime;
-	}
-
-	public String getSecrecy() {
-		return secrecy;
-	}
-
-	public void setSecrecy(String secrecy) {
-		this.secrecy = secrecy;
-	}
-
-	public String getIp() {
-		return ip;
-	}
-
-	public void setIp(String ip) {
-		this.ip = ip;
-	}
-
-	public Integer getPort() {
-		return port;
-	}
-
-	public void setPort(Integer port) {
-		this.port = port;
-	}
-
-	public String getPassword() {
-		return password;
-	}
-
-	public void setPassword(String password) {
-		this.password = password;
-	}
-
-	public String getOnline() {
-		return online;
-	}
-
-	public void setOnline(String online) {
-		this.online = online;
-	}
-
-	public double getLongitude() {
-		return longitude;
-	}
-
-	public void setLongitude(double longitude) {
-		this.longitude = longitude;
-	}
-
-	public double getLatitude() {
-		return latitude;
-	}
-
-	public void setLatitude(double latitude) {
-		this.latitude = latitude;
-	}
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
index e741b5a..59667d0 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -7,6 +7,8 @@
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.vmanager.service.IPlayService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -27,6 +29,7 @@
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import org.springframework.web.context.request.async.DeferredResult;
 
+import javax.sip.message.Response;
 import java.text.DecimalFormat;
 import java.util.UUID;
 
@@ -44,6 +47,9 @@
 	private IVideoManagerStorager storager;
 
 	@Autowired
+	private IRedisCatchStorage redisCatchStorage;
+
+	@Autowired
 	private ZLMRESTfulUtils zlmresTfulUtils;
 
 	@Autowired
@@ -58,18 +64,11 @@
 
 
 		Device device = storager.queryVideoDevice(deviceId);
-		StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId);
+		StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
 
 		UUID uuid = UUID.randomUUID();
 		DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
-		// 瓒呮椂澶勭悊
-		result.onTimeout(()->{
-			logger.warn(String.format("璁惧鐐规挱瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId));
-			RequestMessage msg = new RequestMessage();
-			msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
-			msg.setData("Timeout");
-			resultHolder.invokeResult(msg);
-		});
+
 		// 褰曞儚鏌ヨ浠hannelId浣滀负deviceId鏌ヨ
 		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
 
@@ -78,9 +77,15 @@
 			cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
 				logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
 				playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
+			}, event -> {
+				RequestMessage msg = new RequestMessage();
+				msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+				Response response = event.getResponse();
+				msg.setData(String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", response.getStatusCode(), response.getReasonPhrase()));
+				resultHolder.invokeResult(msg);
 			});
 		} else {
-			String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
+			String streamId = streamInfo.getStreamId();
 			JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
 			if (rtpInfo.getBoolean("exist")) {
 				RequestMessage msg = new RequestMessage();
@@ -88,58 +93,107 @@
 				msg.setData(JSON.toJSONString(streamInfo));
 				resultHolder.invokeResult(msg);
 			} else {
-				storager.stopPlay(streamInfo);
-				// TODO playStreamCmd 瓒呮椂澶勭悊
+				redisCatchStorage.stopPlay(streamInfo);
 				cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
 					logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
 					playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
+				}, event -> {
+					RequestMessage msg = new RequestMessage();
+					msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+					Response response = event.getResponse();
+					msg.setData(String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", response.getStatusCode(), response.getReasonPhrase()));
+					resultHolder.invokeResult(msg);
 				});
 			}
 		}
+
+		// 瓒呮椂澶勭悊
+		result.onTimeout(()->{
+			logger.warn(String.format("璁惧鐐规挱瓒呮椂锛宒eviceId锛�%s 锛宑hannelId锛�%s", deviceId, channelId));
+			// 閲婃斁rtpserver
+			cmder.closeRTPServer(device, channelId);
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+			msg.setData("Timeout");
+			resultHolder.invokeResult(msg);
+		});
 		return result;
 	}
 
-	@PostMapping("/play/{ssrc}/stop")
-	public ResponseEntity<String> playStop(@PathVariable String ssrc) {
+	@PostMapping("/play/{streamId}/stop")
+	public DeferredResult<ResponseEntity<String>> playStop(@PathVariable String streamId) {
 
-		cmder.streamByeCmd(ssrc);
-		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
-		if (streamInfo == null)
-			return new ResponseEntity<String>("ssrc not found", HttpStatus.OK);
-		storager.stopPlay(streamInfo);
-		if (logger.isDebugEnabled()) {
-			logger.debug(String.format("璁惧棰勮鍋滄API璋冪敤锛宻src锛�%s", ssrc));
-		}
+		logger.debug(String.format("璁惧棰勮/鍥炴斁鍋滄API璋冪敤锛宻treamId锛�%s", streamId));
 
-		if (ssrc != null) {
+		UUID uuid = UUID.randomUUID();
+		DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
+
+		// 褰曞儚鏌ヨ浠hannelId浣滀负deviceId鏌ヨ
+		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_STOP + uuid, result);
+
+		cmder.streamByeCmd(streamId, event -> {
+			StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
+			if (streamInfo == null) {
+				RequestMessage msg = new RequestMessage();
+				msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+				msg.setData("streamId not found");
+				resultHolder.invokeResult(msg);
+				redisCatchStorage.stopPlay(streamInfo);
+			}
+
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
+			Response response = event.getResponse();
+			msg.setData(String.format("success"));
+			resultHolder.invokeResult(msg);
+		});
+
+
+
+		if (streamId != null) {
 			JSONObject json = new JSONObject();
-			json.put("ssrc", ssrc);
-			return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
+			json.put("streamId", streamId);
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+			msg.setData(json.toString());
+			resultHolder.invokeResult(msg);
 		} else {
-			logger.warn("璁惧棰勮鍋滄API璋冪敤澶辫触锛�");
-			return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
+			logger.warn("璁惧棰勮/鍥炴斁鍋滄API璋冪敤澶辫触锛�");
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+			msg.setData("streamId null");
+			resultHolder.invokeResult(msg);
 		}
+
+		// 瓒呮椂澶勭悊
+		result.onTimeout(()->{
+			logger.warn(String.format("璁惧棰勮/鍥炴斁鍋滄瓒呮椂锛宻treamId锛�%s ", streamId));
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
+			msg.setData("Timeout");
+			resultHolder.invokeResult(msg);
+		});
+		return result;
 	}
 
 	/**
 	 * 灏嗕笉鏄痟264鐨勮棰戦�氳繃ffmpeg 杞爜涓篽264 + aac
-	 * @param ssrc
+	 * @param streamId 娴両D
 	 * @return
 	 */
-	@PostMapping("/play/{ssrc}/convert")
-	public ResponseEntity<String> playConvert(@PathVariable String ssrc) {
-		StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
+	@PostMapping("/play/{streamId}/convert")
+	public ResponseEntity<String> playConvert(@PathVariable String streamId) {
+		StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
 		if (streamInfo == null) {
 			logger.warn("瑙嗛杞爜API璋冪敤澶辫触锛�, 瑙嗛娴佸凡缁忓仠姝�!");
 			return new ResponseEntity<String>("鏈壘鍒拌棰戞祦淇℃伅, 瑙嗛娴佸彲鑳藉凡缁忓仠姝�", HttpStatus.OK);
 		}
-		String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
 		JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
 		if (!rtpInfo.getBoolean("exist")) {
 			logger.warn("瑙嗛杞爜API璋冪敤澶辫触锛�, 瑙嗛娴佸凡鍋滄鎺ㄦ祦!");
 			return new ResponseEntity<String>("鎺ㄦ祦淇℃伅鍦ㄦ祦濯掍綋涓笉瀛樺湪, 瑙嗛娴佸彲鑳藉凡鍋滄鎺ㄦ祦", HttpStatus.OK);
 		} else {
-			MediaServerConfig mediaInfo = storager.getMediaInfo();
+			MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
 			String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
 					streamId );
 			String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId);
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
index 2e32b1b..9449d26 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
@@ -6,6 +6,7 @@
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.vmanager.service.IPlayService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -27,6 +28,7 @@
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import org.springframework.web.context.request.async.DeferredResult;
 
+import javax.sip.message.Response;
 import java.util.UUID;
 
 @CrossOrigin
@@ -41,6 +43,9 @@
 
 	@Autowired
 	private IVideoManagerStorager storager;
+
+	@Autowired
+	private IRedisCatchStorage redisCatchStorage;
 
 	@Autowired
 	private ZLMRESTfulUtils zlmresTfulUtils;
@@ -69,15 +74,21 @@
 			resultHolder.invokeResult(msg);
 		});
 		Device device = storager.queryVideoDevice(deviceId);
-		StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId);
+		StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId);
 		if (streamInfo != null) {
 			// 鍋滄涔嬪墠鐨勫洖鏀�
-			cmder.streamByeCmd(streamInfo.getSsrc());
+			cmder.streamByeCmd(streamInfo.getStreamId());
 		}
 		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
 		cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
 			logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + response.toJSONString());
 			playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString());
+		}, event -> {
+			Response response = event.getResponse();
+			RequestMessage msg = new RequestMessage();
+			msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
+			msg.setData(String.format("鍥炴斁澶辫触锛� 閿欒鐮侊細 %s, %s", response.getStatusCode(), response.getReasonPhrase()));
+			resultHolder.invokeResult(msg);
 		});
 
 		return result;
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java
index 1a90977..4c41e16 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java
@@ -29,15 +29,14 @@
 	private IVideoManagerStorager storager;
 
 	/***
-	 * http://localhost:8080/api/ptz/34020000001320000002_34020000001320000008?leftRight=1&upDown=0&inOut=0&moveSpeed=50&zoomSpeed=0
-	 * @param deviceId
-	 * @param channelId
-	 * @param leftRight
-	 * @param upDown
-	 * @param inOut
-	 * @param moveSpeed
-	 * @param zoomSpeed
-	 * @return
+	 * 浜戝彴鎺у埗
+	 * @param deviceId 璁惧id
+	 * @param channelId 閫氶亾id
+	 * @param cmdCode		鎸囦护鐮�
+	 * @param horizonSpeed	姘村钩绉诲姩閫熷害
+	 * @param verticalSpeed	鍨傜洿绉诲姩閫熷害
+	 * @param zoomSpeed	    缂╂斁閫熷害
+	 * @return String 鎺у埗缁撴灉
 	 */
 	@PostMapping("/ptz/{deviceId}/{channelId}")
 	public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId,int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed){
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java
index 502087e..519d299 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java
@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.vmanager.record;
 
+import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -32,7 +33,7 @@
 	
 	@Autowired
 	private DeferredResultHolder resultHolder;
-	
+
 	@GetMapping("/record/{deviceId}/{channelId}")
 	public DeferredResult<ResponseEntity<RecordInfo>> recordinfo(@PathVariable String deviceId,@PathVariable String channelId, String startTime,  String endTime){
 		
@@ -42,9 +43,17 @@
 		
 		Device device = storager.queryVideoDevice(deviceId);
 		cmder.recordInfoQuery(device, channelId, startTime, endTime);
-		DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<ResponseEntity<RecordInfo>>();
+		// 鎸囧畾瓒呮椂鏃堕棿 1鍒嗛挓30绉�
+		DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<ResponseEntity<RecordInfo>>(90*1000L);
 		// 褰曞儚鏌ヨ浠hannelId浣滀负deviceId鏌ヨ
 		resultHolder.put(DeferredResultHolder.CALLBACK_CMD_RECORDINFO+channelId, result);
+		result.onTimeout(()->{
+			RequestMessage msg = new RequestMessage();
+			msg.setDeviceId(deviceId);
+			msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO);
+			msg.setData("timeout");
+			resultHolder.invokeResult(msg);
+		});
         return result;
 	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
index e9528d1..f4bdd2b 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
@@ -4,8 +4,10 @@
 import com.alibaba.fastjson.JSONObject;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.vmanager.play.PlayController;
 import com.genersoft.iot.vmp.vmanager.service.IPlayService;
@@ -25,6 +27,9 @@
     private IVideoManagerStorager storager;
 
     @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
+    @Autowired
     private DeferredResultHolder resultHolder;
 
     @Override
@@ -33,7 +38,13 @@
         msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
         StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
         if (streamInfo != null) {
-            storager.startPlay(streamInfo);
+            DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
+            if (deviceChannel != null) {
+                deviceChannel.setStreamId(streamInfo.getStreamId());
+                storager.updateChannel(deviceId, deviceChannel);
+            }
+
+            redisCatchStorage.startPlay(streamInfo);
             msg.setData(JSON.toJSONString(streamInfo));
             resultHolder.invokeResult(msg);
         } else {
@@ -49,7 +60,7 @@
         msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
         StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
         if (streamInfo != null) {
-            storager.startPlayback(streamInfo);
+            redisCatchStorage.startPlayback(streamInfo);
             msg.setData(JSON.toJSONString(streamInfo));
             resultHolder.invokeResult(msg);
         } else {
@@ -61,13 +72,11 @@
 
     public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
         String streamId = resonse.getString("id");
-        String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
         StreamInfo streamInfo = new StreamInfo();
-        streamInfo.setSsrc(ssrc);
         streamInfo.setStreamId(streamId);
         streamInfo.setDeviceID(deviceId);
         streamInfo.setCahnnelId(channelId);
-        MediaServerConfig mediaServerConfig = storager.getMediaInfo();
+        MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo();
 
         streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
         streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
index ce3b7ec..199a9e6 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
@@ -1,22 +1,17 @@
 package com.genersoft.iot.vmp.web;
 
-import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.genersoft.iot.vmp.common.PageResult;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
-import com.genersoft.iot.vmp.vmanager.device.DeviceController;
+import com.github.pagehelper.PageInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
@@ -65,12 +60,12 @@
         JSONObject result = new JSONObject();
         List<Device> devices;
         if (start == null || limit ==null) {
-            devices = storager.queryVideoDeviceList(null);
+            devices = storager.queryVideoDeviceList();
             result.put("DeviceCount", devices.size());
         }else {
-            PageResult<Device> deviceList = storager.queryVideoDeviceList(null, start/limit, limit);
+            PageInfo<Device> deviceList = storager.queryVideoDeviceList(start/limit, limit);
             result.put("DeviceCount", deviceList.getTotal());
-            devices = deviceList.getData();
+            devices = deviceList.getList();
         }
 
         JSONArray deviceJSONList = new JSONArray();
@@ -86,8 +81,8 @@
             deviceJsonObject.put("Online", device.getOnline() == 1);
             deviceJsonObject.put("Password", "");
             deviceJsonObject.put("MediaTransport", device.getTransport());
-            deviceJsonObject.put("RemoteIP", device.getHost().getIp());
-            deviceJsonObject.put("RemotePort", device.getHost().getPort());
+            deviceJsonObject.put("RemoteIP", device.getIp());
+            deviceJsonObject.put("RemotePort", device.getPort());
             deviceJsonObject.put("LastRegisterAt", "");
             deviceJsonObject.put("LastKeepaliveAt", "");
             deviceJsonObject.put("UpdatedAt", "");
@@ -123,9 +118,9 @@
             deviceChannels = storager.queryChannelsByDeviceId(serial);
             result.put("ChannelCount", deviceChannels.size());
         }else {
-            PageResult<DeviceChannel> pageResult = storager.queryChannelsByDeviceId(serial, null, null, null,start/limit, limit);
+            PageInfo<DeviceChannel> pageResult = storager.queryChannelsByDeviceId(serial, null, null, null,start/limit, limit);
             result.put("ChannelCount", pageResult.getTotal());
-            deviceChannels = pageResult.getData();
+            deviceChannels = pageResult.getList();
         }
 
         JSONArray channleJSONList = new JSONArray();
@@ -159,7 +154,7 @@
             deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 浜戝彴绫诲瀷, 0 - 鏈煡, 1 - 鐞冩満, 2 - 鍗婄悆,
                                                                             //   3 - 鍥哄畾鏋満, 4 - 閬ユ帶鏋満
             deviceJOSNChannel.put("CustomPTZType", "");
-            deviceJOSNChannel.put("StreamID", deviceChannel.getSsrc()); // StreamID 鐩存挱娴両D, 鏈夊�艰〃绀烘鍦ㄧ洿鎾�
+            deviceJOSNChannel.put("StreamID", deviceChannel.getStreamId()); // StreamID 鐩存挱娴両D, 鏈夊�艰〃绀烘鍦ㄧ洿鎾�
             deviceJOSNChannel.put("NumOutputs ", -1); // 鐩存挱鍦ㄧ嚎浜烘暟
             channleJSONList.add(deviceJOSNChannel);
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
index 6180fbb..8ebdf64 100644
--- a/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
+++ b/src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
@@ -8,6 +8,7 @@
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.vmanager.play.PlayController;
 import org.slf4j.Logger;
@@ -17,6 +18,7 @@
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.context.request.async.DeferredResult;
 
 /**
  * 鍏煎LiveGBS鐨凙PI锛氬疄鏃剁洿鎾�
@@ -34,11 +36,16 @@
     @Autowired
     private IVideoManagerStorager storager;
 
-    private boolean closeWaitRTPInfo = false;
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
 
 
     @Autowired
     private ZLMRESTfulUtils zlmresTfulUtils;
+
+
+    @Autowired
+    private PlayController playController;
 
     /**
      * 瀹炴椂鐩存挱 - 寮�濮嬬洿鎾�
@@ -54,126 +61,54 @@
      * @return
      */
     @RequestMapping(value = "/start")
-    private JSONObject start(String serial ,
-                             @RequestParam(required = false)Integer channel ,
-                             @RequestParam(required = false)String code,
-                             @RequestParam(required = false)String cdn,
-                             @RequestParam(required = false)String audio,
-                             @RequestParam(required = false)String transport,
-                             @RequestParam(required = false)String checkchannelstatus ,
-                             @RequestParam(required = false)String transportmode,
-                             @RequestParam(required = false)String timeout
+    private DeferredResult<JSONObject> start(String serial ,
+                                             @RequestParam(required = false)Integer channel ,
+                                             @RequestParam(required = false)String code,
+                                             @RequestParam(required = false)String cdn,
+                                             @RequestParam(required = false)String audio,
+                                             @RequestParam(required = false)String transport,
+                                             @RequestParam(required = false)String checkchannelstatus ,
+                                             @RequestParam(required = false)String transportmode,
+                                             @RequestParam(required = false)String timeout
 
     ){
-        int getEncoding = closeWaitRTPInfo?  1: 0;
+        DeferredResult<JSONObject> resultDeferredResult = new DeferredResult<JSONObject>();
         Device device = storager.queryVideoDevice(serial);
-
         if (device == null ) {
             JSONObject result = new JSONObject();
             result.put("error","device[ " + serial + " ]鏈壘鍒�");
-            return result;
+            resultDeferredResult.setResult(result);
         }else if (device.getOnline() == 0) {
             JSONObject result = new JSONObject();
             result.put("error","device[ " + code + " ]offline");
-            return result;
+            resultDeferredResult.setResult(result);
         }
+        resultDeferredResult.onTimeout(()->{
+            logger.info("鎾斁绛夊緟瓒呮椂");
+            JSONObject result = new JSONObject();
+            result.put("error","timeout");
+            resultDeferredResult.setResult(result);
+
+             // 娓呯悊RTP server
+        });
 
         DeviceChannel deviceChannel = storager.queryChannel(serial, code);
         if (deviceChannel == null) {
             JSONObject result = new JSONObject();
             result.put("error","channel[ " + code + " ]鏈壘鍒�");
-            return result;
+            resultDeferredResult.setResult(result);
         }else if (deviceChannel.getStatus() == 0) {
             JSONObject result = new JSONObject();
             result.put("error","channel[ " + code + " ]offline");
-            return result;
+            resultDeferredResult.setResult(result);
         }
+        DeferredResult<ResponseEntity<String>> play = playController.play(serial, code);
 
-        // 鏌ヨ鏄惁宸茬粡鍦ㄦ挱鏀�
-        StreamInfo streamInfo = storager.queryPlayByDevice(device.getDeviceId(), code);
-        if (streamInfo == null) {
-            logger.debug("streamInfo 绛変簬null, 閲嶆柊鐐规挱");
-//            streamInfo = cmder.playStreamCmd(device, code);
-        }else {
-            logger.debug("streamInfo 涓嶇瓑浜巒ull, 鍚戞祦濯掍綋鏌ヨ鏄惁姝e湪鎺ㄦ祦");
-            String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
-            JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
-            if (rtpInfo.getBoolean("exist")) {
-                logger.debug("鍚戞祦濯掍綋鏌ヨ姝e湪鎺ㄦ祦, 鐩存帴杩斿洖: " + streamInfo.getRtsp());
-                JSONObject result = new JSONObject();
-                result.put("StreamID", streamInfo.getSsrc());
-                result.put("DeviceID", device.getDeviceId());
-                result.put("ChannelID", code);
-                result.put("ChannelName", deviceChannel.getName());
-                result.put("ChannelCustomName", "");
-                result.put("FLV", streamInfo.getFlv());
-                result.put("WS_FLV", streamInfo.getWs_flv());
-                result.put("RTMP", streamInfo.getRtmp());
-                result.put("HLS", streamInfo.getHls());
-                result.put("RTSP", streamInfo.getRtsp());
-                result.put("CDN", "");
-                result.put("SnapURL", "");
-                result.put("Transport", device.getTransport());
-                result.put("StartAt", "");
-                result.put("Duration", "");
-                result.put("SourceVideoCodecName", "");
-                result.put("SourceVideoWidth", "");
-                result.put("SourceVideoHeight", "");
-                result.put("SourceVideoFrameRate", "");
-                result.put("SourceAudioCodecName", "");
-                result.put("SourceAudioSampleRate", "");
-                result.put("AudioEnable", "");
-                result.put("Ondemand", "");
-                result.put("InBytes", "");
-                result.put("InBitRate", "");
-                result.put("OutBytes", "");
-                result.put("NumOutputs", "");
-                result.put("CascadeSize", "");
-                result.put("RelaySize", "");
-                result.put("ChannelPTZType", 0);
-                return result;
-            } else {
-                logger.debug("鍚戞祦濯掍綋鏌ヨ娌℃湁鎺ㄦ祦, 閲嶆柊鐐规挱");
-                storager.stopPlay(streamInfo);
-//                streamInfo = cmder.playStreamCmd(device, code);
-            }
-        }
-
-        if (logger.isDebugEnabled()) {
-            logger.debug(String.format("璁惧棰勮 API璋冪敤锛宒eviceId锛�%s 锛宑hannelId锛�%s",serial, code));
-            logger.debug("璁惧棰勮 API璋冪敤锛宻src锛�"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
-        }
-        boolean lockFlag = true;
-        long startTime = System.currentTimeMillis();
-        while (lockFlag) {
-            try {
-                if (System.currentTimeMillis() - startTime > 10 * 1000) {
-                    storager.stopPlay(streamInfo);
-                    logger.info("鎾斁绛夊緟瓒呮椂");
-                    JSONObject result = new JSONObject();
-                    result.put("error","timeout");
-                    return result;
-                } else {
-
-                    StreamInfo streamInfoNow = storager.queryPlayByDevice(serial, code);
-                    logger.debug("姝e湪鍚戞祦濯掍綋鏌ヨ");
-                    if (streamInfoNow != null && streamInfoNow.getFlv() != null) {
-                        streamInfo = streamInfoNow;
-                        logger.debug("鍚戞祦濯掍綋鏌ヨ鍒�: " + streamInfoNow.getRtsp());
-                        lockFlag = false;
-                        continue;
-                    } else {
-                        Thread.sleep(2000);
-                        continue;
-                    }
-                }
-            } catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-        }
-        if(streamInfo!=null) {
+        play.setResultHandler((Object o)->{
+            ResponseEntity<String> responseEntity = (ResponseEntity)o;
+            StreamInfo streamInfo = JSON.parseObject(responseEntity.getBody(), StreamInfo.class);
             JSONObject result = new JSONObject();
-            result.put("StreamID", streamInfo.getSsrc());
+            result.put("StreamID", streamInfo.getStreamId());
             result.put("DeviceID", device.getDeviceId());
             result.put("ChannelID", code);
             result.put("ChannelName", deviceChannel.getName());
@@ -203,13 +138,9 @@
             result.put("CascadeSize", "");
             result.put("RelaySize", "");
             result.put("ChannelPTZType", 0);
-            return result;
-        } else {
-            logger.warn("璁惧棰勮API璋冪敤澶辫触锛�");
-            JSONObject result = new JSONObject();
-            result.put("error","璋冪敤澶辫触");
-            return result;
-        }
+            resultDeferredResult.setResult(result);
+        });
+        return resultDeferredResult;
     }
 
     /**
@@ -228,14 +159,15 @@
                              @RequestParam(required = false)String check_outputs
 
     ){
-        StreamInfo streamInfo = storager.queryPlayByDevice(serial, code);
+
+        StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code);
         if (streamInfo == null) {
             JSONObject result = new JSONObject();
             result.put("error","鏈壘鍒版祦淇℃伅");
             return result;
         }
-        cmder.streamByeCmd(streamInfo.getSsrc());
-        storager.stopPlay(streamInfo);
+        cmder.streamByeCmd(streamInfo.getStreamId());
+        redisCatchStorage.stopPlay(streamInfo);
         return null;
     }
 
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 638d5ae..7b98bd1 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -20,12 +20,20 @@
         timeout: 10000
     # [涓嶅彲鐢╙ jdbc鏁版嵁搴撻厤缃�, 鏆備笉鏀寔
     datasource:
+        #        name: eiot
+        #        url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
+        #        username:
+        #        password:
+        #        type: com.alibaba.druid.pool.DruidDataSource
+        #        driver-class-name: com.mysql.jdbc.Driver
         name: eiot
-        url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true
+        url: jdbc:sqlite::resource:wvp.sqlite
         username:
         password:
         type: com.alibaba.druid.pool.DruidDataSource
-        driver-class-name: com.mysql.jdbc.Driver
+        driver-class-name:  org.sqlite.JDBC
+        max-active: 1
+        min-idle: 1
 
 # [鍙�塢 WVP鐩戝惉鐨凥TTP绔彛, 缃戦〉鍜屾帴鍙h皟鐢ㄩ兘鏄繖涓鍙�
 server:
@@ -34,18 +42,18 @@
 # 浣滀负28181鏈嶅姟鍣ㄧ殑閰嶇疆
 sip:
     # [蹇呴』淇敼] 鏈満鐨処P, 蹇呴』鏄綉鍗′笂鐨処P
-    ip: 192.168.0.100
+    ip: 192.168.1.44
     # [鍙�塢 28181鏈嶅姟鐩戝惉鐨勭鍙�
     port: 5060
     # 鏍规嵁鍥芥爣6.1.2涓瀹氾紝domain瀹滈噰鐢↖D缁熶竴缂栫爜鐨勫墠鍗佷綅缂栫爜銆傚浗鏍囬檮褰旸涓畾涔夊墠8浣嶄负涓績缂栫爜锛堢敱鐪佺骇銆佸競绾с�佸尯绾с�佸熀灞傜紪鍙风粍鎴愶紝鍙傜収GB/T 2260-2007锛�
     # 鍚庝袱浣嶄负琛屼笟缂栫爜锛屽畾涔夊弬鐓ч檮褰旸.3
     # 3701020049鏍囪瘑灞变笢娴庡崡鍘嗕笅鍖� 淇℃伅琛屼笟鎺ュ叆
     # [鍙�塢
-    domain: 4401020049
+    domain: 3402000000
     # [鍙�塢
-    id: 44010200492000000001
+    id: 34020000002000000001
     # [鍙�塢 榛樿璁惧璁よ瘉瀵嗙爜锛屽悗缁墿灞曚娇鐢ㄨ澶囧崟鐙瘑鐮�
-    password: admin123
+    password: 12345678
 
 # 鐧婚檰鐨勭敤鎴峰悕瀵嗙爜
 auth:
@@ -57,7 +65,7 @@
 #zlm鏈嶅姟鍣ㄩ厤缃�
 media:
     # [蹇呴』淇敼] zlm鏈嶅姟鍣ㄧ殑鍐呯綉IP
-    ip: 192.168.0.100
+    ip: 192.168.1.44
     # [鍙�塢 zlm鏈嶅姟鍣ㄧ殑鍏綉IP, 鍐呯綉閮ㄧ讲缃┖鍗冲彲
     wanIp:
     # [鍙�塢 zlm鏈嶅姟鍣ㄧ殑hook鎵�浣跨敤鐨処P, 榛樿浣跨敤sip.ip
@@ -69,12 +77,12 @@
     # [鍙�塢 zlm鏈嶅姟鍣ㄧ殑hook.admin_params=secret
     secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
     # [鍙�塢 zlm鏈嶅姟鍣ㄧ殑general.streamNoneReaderDelayMS
-    streamNoneReaderDelayMS:  18000  # 鏃犱汉瑙傜湅澶氫箙鑷姩鍏抽棴娴�
-    # [鍙�塢 鍏抽棴绛夊緟鏀跺埌娴佺紪鐮佷俊鎭悗鍦ㄨ繑鍥�,
-    # 璁句负false鍙互鑾峰緱鏇村ソ鐨勫吋瀹规��,淇濊瘉杩斿洖鍚庢祦灏卞彲浠ユ挱鏀�,
-    # 璁句负true鍙互蹇�熸墦寮�鎾斁绐楀彛,鍙互鑾峰緱鏇村ソ鐨勪綋楠�
-    closeWaitRTPInfo: false
-    # 鍚敤udp澶氱鍙fā寮�
+    streamNoneReaderDelayMS:  600000  # 鏃犱汉瑙傜湅澶氫箙鑷姩鍏抽棴娴�, -1琛ㄧず姘镐笉鑷姩鍏抽棴,鍗� 鍏抽棴鎸夐渶鎷夋祦
+    # [鍙�塢 鑷姩鐐规挱锛� 浣跨敤鍥哄畾娴佸湴鍧�杩涜鎾斁鏃讹紝濡傛灉鏈偣鎾垯鑷姩杩涜鐐规挱, 闇�瑕乺tp.enable=true
+    autoApplyPlay: true
+    # [鍙�塢 閮ㄥ垎璁惧闇�瑕佹墿灞昐DP锛岄渶瑕佹墦寮�姝よ缃�
+    seniorSdp: false
+    # 鍚敤udp澶氱鍙fā寮�, 璇︾粏瑙i噴鍙傝��: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 涓嬬殑楂橀樁浣跨敤
     rtp:
         # [鍙�塢 鏄惁鍚敤udp澶氱鍙fā寮�, 寮�鍚悗浼氬湪udpPortRange鑼冨洿鍐呴�夋嫨绔彛鐢ㄤ簬濯掍綋娴佷紶杈�
         enable: true
diff --git a/src/main/resources/wvp.sqlite b/src/main/resources/wvp.sqlite
new file mode 100644
index 0000000..023ea35
--- /dev/null
+++ b/src/main/resources/wvp.sqlite
Binary files differ
diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue
index 4c39a3f..e221974 100644
--- a/web_src/src/components/channelList.vue
+++ b/web_src/src/components/channelList.vue
@@ -19,12 +19,12 @@
                     <el-option label="璁惧" value="false"></el-option>
                     <el-option label="瀛愮洰褰�" value="true"></el-option>
                 </el-select>
-                鍦ㄧ嚎鐘舵��: <el-select size="mini" @change="search" v-model="online" placeholder="璇烽�夋嫨" default-first-option>
+                鍦ㄧ嚎鐘舵��: <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="online" placeholder="璇烽�夋嫨" default-first-option>
                     <el-option label="鍏ㄩ儴" value=""></el-option>
-                    <el-option label="鍦ㄧ嚎" value="on"></el-option>
-                    <el-option label="绂荤嚎" value="off"></el-option>
+                    <el-option label="鍦ㄧ嚎" value="true"></el-option>
+                    <el-option label="绂荤嚎" value="false"></el-option>
                 </el-select>
-
+                <el-checkbox size="mini" style="margin-right: 1rem; float: right;" v-model="autoList" @change="autoListChange">鑷姩鍒锋柊</el-checkbox>
             </div>
             <devicePlayer ref="devicePlayer" v-loading="isLoging"></devicePlayer>
             <!--璁惧鍒楄〃-->
@@ -56,7 +56,7 @@
                         <el-button-group>
                             <!-- <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">鎾斁</el-button> -->
                             <el-button size="mini" icon="el-icon-video-play" @click="sendDevicePush(scope.row)">鎾斁</el-button>
-                            <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="scope.row.play" @click="stopDevicePush(scope.row)">鍋滄</el-button>
+                            <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopDevicePush(scope.row)">鍋滄</el-button>
                             <el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.parental == 1" @click="changeSubchannel(scope.row)">鏌ョ湅</el-button>
                             <el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">璁惧褰曡薄</el-button>
                             <!--                             <el-button size="mini" @click="sendDevicePush(scope.row)">褰曞儚鏌ヨ</el-button> -->
@@ -98,13 +98,17 @@
             count: parseInt(this.$route.params.count),
             total: 0,
             beforeUrl: "/videoList",
-            isLoging: false
+            isLoging: false,
+            autoList: false
         };
     },
 
     mounted() {
         this.initData();
-        this.updateLooper = setInterval(this.initData, 10000);
+        if (this.autoList) {
+            this.updateLooper = setInterval(this.initData, 1500);
+        }
+        
     },
     destroyed() {
         this.$destroy('videojs');
@@ -161,7 +165,7 @@
                 .then(function (res) {
                     console.log(res);
                     that.total = res.data.total;
-                    that.deviceChannelList = res.data.data;
+                    that.deviceChannelList = res.data.list;
                     // 闃叉鍑虹幇琛ㄦ牸閿欎綅
                     that.$nextTick(() => {
                         that.$refs.channelListTable.doLayout();
@@ -179,17 +183,16 @@
             let deviceId = this.deviceId;
             this.isLoging = true;
             let channelId = itemData.channelId;
-            let getEncoding = itemData.hasAudio ? '1' : '0'
-            console.log("閫氱煡璁惧鎺ㄦ祦1锛�" + deviceId + " : " + channelId + ":" + getEncoding);
+            console.log("閫氱煡璁惧鎺ㄦ祦1锛�" + deviceId + " : " + channelId );
             let that = this;
             this.$axios({
                 method: 'get',
-                url: '/api/play/' + deviceId + '/' + channelId + '?getEncoding=' + getEncoding
+                url: '/api/play/' + deviceId + '/' + channelId
             }).then(function (res) {
                 console.log(res.data)
-                let ssrc = res.data.ssrc;
+                let streamId = res.data.streamId;
                 that.isLoging = false;
-                if (!!ssrc) {
+                if (!!streamId) {
                     // that.$refs.devicePlayer.play(res.data, deviceId, channelId, itemData.hasAudio);
                     that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
                         streamInfo: res.data,
@@ -212,7 +215,7 @@
             var that = this;
             this.$axios({
                 method: 'post',
-                url: '/api/play/' + itemData.ssrc + '/stop'
+                url: '/api/play/' + itemData.streamId + '/stop'
             }).then(function (res) {
                 console.log(JSON.stringify(res));
                 that.initData();
@@ -258,7 +261,7 @@
                 })
                 .then(function (res) {
                     that.total = res.data.total;
-                    that.deviceChannelList = res.data.data;
+                    that.deviceChannelList = res.data.list;
                     // 闃叉鍑虹幇琛ㄦ牸閿欎綅
                     that.$nextTick(() => {
                         that.$refs.channelListTable.doLayout();
@@ -283,6 +286,13 @@
             }).then(function (res) {
                 console.log(JSON.stringify(res));
             });
+        },
+        autoListChange: function () {
+            if (this.autoList) {
+                this.updateLooper = setInterval(this.initData, 1500);
+            }else{
+                window.clearInterval(this.updateLooper);
+            }
         }
 
     }
diff --git a/web_src/src/components/gb28181/devicePlayer.vue b/web_src/src/components/gb28181/devicePlayer.vue
index 8442a82..babf0fe 100644
--- a/web_src/src/components/gb28181/devicePlayer.vue
+++ b/web_src/src/components/gb28181/devicePlayer.vue
@@ -1,6 +1,6 @@
 <template>
 <div id="devicePlayer" v-loading="isLoging">
-    
+
     <el-dialog title="瑙嗛鎾斁" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="close()">
         <!-- <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer> -->
         <player ref="videoPlayer" :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></player>
@@ -121,7 +121,7 @@
                                 <p>閲囨牱鐜�: {{item.sample_rate}}</p>
                             </div>
                         </div>
-                        
+
                     </div>
 
                 </el-tab-pane>
@@ -158,7 +158,6 @@
                 searchHistoryResult: [] //濯掍綋娴佸巻鍙茶褰曟悳绱㈢粨鏋�
             },
             showVideoDialog: false,
-            ssrc: '',
             streamId: '',
             convertKey: '',
             deviceId: '',
@@ -210,7 +209,6 @@
             this.tabActiveName = tab;
             this.channelId = channelId;
             this.deviceId = deviceId;
-            this.ssrc = "";
             this.streamId = "";
             this.videoUrl = ""
             if (!!this.$refs.videoPlayer) {
@@ -234,11 +232,10 @@
             console.log(val)
         },
         play: function (streamInfo, hasAudio) {
-            
+
             this.hasaudio = hasAudio;
             this.isLoging = false;
             this.videoUrl = streamInfo.ws_flv;
-            this.ssrc = streamInfo.ssrc;
             this.streamId = streamInfo.streamId;
             this.playFromStreamInfo(false, streamInfo)
         },
@@ -248,7 +245,7 @@
             this.$refs.videoPlayer.pause()
             that.$axios({
                 method: 'post',
-                url: '/api/play/' + that.ssrc + '/convert'
+                url: '/api/play/' + that.streamId + '/convert'
                 }).then(function (res) {
                     if (res.data.code == 0) {
                         that.convertKey = res.data.key;
@@ -317,7 +314,7 @@
             }
             this.convertKey = ''
         },
-        
+
         copySharedInfo: function (data) {
             console.log('澶嶅埗鍐呭锛�' + data);
             this.coverPlaying = false;
@@ -368,9 +365,9 @@
         },
         playRecord: function (row) {
             let that = this;
-            if (that.ssrc != "") {
+            if (that.streamId != "") {
                 that.stopPlayRecord(function () {
-                    that.ssrc = "",
+                    that.streamId = "",
                         that.playRecord(row);
                 })
             } else {
@@ -380,7 +377,7 @@
                         row.endTime
                 }).then(function (res) {
                     var streamInfo = res.data;
-                    that.ssrc = streamInfo.ssrc;
+                    that.streamId = streamInfo.streamId;
                     that.videoUrl = streamInfo.ws_flv;
                 });
             }
@@ -390,7 +387,7 @@
             this.videoUrl = '';
             this.$axios({
                 method: 'get',
-                url: '/api/playback/' + this.ssrc + '/stop'
+                url: '/api/playback/' + this.streamId + '/stop'
             }).then(function (res) {
                 if (callback) callback()
             });
diff --git a/web_src/src/components/videoList.vue b/web_src/src/components/videoList.vue
index ad2f701..46b4aac 100644
--- a/web_src/src/components/videoList.vue
+++ b/web_src/src/components/videoList.vue
@@ -8,7 +8,7 @@
 				<div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
 					<span style="font-size: 1rem; font-weight: bold;">璁惧鍒楄〃</span>
 					<div style="position: absolute; right: 1rem; top: 0.3rem;">
-						<el-button icon="el-icon-refresh-right" circle size="mini" @click="getDeviceList()"></el-button>
+						<el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" @click="getDeviceList()"></el-button>
 					</div>
 				</div>
 				<devicePlayer ref="devicePlayer"></devicePlayer>
@@ -21,7 +21,7 @@
 					<el-table-column label="鍦板潃" width="180" align="center">
 						<template slot-scope="scope">
 							<div slot="reference" class="name-wrapper">
-								<el-tag size="medium">{{ scope.row.host.address }}</el-tag>
+								<el-tag size="medium">{{ scope.row.hostAddress }}</el-tag>
 							</div>
 						</template>
 					</el-table-column>
@@ -51,7 +51,7 @@
 
 					<el-table-column label="鎿嶄綔" width="240" align="center" fixed="right">
 						<template slot-scope="scope">
-							<el-button size="mini" icon="el-icon-refresh"  @click="refDevice(scope.row)">鍒锋柊閫氶亾</el-button>
+							<el-button size="mini" :ref="scope.row.deviceId + 'refbtn' " icon="el-icon-refresh"  @click="refDevice(scope.row)">鍒锋柊閫氶亾</el-button>
 							<el-button size="mini" icon="el-icon-s-open"  type="primary" @click="showChannelList(scope.row)">鏌ョ湅閫氶亾</el-button>
 						</template>
 					</el-table-column>
@@ -90,7 +90,8 @@
 				winHeight: window.innerHeight - 200,
 				currentPage:1,
 				count:15,
-				total:0
+				total:0,
+				getDeviceListLoading: false
 			};
 		},
 		computed: {
@@ -130,7 +131,7 @@
 			},
 			getDeviceList: function() {
 				let that = this;
-
+				this.getDeviceListLoading = true;
 				this.$axios.get(`/api/devices`,{
 					params: {
 						page: that.currentPage - 1,
@@ -139,11 +140,14 @@
 				} )
 				.then(function (res) {
 					console.log(res);
+					console.log(res.data.list);
 					that.total = res.data.total;
-					that.deviceList = res.data.data;
+					that.deviceList = res.data.list;
+					that.getDeviceListLoading = false;
 				})
 				.catch(function (error) {
 					console.log(error);
+					that.getDeviceListLoading = false;
 				});
 
 			},
@@ -158,17 +162,31 @@
 			refDevice: function(itemData) {
 				///api/devices/{deviceId}/sync
 				console.log("鍒锋柊瀵瑰簲璁惧:" + itemData.deviceId);
+				var that = this;
+				that.$refs[itemData.deviceId + 'refbtn' ].loading = true;
 				this.$axios({
 					method: 'post',
 					url: '/api/devices/' + itemData.deviceId + '/sync'
 				}).then(function(res) {
-					// console.log("鍒锋柊璁惧缁撴灉锛�"+JSON.stringify(res));
+					console.log("鍒锋柊璁惧缁撴灉锛�"+JSON.stringify(res));
+					if (!res.data.deviceId) {
+						that.$message({
+							showClose: true,
+							message: res.data,
+							type: 'error'
+						});
+					}else{
+						that.$message({
+							showClose: true,
+							message: '璇锋眰鎴愬姛',
+							type: 'success'
+						});
+					}
+					that.initData()
+					that.$refs[itemData.deviceId + 'refbtn' ].loading = false;
 				}).catch(function(e) {
-					that.$message({
-						showClose: true,
-						message: '璇锋眰鎴愬姛',
-						type: 'success'
-					});
+					console.error(e)
+					that.$refs[itemData.deviceId + 'refbtn' ].loading = false;
 				});;
 			},
 			//閫氱煡璁惧涓婁紶濯掍綋娴�

--
Gitblit v1.8.0