From 509d9b3cbba7ba8fdc7466c34e46db70d41517a8 Mon Sep 17 00:00:00 2001
From: 648540858 <648540858@qq.com>
Date: 星期二, 27 二月 2024 10:22:13 +0800
Subject: [PATCH] Merge branch 'wvp-28181-2.0' into main-dev

---
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java                                                                  |   28 
 src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java                                               |   15 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                                               |   32 
 src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java                                                        |    5 
 src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java                                                |   14 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java                                                         |    4 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java                                                  |   10 
 数据库/2.7.0/初始化-postgresql-kingbase-2.7.0.sql                                                                                   |  324 ++++++++++++++
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbSteamIdentification.java                                                   |   44 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java                                                   |    5 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java |    5 
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java                                                            |    9 
 web_src/src/components/dialog/deviceEdit.vue                                                                                  |    6 
 数据库/2.7.0/更新-mysql-2.7.0.sql                                                                                                  |    5 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java                                                           |   12 
 src/main/java/com/genersoft/iot/vmp/gb28181/session/CommonSessionManager.java                                                 |   86 +++
 src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java                                        |   15 
 src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java                                 |   15 
 数据库/2.7.0/初始化-mysql-2.7.0.sql                                                                                                 |  324 ++++++++++++++
 src/main/java/com/genersoft/iot/vmp/service/IPlayService.java                                                                 |    3 
 数据库/2.7.0/更新-postgresql-kingbase-2.7.0.sql                                                                                    |    5 
 src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java                                                       |   99 +--
 src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java                                                           |   26 
 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java                                                         |  117 ++--
 src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java                                                                    |   17 
 src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java                                                          |    4 
 README.md                                                                                                                     |    1 
 src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java                                                               |    5 
 web_src/src/components/channelList.vue                                                                                        |   96 +++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java                           |    5 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java                             |    5 
 src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java                                                     |   16 
 32 files changed, 1,104 insertions(+), 253 deletions(-)

diff --git a/README.md b/README.md
index a29280b..12c7673 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,7 @@
 - [X] 鏀寔鐢靛瓙鍦板浘锛屾敮鎸佹帴鍏GS84鍜孏CJ02涓ょ鍧愭爣绯伙紝骞朵笖鑷姩杞寲涓哄悎閫傜殑鍧愭爣绯昏繘琛屽睍绀哄拰鍒嗗彂
 - [X] 鎺ュ叆璁惧
   - [X] 瑙嗛棰勮
+  - [X] 鏀寔涓荤爜娴佸瓙鐮佹祦鍒囨崲
   - [X] 鏃犻檺鍒舵帴鍏ヨ矾鏁帮紝鑳芥帴鍏ュ灏戣澶囧彧鍙栧喅浜庝綘鐨勬湇鍔″櫒鎬ц兘
   - [X] 浜戝彴鎺у埗锛屾帶鍒惰澶囪浆鍚戯紝鎷夎繎锛屾媺杩�
   - [X] 棰勭疆浣嶆煡璇紝浣跨敤涓庤缃�
diff --git a/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java b/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java
index dabdb4f..dbe9e09 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java
@@ -1,7 +1,6 @@
 package com.genersoft.iot.vmp.common;
 
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
-import io.swagger.v3.oas.annotations.media.Schema;
 
 /**
  * 璁板綍姣忔鍙戦�乮nvite娑堟伅鐨勭姸鎬�
@@ -124,21 +123,5 @@
     public void setStreamMode(String streamMode) {
         this.streamMode = streamMode;
     }
-
-
-    /*=========================璁惧涓诲瓙鐮佹祦閫昏緫START====================*/
-    @Schema(description = "鏄惁涓哄瓙鐮佹祦(true-鏄紝false-涓荤爜娴�)")
-    private boolean subStream;
-
-    public boolean isSubStream() {
-        return subStream;
-    }
-
-    public void setSubStream(boolean subStream) {
-        this.subStream = subStream;
-    }
-
-
-
 
 }
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 9bfab63..a9752f1 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
@@ -452,27 +452,11 @@
 	public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
 		this.sipTransactionInfo = sipTransactionInfo;
 	}
+    public boolean isBroadcastPushAfterAck() {
+        return broadcastPushAfterAck;
+    }
 
-	/*======================璁惧涓诲瓙鐮佹祦閫昏緫START=========================*/
-	@Schema(description = "寮�鍚富瀛愮爜娴佸垏鎹㈢殑寮�鍏筹紙false-涓嶅紑鍚紝true-寮�鍚級")
-	private boolean switchPrimarySubStream;
-
-	public boolean isSwitchPrimarySubStream() {
-		return switchPrimarySubStream;
-	}
-
-	public void setSwitchPrimarySubStream(boolean switchPrimarySubStream) {
-		this.switchPrimarySubStream = switchPrimarySubStream;
-	}
-
-	/*======================璁惧涓诲瓙鐮佹祦閫昏緫END=========================*/
-
-
-	public boolean isBroadcastPushAfterAck() {
-		return broadcastPushAfterAck;
-	}
-
-	public void setBroadcastPushAfterAck(boolean broadcastPushAfterAck) {
-		this.broadcastPushAfterAck = broadcastPushAfterAck;
-	}
+    public void setBroadcastPushAfterAck(boolean broadcastPushAfterAck) {
+        this.broadcastPushAfterAck = broadcastPushAfterAck;
+    }
 }
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 f7ef12d..d58abcb 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
@@ -246,6 +246,10 @@
 	@Schema(description = "GPS鐨勬洿鏂版椂闂�")
 	private String gpsTime;
 
+	@Schema(description = "鐮佹祦鏍囪瘑锛屼紭鍏堢骇楂樹簬璁惧涓爜娴佹爣璇嗭紝" +
+			"鐢ㄤ簬閫夋嫨鐮佹祦鏃剁粍鎴愮爜娴佹爣璇嗐�傞粯璁や负null锛屼笉璁剧疆銆傚彲閫夊��: stream/streamnumber/streamprofile/streamMode")
+	private String streamIdentification;
+
 	public int getId() {
 		return id;
 	}
@@ -574,4 +578,12 @@
 	public void setGpsTime(String gpsTime) {
 		this.gpsTime = gpsTime;
 	}
