From 03ee15ece2ff749be8f4c211e1ee6fd3a3a6066d Mon Sep 17 00:00:00 2001
From: 648540858 <648540858@qq.com>
Date: 星期四, 09 二月 2023 14:13:44 +0800
Subject: [PATCH] Merge pull request #741 from gaofuwang/wvp-28181-2.0

---
 src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java                                               |   37 +
 src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java                                                                     |   79 ++++
 src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java                                                           |    7 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                                                    |   19 
 src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java                                                     |    8 
 src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java                                                        |    3 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarmMethod.java                                                            |   14 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java                                                          |   94 +++++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java          |    5 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java                                                          |   15 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java |    8 
 src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java                                                    |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java                                                                   |   11 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java                                                        |   24 
 src/main/java/com/genersoft/iot/vmp/gb28181/utils/MessageElement.java                                                              |   17 +
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java                                                              |  143 ++++++++
 src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java                                                     |    9 
 src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java                                                            |   77 ++++
 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java                                                       |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java  |  274 +++++++++++++++-
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java                                                                |  104 +++---
 21 files changed, 831 insertions(+), 121 deletions(-)

diff --git a/src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java b/src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java
new file mode 100644
index 0000000..02202d8
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java
@@ -0,0 +1,77 @@
+package com.genersoft.iot.vmp.common.enums;
+
+import org.dom4j.Element;
+import org.springframework.util.ObjectUtils;
+
+
+/**
+ * @author gaofuwang
+ * @date 2023/01/18/ 10:09:00
+ * @since 1.0
+ */
+public enum DeviceControlType {
+
+    /**
+     * 浜戝彴鎺у埗
+     * 涓婁笅宸﹀彸锛岄缃綅锛屾壂鎻忥紝杈呭姪鍔熻兘锛屽贰鑸�
+     */
+    PTZ("PTZCmd","浜戝彴鎺у埗"),
+    /**
+     * 杩滅▼鍚姩
+     */
+    TELE_BOOT("TeleBoot","杩滅▼鍚姩"),
+    /**
+     * 褰曞儚鎺у埗
+     */
+    RECORD("RecordCmd","褰曞儚鎺у埗"),
+    /**
+     * 甯冮槻鎾ら槻
+     */
+    GUARD("GuardCmd","甯冮槻鎾ら槻"),
+    /**
+     * 鍛婅鎺у埗
+     */
+    ALARM("AlarmCmd","鍛婅鎺у埗"),
+    /**
+     * 寮哄埗鍏抽敭甯�
+     */
+    I_FRAME("IFameCmd","寮哄埗鍏抽敭甯�"),
+    /**
+     * 鎷夋鏀惧ぇ
+     */
+    DRAG_ZOOM_IN("DragZoomIn","鎷夋鏀惧ぇ"),
+    /**
+     * 鎷夋缂╁皬
+     */
+    DRAG_ZOOM_OUT("DragZoomOut","鎷夋缂╁皬"),
+    /**
+     * 鐪嬪畧浣�
+     */
+    HOME_POSITION("HomePosition","鐪嬪畧浣�");
+
+    private final String val;
+
+    private final String desc;
+
+    DeviceControlType(String val, String desc) {
+        this.val = val;
+        this.desc = desc;
+    }
+
+    public String getVal() {
+        return val;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public static DeviceControlType typeOf(Element rootElement) {
+        for (DeviceControlType item : DeviceControlType.values()) {
+            if (!ObjectUtils.isEmpty(rootElement.element(item.val)) || !ObjectUtils.isEmpty(rootElement.elements(item.val))) {
+                return item;
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java
index 96d25c4..7f50f4d 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java
@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
+
 /**
  * 閫氳繃redis鍒嗗彂鎶ヨ娑堟伅
  */
@@ -8,12 +9,14 @@
      * 鍥芥爣缂栧彿
      */
     private String gbId;
-
     /**
      * 鎶ヨ缂栧彿
      */
     private int alarmSn;
-
+    /**
+     * 鍛婅绫诲瀷
+     */
+    private int alarmType;
 
     /**
      * 鎶ヨ鎻忚堪
@@ -36,6 +39,14 @@
         this.alarmSn = alarmSn;
     }
 
+    public int getAlarmType() {
+        return alarmType;
+    }
+
+    public void setAlarmType(int alarmType) {
+        this.alarmType = alarmType;
+    }
+
     public String getAlarmDescription() {
         return alarmDescription;
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarmMethod.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarmMethod.java
index ff8761e..d1fb6db 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarmMethod.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarmMethod.java
@@ -37,4 +37,18 @@
     public int getVal() {
         return val;
     }
+
+    /**
+     * 鏌ヨ鏄惁鍖归厤绫诲瀷
+     * @param code
+     * @return
+     */
+    public static DeviceAlarmMethod typeOf(int code) {
+        for (DeviceAlarmMethod item : DeviceAlarmMethod.values()) {
+            if (code==item.getVal()) {
+                return item;
+            }
+        }
+        return null;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java
new file mode 100644
index 0000000..86fdb4d
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java
@@ -0,0 +1,143 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
+
+/**
+ * 璁惧淇℃伅鏌ヨ鍝嶅簲
+ *
+ * @author Y.G
+ * @version 1.0
+ * @date 2022/6/28 14:55
+ */
+public class DragZoomRequest {
+    /**
+     * 搴忓垪鍙�
+     */
+    @MessageElement("SN")
+    private String sn;
+
+    @MessageElement("DeviceID")
+    private String deviceId;
+
+    @MessageElement(value = "DragZoomIn")
+    private DragZoom dragZoomIn;
+
+    @MessageElement(value = "DragZoomOut")
+    private DragZoom dragZoomOut;
+
+    /**
+     * 鍩烘湰鍙傛暟
+     */
+    public static class DragZoom {
+        /**
+         * 鎾斁绐楀彛闀垮害鍍忕礌鍊�
+         */
+        @MessageElement("Length")
+        protected Integer length;
+        /**
+         * 鎾斁绐楀彛瀹藉害鍍忕礌鍊�
+         */
+        @MessageElement("Width")
+        protected Integer width;
+        /**
+         * 鎷夋涓績鐨勬í杞村潗鏍囧儚绱犲��
+         */
+        @MessageElement("MidPointX")
+        protected Integer midPointX;
+        /**
+         * 鎷夋涓績鐨勭旱杞村潗鏍囧儚绱犲��
+         */
+        @MessageElement("MidPointY")
+        protected Integer midPointY;
+        /**
+         * 鎷夋闀垮害鍍忕礌鍊�
+         */
+        @MessageElement("LengthX")
+        protected Integer lengthX;
+        /**
+         * 鎷夋瀹藉害鍍忕礌鍊�
+         */
+        @MessageElement("LengthY")
+        protected Integer lengthY;
+
+        public Integer getLength() {
+            return length;
+        }
+
+        public void setLength(Integer length) {
+            this.length = length;
+        }
+
+        public Integer getWidth() {
+            return width;
+        }
+
+        public void setWidth(Integer width) {
+            this.width = width;
+        }
+
+        public Integer getMidPointX() {
+            return midPointX;
+        }
+
+        public void setMidPointX(Integer midPointX) {
+            this.midPointX = midPointX;
+        }
+
+        public Integer getMidPointY() {
+            return midPointY;
+        }
+
+        public void setMidPointY(Integer midPointY) {
+            this.midPointY = midPointY;
+        }
+
+        public Integer getLengthX() {
+            return lengthX;
+        }
+
+        public void setLengthX(Integer lengthX) {
+            this.lengthX = lengthX;
+        }
+
+        public Integer getLengthY() {
+            return lengthY;
+        }
+
+        public void setLengthY(Integer lengthY) {
+            this.lengthY = lengthY;
+        }
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public DragZoom getDragZoomIn() {
+        return dragZoomIn;
+    }
+
+    public void setDragZoomIn(DragZoom dragZoomIn) {
+        this.dragZoomIn = dragZoomIn;
+    }
+
+    public DragZoom getDragZoomOut() {
+        return dragZoomOut;
+    }
+
+    public void setDragZoomOut(DragZoom dragZoomOut) {
+        this.dragZoomOut = dragZoomOut;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java
new file mode 100644
index 0000000..2c20713
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java
@@ -0,0 +1,94 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
+
+/**
+ * 璁惧淇℃伅鏌ヨ鍝嶅簲
+ *
+ * @author Y.G
+ * @version 1.0
+ * @date 2022/6/28 14:55
+ */
+public class HomePositionRequest {
+    /**
+     * 搴忓垪鍙�
+     */
+    @MessageElement("SN")
+    private String sn;
+
+    @MessageElement("DeviceID")
+    private String deviceId;
+
+    @MessageElement(value = "HomePosition")
+    private HomePosition homePosition;
+
+
+    /**
+     * 鍩烘湰鍙傛暟
+     */
+    public static class HomePosition {
+        /**
+         * 鎾斁绐楀彛闀垮害鍍忕礌鍊�
+         */
+        @MessageElement("Enabled")
+        protected String enabled;
+        /**
+         * 鎾斁绐楀彛瀹藉害鍍忕礌鍊�
+         */
+        @MessageElement("ResetTime")
+        protected String resetTime;
+        /**
+         * 鎷夋涓績鐨勬í杞村潗鏍囧儚绱犲��
+         */
+        @MessageElement("PresetIndex")
+        protected String presetIndex;
+
+        public String getEnabled() {
+            return enabled;
+        }
+
+        public void setEnabled(String enabled) {
+            this.enabled = enabled;
+        }
+
+        public String getResetTime() {
+            return resetTime;
+        }
+
+        public void setResetTime(String resetTime) {
+            this.resetTime = resetTime;
+        }
+
+        public String getPresetIndex() {
+            return presetIndex;
+        }
+
+        public void setPresetIndex(String presetIndex) {
+            this.presetIndex = presetIndex;
+        }
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public HomePosition getHomePosition() {
+        return homePosition;
+    }
+
+    public void setHomePosition(HomePosition homePosition) {
+        this.homePosition = homePosition;
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
index 2121db7..41aebf5 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
+
 import java.time.Instant;
 import java.util.List;
 
@@ -19,6 +20,8 @@
 	private String name;
 	
 	private int sumNum;
+
+	private int count;
 
 	private Instant lastTime;
 	
@@ -79,4 +82,12 @@
 	public void setLastTime(Instant lastTime) {
 		this.lastTime = lastTime;
 	}
+
+	public int getCount() {
+		return count;
+	}
+
+	public void setCount(int count) {
+		this.count = count;
+	}
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
index 92a4351..cb46823 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
@@ -1,8 +1,10 @@
 package com.genersoft.iot.vmp.gb28181.event.record;
 
 import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
+import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationListener;
 import org.springframework.stereotype.Component;
 
@@ -20,25 +22,46 @@
 
     private final static Logger logger = LoggerFactory.getLogger(RecordEndEventListener.class);
 
+    private Map<String, RecordEndEventHandler> handlerMap = new ConcurrentHashMap<>();
     public interface RecordEndEventHandler{
         void  handler(RecordInfo recordInfo);
     }
 
-    private Map<String, RecordEndEventHandler> handlerMap = new ConcurrentHashMap<>();
-
     @Override
     public void onApplicationEvent(RecordEndEvent event) {
-        logger.info("褰曞儚鏌ヨ瀹屾垚浜嬩欢瑙﹀彂锛宒eviceId锛歿}, channelId: {}, 褰曞儚鏁伴噺{}鏉�", event.getRecordInfo().getDeviceId(),
-                event.getRecordInfo().getChannelId(), event.getRecordInfo().getSumNum() );
+        String deviceId = event.getRecordInfo().getDeviceId();
+        String channelId = event.getRecordInfo().getChannelId();
+        int count = event.getRecordInfo().getCount();
+        int sumNum = event.getRecordInfo().getSumNum();
+        logger.info("褰曞儚鏌ヨ瀹屾垚浜嬩欢瑙﹀彂锛宒eviceId锛歿}, channelId: {}, 褰曞儚鏁伴噺{}/{}鏉�", event.getRecordInfo().getDeviceId(),
+                event.getRecordInfo().getChannelId(), count,sumNum);
         if (handlerMap.size() > 0) {
-            for (RecordEndEventHandler recordEndEventHandler : handlerMap.values()) {
-                recordEndEventHandler.handler(event.getRecordInfo());
+            RecordEndEventHandler handler = handlerMap.get(deviceId + channelId);
+            if (handler !=null){
+                handler.handler(event.getRecordInfo());
+                if (count ==sumNum){
+                    handlerMap.remove(deviceId + channelId);
+                }
             }
         }
-        handlerMap.clear();
     }
 
+    /**
+     * 娣诲姞
+     * @param device
+     * @param channelId
+     * @param recordEndEventHandler
+     */
     public void addEndEventHandler(String device, String channelId, RecordEndEventHandler recordEndEventHandler) {
         handlerMap.put(device + channelId, recordEndEventHandler);
     }
+    /**
+     * 娣诲姞
+     * @param device
+     * @param channelId
+     */
+    public void delEndEventHandler(String device, String channelId) {
+        handlerMap.remove(device + channelId);
+    }
+
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java
index 1d2b34b..3f24dbe 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java
@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.session;
 
 import com.genersoft.iot.vmp.gb28181.bean.*;
+import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEventListener;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
@@ -23,14 +24,17 @@
 
     @Autowired
     private DeferredResultHolder deferredResultHolder;
+    @Autowired
+    private RecordEndEventListener recordEndEventListener;
 
 
-    public int put(String deviceId, String sn, int sumNum, List<RecordItem> recordItems) {
+    public int put(String deviceId,String channelId, String sn, int sumNum, List<RecordItem> recordItems) {
         String key = deviceId + sn;
         RecordInfo recordInfo = data.get(key);
         if (recordInfo == null) {
             recordInfo = new RecordInfo();
             recordInfo.setDeviceId(deviceId);
+            recordInfo.setChannelId(channelId);
             recordInfo.setSn(sn.trim());
             recordInfo.setSumNum(sumNum);
             recordInfo.setRecordList(Collections.synchronizedList(new ArrayList<>()));
@@ -67,6 +71,7 @@
                 msg.setKey(msgKey);
                 msg.setData(recordInfo);
                 deferredResultHolder.invokeAllResult(msg);
+                recordEndEventListener.delEndEventHandler(recordInfo.getDeviceId(),recordInfo.getChannelId());
                 data.remove(key);
             }
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java
index 0aff21d..742b8bb 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java
@@ -47,61 +47,65 @@
     }
 
     public void transmitRequest(String ip, Message message, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, ParseException {
-        ViaHeader viaHeader = (ViaHeader)message.getHeader(ViaHeader.NAME);
-        String transport = "UDP";
-        if (viaHeader == null) {
-            logger.warn("[娑堟伅澶寸己澶盷锛� ViaHeader锛� 浣跨敤榛樿鐨刄DP鏂瑰紡澶勭悊鏁版嵁");
-        }else {
-            transport = viaHeader.getTransport();
-        }
-        if (message.getHeader(UserAgentHeader.NAME) == null) {
-            try {
-                message.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
-            } catch (ParseException e) {
-                logger.error("娣诲姞UserAgentHeader澶辫触", e);
+        try {
+            ViaHeader viaHeader = (ViaHeader)message.getHeader(ViaHeader.NAME);
+            String transport = "UDP";
+            if (viaHeader == null) {
+                logger.warn("[娑堟伅澶寸己澶盷锛� ViaHeader锛� 浣跨敤榛樿鐨刄DP鏂瑰紡澶勭悊鏁版嵁");
+            }else {
+                transport = viaHeader.getTransport();
             }
-        }
-
-        CallIdHeader callIdHeader = (CallIdHeader) message.getHeader(CallIdHeader.NAME);
-        // 娣诲姞閿欒璁㈤槄
-        if (errorEvent != null) {
-            sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
-                errorEvent.response(eventResult);
-                sipSubscribe.removeErrorSubscribe(eventResult.callId);
-                sipSubscribe.removeOkSubscribe(eventResult.callId);
-            }));
-        }
-        // 娣诲姞璁㈤槄
-        if (okEvent != null) {
-            sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
-                okEvent.response(eventResult);
-                sipSubscribe.removeOkSubscribe(eventResult.callId);
-                sipSubscribe.removeErrorSubscribe(eventResult.callId);
-            });
-        }
-        if ("TCP".equals(transport)) {
-            SipProviderImpl tcpSipProvider = sipLayer.getTcpSipProvider(ip);
-            if (tcpSipProvider == null) {
-                logger.error("[鍙戦�佷俊鎭け璐 鏈壘鍒皌cp://{}鐨勭洃鍚俊鎭�", ip);
-                return;
-            }
-            if (message instanceof Request) {
-                tcpSipProvider.sendRequest((Request)message);
-            }else if (message instanceof Response) {
-                tcpSipProvider.sendResponse((Response)message);
+            if (message.getHeader(UserAgentHeader.NAME) == null) {
+                try {
+                    message.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
+                } catch (ParseException e) {
+                    logger.error("娣诲姞UserAgentHeader澶辫触", e);
+                }
             }
 
-        } else if ("UDP".equals(transport)) {
-            SipProviderImpl sipProvider = sipLayer.getUdpSipProvider(ip);
-            if (sipProvider == null) {
-                logger.error("[鍙戦�佷俊鎭け璐 鏈壘鍒皍dp://{}鐨勭洃鍚俊鎭�", ip);
-                return;
+            CallIdHeader callIdHeader = (CallIdHeader) message.getHeader(CallIdHeader.NAME);
+            // 娣诲姞閿欒璁㈤槄
+            if (errorEvent != null) {
+                sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
+                    errorEvent.response(eventResult);
+                    sipSubscribe.removeErrorSubscribe(eventResult.callId);
+                    sipSubscribe.removeOkSubscribe(eventResult.callId);
+                }));
             }
-            if (message instanceof Request) {
-                sipProvider.sendRequest((Request)message);
-            }else if (message instanceof Response) {
-                sipProvider.sendResponse((Response)message);
+            // 娣诲姞璁㈤槄
+            if (okEvent != null) {
+                sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
+                    okEvent.response(eventResult);
+                    sipSubscribe.removeOkSubscribe(eventResult.callId);
+                    sipSubscribe.removeErrorSubscribe(eventResult.callId);
+                });
             }
+            if ("TCP".equals(transport)) {
+                SipProviderImpl tcpSipProvider = sipLayer.getTcpSipProvider(ip);
+                if (tcpSipProvider == null) {
+                    logger.error("[鍙戦�佷俊鎭け璐 鏈壘鍒皌cp://{}鐨勭洃鍚俊鎭�", ip);
+                    return;
+                }
+                if (message instanceof Request) {
+                    tcpSipProvider.sendRequest((Request)message);
+                }else if (message instanceof Response) {
+                    tcpSipProvider.sendResponse((Response)message);
+                }
+
+            } else if ("UDP".equals(transport)) {
+                SipProviderImpl sipProvider = sipLayer.getUdpSipProvider(ip);
+                if (sipProvider == null) {
+                    logger.error("[鍙戦�佷俊鎭け璐 鏈壘鍒皍dp://{}鐨勭洃鍚俊鎭�", ip);
+                    return;
+                }
+                if (message instanceof Request) {
+                    sipProvider.sendRequest((Request)message);
+                }else if (message instanceof Response) {
+                    sipProvider.sendResponse((Response)message);
+                }
+            }
+        } finally {
+            logger.info("[SEND]:SUCCESS:{}", message);
         }
     }
 
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 eebed4e..1f1d10a 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -183,7 +183,7 @@
 	 * @param channelId  	棰勮閫氶亾
 	 * @param recordCmdStr	褰曞儚鍛戒护锛歊ecord / StopRecord
 	 */
-	void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
+	void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
 	
 	/**
 	 * 杩滅▼鍚姩鎺у埗鍛戒护
@@ -197,7 +197,7 @@
 	 * 
 	 * @param device  	瑙嗛璁惧
 	 */
-	void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
+	void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
 	
 	/**
 	 * 鎶ヨ澶嶄綅鍛戒护
@@ -206,7 +206,7 @@
 	 * @param alarmMethod	鎶ヨ鏂瑰紡锛堝彲閫夛級
 	 * @param alarmType		鎶ヨ绫诲瀷锛堝彲閫夛級
 	 */
-	void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
+	void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
 	
 	/**
 	 * 寮哄埗鍏抽敭甯у懡浠�,璁惧鏀跺埌姝ゅ懡浠ゅ簲绔嬪埢鍙戦�佷竴涓狪DR甯�
@@ -215,17 +215,19 @@
 	 * @param channelId  棰勮閫氶亾
 	 */
 	void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException;
-	
+
 	/**
 	 * 鐪嬪畧浣嶆帶鍒跺懡浠�
-	 * 
-	 * @param device		瑙嗛璁惧
-	 * @param enabled		鐪嬪畧浣嶄娇鑳斤細1 = 寮�鍚紝0 = 鍏抽棴
-	 * @param resetTime		鑷姩褰掍綅鏃堕棿闂撮殧锛屽紑鍚湅瀹堜綅鏃朵娇鐢紝鍗曚綅:绉�(s)
-	 * @param presetIndex	璋冪敤棰勭疆浣嶇紪鍙凤紝寮�鍚湅瀹堜綅鏃朵娇鐢紝鍙栧�艰寖鍥�0~255
+	 *
+	 * @param device      瑙嗛璁惧
+	 * @param channelId      閫氶亾id锛岄潪閫氶亾鍒欐槸璁惧鏈韩
+	 * @param frontCmd     涓婄骇骞冲彴鐨勬寚浠わ紝濡傛灉瀛樺湪鍒欑洿鎺ヤ笅鍙�
+	 * @param enabled     鐪嬪畧浣嶄娇鑳斤細1 = 寮�鍚紝0 = 鍏抽棴
+	 * @param resetTime   鑷姩褰掍綅鏃堕棿闂撮殧锛屽紑鍚湅瀹堜綅鏃朵娇鐢紝鍗曚綅:绉�(s)
+	 * @param presetIndex 璋冪敤棰勭疆浣嶇紪鍙凤紝寮�鍚湅瀹堜綅鏃朵娇鐢紝鍙栧�艰寖鍥�0~255
 	 */
-	void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
-	
+	void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) 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 2415538..fbd9ece 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -29,6 +29,7 @@
 import org.springframework.context.annotation.DependsOn;
 import org.springframework.stereotype.Component;
 import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
 
 import javax.sip.InvalidArgumentException;
 import javax.sip.ResponseEvent;
@@ -663,7 +664,7 @@
      * @param recordCmdStr 褰曞儚鍛戒护锛歊ecord / StopRecord
      */
     @Override
-    public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
+    public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
         StringBuffer cmdXml = new StringBuffer(200);
         String charset = device.getCharset();
         cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
@@ -681,7 +682,7 @@
         
 
         Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
-        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
+        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
     }
 
     /**
@@ -715,7 +716,7 @@
      * @param guardCmdStr "SetGuard"/"ResetGuard"
      */
     @Override
-    public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
+    public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
 
         StringBuffer cmdXml = new StringBuffer(200);
         String charset = device.getCharset();
@@ -728,7 +729,7 @@
         cmdXml.append("</Control>\r\n");
 
         Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
-        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
+        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
     }
 
     /**
@@ -737,7 +738,7 @@
      * @param device 瑙嗛璁惧
      */
     @Override
-    public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
+    public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
 
         StringBuffer cmdXml = new StringBuffer(200);
         String charset = device.getCharset();
@@ -764,7 +765,7 @@
         
 
         Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
-        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
+        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
     }
 
     /**
@@ -800,12 +801,14 @@
      * 鐪嬪畧浣嶆帶鍒跺懡浠�
      *
      * @param device      瑙嗛璁惧
+     * @param channelId      閫氶亾id锛岄潪閫氶亾鍒欐槸璁惧鏈韩
+     * @param frontCmd     涓婄骇骞冲彴鐨勬寚浠わ紝濡傛灉瀛樺湪鍒欑洿鎺ヤ笅鍙�
      * @param enabled     鐪嬪畧浣嶄娇鑳斤細1 = 寮�鍚紝0 = 鍏抽棴
      * @param resetTime   鑷姩褰掍綅鏃堕棿闂撮殧锛屽紑鍚湅瀹堜綅鏃朵娇鐢紝鍗曚綅:绉�(s)
      * @param presetIndex 璋冪敤棰勭疆浣嶇紪鍙凤紝寮�鍚湅瀹堜綅鏃朵娇鐢紝鍙栧�艰寖鍥�0~255
      */
     @Override
-    public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
+    public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
 
         StringBuffer cmdXml = new StringBuffer(200);
         String charset = device.getCharset();
@@ -840,7 +843,7 @@
         
 
         Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
-        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
+        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
     }
 
     /**
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
index f97a659..4ac83de 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
@@ -1,8 +1,11 @@
 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control.cmd;
 
-import com.genersoft.iot.vmp.VManageBootstrap;
+import com.genersoft.iot.vmp.common.enums.DeviceControlType;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.DragZoomRequest;
+import com.genersoft.iot.vmp.gb28181.bean.HomePositionRequest;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
@@ -19,17 +22,14 @@
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
 
 import javax.sip.*;
 import javax.sip.address.SipURI;
-import javax.sip.header.HeaderAddress;
-import javax.sip.header.ToHeader;
 import javax.sip.message.Response;
 import java.text.ParseException;
-import java.util.Iterator;
+import java.util.List;
 
-import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
+import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.*;
 
 @Component
 public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
@@ -81,7 +81,7 @@
                 } catch (InvalidArgumentException | ParseException | SipException e) {
                     logger.error("[鍛戒护鍙戦�佸け璐 鍥芥爣绾ц仈 娉ㄩ攢: {}", e.getMessage());
                 }
-                taskExecutor.execute(()->{
+                taskExecutor.execute(() -> {
                     // 杩滅▼鍚姩
 //                    try {
 //                        Thread.sleep(3000);
@@ -101,13 +101,12 @@
 //                        logger.error("[浠诲姟鎵ц澶辫触] 鏈嶅姟閲嶅惎: {}", e.getMessage());
 //                    }
                 });
-            } else {
-                // 杩滅▼鍚姩鎸囧畾璁惧
             }
         }
-        // 浜戝彴/鍓嶇鎺у埗鍛戒护
-        if (!ObjectUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) {
-            String cmdString = getText(rootElement,"PTZCmd");
+        DeviceControlType deviceControlType = DeviceControlType.typeOf(rootElement);
+        logger.info("[鎺ュ彈deviceControl鍛戒护] 鍛戒护: {}", deviceControlType);
+        if (!ObjectUtils.isEmpty(deviceControlType) && !parentPlatform.getServerGBId().equals(targetGBId)) {
+            //鍒ゆ柇鏄惁瀛樺湪璇ラ�氶亾
             Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
             if (deviceForPlatform == null) {
                 try {
@@ -117,25 +116,240 @@
                 }
                 return;
             }
-            try {
-                cmder.fronEndCmd(deviceForPlatform, channelId, cmdString, eventResult -> {
-                    // 澶辫触鐨勫洖澶�
-                    try {
-                        responseAck(request, eventResult.statusCode, eventResult.msg);
-                    } catch (SipException | InvalidArgumentException | ParseException e) {
-                        logger.error("[鍛戒护鍙戦�佸け璐 浜戝彴/鍓嶇鍥炲: {}", e.getMessage());
-                    }
-                }, eventResult -> {
-                    // 鎴愬姛鐨勫洖澶�
-                    try {
-                        responseAck(request, eventResult.statusCode);
-                    } catch (SipException | InvalidArgumentException | ParseException e) {
-                        logger.error("[鍛戒护鍙戦�佸け璐 浜戝彴/鍓嶇鍥炲: {}", e.getMessage());
-                    }
-                });
-            } catch (InvalidArgumentException | SipException | ParseException e) {
-                logger.error("[鍛戒护鍙戦�佸け璐 浜戝彴/鍓嶇: {}", e.getMessage());
+            switch (deviceControlType) {
+                case PTZ:
+                    handlePtzCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.PTZ);
+                    break;
+                case ALARM:
+                    handleAlarmCmd(deviceForPlatform, rootElement, request);
+                    break;
+                case GUARD:
+                    handleGuardCmd(deviceForPlatform, rootElement, request, DeviceControlType.GUARD);
+                    break;
+                case RECORD:
+                    handleRecordCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.RECORD);
+                    break;
+                case I_FRAME:
+                    handleIFameCmd(deviceForPlatform, request, channelId);
+                    break;
+                case TELE_BOOT:
+                    handleTeleBootCmd(deviceForPlatform, request);
+                    break;
+                case DRAG_ZOOM_IN:
+                    handleDragZoom(deviceForPlatform, channelId, rootElement, request, DeviceControlType.DRAG_ZOOM_IN);
+                    break;
+                case DRAG_ZOOM_OUT:
+                    handleDragZoom(deviceForPlatform, channelId, rootElement, request, DeviceControlType.DRAG_ZOOM_OUT);
+                    break;
+                case HOME_POSITION:
+                    handleHomePositionCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.HOME_POSITION);
+                    break;
+                default:
+                    break;
             }
         }
     }
+
+    /**
+     * 澶勭悊浜戝彴鎸囦护
+     *
+     * @param device      璁惧
+     * @param channelId   閫氶亾id
+     * @param rootElement
+     * @param request
+     */
+    private void handlePtzCmd(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
+        String cmdString = getText(rootElement, type.getVal());
+        try {
+            cmder.fronEndCmd(device, channelId, cmdString,
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
+        } catch (InvalidArgumentException | SipException | ParseException e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 浜戝彴/鍓嶇: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 澶勭悊寮哄埗鍏抽敭甯�
+     *
+     * @param device    璁惧
+     * @param channelId 閫氶亾id
+     */
+    private void handleIFameCmd(Device device, SIPRequest request, String channelId) {
+        try {
+            cmder.iFrameCmd(device, channelId);
+            responseAck(request, Response.OK);
+        } catch (InvalidArgumentException | SipException | ParseException e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 寮哄埗鍏抽敭甯�: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 澶勭悊閲嶅惎鍛戒护
+     *
+     * @param device 璁惧淇℃伅
+     */
+    private void handleTeleBootCmd(Device device, SIPRequest request) {
+        try {
+            cmder.teleBootCmd(device);
+            responseAck(request, Response.OK);
+        } catch (InvalidArgumentException | SipException | ParseException e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 閲嶅惎: {}", e.getMessage());
+        }
+
+    }
+
+    /**
+     * 澶勭悊鎷夋鎺у埗***
+     *
+     * @param device      璁惧淇℃伅
+     * @param channelId   閫氶亾id
+     * @param rootElement 鏍硅妭鐐�
+     * @param type        娑堟伅绫诲瀷
+     */
+    private void handleDragZoom(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
+        try {
+            DragZoomRequest dragZoomRequest = loadElement(rootElement, DragZoomRequest.class);
+            DragZoomRequest.DragZoom dragZoom = dragZoomRequest.getDragZoomIn();
+            if (dragZoom == null) {
+                dragZoom = dragZoomRequest.getDragZoomOut();
+            }
+            StringBuffer cmdXml = new StringBuffer(200);
+            cmdXml.append("<" + type.getVal() + ">\r\n");
+            cmdXml.append("<Length>" + dragZoom.getLength() + "</Length>\r\n");
+            cmdXml.append("<Width>" + dragZoom.getWidth() + "</Width>\r\n");
+            cmdXml.append("<MidPointX>" + dragZoom.getMidPointX() + "</MidPointX>\r\n");
+            cmdXml.append("<MidPointY>" + dragZoom.getMidPointY() + "</MidPointY>\r\n");
+            cmdXml.append("<LengthX>" + dragZoom.getLengthX() + "</LengthX>\r\n");
+            cmdXml.append("<LengthY>" + dragZoom.getLengthY() + "</LengthY>\r\n");
+            cmdXml.append("</" + type.getVal() + ">\r\n");
+            cmder.dragZoomCmd(device, channelId, cmdXml.toString());
+            responseAck(request, Response.OK);
+        } catch (Exception e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 鎷夋鎺у埗: {}", e.getMessage());
+        }
+
+    }
+
+    /**
+     * 澶勭悊鐪嬪畧浣嶅懡浠�***
+     *
+     * @param device      璁惧淇℃伅
+     * @param channelId   閫氶亾id
+     * @param rootElement 鏍硅妭鐐�
+     * @param request     璇锋眰淇℃伅
+     * @param type        娑堟伅绫诲瀷
+     */
+    private void handleHomePositionCmd(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
+        try {
+            HomePositionRequest homePosition = loadElement(rootElement, HomePositionRequest.class);
+            //鑾峰彇鏁翠釜娑堟伅涓讳綋锛屾垜浠彧闇�瑕佷慨鏀硅姹傚ご鍗冲彲
+            HomePositionRequest.HomePosition info = homePosition.getHomePosition();
+            cmder.homePositionCmd(device, channelId, info.getEnabled(), info.getResetTime(), info.getPresetIndex(),
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
+        } catch (Exception e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 鐪嬪畧浣嶈缃�: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 澶勭悊鍛婅娑堟伅***
+     *
+     * @param device      璁惧淇℃伅
+     * @param rootElement 鏍硅妭鐐�
+     * @param request     璇锋眰淇℃伅
+     */
+    private void handleAlarmCmd(Device device, Element rootElement, SIPRequest request) {
+        //鍛婅鏂规硶
+        String alarmMethod = "";
+        //鍛婅绫诲瀷
+        String alarmType = "";
+        List<Element> info = rootElement.elements("Info");
+        if (info != null) {
+            for (Element element : info) {
+                alarmMethod = getText(element, "AlarmMethod");
+                alarmType = getText(element, "AlarmType");
+            }
+        }
+        try {
+            cmder.alarmCmd(device, alarmMethod, alarmType,
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
+        } catch (InvalidArgumentException | SipException | ParseException e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 鍛婅娑堟伅: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 澶勭悊褰曞儚鎺у埗
+     *
+     * @param device      璁惧淇℃伅
+     * @param channelId   閫氶亾id
+     * @param rootElement 鏍硅妭鐐�
+     * @param request     璇锋眰淇℃伅
+     * @param type        娑堟伅绫诲瀷
+     */
+    private void handleRecordCmd(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
+        //鑾峰彇鏁翠釜娑堟伅涓讳綋锛屾垜浠彧闇�瑕佷慨鏀硅姹傚ご鍗冲彲
+        String cmdString = getText(rootElement, type.getVal());
+        try {
+            cmder.recordCmd(device, channelId, cmdString,
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
+        } catch (InvalidArgumentException | SipException | ParseException e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 褰曞儚鎺у埗: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 澶勭悊鎶ヨ甯冮槻/鎾ら槻鍛戒护
+     *
+     * @param device      璁惧淇℃伅
+     * @param rootElement 鏍硅妭鐐�
+     * @param request     璇锋眰淇℃伅
+     * @param type        娑堟伅绫诲瀷
+     */
+    private void handleGuardCmd(Device device, Element rootElement, SIPRequest request, DeviceControlType type) {
+        //鑾峰彇鏁翠釜娑堟伅涓讳綋锛屾垜浠彧闇�瑕佷慨鏀硅姹傚ご鍗冲彲
+        String cmdString = getText(rootElement, type.getVal());
+        try {
+            cmder.guardCmd(device, cmdString,
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
+        } catch (InvalidArgumentException | SipException | ParseException e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 甯冮槻/鎾ら槻鍛戒护: {}", e.getMessage());
+        }
+    }
+
+
+    /**
+     * 閿欒鍝嶅簲澶勭悊
+     *
+     * @param request     璇锋眰
+     * @param eventResult 鍝嶅簲缁撴瀯
+     */
+    private void onError(SIPRequest request, SipSubscribe.EventResult eventResult) {
+        // 澶辫触鐨勫洖澶�
+        try {
+            responseAck(request, eventResult.statusCode, eventResult.msg);
+        } catch (SipException | InvalidArgumentException | ParseException e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 鍥炲: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 鎴愬姛鍝嶅簲澶勭悊
+     *
+     * @param request     璇锋眰
+     * @param eventResult 鍝嶅簲缁撴瀯
+     */
+    private void onOk(SIPRequest request, SipSubscribe.EventResult eventResult) {
+        // 鎴愬姛鐨勫洖澶�
+        try {
+            responseAck(request, eventResult.statusCode);
+        } catch (SipException | InvalidArgumentException | ParseException e) {
+            logger.error("[鍛戒护鍙戦�佸け璐 鍥炲: {}", e.getMessage());
+        }
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
index 09a5ffc..0c1d5d6 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
@@ -181,11 +181,13 @@
                             }
                         }
                         logger.info("[鏀跺埌鎶ヨ閫氱煡]鍐呭锛歿}", JSON.toJSONString(deviceAlarm));
-                        if ("7".equals(deviceAlarm.getAlarmMethod()) ) {
+                        if (DeviceAlarmMethod.typeOf(Integer.parseInt(deviceAlarm.getAlarmMethod())) !=null) {
                             // 鍙戦�佺粰骞冲彴鐨勬姤璀︿俊鎭�� 鍙戦�乺edis閫氱煡
+                            logger.info("[鍙戦�佺粰骞冲彴鐨勬姤璀︿俊鎭痌鍐呭锛歿}", JSONObject.toJSONString(deviceAlarm));
                             AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage();
                             alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod()));
                             alarmChannelMessage.setAlarmDescription(deviceAlarm.getAlarmDescription());
+                            alarmChannelMessage.setAlarmType(Integer.parseInt(deviceAlarm.getAlarmType()));
                             alarmChannelMessage.setGbId(channelId);
                             redisCatchStorage.sendAlarmMsg(alarmChannelMessage);
                             continue;
@@ -264,6 +266,7 @@
             alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod()));
             alarmChannelMessage.setAlarmDescription(deviceAlarm.getAlarmDescription());
             alarmChannelMessage.setGbId(channelId);
+            alarmChannelMessage.setAlarmType(Integer.parseInt(deviceAlarm.getAlarmType()));
             redisCatchStorage.sendAlarmMsg(alarmChannelMessage);
             return;
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
index 11d239e..8b4ae2e 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
@@ -102,8 +102,9 @@
                         Element recordListElement = rootElementForCharset.element("RecordList");
                         if (recordListElement == null || sumNum == 0) {
                             logger.info("鏃犲綍鍍忔暟鎹�");
+                            int count = recordDataCatch.put(take.getDevice().getDeviceId(),channelId, sn, sumNum, new ArrayList<>());
+                            recordInfo.setCount(count);
                             eventPublisher.recordEndEventPush(recordInfo);
-                            recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, new ArrayList<>());
                             releaseRequest(take.getDevice().getDeviceId(), sn);
                         } else {
                             Iterator<Element> recordListIterator = recordListElement.elementIterator();
@@ -137,12 +138,11 @@
                                     recordList.add(record);
                                 }
                                 recordInfo.setRecordList(recordList);
+                                int count = recordDataCatch.put(take.getDevice().getDeviceId(),channelId, sn, sumNum, recordList);recordInfo.setCount(count);
+                                logger.info("[鍥芥爣褰曞儚]锛� {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum);
                                 // 鍙戦�佹秷鎭紝濡傛灉鏄笂绾ф煡璇㈡褰曞儚锛屽垯浼氶�氳繃杩欓噷閫氱煡缁欎笂绾�
                                 eventPublisher.recordEndEventPush(recordInfo);
-                                int count = recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, recordList);
-                                logger.info("[鍥芥爣褰曞儚]锛� {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum);
                             }
-
                             if (recordDataCatch.isComplete(take.getDevice().getDeviceId(), sn)){
                                 releaseRequest(take.getDevice().getDeviceId(), sn);
                             }
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/MessageElement.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/MessageElement.java
new file mode 100644
index 0000000..f94237c
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/MessageElement.java
@@ -0,0 +1,17 @@
+package com.genersoft.iot.vmp.gb28181.utils;
+
+import java.lang.annotation.*;
+
+/**
+ * @author gaofuwang
+ * @version 1.0
+ * @date 2022/6/28 14:58
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface MessageElement {
+    String value();
+
+    String subVal() default "";
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
index 35d563d..0ea6d87 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.utils;
 
+import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -15,12 +16,16 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
+import org.springframework.util.ReflectionUtils;
 
 import javax.sip.RequestEvent;
 import javax.sip.message.Request;
 import java.io.ByteArrayInputStream;
 import java.io.StringReader;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.util.*;
 
 /**
@@ -411,4 +416,76 @@
         }
         return deviceChannel;
     }
+
+    /**
+     * 鏂板鏂规硶鏀寔鍐呴儴宓屽
+     *
+     * @param element xmlElement
+     * @param clazz 缁撴灉绫�
+     * @param <T> 娉涘瀷
+     * @return 缁撴灉瀵硅薄
+     * @throws NoSuchMethodException
+     * @throws InvocationTargetException
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     */
+    public static <T> T loadElement(Element element, Class<T> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
+        Field[] fields = clazz.getDeclaredFields();
+        T t = clazz.getDeclaredConstructor().newInstance();
+        for (Field field : fields) {
+            ReflectionUtils.makeAccessible(field);
+            MessageElement annotation = field.getAnnotation(MessageElement.class);
+            if (annotation == null) {
+                continue;
+            }
+            String value = annotation.value();
+            String subVal = annotation.subVal();
+            Element element1 = element.element(value);
+            if (element1 == null) {
+                continue;
+            }
+            if ("".equals(subVal)) {
+                // 鏃犱笅绾ф暟鎹�
+                Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType());
+                Object o = simpleTypeDeal(field.getType(), fieldVal);
+                ReflectionUtils.setField(field, t,  o);
+            } else {
+                // 瀛樺湪涓嬬骇鏁版嵁
+                ArrayList<Object> list = new ArrayList<>();
+                Type genericType = field.getGenericType();
+                if (!(genericType instanceof ParameterizedType)) {
+                    continue;
+                }
+                Class<?> aClass = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
+                for (Element element2 : element1.elements(subVal)) {
+                    list.add(loadElement(element2, aClass));
+                }
+                ReflectionUtils.setField(field, t, list);
+            }
+        }
+        return t;
+    }
+
+    /**
+     * 绠�鍗曠被鍨嬪鐞�
+     *
+     * @param tClass
+     * @param val
+     * @return
+     */
+    private static Object simpleTypeDeal(Class<?> tClass, Object val) {
+        if (tClass.equals(String.class)) {
+            return val.toString();
+        }
+        if (tClass.equals(Integer.class)) {
+            return Integer.valueOf(val.toString());
+        }
+        if (tClass.equals(Double.class)) {
+            return Double.valueOf(val.toString());
+        }
+        if (tClass.equals(Long.class)) {
+            return Long.valueOf(val.toString());
+        }
+        return val;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java
index 9bb3bbd..2e18db3 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java
@@ -67,9 +67,9 @@
                         deviceAlarm.setChannelId(gbId);
                         deviceAlarm.setAlarmDescription(alarmChannelMessage.getAlarmDescription());
                         deviceAlarm.setAlarmMethod("" + alarmChannelMessage.getAlarmSn());
+                        deviceAlarm.setAlarmType("" + alarmChannelMessage.getAlarmType());
                         deviceAlarm.setAlarmPriority("1");
                         deviceAlarm.setAlarmTime(DateUtil.getNowForISO8601());
-                        deviceAlarm.setAlarmType("1");
                         deviceAlarm.setLongitude(0);
                         deviceAlarm.setLatitude(0);
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
index 35a42c5..ae130cf 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
@@ -114,4 +114,7 @@
             "         left join device d on dc.deviceId = d.deviceId\n" +
             "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}")
     List<Device> queryDeviceInfoByPlatformIdAndChannelId(String platformId, String channelId);
+
+    @Select("SELECT pgc.platformId FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId='${channelId}'")
+    List<String> queryParentPlatformByChannelId(String channelId);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
index 55ebf7a..e997e4d 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -830,7 +830,7 @@
 
     @Override
     public void sendAlarmMsg(AlarmChannelMessage msg) {
-        String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM;
+        String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE;
         logger.info("[redis鍙戦�侀�氱煡] 鎶ヨ{}: {}", key, JSON.toJSON(msg));
         RedisUtil.convertAndSend(key, (JSONObject)JSON.toJSON(msg));
     }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
index 41cabad..35656dd 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -133,6 +133,15 @@
 					if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
 						deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
 						deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
+						if (allChannelMap.get(deviceChannel.getChannelId()).getStatus() !=deviceChannel.getStatus()){
+							List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId());
+							if (!CollectionUtils.isEmpty(strings)){
+								strings.forEach(platformId->{
+									eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.getStatus()==1?CatalogEvent.ON:CatalogEvent.OFF);
+								});
+							}
+
+						}
 					}
 					channels.add(deviceChannel);
 					if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
index 18618e7..ff0d8b4 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
@@ -110,7 +110,7 @@
 				msg.setKey(key);
 				msg.setData(String.format("寮�濮�/鍋滄褰曞儚鎿嶄綔澶辫触锛岄敊璇爜锛� %s, %s", event.statusCode, event.msg));
 				resultHolder.invokeAllResult(msg);
-			});
+			},null);
 		} catch (InvalidArgumentException | SipException | ParseException e) {
 			logger.error("[鍛戒护鍙戦�佸け璐 寮�濮�/鍋滄褰曞儚: {}", e.getMessage());
 			throw new ControllerException(ErrorCode.ERROR100.getCode(), "鍛戒护鍙戦�佸け璐�: " + e.getMessage());
@@ -143,7 +143,7 @@
 				msg.setKey(key);
 				msg.setData(String.format("甯冮槻/鎾ら槻鎿嶄綔澶辫触锛岄敊璇爜锛� %s, %s", event.statusCode, event.msg));
 				resultHolder.invokeResult(msg);
-			});
+			},null);
 		} catch (InvalidArgumentException | SipException | ParseException e) {
 			logger.error("[鍛戒护鍙戦�佸け璐 甯冮槻/鎾ら槻鎿嶄綔: {}", e.getMessage());
 			throw new ControllerException(ErrorCode.ERROR100.getCode(), "鍛戒护鍙戦��: " + e.getMessage());
@@ -192,7 +192,7 @@
 				msg.setKey(key);
 				msg.setData(String.format("鎶ヨ澶嶄綅鎿嶄綔澶辫触锛岄敊璇爜锛� %s, %s", event.statusCode, event.msg));
 				resultHolder.invokeResult(msg);
-			});
+			},null);
 		} catch (InvalidArgumentException | SipException | ParseException e) {
 			logger.error("[鍛戒护鍙戦�佸け璐 鎶ヨ澶嶄綅: {}", e.getMessage());
 			throw new ControllerException(ErrorCode.ERROR100.getCode(), "鍛戒护鍙戦�佸け璐�: " + e.getMessage());
@@ -274,7 +274,7 @@
 				msg.setKey(key);
 				msg.setData(String.format("鐪嬪畧浣嶆帶鍒舵搷浣滃け璐ワ紝閿欒鐮侊細 %s, %s", event.statusCode, event.msg));
 				resultHolder.invokeResult(msg);
-			});
+			},null);
 		} catch (InvalidArgumentException | SipException | ParseException e) {
 			logger.error("[鍛戒护鍙戦�佸け璐 鐪嬪畧浣嶆帶鍒�: {}", e.getMessage());
 			throw new ControllerException(ErrorCode.ERROR100.getCode(), "鍛戒护鍙戦�佸け璐�: " + e.getMessage());

--
Gitblit v1.8.0