+
+	public String getStreamIdentification() {
+		return streamIdentification;
+	}
+
+	public void setStreamIdentification(String streamIdentification) {
+		this.streamIdentification = streamIdentification;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbSteamIdentification.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbSteamIdentification.java
new file mode 100644
index 0000000..63c17a8
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbSteamIdentification.java
@@ -0,0 +1,44 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+/**
+ * 鐮佹祦绱㈠紩鏍囪瘑
+ */
+public enum GbSteamIdentification {
+    /**
+     * 涓荤爜娴� stream:0
+     * 瀛愮爜娴� stream:1s
+     */
+    streamMain("stream", new String[]{"0","1"}),
+    /**
+     * 鍥芥爣28181-2022瀹氫箟鐨勬柟寮�
+     * 涓荤爜娴� streamnumber:0
+     * 瀛愮爜娴� streamnumber:1
+     */
+    streamnumber("streamnumber", new String[]{"0","1"}),
+    /**
+     * 涓荤爜娴� streamprofile:0
+     * 瀛愮爜娴� streamprofile:1
+     */
+    streamprofile("streamprofile", new String[]{"0","1"}),
+    /**
+     * 閫傜敤鐨勫搧鐗岋細 TP-LINK
+     */
+    streamMode("streamMode", new String[]{"main","sub"}),
+    ;
+
+    GbSteamIdentification(String value, String[] indexArray) {
+        this.value = value;
+        this.indexArray = indexArray;
+    }
+
+    private String value;
+    private String[] indexArray;
+
+    public String getValue() {
+        return value;
+    }
+
+    public String[] getIndexArray() {
+        return indexArray;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
index d932a20..e7b7ab8 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
@@ -52,7 +52,7 @@
         Runnable runnable = dynamicTask.get(taskOverdueKey);
         if (runnable instanceof ISubscribeTask) {
             ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
-            subscribeTask.stop();
+            subscribeTask.stop(null);
         }
         // 娣诲姞浠诲姟澶勭悊璁㈤槄杩囨湡
         dynamicTask.stop(taskOverdueKey);
@@ -87,7 +87,7 @@
         Runnable runnable = dynamicTask.get(taskOverdueKey);
         if (runnable instanceof ISubscribeTask) {
             ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
-            subscribeTask.stop();
+            subscribeTask.stop(null);
         }
         // 娣诲姞浠诲姟澶勭悊璁㈤槄杩囨湡
         dynamicTask.stop(taskOverdueKey);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
index 36e5714..e07761a 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
@@ -2,6 +2,8 @@
 
 import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent;
 import gov.nist.javax.sip.message.SIPRequest;
+import gov.nist.javax.sip.message.SIPResponse;
+import org.apache.commons.lang3.ObjectUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -11,8 +13,7 @@
 import javax.sip.ResponseEvent;
 import javax.sip.TimeoutEvent;
 import javax.sip.TransactionTerminatedEvent;
-import javax.sip.header.CallIdHeader;
-import javax.sip.message.Response;
+import javax.sip.header.WarningHeader;
 import java.time.Instant;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
@@ -97,14 +98,27 @@
             this.event = event;
             if (event instanceof ResponseEvent) {
                 ResponseEvent responseEvent = (ResponseEvent)event;
-                Response response = responseEvent.getResponse();
+                SIPResponse response = (SIPResponse)responseEvent.getResponse();
                 this.type = EventResultType.response;
                 if (response != null) {
-                    this.msg = response.getReasonPhrase();
+                    WarningHeader warningHeader = (WarningHeader)response.getHeader(WarningHeader.NAME);
+                    if (warningHeader != null && !ObjectUtils.isEmpty(warningHeader.getText())) {
+                        this.msg = "";
+                        if (warningHeader.getCode() > 0) {
+                            this.msg += warningHeader.getCode() + ":";
+                        }
+                        if (warningHeader.getAgent() != null) {
+                            this.msg += warningHeader.getCode() + ":";
+                        }
+                        if (warningHeader.getText() != null) {
+                            this.msg += warningHeader.getText();
+                        }
+                    }else {
+                        this.msg = response.getReasonPhrase();
+                    }
                     this.statusCode = response.getStatusCode();
+                    this.callId = response.getCallIdHeader().getCallId();
                 }
-                this.callId = ((CallIdHeader)response.getHeader(CallIdHeader.NAME)).getCallId();
-
             }else if (event instanceof TimeoutEvent) {
                 TimeoutEvent timeoutEvent = (TimeoutEvent)event;
                 this.type = EventResultType.timeout;
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/CommonSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/CommonSessionManager.java
new file mode 100755
index 0000000..2d8c7e1
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/CommonSessionManager.java
@@ -0,0 +1,86 @@
+package com.genersoft.iot.vmp.gb28181.session;
+
+import com.genersoft.iot.vmp.common.CommonCallback;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.util.Calendar;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 閫氱敤鍥炶皟绠$悊
+ */
+@Component
+public class CommonSessionManager {
+
+    public static Map<String, CommonSession> callbackMap = new ConcurrentHashMap<>();
+
+    /**
+     * 瀛樺偍鍥炶皟鐩稿叧鐨勪俊鎭�
+     */
+    class CommonSession{
+        public String session;
+        public long createTime;
+        public int timeout;
+
+        public CommonCallback<Object> callback;
+        public CommonCallback<String> timeoutCallback;
+    }
+
+    /**
+     * 娣诲姞鍥炶皟
+     * @param sessionId 鍞竴鏍囪瘑
+     * @param callback 鍥炶皟
+     * @param timeout 瓒呮椂鏃堕棿, 鍗曚綅鍒嗛挓
+     */
+    public void add(String sessionId, CommonCallback<Object> callback, CommonCallback<String> timeoutCallback,
+                    Integer timeout) {
+        CommonSession commonSession = new CommonSession();
+        commonSession.session = sessionId;
+        commonSession.callback = callback;
+        commonSession.createTime = System.currentTimeMillis();
+        if (timeoutCallback != null) {
+            commonSession.timeoutCallback = timeoutCallback;
+        }
+        if (timeout != null) {
+            commonSession.timeout = timeout;
+        }
+        callbackMap.put(sessionId, commonSession);
+    }
+
+    public void add(String sessionId, CommonCallback<Object> callback) {
+        add(sessionId, callback, null, 1);
+    }
+
+    public CommonCallback<Object> get(String sessionId, boolean destroy) {
+        CommonSession commonSession = callbackMap.get(sessionId);
+        if (destroy) {
+            callbackMap.remove(sessionId);
+        }
+        return commonSession.callback;
+    }
+
+    public CommonCallback<Object> get(String sessionId) {
+        return get(sessionId, false);
+    }
+
+    public void delete(String sessionID) {
+        callbackMap.remove(sessionID);
+    }
+
+    @Scheduled(fixedRate= 60)   //姣忓垎閽熸墽琛屼竴娆�
+    public void execute(){
+        Calendar cal = Calendar.getInstance();
+        cal.add(Calendar.MINUTE, -1);
+        for (String session : callbackMap.keySet()) {
+            if (callbackMap.get(session).createTime < cal.getTimeInMillis()) {
+                // 瓒呮椂
+                if (callbackMap.get(session).timeoutCallback != null) {
+                    callbackMap.get(session).timeoutCallback.run("timeout");
+                }
+                callbackMap.remove(session);
+            }
+        }
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
index a4e711d..8d1c7d2 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
@@ -1,10 +1,10 @@
 package com.genersoft.iot.vmp.gb28181.task;
 
-import javax.sip.DialogState;
+import com.genersoft.iot.vmp.common.CommonCallback;
 
 /**
  * @author lin
  */
 public interface ISubscribeTask extends Runnable{
-    void stop();
+    void stop(CommonCallback<Boolean> callback);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
index 2ffbfe4..d9270bb 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.task.impl;
 
+import com.genersoft.iot.vmp.common.CommonCallback;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
@@ -7,14 +8,13 @@
 import gov.nist.javax.sip.message.SIPRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
-import javax.sip.*;
+import javax.sip.DialogState;
+import javax.sip.InvalidArgumentException;
+import javax.sip.ResponseEvent;
+import javax.sip.SipException;
 import javax.sip.header.ToHeader;
 import java.text.ParseException;
-import java.util.Timer;
-import java.util.TimerTask;
 
 /**
  * 鐩綍璁㈤槄浠诲姟
@@ -71,7 +71,7 @@
     }
 
     @Override
-    public void stop() {
+    public void stop(CommonCallback<Boolean> callback) {
         /**
          * dialog 鐨勫悇涓姸鎬�
          * EARLY-> Early state鐘舵��-鍒濆璇锋眰鍙戦�佷互鍚庯紝鏀跺埌浜嗕竴涓复鏃跺搷搴旀秷鎭�
@@ -94,6 +94,9 @@
                     // 鎴愬姛
                     logger.info("[鍙栨秷鐩綍璁㈤槄]鎴愬姛锛� {}", device.getDeviceId());
                 }
+                if (callback != null) {
+                    callback.run(event.getResponse().getRawContent() != null);
+                }
             },eventResult -> {
                 // 澶辫触
                 logger.warn("[鍙栨秷鐩綍璁㈤槄]澶辫触锛屼俊浠ゅ彂閫佸け璐ワ細 {}-{} ", device.getDeviceId(), eventResult.msg);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
index 2e792c1..a4512f3 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
@@ -1,20 +1,9 @@
 package com.genersoft.iot.vmp.gb28181.task.impl;
 
-import com.genersoft.iot.vmp.conf.DynamicTask;
-import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.common.CommonCallback;
 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
-import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.service.IPlatformService;
-import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
-import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
-import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import com.genersoft.iot.vmp.utils.SpringBeanFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.scheduling.annotation.Async;
-
-import javax.sip.DialogState;
-import java.util.List;
 
 /**
  * 鍚戝凡缁忚闃�(绉诲姩浣嶇疆)鐨勪笂绾у彂閫丮obilePosition娑堟伅
@@ -38,7 +27,7 @@
     }
 
     @Override
-    public void stop() {
+    public void stop(CommonCallback<Boolean> callback) {
 
     }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
index 0abd3ca..9fed079 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
@@ -1,21 +1,19 @@
 package com.genersoft.iot.vmp.gb28181.task.impl;
 
+import com.genersoft.iot.vmp.common.CommonCallback;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
 import gov.nist.javax.sip.message.SIPRequest;
-import gov.nist.javax.sip.message.SIPResponse;
-import org.dom4j.Element;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.scheduling.annotation.Async;
 
-import javax.sip.*;
+import javax.sip.InvalidArgumentException;
+import javax.sip.ResponseEvent;
+import javax.sip.SipException;
 import javax.sip.header.ToHeader;
 import java.text.ParseException;
-import java.util.Timer;
-import java.util.TimerTask;
 
 /**
  * 绉诲姩浣嶇疆璁㈤槄鐨勫畾鏃舵洿鏂�
@@ -70,7 +68,7 @@
     }
 
     @Override
-    public void stop() {
+    public void stop(CommonCallback<Boolean> callback) {
         /**
          * dialog 鐨勫悇涓姸鎬�
          * EARLY-> Early state鐘舵��-鍒濆璇锋眰鍙戦�佷互鍚庯紝鏀跺埌浜嗕竴涓复鏃跺搷搴旀秷鎭�
@@ -92,6 +90,9 @@
                     // 鎴愬姛
                     logger.info("[鍙栨秷绉诲姩浣嶇疆璁㈤槄]鎴愬姛锛� {}", device.getDeviceId());
                 }
+                if (callback != null) {
+                    callback.run(event.getResponse().getRawContent() != null);
+                }
             },eventResult -> {
                 // 澶辫触
                 logger.warn("[鍙栨秷绉诲姩浣嶇疆璁㈤槄]澶辫触锛屼俊浠ゅ彂閫佸け璐ワ細 {}-{} ", device.getDeviceId(), eventResult.msg);
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 d2510d0..d48e3a8 100755
--- 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
@@ -5,6 +5,7 @@
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
+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.dto.MediaServerItem;
@@ -97,9 +98,9 @@
 	/**
 	 * 璇锋眰棰勮瑙嗛娴�
 	 * @param device  瑙嗛璁惧
-	 * @param channelId  棰勮閫氶亾
+	 * @param channel  棰勮閫氶亾
 	 */
-	void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
+	void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
 
 	/**
 	 * 璇锋眰鍥炴斁瑙嗛娴�
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
index 48ad41c..723c715 100755
--- 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
@@ -7,6 +7,10 @@
 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
 import com.genersoft.iot.vmp.gb28181.SipLayer;
 import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
@@ -266,12 +270,12 @@
      * 璇锋眰棰勮瑙嗛娴�
      *
      * @param device     瑙嗛璁惧
-     * @param channelId  棰勮閫氶亾
+     * @param channel  棰勮閫氶亾
      * @param event      hook璁㈤槄
      * @param errorEvent sip閿欒璁㈤槄
      */
     @Override
-    public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
+    public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
                               ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
         String stream = ssrcInfo.getStream();
 
@@ -295,7 +299,7 @@
         }
         StringBuffer content = new StringBuffer(200);
         content.append("v=0\r\n");
-        content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");
+        content.append("o=" + channel.getChannelId() + " 0 0 IN IP4 " + sdpIp + "\r\n");
         content.append("s=Play\r\n");
         content.append("c=IN IP4 " + sdpIp + "\r\n");
         content.append("t=0 0\r\n");
@@ -346,20 +350,8 @@
             }
         }
 
-        if( device.isSwitchPrimarySubStream() ){
-            if("TP-LINK".equals(device.getManufacturer())){
-                if (device.isSwitchPrimarySubStream()){
-                    content.append("a=streamMode:sub\r\n");
-                }else {
-                    content.append("a=streamMode:main\r\n");
-                }
-            }else {
-                if (device.isSwitchPrimarySubStream()){
-                    content.append("a=streamprofile:1\r\n");
-                }else {
-                    content.append("a=streamprofile:0\r\n");
-                }
-            }
+        if (!ObjectUtils.isEmpty(channel.getStreamIdentification())) {
+            content.append("a=" + channel.getStreamIdentification() + "\r\n");
         }
 
         content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
@@ -368,16 +360,16 @@
 
 
 
-        Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
+        Request request = headerProvider.createInviteRequest(device, channel.getChannelId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
         sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
-            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
+            streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
             mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
             errorEvent.response(e);
         }), e -> {
             ResponseEvent responseEvent = (ResponseEvent) e.event;
             SIPResponse response = (SIPResponse) responseEvent.getResponse();
             String callId = response.getCallIdHeader().getCallId();
-            streamSession.put(device.getDeviceId(), channelId, callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response,
+            streamSession.put(device.getDeviceId(), channel.getChannelId(), callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response,
                     InviteSessionType.PLAY);
             okEvent.response(e);
         });
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
index d35c6a6..435f35f 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -6,7 +6,6 @@
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
-import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
@@ -38,7 +37,6 @@
 import javax.sip.header.FromHeader;
 import javax.sip.message.Response;
 import java.text.ParseException;
-import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
@@ -222,7 +220,6 @@
 					mobilePosition.getLongitude(), mobilePosition.getLatitude());
 			mobilePosition.setReportSource("Mobile Position");
 
-
 			// 鏇存柊device channel 鐨勭粡绾害
 			DeviceChannel deviceChannel = new DeviceChannel();
 			deviceChannel.setDeviceId(device.getDeviceId());
@@ -242,6 +239,8 @@
 			}
 
 			storager.updateChannelPosition(deviceChannel);
+			// 鍚戝叧鑱斾簡璇ラ�氶亾骞朵笖寮�鍚Щ鍔ㄤ綅缃闃呯殑涓婄骇骞冲彴鍙戦�佺Щ鍔ㄤ綅缃闃呮秷鎭�
+
 
 			// 鍙戦�乺edis娑堟伅銆� 閫氱煡浣嶇疆淇℃伅鐨勫彉鍖�
 			JSONObject jsonObject = new JSONObject();
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
index 22c34a6..034e24f 100755
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -82,8 +82,9 @@
             device.setIp(remoteAddressInfo.getIp());
             // 璁惧鍦板潃鍙樺寲浼氬紩璧风洰褰曡闃呬换鍔″け鏁堬紝闇�瑕侀噸鏂版坊鍔�
             if (device.getSubscribeCycleForCatalog() > 0) {
-                deviceService.removeCatalogSubscribe(device);
-                deviceService.addCatalogSubscribe(device);
+                deviceService.removeCatalogSubscribe(device, result->{
+                    deviceService.addCatalogSubscribe(device);
+                });
             }
         }
         if (device.getKeepaliveTime() == null) {
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java b/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
index cd402a1..5a20841 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
@@ -87,4 +87,9 @@
      * 鐩存帴鎵归噺娣诲姞
      */
     void batchAddChannel(List<DeviceChannel> deviceChannels);
+
+    /**
+     * 淇敼閫氶亾鐨勭爜娴佺被鍨�
+     */
+    void updateChannelStreamIdentification(DeviceChannel channel);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java b/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
index e20c3bf..afa0044 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.service;
 
+import com.genersoft.iot.vmp.common.CommonCallback;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
@@ -39,7 +40,7 @@
      * @param device 璁惧淇℃伅
      * @return 甯冨皵
      */
-    boolean removeCatalogSubscribe(Device device);
+    boolean removeCatalogSubscribe(Device device, CommonCallback<Boolean> callback);
 
     /**
      * 娣诲姞绉诲姩浣嶇疆璁㈤槄
@@ -53,7 +54,7 @@
      * @param device 璁惧淇℃伅
      * @return 甯冨皵
      */
-    boolean removeMobilePositionSubscribe(Device device);
+    boolean removeMobilePositionSubscribe(Device device, CommonCallback<Boolean> callback);
 
     /**
      * 绉婚櫎绉诲姩浣嶇疆璁㈤槄
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
index ca4256e..77525e8 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -6,6 +6,7 @@
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
 import com.genersoft.iot.vmp.service.bean.ErrorCallback;
@@ -25,7 +26,7 @@
  */
 public interface IPlayService {
 
-    void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
+    void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channelId,
               ErrorCallback<Object> callback);
     SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<Object> callback);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
index 43cdf42..55fa5e9 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
@@ -18,6 +18,7 @@
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -267,5 +268,16 @@
         }
     }
 
-
+    @Override
+    public void updateChannelStreamIdentification(DeviceChannel channel) {
+        assert !ObjectUtils.isEmpty(channel.getDeviceId());
+        assert !ObjectUtils.isEmpty(channel.getStreamIdentification());
+        if (ObjectUtils.isEmpty(channel.getStreamIdentification())) {
+            logger.info("[閲嶇疆閫氶亾鐮佹祦绫诲瀷] 璁惧: {}, 鐮佹祦锛� {}", channel.getDeviceId(), channel.getStreamIdentification());
+        }else {
+            logger.info("[鏇存柊閫氶亾鐮佹祦绫诲瀷] 璁惧: {}, 閫氶亾锛歿}锛� 鐮佹祦锛� {}", channel.getDeviceId(), channel.getChannelId(),
+                    channel.getStreamIdentification());
+        }
+        channelMapper.updateChannelStreamIdentification(channel);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
index 373c862..3da2845 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -1,10 +1,10 @@
 package com.genersoft.iot.vmp.service.impl;
 
 import com.baomidou.dynamic.datasource.annotation.DS;
+import com.genersoft.iot.vmp.common.CommonCallback;
 import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
-import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
 import com.genersoft.iot.vmp.gb28181.bean.*;
 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
@@ -145,10 +145,6 @@
             }
             sync(device);
         }else {
-
-            if (deviceInDb != null) {
-                device.setSwitchPrimarySubStream(deviceInDb.isSwitchPrimarySubStream());
-            }
             if(!device.isOnLine()){
                 device.setOnLine(true);
                 device.setCreateTime(now);
@@ -238,12 +234,8 @@
             }
         }
         // 绉婚櫎璁㈤槄
-        removeCatalogSubscribe(device);
-        removeMobilePositionSubscribe(device);
-        if (userSetting.getDeviceStatusNotify()) {
-            // 鍙戦�乺edis娑堟伅
-            redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, false);
-        }
+        removeCatalogSubscribe(device, null);
+        removeMobilePositionSubscribe(device, null);
 
         List<AudioBroadcastCatch> audioBroadcastCatches = audioBroadcastManager.get(deviceId);
         if (audioBroadcastCatches.size() > 0) {
@@ -281,7 +273,7 @@
     }
 
     @Override
-    public boolean removeCatalogSubscribe(Device device) {
+    public boolean removeCatalogSubscribe(Device device, CommonCallback<Boolean> callback) {
         if (device == null || device.getSubscribeCycleForCatalog() < 0) {
             return false;
         }
@@ -291,7 +283,7 @@
             Runnable runnable = dynamicTask.get(taskKey);
             if (runnable instanceof ISubscribeTask) {
                 ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
-                subscribeTask.stop();
+                subscribeTask.stop(callback);
             }
         }
         dynamicTask.stop(taskKey);
@@ -314,7 +306,7 @@
     }
 
     @Override
-    public boolean removeMobilePositionSubscribe(Device device) {
+    public boolean removeMobilePositionSubscribe(Device device, CommonCallback<Boolean> callback) {
         if (device == null || device.getSubscribeCycleForCatalog() < 0) {
             return false;
         }
@@ -324,7 +316,7 @@
             Runnable runnable = dynamicTask.get(taskKey);
             if (runnable instanceof ISubscribeTask) {
                 ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
-                subscribeTask.stop();
+                subscribeTask.stop(callback);
             }
         }
         dynamicTask.stop(taskKey);
@@ -515,21 +507,6 @@
             logger.warn("鏇存柊璁惧鏃舵湭鎵惧埌璁惧淇℃伅");
             return;
         }
-        if(deviceInStore.isSwitchPrimarySubStream() != device.isSwitchPrimarySubStream()){
-            //褰撲慨鏀硅澶囩殑涓诲瓙鐮佹祦寮�鍏虫椂锛岄渶瑕佹牎楠屾槸鍚﹀瓨鍦ㄦ祦锛屽鏋滃瓨鍦ㄦ祦鍒欑洿鎺ュ叧闂�
-            List<SsrcTransaction> ssrcTransactionForAll = streamSession.getSsrcTransactionForAll(device.getDeviceId(), null, null, null);
-            if(ssrcTransactionForAll != null){
-                for (SsrcTransaction ssrcTransaction: ssrcTransactionForAll) {
-                    try {
-                        cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), ssrcTransaction.getStream(), null, null);
-                    } catch (InvalidArgumentException | SsrcTransactionNotFoundException | ParseException | SipException e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            }
-            deviceChannelMapper.clearPlay(device.getDeviceId());
-            inviteStreamService.clearInviteInfo(device.getDeviceId());
-        }
 
         if (!ObjectUtils.isEmpty(device.getName())) {
             deviceInStore.setName(device.getName());
@@ -552,39 +529,54 @@
         if (!ObjectUtils.isEmpty(device.getStreamMode())) {
             deviceInStore.setStreamMode(device.getStreamMode());
         }
-
-
         //  鐩綍璁㈤槄鐩稿叧鐨勪俊鎭�
         if (deviceInStore.getSubscribeCycleForCatalog() != device.getSubscribeCycleForCatalog()) {
             if (device.getSubscribeCycleForCatalog() > 0) {
                 // 鑻ュ凡寮�鍚闃咃紝浣嗚闃呭懆鏈熶笉鍚岋紝鍒欏厛鍙栨秷
                 if (deviceInStore.getSubscribeCycleForCatalog() != 0) {
-                    removeCatalogSubscribe(deviceInStore);
+                    removeCatalogSubscribe(deviceInStore, result->{
+                        // 寮�鍚闃�
+                        deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog());
+                        addCatalogSubscribe(deviceInStore);
+                        // 鍥犱负鏄紓姝ユ墽琛岋紝闇�瑕佸湪杩欓噷鏇存柊涓嬫暟鎹�
+                        deviceMapper.updateCustom(deviceInStore);
+                        redisCatchStorage.updateDevice(deviceInStore);
+                    });
+                }else {
+                    // 寮�鍚闃�
+                    deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog());
+                    addCatalogSubscribe(deviceInStore);
                 }
-                // 寮�鍚闃�
-                deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog());
-                addCatalogSubscribe(deviceInStore);
+
             }else if (device.getSubscribeCycleForCatalog() == 0) {
                 // 鍙栨秷璁㈤槄
-                deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog());
-                removeCatalogSubscribe(deviceInStore);
+                deviceInStore.setSubscribeCycleForCatalog(0);
+                removeCatalogSubscribe(deviceInStore, null);
             }
         }
-
         // 绉诲姩浣嶇疆璁㈤槄鐩稿叧鐨勪俊鎭�
-        if (device.getSubscribeCycleForMobilePosition() > 0) {
-            if (deviceInStore.getSubscribeCycleForMobilePosition() == 0 || deviceInStore.getSubscribeCycleForMobilePosition() != device.getSubscribeCycleForMobilePosition()) {
-                deviceInStore.setMobilePositionSubmissionInterval(device.getMobilePositionSubmissionInterval());
-                deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition());
-                // 寮�鍚闃�
-                addMobilePositionSubscribe(deviceInStore);
-            }
-        }else if (device.getSubscribeCycleForMobilePosition() == 0) {
-            if (deviceInStore.getSubscribeCycleForMobilePosition() != 0) {
-                deviceInStore.setMobilePositionSubmissionInterval(device.getMobilePositionSubmissionInterval());
-                deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition());
+        if (deviceInStore.getSubscribeCycleForMobilePosition() != device.getSubscribeCycleForMobilePosition()) {
+            if (device.getSubscribeCycleForMobilePosition() > 0) {
+                // 鑻ュ凡寮�鍚闃咃紝浣嗚闃呭懆鏈熶笉鍚岋紝鍒欏厛鍙栨秷
+                if (deviceInStore.getSubscribeCycleForMobilePosition() != 0) {
+                    removeMobilePositionSubscribe(deviceInStore, result->{
+                        // 寮�鍚闃�
+                        deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition());
+                        addMobilePositionSubscribe(deviceInStore);
+                        // 鍥犱负鏄紓姝ユ墽琛岋紝闇�瑕佸湪杩欓噷鏇存柊涓嬫暟鎹�
+                        deviceMapper.updateCustom(deviceInStore);
+                        redisCatchStorage.updateDevice(deviceInStore);
+                    });
+                }else {
+                    // 寮�鍚闃�
+                    deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition());
+                    addMobilePositionSubscribe(deviceInStore);
+                }
+
+            }else if (device.getSubscribeCycleForMobilePosition() == 0) {
                 // 鍙栨秷璁㈤槄
-                removeMobilePositionSubscribe(deviceInStore);
+                deviceInStore.setSubscribeCycleForCatalog(0);
+                removeCatalogSubscribe(deviceInStore, null);
             }
         }
         if (deviceInStore.getGeoCoordSys() != null) {
@@ -603,10 +595,9 @@
         deviceInStore.setSsrcCheck(device.isSsrcCheck());
         //浣滀负娑堟伅閫氶亾
         deviceInStore.setAsMessageChannel(device.isAsMessageChannel());
-        
-        // 鏇存柊redis
+
         deviceMapper.updateCustom(deviceInStore);
-        redisCatchStorage.removeDevice(deviceInStore.getDeviceId());
+        redisCatchStorage.updateDevice(deviceInStore);
     }
 
     @Override
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
index f7acfad..8cd8dcf 100755
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -20,6 +20,8 @@
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
 import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
@@ -27,6 +29,10 @@
 import com.genersoft.iot.vmp.media.zlm.dto.*;
 import com.genersoft.iot.vmp.media.zlm.*;
 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
+import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRecordMp4;
 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
 import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
@@ -39,9 +45,12 @@
 import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener;
+import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
+import com.genersoft.iot.vmp.service.bean.ErrorCallback;
+import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
+import com.genersoft.iot.vmp.service.bean.SSRCInfo;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
-import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
 import com.genersoft.iot.vmp.utils.CloudRecordUtils;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
@@ -80,7 +89,7 @@
     private IVideoManagerStorage storager;
 
     @Autowired
-    private SIPCommander cmder;
+    private ISIPCommander cmder;
 
     @Autowired
     private AudioBroadcastManager audioBroadcastManager;
@@ -120,6 +129,9 @@
 
     @Autowired
     private UserSetting userSetting;
+
+    @Autowired
+    private IDeviceChannelService channelService;
 
     @Autowired
     private SipConfig sipConfig;
@@ -162,6 +174,11 @@
         if (device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE") && !mediaServerItem.isRtpEnable()) {
             logger.warn("[鐐规挱] 鍗曠鍙f敹娴佹椂涓嶆敮鎸乀CP涓诲姩鏂瑰紡鏀舵祦 deviceId: {},channelId:{}", deviceId, channelId);
             throw new ControllerException(ErrorCode.ERROR100.getCode(), "鍗曠鍙f敹娴佹椂涓嶆敮鎸乀CP涓诲姩鏂瑰紡鏀舵祦");
+        }
+        DeviceChannel channel = channelService.getOne(deviceId, channelId);
+        if (channel == null) {
+            logger.warn("[鐐规挱] 鏈壘鍒伴�氶亾 deviceId: {},channelId:{}", deviceId, channelId);
+            throw new ControllerException(ErrorCode.ERROR100.getCode(), "鏈壘鍒伴�氶亾");
         }
         InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
         if (inviteInfo != null ) {
@@ -211,7 +228,7 @@
                     null);
             return null;
         }
-        play(mediaServerItem, ssrcInfo, device, channelId, callback);
+        play(mediaServerItem, ssrcInfo, device, channel, callback);
         return ssrcInfo;
     }
 
@@ -358,7 +375,7 @@
 
 
     @Override
-    public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
+    public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, DeviceChannel channel,
                      ErrorCallback<Object> callback) {
 
         if (mediaServerItem == null || ssrcInfo == null) {
@@ -367,111 +384,109 @@
                     null);
             return;
         }
-        logger.info("[鐐规挱寮�濮媇 deviceId: {}, channelId: {},鐮佹祦绫诲瀷锛歿}, 鏀舵祦绔彛锛� {}, STREAM锛歿}, 鏀舵祦妯″紡锛歿}, SSRC: {}, SSRC鏍¢獙锛歿}",
-                device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "杈呯爜娴�" : "涓荤爜娴�", ssrcInfo.getPort(), ssrcInfo.getStream(),
+        logger.info("[鐐规挱寮�濮媇 deviceId: {}, channelId: {},鐮佹祦绫诲瀷锛歿}, 鏀舵祦绔彛锛� {}, 鐮佹祦锛歿}, 鏀舵祦妯″紡锛歿}, SSRC: {}, SSRC鏍¢獙锛歿}",
+                device.getDeviceId(), channel.getChannelId(), channel.getStreamIdentification(), ssrcInfo.getPort(), ssrcInfo.getStream(),
                 device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
         //绔彛鑾峰彇澶辫触鐨剆srcInfo 娌℃湁蹇呰鍙戦�佺偣鎾寚浠�
         if (ssrcInfo.getPort() <= 0) {
-            logger.info("[鐐规挱绔彛鍒嗛厤寮傚父]锛宒eviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);
+            logger.info("[鐐规挱绔彛鍒嗛厤寮傚父]锛宒eviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channel.getChannelId(), ssrcInfo);
             // 閲婃斁ssrc
             mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
-            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
+            streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
 
             callback.run(InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "鐐规挱绔彛鍒嗛厤寮傚父", null);
-            inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
+            inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null,
                     InviteErrorCode.ERROR_FOR_RESOURCE_EXHAUSTION.getCode(), "鐐规挱绔彛鍒嗛厤寮傚父", null);
             return;
         }
 
         // 鍒濆鍖杛edis涓殑invite娑堟伅鐘舵��
-        InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
+        InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream(), ssrcInfo,
                 mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY,
                 InviteSessionStatus.ready);
-        inviteInfo.setSubStream(device.isSwitchPrimarySubStream());
         inviteStreamService.updateInviteInfo(inviteInfo);
         // 瓒呮椂澶勭悊
         String timeOutTaskKey = UUID.randomUUID().toString();
         dynamicTask.startDelay(timeOutTaskKey, () -> {
             // 鎵ц瓒呮椂浠诲姟鏃舵煡璇㈡槸鍚﹀凡缁忔垚鍔燂紝鎴愬姛浜嗗垯涓嶆墽琛岃秴鏃朵换鍔★紝闃叉瓒呮椂浠诲姟鍙栨秷澶辫触鐨勬儏鍐�
-            InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
+            InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId());
             if (inviteInfoForTimeOut == null || inviteInfoForTimeOut.getStreamInfo() == null) {
-                logger.info("[鐐规挱瓒呮椂] 鏀舵祦瓒呮椂 deviceId: {}, channelId: {},鐮佹祦绫诲瀷锛歿}锛岀鍙o細{}, SSRC: {}",
-                        device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "杈呯爜娴�" : "涓荤爜娴�",
+                logger.info("[鐐规挱瓒呮椂] 鏀舵祦瓒呮椂 deviceId: {}, channelId: {},鐮佹祦锛歿}锛岀鍙o細{}, SSRC: {}",
+                        device.getDeviceId(), channel.getChannelId(), channel.getStreamIdentification(),
                         ssrcInfo.getPort(), ssrcInfo.getSsrc());
 
                 callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
-                inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
+                inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null,
                         InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
-                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
+                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId());
 
                 try {
-                    cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
-                } catch (InvalidArgumentException | ParseException | SipException |
-                         SsrcTransactionNotFoundException e) {
+                    cmder.streamByeCmd(device, channel.getChannelId(), ssrcInfo.getStream(), null);
+                } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) {
                     logger.error("[鐐规挱瓒呮椂]锛� 鍙戦�丅YE澶辫触 {}", e.getMessage());
                 } finally {
                     mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
                     mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
-                    streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
+                    streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
                     mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
                     // 鍙栨秷璁㈤槄娑堟伅鐩戝惉
                     HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
                     subscribe.removeSubscribe(hookSubscribe);
                 }
             }else {
-                logger.info("[鐐规挱瓒呮椂] 鏀舵祦瓒呮椂 deviceId: {}, channelId: {},鐮佹祦绫诲瀷锛歿}锛岀鍙o細{}, SSRC: {}",
-                        device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "杈呯爜娴�" : "涓荤爜娴�",
+                logger.info("[鐐规挱瓒呮椂] 鏀舵祦瓒呮椂 deviceId: {}, channelId: {},鐮佹祦锛歿}锛岀鍙o細{}, SSRC: {}",
+                        device.getDeviceId(), channel.getChannelId(), channel.getStreamIdentification(),
                         ssrcInfo.getPort(), ssrcInfo.getSsrc());
 
                 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 
                 mediaServerService.closeRTPServer(mediaServerItem.getId(), ssrcInfo.getStream());
-                streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
+                streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
             }
         }, userSetting.getPlayTimeout());
 
         try {
-            cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInuse, hookParam ) -> {
+            cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channel, (mediaServerItemInuse, hookParam ) -> {
                 logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + hookParam);
                 dynamicTask.stop(timeOutTaskKey);
                 // hook鍝嶅簲
-                StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, hookParam, device.getDeviceId(), channelId);
+                StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, hookParam, device.getDeviceId(), channel.getChannelId());
                 if (streamInfo == null){
                     callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
                             InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
-                    inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
+                    inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null,
                             InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
                             InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
                     return;
                 }
                 callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
-                inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
+                inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null,
                         InviteErrorCode.SUCCESS.getCode(),
                         InviteErrorCode.SUCCESS.getMsg(),
                         streamInfo);
-                logger.info("[鐐规挱鎴愬姛] deviceId: {}, channelId:{}, 鐮佹祦绫诲瀷锛歿}", device.getDeviceId(), channelId,
-                        device.isSwitchPrimarySubStream() ? "杈呯爜娴�" : "涓荤爜娴�");
-                snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channelId, ssrcInfo.getStream());
+                logger.info("[鐐规挱鎴愬姛] deviceId: {}, channelId:{}, 鐮佹祦绫诲瀷锛歿}", device.getDeviceId(), channel.getChannelId(),
+                        channel.getStreamIdentification());
+                snapOnPlay(mediaServerItemInuse, device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
             }, (eventResult) -> {
                 // 澶勭悊鏀跺埌200ok鍚庣殑TCP涓诲姩杩炴帴浠ュ強SSRC涓嶄竴鑷寸殑闂
-                InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId,
+                InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channel.getChannelId(),
                         timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY);
             }, (event) -> {
-                logger.info("[鐐规挱澶辫触] deviceId: {}, channelId:{}, {}: {}", device.getDeviceId(), channelId, event.statusCode, event.msg);
+                logger.info("[鐐规挱澶辫触] deviceId: {}, channelId:{}, {}: {}", device.getDeviceId(), channel.getChannelId(), event.statusCode, event.msg);
                 dynamicTask.stop(timeOutTaskKey);
                 mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
                 // 閲婃斁ssrc
                 mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 
-                streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
+                streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
 
                 callback.run(InviteErrorCode.ERROR_FOR_SIGNALLING_ERROR.getCode(),
                         String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg), null);
-                inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
+                inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null,
                         InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(),
                         String.format("鐐规挱澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg), null);
 
-                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
+                inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId());
             });
         } catch (InvalidArgumentException | SipException | ParseException e) {
 
@@ -481,15 +496,15 @@
             // 閲婃斁ssrc
             mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
 
-            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
+            streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
 
             callback.run(InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
                     InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
-            inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
+            inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId(), null,
                     InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(),
                     InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null);
 
-            inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
+            inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channel.getChannelId());
         }
     }
 
@@ -626,7 +641,7 @@
 
     @Override
     public void playBack(String deviceId, String channelId, String startTime,
-                                                          String endTime, ErrorCallback<Object> callback) {
+                         String endTime, ErrorCallback<Object> callback) {
         Device device = storager.queryVideoDevice(deviceId);
         if (device == null) {
             logger.warn("[褰曞儚鍥炴斁] 鏈壘鍒拌澶� deviceId: {},channelId:{}", deviceId, channelId);
@@ -651,8 +666,8 @@
 
     @Override
     public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
-                                                          String deviceId, String channelId, String startTime,
-                                                          String endTime, ErrorCallback<Object> callback) {
+                         String deviceId, String channelId, String startTime,
+                         String endTime, ErrorCallback<Object> callback) {
         if (mediaServerItem == null || ssrcInfo == null) {
             callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
                     InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
@@ -1548,16 +1563,16 @@
 
         MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
         play(newMediaServerItem, deviceId, channelId, null, (code, msg, data)->{
-           if (code == InviteErrorCode.SUCCESS.getCode()) {
-               InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
-               if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) {
-                   getSnap(deviceId, channelId, fileName, errorCallback);
-               }else {
-                   errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
-               }
-           }else {
-               errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
-           }
+            if (code == InviteErrorCode.SUCCESS.getCode()) {
+                InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
+                if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) {
+                    getSnap(deviceId, channelId, fileName, errorCallback);
+                }else {
+                    errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
+                }
+            }else {
+                errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
+            }
         });
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
index 0759708..e823c6e 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -20,11 +20,11 @@
     @Insert("INSERT INTO wvp_device_channel (channel_id, device_id, name, manufacture, model, owner, civil_code, block, " +
             "address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " +
             "ip_address, port, password, ptz_type, status, stream_id, longitude, latitude, longitude_gcj02, latitude_gcj02, " +
-            "longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time) " +
+            "longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time, stream_identification) " +
             "VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," +
             "#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " +
             "#{ipAddress}, #{port}, #{password}, #{PTZType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " +
-            "#{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{hasAudio}, #{createTime}, #{updateTime}, #{businessGroupId}, #{gpsTime})")
+            "#{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{hasAudio}, #{createTime}, #{updateTime}, #{businessGroupId}, #{gpsTime}, #{streamIdentification})")
     int add(DeviceChannel channel);
 
     @Update(value = {" <script>" +
@@ -60,6 +60,7 @@
             "<if test='latitudeWgs84 != null'>, latitude_wgs84=#{latitudeWgs84}</if>" +
             "<if test='businessGroupId != null'>, business_group_id=#{businessGroupId}</if>" +
             "<if test='gpsTime != null'>, gps_time=#{gpsTime}</if>" +
+            "<if test='streamIdentification != null'>, stream_identification=#{streamIdentification}</if>" +
             "WHERE device_id=#{deviceId} AND channel_id=#{channelId}"+
             " </script>"})
     int update(DeviceChannel channel);
@@ -102,6 +103,7 @@
             "dc.longitude_wgs84, " +
             "dc.latitude_wgs84, " +
             "dc.business_group_id, " +
+            "dc.stream_identification, " +
             "dc.gps_time " +
             "from " +
             "wvp_device_channel dc " +
@@ -241,7 +243,7 @@
             "(channel_id, device_id, name, manufacture, model, owner, civil_code, block, sub_count, " +
             "  address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " +
             "  ip_address,port,password,ptz_type,status,stream_id,longitude,latitude,longitude_gcj02,latitude_gcj02,"+
-            "  longitude_wgs84,latitude_wgs84,has_audio,create_time,update_time,business_group_id,gps_time)"+
+            "  longitude_wgs84,latitude_wgs84,has_audio,create_time,update_time,business_group_id,gps_time,stream_identification)"+
             "values " +
             "<foreach collection='addChannels' index='index' item='item' separator=','> " +
             "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " +
@@ -251,7 +253,7 @@
             "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " +
             "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " +
             "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " +
-            "#{item.businessGroupId}, #{item.gpsTime}) " +
+            "#{item.businessGroupId}, #{item.gpsTime}, #{item.streamIdentification}) " +
             "</foreach> " +
             "</script>")
     int batchAdd(@Param("addChannels") List<DeviceChannel> addChannels);
@@ -349,6 +351,7 @@
             "<if test='item.latitudeWgs84 != null'>, latitude_wgs84=#{item.latitudeWgs84}</if>" +
             "<if test='item.businessGroupId != null'>, business_group_id=#{item.businessGroupId}</if>" +
             "<if test='item.gpsTime != null'>, gps_time=#{item.gpsTime}</if>" +
+            "<if test='item.streamIdentification != null'>, stream_identification=#{item.streamIdentification}</if>" +
             "<if test='item.id > 0'>WHERE id=#{item.id}</if>" +
             "<if test='item.id == 0'>WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}</if>" +
             "</foreach>" +
@@ -542,4 +545,9 @@
             " </script>"})
     List<DeviceChannel> getSubChannelsByDeviceId(@Param("deviceId") String deviceId, @Param("parentId") String parentId, @Param("onlyCatalog") boolean onlyCatalog);
 
+    @Update("<script>" +
+            "UPDATE wvp_device_channel SET stream_identification=#{streamIdentification} WHERE device_id=#{deviceId}" +
+            " <if test='channelId != null'> and channel_id = #{channelId} </if>" +
+            "</script>")
+    void updateChannelStreamIdentification(DeviceChannel channel);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
index 77867bc..42d2b7a 100755
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
@@ -43,7 +43,6 @@
             "geo_coord_sys," +
             "on_line," +
             "media_server_id," +
-            "switch_primary_sub_stream," +
             "broadcast_push_after_ack," +
             "(SELECT count(0) FROM wvp_device_channel WHERE device_id=wvp_device.device_id) as channel_count "+
             " FROM wvp_device WHERE device_id = #{deviceId}")
@@ -163,7 +162,6 @@
             "geo_coord_sys,"+
             "on_line,"+
             "media_server_id,"+
-            "switch_primary_sub_stream switchPrimarySubStream,"+
             "(SELECT count(0) FROM wvp_device_channel WHERE device_id=de.device_id) as channel_count " +
             "FROM wvp_device de" +
             "<if test=\"onLine != null\"> where on_line=${onLine}</if>"+
@@ -256,7 +254,6 @@
             "<if test=\"asMessageChannel != null\">, as_message_channel=#{asMessageChannel}</if>" +
             "<if test=\"broadcastPushAfterAck != null\">, broadcast_push_after_ack=#{broadcastPushAfterAck}</if>" +
             "<if test=\"geoCoordSys != null\">, geo_coord_sys=#{geoCoordSys}</if>" +
-            "<if test=\"switchPrimarySubStream != null\">, switch_primary_sub_stream=#{switchPrimarySubStream}</if>" +
             "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" +
             "WHERE device_id=#{deviceId}"+
             " </script>"})
@@ -275,8 +272,7 @@
             "broadcastPushAfterAck,"+
             "geo_coord_sys,"+
             "on_line,"+
-            "media_server_id,"+
-            "switch_primary_sub_stream"+
+            "media_server_id"+
             ") VALUES (" +
             "#{deviceId}," +
             "#{name}," +
@@ -290,8 +286,7 @@
             "#{broadcastPushAfterAck}," +
             "#{geoCoordSys}," +
             "#{onLine}," +
-            "#{mediaServerId}," +
-            "#{switchPrimarySubStream}" +
+            "#{mediaServerId}" +
             ")")
     void addCustomDevice(Device device);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
index 91c992f..05501cc 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
@@ -153,10 +153,7 @@
         Device device = storager.queryVideoDevice(deviceId);
         device.setSubscribeCycleForMobilePosition(Integer.parseInt(expires));
         device.setMobilePositionSubmissionInterval(Integer.parseInt(interval));
-        deviceService.updateDevice(device);
-        if (!deviceService.removeMobilePositionSubscribe(device)) {
-            throw new ControllerException(ErrorCode.ERROR100);
-        }
+        deviceService.updateCustomDevice(device);
     }
 
     /**
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
index f0af27f..9dd4c3d 100755
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -199,7 +199,7 @@
 					Runnable runnable = dynamicTask.get(key);
 					if (runnable instanceof ISubscribeTask) {
 						ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
-						subscribeTask.stop();
+						subscribeTask.stop(null);
 					}
 					dynamicTask.stop(key);
 				}
@@ -264,6 +264,14 @@
 		deviceChannelService.updateChannel(deviceId, channel);
 	}
 
+	@Operation(summary = "淇敼閫氶亾鐨勭爜娴佺被鍨�", security = @SecurityRequirement(name = JwtUtils.HEADER))
+	@Parameter(name = "deviceId", description = "璁惧鍥芥爣缂栧彿", required = true)
+	@Parameter(name = "channel", description = "閫氶亾淇℃伅", required = true)
+	@PostMapping("/channel/stream/identification/update/")
+	public void updateChannelStreamIdentification(DeviceChannel channel){
+		deviceChannelService.updateChannelStreamIdentification(channel);
+	}
+
 	/**
 	 * 淇敼鏁版嵁娴佷紶杈撴ā寮�
 	 * @param deviceId 璁惧id
diff --git a/web_src/src/components/channelList.vue b/web_src/src/components/channelList.vue
index 5547913..8af4269 100755
--- a/web_src/src/components/channelList.vue
+++ b/web_src/src/components/channelList.vue
@@ -13,24 +13,30 @@
                     prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
 
           閫氶亾绫诲瀷:
-          <el-select size="mini" @change="search" style="margin-right: 1rem;" v-model="channelType" placeholder="璇烽�夋嫨"
+          <el-select size="mini" @change="search" style="width: 8rem; margin-right: 1rem;" v-model="channelType" placeholder="璇烽�夋嫨"
                      default-first-option>
             <el-option label="鍏ㄩ儴" value=""></el-option>
             <el-option label="璁惧" value="false"></el-option>
             <el-option label="瀛愮洰褰�" value="true"></el-option>
           </el-select>
           鍦ㄧ嚎鐘舵��:
-          <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="online" placeholder="璇烽�夋嫨"
+          <el-select size="mini" style="width: 8rem; margin-right: 1rem;" @change="search" v-model="online" placeholder="璇烽�夋嫨"
                      default-first-option>
             <el-option label="鍏ㄩ儴" value=""></el-option>
             <el-option label="鍦ㄧ嚎" value="true"></el-option>
             <el-option label="绂荤嚎" value="false"></el-option>
           </el-select>
-          娓呮櫚搴�:
-          <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="isSubStream" placeholder="璇烽�夋嫨"
-                     default-first-option>
-            <el-option label="鍘熺敾" :value="false"></el-option>
-            <el-option label="娴佺晠" :value="true"></el-option>
+          鐮佹祦绫诲瀷閲嶇疆:
+          <el-select size="mini" style="width: 16rem; margin-right: 1rem;" @change="subStreamChange" v-model="subStream"
+                     placeholder="璇烽�夋嫨鐮佹祦绫诲瀷" default-first-option >
+            <el-option label="stream:0(涓荤爜娴�)" value="stream:0"></el-option>
+            <el-option label="stream:1(瀛愮爜娴�)" value="stream:1"></el-option>
+            <el-option label="streamnumber:0(涓荤爜娴�-2022)" value="streamnumber:0"></el-option>
+            <el-option label="streamnumber:1(瀛愮爜娴�-2022)" value="streamnumber:1"></el-option>
+            <el-option label="streamprofile:0(涓荤爜娴�-澶у崕)" value="streamprofile:0"></el-option>
+            <el-option label="streamprofile:1(瀛愮爜娴�-澶у崕)" value="streamprofile:1"></el-option>
+            <el-option label="streamMode:main(涓荤爜娴�-姘存槦+TP-LINK)" value="streamMode:main"></el-option>
+            <el-option label="streamMode:sub(瀛愮爜娴�-姘存槦+TP-LINK)" value="streamMode:sub"></el-option>
           </el-select>
         </div>
         <el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button>
@@ -46,11 +52,11 @@
       <el-main style="padding: 5px;">
         <el-table ref="channelListTable" :data="deviceChannelList" :height="winHeight" style="width: 100%"
                   header-row-class-name="table-header">
-          <el-table-column prop="channelId" label="閫氶亾缂栧彿" min-width="200">
+          <el-table-column prop="channelId" label="閫氶亾缂栧彿" min-width="180">
           </el-table-column>
-          <el-table-column prop="deviceId" label="璁惧缂栧彿" min-width="200">
+          <el-table-column prop="deviceId" label="璁惧缂栧彿" min-width="180">
           </el-table-column>
-          <el-table-column prop="name" label="閫氶亾鍚嶇О" min-width="200">
+          <el-table-column prop="name" label="閫氶亾鍚嶇О" min-width="180">
             <template v-slot:default="scope">
               <el-input
                 v-show="scope.row.edit"
@@ -63,7 +69,7 @@
               <span v-show="!scope.row.edit">{{ scope.row.name }}</span>
             </template>
           </el-table-column>
-          <el-table-column label="蹇収" min-width="120">
+          <el-table-column label="蹇収" min-width="100">
             <template v-slot:default="scope">
               <el-image
                 :src="getSnap(scope.row)"
@@ -77,11 +83,11 @@
               </el-image>
             </template>
           </el-table-column>
-          <el-table-column prop="subCount" label="瀛愯妭鐐规暟" min-width="120">
+          <el-table-column prop="subCount" label="瀛愯妭鐐规暟" min-width="100">
           </el-table-column>
-          <el-table-column prop="manufacture" label="鍘傚" min-width="120">
+          <el-table-column prop="manufacture" label="鍘傚" min-width="100">
           </el-table-column>
-          <el-table-column label="浣嶇疆淇℃伅" min-width="200">
+          <el-table-column label="浣嶇疆淇℃伅" min-width="120">
             <template v-slot:default="scope">
               <el-input
                 v-show="scope.row.edit"
@@ -94,7 +100,7 @@
               <span v-show="!scope.row.edit">{{ scope.row.location }}</span>
             </template>
           </el-table-column>
-          <el-table-column prop="PTZType" label="浜戝彴绫诲瀷" min-width="120">
+          <el-table-column prop="PTZType" label="浜戝彴绫诲瀷" min-width="100">
             <template v-slot:default="scope">
               <el-select v-show="scope.row.edit" v-model="scope.row.PTZType"
                          placeholder="浜戝彴绫诲瀷" filterable>
@@ -108,13 +114,28 @@
               <div v-show="!scope.row.edit">{{ scope.row.PTZTypeText }}</div>
             </template>
           </el-table-column>
-          <el-table-column label="寮�鍚煶棰�" min-width="120">
+          <el-table-column label="寮�鍚煶棰�" min-width="100">
             <template slot-scope="scope">
               <el-switch @change="updateChannel(scope.row)" v-model="scope.row.hasAudio" active-color="#409EFF">
               </el-switch>
             </template>
           </el-table-column>
-          <el-table-column label="鐘舵��" min-width="120">
+          <el-table-column label="鐮佹祦绫诲瀷" min-width="180">
+            <template slot-scope="scope">
+              <el-select size="mini" style="margin-right: 1rem;" @change="channelSubStreamChange(scope.row)" v-model="scope.row.streamIdentification"
+                         placeholder="璇烽�夋嫨鐮佹祦绫诲瀷" default-first-option >
+                <el-option label="stream:0(涓荤爜娴�)" value="stream:0"></el-option>
+                <el-option label="stream:1(瀛愮爜娴�)" value="stream:1"></el-option>
+                <el-option label="streamnumber:0(涓荤爜娴�-2022)" value="streamnumber:0"></el-option>
+                <el-option label="streamnumber:1(瀛愮爜娴�-2022)" value="streamnumber:1"></el-option>
+                <el-option label="streamprofile:0(涓荤爜娴�-澶у崕)" value="streamprofile:0"></el-option>
+                <el-option label="streamprofile:1(瀛愮爜娴�-澶у崕)" value="streamprofile:1"></el-option>
+                <el-option label="streamMode:main(涓荤爜娴�-姘存槦+TP-LINK)" value="streamMode:main"></el-option>
+                <el-option label="streamMode:sub(瀛愮爜娴�-姘存槦+TP-LINK)" value="streamMode:sub"></el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="鐘舵��" min-width="100">
             <template slot-scope="scope">
               <div slot="reference" class="name-wrapper">
                 <el-tag size="medium" v-if="scope.row.status === true">鍦ㄧ嚎</el-tag>
@@ -122,8 +143,6 @@
               </div>
             </template>
           </el-table-column>
-
-
           <el-table-column label="鎿嶄綔" min-width="340" fixed="right">
             <template slot-scope="scope">
               <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-video-play"
@@ -213,7 +232,7 @@
       searchSrt: "",
       channelType: "",
       online: "",
-      isSubStream: false,
+      subStream: "",
       winHeight: window.innerHeight - 200,
       currentPage: 1,
       count: 15,
@@ -495,6 +514,43 @@
         console.log(JSON.stringify(res));
       });
     },
+    subStreamChange: function () {
+      this.$confirm('纭畾閲嶇疆鎵�鏈夐�氶亾鐨勭爜娴佺被鍨�?', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }).then(() => {
+        this.$axios({
+          method: 'post',
+          url: `/api/device/query/channel/stream/identification/update/`,
+          params: {
+            deviceId: this.deviceId,
+            streamIdentification: this.subStream
+          }
+        }).then((res)=> {
+          console.log(JSON.stringify(res));
+          this.initData()
+        }).finally(()=>{
+          this.subStream = ""
+        })
+      }).catch(() => {
+        this.subStream = ""
+      });
+
+    },
+    channelSubStreamChange: function (row) {
+      this.$axios({
+        method: 'post',
+        url: `/api/device/query/channel/stream/identification/update/`,
+        params: {
+          deviceId: this.deviceId,
+          channelId: row.channelId,
+          streamIdentification: row.streamIdentification
+        }
+      }).then(function (res) {
+        console.log(JSON.stringify(res));
+      });
+    },
     refresh: function () {
       this.initData();
     },
diff --git a/web_src/src/components/dialog/deviceEdit.vue b/web_src/src/components/dialog/deviceEdit.vue
index 6f37639..d8e0b43 100755
--- a/web_src/src/components/dialog/deviceEdit.vue
+++ b/web_src/src/components/dialog/deviceEdit.vue
@@ -61,12 +61,6 @@
           <el-form-item v-if="form.subscribeCycleForMobilePosition > 0" label="绉诲姩浣嶇疆鎶ラ�侀棿闅�" prop="subscribeCycleForCatalog" >
             <el-input v-model="form.mobilePositionSubmissionInterval" clearable ></el-input>
           </el-form-item>
-          <el-form-item label="涓诲瓙鐮佹祦寮�鍏�" prop="switchPrimarySubStream" >
-            <el-select v-model="form.switchPrimarySubStream" style="float: left; width: 100%" >
-              <el-option key="true" label="寮�鍚�" :value="true"></el-option>
-              <el-option key="false" label="鍏抽棴" :value="false"></el-option>
-            </el-select>
-          </el-form-item>
           <el-form-item label="鍏朵粬閫夐」">
             <el-checkbox label="SSRC鏍¢獙" v-model="form.ssrcCheck" style="float: left"></el-checkbox>
             <el-checkbox label="浣滀负娑堟伅閫氶亾" v-model="form.asMessageChannel" style="float: left"></el-checkbox>
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql"
new file mode 100644
index 0000000..a3f4a1d
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-mysql-2.7.0.sql"
@@ -0,0 +1,324 @@
+/*寤鸿〃*/
+create table wvp_device (
+                            id serial primary key ,
+                            device_id character varying(50) not null ,
+                            name character varying(255),
+                            manufacturer character varying(255),
+                            model character varying(255),
+                            firmware character varying(255),
+                            transport character varying(50),
+                            stream_mode character varying(50),
+                            on_line bool default false,
+                            register_time character varying(50),
+                            keepalive_time character varying(50),
+                            ip character varying(50),
+                            create_time character varying(50),
+                            update_time character varying(50),
+                            port integer,
+                            expires integer,
+                            subscribe_cycle_for_catalog integer DEFAULT 0,
+                            subscribe_cycle_for_mobile_position integer DEFAULT 0,
+                            mobile_position_submission_interval integer DEFAULT 5,
+                            subscribe_cycle_for_alarm integer DEFAULT 0,
+                            host_address character varying(50),
+                            charset character varying(50),
+                            ssrc_check bool default false,
+                            geo_coord_sys character varying(50),
+                            media_server_id character varying(50),
+                            custom_name character varying(255),
+                            sdp_ip character varying(50),
+                            local_ip character varying(50),
+                            password character varying(255),
+                            as_message_channel bool default false,
+                            keepalive_interval_time integer,
+                            switch_primary_sub_stream bool default false,
+                            broadcast_push_after_ack bool default false,
+                            constraint uk_device_device unique (device_id)
+);
+
+create table wvp_device_alarm (
+                                  id serial primary key ,
+                                  device_id character varying(50) not null,
+                                  channel_id character varying(50) not null,
+                                  alarm_priority character varying(50),
+                                  alarm_method character varying(50),
+                                  alarm_time character varying(50),
+                                  alarm_description character varying(255),
+                                  longitude double precision,
+                                  latitude double precision,
+                                  alarm_type character varying(50),
+                                  create_time character varying(50) not null
+);
+
+create table wvp_device_channel (
+                                    id serial primary key ,
+                                    channel_id character varying(50) not null,
+                                    name character varying(255),
+                                    custom_name character varying(255),
+                                    manufacture character varying(50),
+                                    model character varying(50),
+                                    owner character varying(50),
+                                    civil_code character varying(50),
+                                    block character varying(50),
+                                    address character varying(50),
+                                    parent_id character varying(50),
+                                    safety_way integer,
+                                    register_way integer,
+                                    cert_num character varying(50),
+                                    certifiable integer,
+                                    err_code integer,
+                                    end_time character varying(50),
+                                    secrecy character varying(50),
+                                    ip_address character varying(50),
+                                    port integer,
+                                    password character varying(255),
+                                    ptz_type integer,
+                                    custom_ptz_type integer,
+                                    status bool default false,
+                                    longitude double precision,
+                                    custom_longitude double precision,
+                                    latitude double precision,
+                                    custom_latitude double precision,
+                                    stream_id character varying(255),
+                                    device_id character varying(50) not null,
+                                    parental character varying(50),
+                                    has_audio bool default false,
+                                    create_time character varying(50) not null,
+                                    update_time character varying(50) not null,
+                                    sub_count integer,
+                                    longitude_gcj02 double precision,
+                                    latitude_gcj02 double precision,
+                                    longitude_wgs84 double precision,
+                                    latitude_wgs84 double precision,
+                                    business_group_id character varying(50),
+                                    gps_time character varying(50),
+                                    stream_identification character varying(50),
+                                    constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id)
+);
+
+create table wvp_device_mobile_position (
+                                            id serial primary key,
+                                            device_id character varying(50) not null,
+                                            channel_id character varying(50) not null,
+                                            device_name character varying(255),
+                                            time character varying(50),
+                                            longitude double precision,
+                                            latitude double precision,
+                                            altitude double precision,
+                                            speed double precision,
+                                            direction double precision,
+                                            report_source character varying(50),
+                                            longitude_gcj02 double precision,
+                                            latitude_gcj02 double precision,
+                                            longitude_wgs84 double precision,
+                                            latitude_wgs84 double precision,
+                                            create_time character varying(50)
+);
+
+create table wvp_gb_stream (
+                               gb_stream_id serial primary key,
+                               app character varying(255) not null,
+                               stream character varying(255) not null,
+                               gb_id character varying(50) not null,
+                               name character varying(255),
+                               longitude double precision,
+                               latitude double precision,
+                               stream_type character varying(50),
+                               media_server_id character varying(50),
+                               create_time character varying(50),
+                               constraint uk_gb_stream_unique_gb_id unique (gb_id),
+                               constraint uk_gb_stream_unique_app_stream unique (app, stream)
+);
+
+create table wvp_log (
+                         id serial primary key ,
+                         name character varying(50),
+                         type character varying(50),
+                         uri character varying(200),
+                         address character varying(50),
+                         result character varying(50),
+                         timing bigint,
+                         username character varying(50),
+                         create_time character varying(50)
+);
+
+create table wvp_media_server (
+                                  id character varying(255) primary key ,
+                                  ip character varying(50),
+                                  hook_ip character varying(50),
+                                  sdp_ip character varying(50),
+                                  stream_ip character varying(50),
+                                  http_port integer,
+                                  http_ssl_port integer,
+                                  rtmp_port integer,
+                                  rtmp_ssl_port integer,
+                                  rtp_proxy_port integer,
+                                  rtsp_port integer,
+                                  rtsp_ssl_port integer,
+                                  auto_config bool default false,
+                                  secret character varying(50),
+                                  rtp_enable bool default false,
+                                  rtp_port_range character varying(50),
+                                  send_rtp_port_range character varying(50),
+                                  record_assist_port integer,
+                                  default_server bool default false,
+                                  create_time character varying(50),
+                                  update_time character varying(50),
+                                  hook_alive_interval integer,
+                                  record_path character varying(255),
+                                  record_day integer default 7,
+                                  constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
+);
+
+create table wvp_platform (
+                              id serial primary key ,
+                              enable bool default false,
+                              name character varying(255),
+                              server_gb_id character varying(50),
+                              server_gb_domain character varying(50),
+                              server_ip character varying(50),
+                              server_port integer,
+                              device_gb_id character varying(50),
+                              device_ip character varying(50),
+                              device_port character varying(50),
+                              username character varying(255),
+                              password character varying(50),
+                              expires character varying(50),
+                              keep_timeout character varying(50),
+                              transport character varying(50),
+                              character_set character varying(50),
+                              catalog_id character varying(50),
+                              ptz bool default false,
+                              rtcp bool default false,
+                              status bool default false,
+                              start_offline_push bool default false,
+                              administrative_division character varying(50),
+                              catalog_group integer,
+                              create_time character varying(50),
+                              update_time character varying(50),
+                              as_message_channel bool default false,
+                              auto_push_channel bool default false,
+                              constraint uk_platform_unique_server_gb_id unique (server_gb_id)
+);
+
+create table wvp_platform_catalog (
+                                      id character varying(50),
+                                      platform_id character varying(50),
+                                      name character varying(255),
+                                      parent_id character varying(50),
+                                      civil_code character varying(50),
+                                      business_group_id character varying(50),
+                                      constraint uk_platform_catalog_id_platform_id unique (id, platform_id)
+);
+
+create table wvp_platform_gb_channel (
+                                         id serial primary key ,
+                                         platform_id character varying(50),
+                                         catalog_id character varying(50),
+                                         device_channel_id integer,
+                                         constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id)
+);
+
+create table wvp_platform_gb_stream (
+                                        id serial primary key,
+                                        platform_id character varying(50),
+                                        catalog_id character varying(50),
+                                        gb_stream_id integer,
+                                        constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id)
+);
+
+create table wvp_stream_proxy (
+                                  id serial primary key,
+                                  type character varying(50),
+                                  app character varying(255),
+                                  stream character varying(255),
+                                  url character varying(255),
+                                  src_url character varying(255),
+                                  dst_url character varying(255),
+                                  timeout_ms integer,
+                                  ffmpeg_cmd_key character varying(255),
+                                  rtp_type character varying(50),
+                                  media_server_id character varying(50),
+                                  enable_audio bool default false,
+                                  enable_mp4 bool default false,
+                                  enable bool default false,
+                                  status boolean,
+                                  enable_remove_none_reader bool default false,
+                                  create_time character varying(50),
+                                  name character varying(255),
+                                  update_time character varying(50),
+                                  stream_key character varying(255),
+                                  enable_disable_none_reader bool default false,
+                                  constraint uk_stream_proxy_app_stream unique (app, stream)
+);
+
+create table wvp_stream_push (
+                                 id serial primary key,
+                                 app character varying(255),
+                                 stream character varying(255),
+                                 total_reader_count character varying(50),
+                                 origin_type integer,
+                                 origin_type_str character varying(50),
+                                 create_time character varying(50),
+                                 alive_second integer,
+                                 media_server_id character varying(50),
+                                 server_id character varying(50),
+                                 push_time character varying(50),
+                                 status bool default false,
+                                 update_time character varying(50),
+                                 push_ing bool default false,
+                                 self bool default false,
+                                 constraint uk_stream_push_app_stream unique (app, stream)
+);
+create table wvp_cloud_record (
+                                  id serial primary key,
+                                  app character varying(255),
+                                  stream character varying(255),
+                                  call_id character varying(255),
+                                  start_time bigint,
+                                  end_time bigint,
+                                  media_server_id character varying(50),
+                                  file_name character varying(255),
+                                  folder character varying(255),
+                                  file_path character varying(255),
+                                  collect bool default false,
+                                  file_size bigint,
+                                  time_len bigint,
+                                  constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
+);
+
+create table wvp_user (
+                          id serial primary key,
+                          username character varying(255),
+                          password character varying(255),
+                          role_id integer,
+                          create_time character varying(50),
+                          update_time character varying(50),
+                          push_key character varying(50),
+                          constraint uk_user_username unique (username)
+);
+
+create table wvp_user_role (
+                               id serial primary key,
+                               name character varying(50),
+                               authority character varying(50),
+                               create_time character varying(50),
+                               update_time character varying(50)
+);
+create table wvp_resources_tree (
+                                    id serial primary key ,
+                                    is_catalog bool default true,
+                                    device_channel_id integer ,
+                                    gb_stream_id integer,
+                                    name character varying(255),
+                                    parentId integer,
+                                    path character varying(255)
+);
+
+
+/*鍒濆鏁版嵁*/
+INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
+INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
+
+
+
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql"
new file mode 100644
index 0000000..9f41667
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.0/\345\210\235\345\247\213\345\214\226-postgresql-kingbase-2.7.0.sql"
@@ -0,0 +1,324 @@
+/*寤鸿〃*/
+create table wvp_device (
+                            id serial primary key ,
+                            device_id character varying(50) not null ,
+                            name character varying(255),
+                            manufacturer character varying(255),
+                            model character varying(255),
+                            firmware character varying(255),
+                            transport character varying(50),
+                            stream_mode character varying(50),
+                            on_line bool default false,
+                            register_time character varying(50),
+                            keepalive_time character varying(50),
+                            ip character varying(50),
+                            create_time character varying(50),
+                            update_time character varying(50),
+                            port integer,
+                            expires integer,
+                            subscribe_cycle_for_catalog integer DEFAULT 0,
+                            subscribe_cycle_for_mobile_position integer DEFAULT 0,
+                            mobile_position_submission_interval integer DEFAULT 5,
+                            subscribe_cycle_for_alarm integer DEFAULT 0,
+                            host_address character varying(50),
+                            charset character varying(50),
+                            ssrc_check bool default false,
+                            geo_coord_sys character varying(50),
+                            media_server_id character varying(50),
+                            custom_name character varying(255),
+                            sdp_ip character varying(50),
+                            local_ip character varying(50),
+                            password character varying(255),
+                            as_message_channel bool default false,
+                            keepalive_interval_time integer,
+                            switch_primary_sub_stream bool default false,
+                            broadcast_push_after_ack bool default false,
+                            constraint uk_device_device unique (device_id)
+);
+
+create table wvp_device_alarm (
+                                  id serial primary key ,
+                                  device_id character varying(50) not null,
+                                  channel_id character varying(50) not null,
+                                  alarm_priority character varying(50),
+                                  alarm_method character varying(50),
+                                  alarm_time character varying(50),
+                                  alarm_description character varying(255),
+                                  longitude double precision,
+                                  latitude double precision,
+                                  alarm_type character varying(50),
+                                  create_time character varying(50) not null
+);
+
+create table wvp_device_channel (
+                                    id serial primary key ,
+                                    channel_id character varying(50) not null,
+                                    name character varying(255),
+                                    custom_name character varying(255),
+                                    manufacture character varying(50),
+                                    model character varying(50),
+                                    owner character varying(50),
+                                    civil_code character varying(50),
+                                    block character varying(50),
+                                    address character varying(50),
+                                    parent_id character varying(50),
+                                    safety_way integer,
+                                    register_way integer,
+                                    cert_num character varying(50),
+                                    certifiable integer,
+                                    err_code integer,
+                                    end_time character varying(50),
+                                    secrecy character varying(50),
+                                    ip_address character varying(50),
+                                    port integer,
+                                    password character varying(255),
+                                    ptz_type integer,
+                                    custom_ptz_type integer,
+                                    status bool default false,
+                                    longitude double precision,
+                                    custom_longitude double precision,
+                                    latitude double precision,
+                                    custom_latitude double precision,
+                                    stream_id character varying(255),
+                                    device_id character varying(50) not null,
+                                    parental character varying(50),
+                                    has_audio bool default false,
+                                    create_time character varying(50) not null,
+                                    update_time character varying(50) not null,
+                                    sub_count integer,
+                                    longitude_gcj02 double precision,
+                                    latitude_gcj02 double precision,
+                                    longitude_wgs84 double precision,
+                                    latitude_wgs84 double precision,
+                                    business_group_id character varying(50),
+                                    gps_time character varying(50),
+                                    stream_identification character varying(50),
+                                    constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id)
+);
+
+create table wvp_device_mobile_position (
+                                            id serial primary key,
+                                            device_id character varying(50) not null,
+                                            channel_id character varying(50) not null,
+                                            device_name character varying(255),
+                                            time character varying(50),
+                                            longitude double precision,
+                                            latitude double precision,
+                                            altitude double precision,
+                                            speed double precision,
+                                            direction double precision,
+                                            report_source character varying(50),
+                                            longitude_gcj02 double precision,
+                                            latitude_gcj02 double precision,
+                                            longitude_wgs84 double precision,
+                                            latitude_wgs84 double precision,
+                                            create_time character varying(50)
+);
+
+create table wvp_gb_stream (
+                               gb_stream_id serial primary key,
+                               app character varying(255) not null,
+                               stream character varying(255) not null,
+                               gb_id character varying(50) not null,
+                               name character varying(255),
+                               longitude double precision,
+                               latitude double precision,
+                               stream_type character varying(50),
+                               media_server_id character varying(50),
+                               create_time character varying(50),
+                               constraint uk_gb_stream_unique_gb_id unique (gb_id),
+                               constraint uk_gb_stream_unique_app_stream unique (app, stream)
+);
+
+create table wvp_log (
+                         id serial primary key ,
+                         name character varying(50),
+                         type character varying(50),
+                         uri character varying(200),
+                         address character varying(50),
+                         result character varying(50),
+                         timing bigint,
+                         username character varying(50),
+                         create_time character varying(50)
+);
+
+create table wvp_media_server (
+                                  id character varying(255) primary key ,
+                                  ip character varying(50),
+                                  hook_ip character varying(50),
+                                  sdp_ip character varying(50),
+                                  stream_ip character varying(50),
+                                  http_port integer,
+                                  http_ssl_port integer,
+                                  rtmp_port integer,
+                                  rtmp_ssl_port integer,
+                                  rtp_proxy_port integer,
+                                  rtsp_port integer,
+                                  rtsp_ssl_port integer,
+                                  auto_config bool default false,
+                                  secret character varying(50),
+                                  rtp_enable bool default false,
+                                  rtp_port_range character varying(50),
+                                  send_rtp_port_range character varying(50),
+                                  record_assist_port integer,
+                                  default_server bool default false,
+                                  create_time character varying(50),
+                                  update_time character varying(50),
+                                  hook_alive_interval integer,
+                                  record_path character varying(255),
+                                  record_day integer default 7,
+                                  constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
+);
+
+create table wvp_platform (
+                              id serial primary key ,
+                              enable bool default false,
+                              name character varying(255),
+                              server_gb_id character varying(50),
+                              server_gb_domain character varying(50),
+                              server_ip character varying(50),
+                              server_port integer,
+                              device_gb_id character varying(50),
+                              device_ip character varying(50),
+                              device_port character varying(50),
+                              username character varying(255),
+                              password character varying(50),
+                              expires character varying(50),
+                              keep_timeout character varying(50),
+                              transport character varying(50),
+                              character_set character varying(50),
+                              catalog_id character varying(50),
+                              ptz bool default false,
+                              rtcp bool default false,
+                              status bool default false,
+                              start_offline_push bool default false,
+                              administrative_division character varying(50),
+                              catalog_group integer,
+                              create_time character varying(50),
+                              update_time character varying(50),
+                              as_message_channel bool default false,
+                              auto_push_channel bool default false,
+                              constraint uk_platform_unique_server_gb_id unique (server_gb_id)
+);
+
+create table wvp_platform_catalog (
+                                      id character varying(50),
+                                      platform_id character varying(50),
+                                      name character varying(255),
+                                      parent_id character varying(50),
+                                      civil_code character varying(50),
+                                      business_group_id character varying(50),
+                                      constraint uk_platform_catalog_id_platform_id unique (id, platform_id)
+);
+
+create table wvp_platform_gb_channel (
+                                         id serial primary key ,
+                                         platform_id character varying(50),
+                                         catalog_id character varying(50),
+                                         device_channel_id integer,
+                                         constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id)
+);
+
+create table wvp_platform_gb_stream (
+                                        id serial primary key,
+                                        platform_id character varying(50),
+                                        catalog_id character varying(50),
+                                        gb_stream_id integer,
+                                        constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id)
+);
+
+create table wvp_stream_proxy (
+                                  id serial primary key,
+                                  type character varying(50),
+                                  app character varying(255),
+                                  stream character varying(255),
+                                  url character varying(255),
+                                  src_url character varying(255),
+                                  dst_url character varying(255),
+                                  timeout_ms integer,
+                                  ffmpeg_cmd_key character varying(255),
+                                  rtp_type character varying(50),
+                                  media_server_id character varying(50),
+                                  enable_audio bool default false,
+                                  enable_mp4 bool default false,
+                                  enable bool default false,
+                                  status boolean,
+                                  enable_remove_none_reader bool default false,
+                                  create_time character varying(50),
+                                  name character varying(255),
+                                  update_time character varying(50),
+                                  stream_key character varying(255),
+                                  enable_disable_none_reader bool default false,
+                                  constraint uk_stream_proxy_app_stream unique (app, stream)
+);
+
+create table wvp_stream_push (
+                                 id serial primary key,
+                                 app character varying(255),
+                                 stream character varying(255),
+                                 total_reader_count character varying(50),
+                                 origin_type integer,
+                                 origin_type_str character varying(50),
+                                 create_time character varying(50),
+                                 alive_second integer,
+                                 media_server_id character varying(50),
+                                 server_id character varying(50),
+                                 push_time character varying(50),
+                                 status bool default false,
+                                 update_time character varying(50),
+                                 push_ing bool default false,
+                                 self bool default false,
+                                 constraint uk_stream_push_app_stream unique (app, stream)
+);
+create table wvp_cloud_record (
+                                  id serial primary key,
+                                  app character varying(255),
+                                  stream character varying(255),
+                                  call_id character varying(255),
+                                  start_time int8,
+                                  end_time int8,
+                                  media_server_id character varying(50),
+                                  file_name character varying(255),
+                                  folder character varying(255),
+                                  file_path character varying(255),
+                                  collect bool default false,
+                                  file_size int8,
+                                  time_len int8,
+                                  constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
+);
+
+create table wvp_user (
+                          id serial primary key,
+                          username character varying(255),
+                          password character varying(255),
+                          role_id integer,
+                          create_time character varying(50),
+                          update_time character varying(50),
+                          push_key character varying(50),
+                          constraint uk_user_username unique (username)
+);
+
+create table wvp_user_role (
+                               id serial primary key,
+                               name character varying(50),
+                               authority character varying(50),
+                               create_time character varying(50),
+                               update_time character varying(50)
+);
+create table wvp_resources_tree (
+                                    id serial primary key ,
+                                    is_catalog bool default true,
+                                    device_channel_id integer ,
+                                    gb_stream_id integer,
+                                    name character varying(255),
+                                    parentId integer,
+                                    path character varying(255)
+);
+
+
+/*鍒濆鏁版嵁*/
+INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
+INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
+
+
+
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-mysql-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-mysql-2.7.0.sql"
new file mode 100644
index 0000000..141c26e
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-mysql-2.7.0.sql"
@@ -0,0 +1,5 @@
+alter table wvp_device_channel
+    add stream_identification character varying(50);
+
+alter table wvp_device
+    drop switch_primary_sub_stream;
\ No newline at end of file
diff --git "a/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql" "b/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql"
new file mode 100644
index 0000000..141c26e
--- /dev/null
+++ "b/\346\225\260\346\215\256\345\272\223/2.7.0/\346\233\264\346\226\260-postgresql-kingbase-2.7.0.sql"
@@ -0,0 +1,5 @@
+alter table wvp_device_channel
+    add stream_identification character varying(50);
+
+alter table wvp_device
+    drop switch_primary_sub_stream;
\ No newline at end of file

--
Gitblit v1.8.0