From 7a9f001dcb5b8d6c4b52e8ce2c5a8764752ff7ef Mon Sep 17 00:00:00 2001
From: gaofw189 <gaofw189@chinatelecom.cn>
Date: Thu, 2 Feb 2023 18:21:25 +0800
Subject: [PATCH 1/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8DWVP=E4=BD=9C=E4=B8=BA?=
 =?UTF-8?q?=E4=B8=8B=E7=BA=A7=E5=B9=B3=E5=8F=B0=E6=8E=A5=E6=94=B6=E4=B8=8A?=
 =?UTF-8?q?=E7=BA=A7=E5=B9=B3=E5=8F=B0DeviceControl=E4=BF=A1=E4=BB=A4?=
 =?UTF-8?q?=E4=B8=8D=E5=81=9A=E5=A4=84=E7=90=86=E7=9A=84=E9=97=AE=E9=A2=98?=
 =?UTF-8?q?=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                                       |   5 +
 .../vmp/common/enums/DeviceControlType.java   |  69 +++++
 .../gb28181/transmit/cmd/ISIPCommander.java   |  18 +-
 .../transmit/cmd/impl/SIPCommander.java       |  36 +--
 .../cmd/DeviceControlQueryMessageHandler.java | 235 ++++++++++++++++--
 .../gb28181/device/DeviceControl.java         |   4 +-
 6 files changed, 319 insertions(+), 48 deletions(-)
 create mode 100644 src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java

diff --git a/pom.xml b/pom.xml
index c0c99004a..9e369e0f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,11 @@
 	</properties>
 
 	<dependencies>
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+			<optional>true</optional>
+		</dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-data-redis</artifactId>
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 000000000..3b801d294
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java
@@ -0,0 +1,69 @@
+package com.genersoft.iot.vmp.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.dom4j.Element;
+import org.springframework.util.ObjectUtils;
+
+import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
+
+/**
+ * @author gaofuwang
+ * @date 2023/01/18/ 10:09:00
+ * @since 1.0
+ */
+@Getter
+@AllArgsConstructor
+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;
+
+    public static DeviceControlType typeOf(Element rootElement) {
+        for (DeviceControlType item : DeviceControlType.values()) {
+            if (!ObjectUtils.isEmpty(getText(rootElement,item.val))) {
+                return item;
+            }
+        }
+        return null;
+    }
+}
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 eebed4eb7..40571fe25 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
@@ -215,17 +215,19 @@ public interface ISIPCommander {
 	 * @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 frontCmd, 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 241553844..47c798fb6 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.beans.factory.annotation.Autowired;
 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;
@@ -800,12 +801,14 @@ public class SIPCommander implements ISIPCommander {
      * 看守位控制命令
      *
      * @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 frontCmd, 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();
@@ -819,28 +822,33 @@ public class SIPCommander implements ISIPCommander {
             cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
         }
         cmdXml.append("<HomePosition>\r\n");
-        if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
-            cmdXml.append("<Enabled>1</Enabled>\r\n");
-            if (NumericUtil.isInteger(resetTime)) {
-                cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
+        if (StringUtils.hasText(frontCmd)){
+            cmdXml.append(frontCmd);
+        }else{
+            if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
+                cmdXml.append("<Enabled>1</Enabled>\r\n");
+                if (NumericUtil.isInteger(resetTime)) {
+                    cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
+                } else {
+                    cmdXml.append("<ResetTime>0</ResetTime>\r\n");
+                }
+                if (NumericUtil.isInteger(presetIndex)) {
+                    cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
+                } else {
+                    cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
+                }
             } else {
-                cmdXml.append("<ResetTime>0</ResetTime>\r\n");
+                cmdXml.append("<Enabled>0</Enabled>\r\n");
             }
-            if (NumericUtil.isInteger(presetIndex)) {
-                cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
-            } else {
-                cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
-            }
-        } else {
-            cmdXml.append("<Enabled>0</Enabled>\r\n");
         }
+
         cmdXml.append("</HomePosition>\r\n");
         cmdXml.append("</Control>\r\n");
 
         
 
         Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
-        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
+        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 f97a6592f..e2c8fd9a9 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,9 @@
 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.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;
@@ -28,6 +29,7 @@ import javax.sip.header.ToHeader;
 import javax.sip.message.Response;
 import java.text.ParseException;
 import java.util.Iterator;
+import java.util.Objects;
 
 import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
 
@@ -101,13 +103,11 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
 //                        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);
+        if (!ObjectUtils.isEmpty(deviceControlType) && !parentPlatform.getServerGBId().equals(targetGBId)){
+            //判断是否存在该通道
             Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
             if (deviceForPlatform == null) {
                 try {
@@ -117,25 +117,212 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
                 }
                 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,channelId);
+                    break;
+                case TELE_BOOT:
+                    handleTeleBootCmd(deviceForPlatform);
+                    break;
+                case DRAG_ZOOM_IN:
+                    handleDragZoom(deviceForPlatform,channelId,rootElement,DeviceControlType.DRAG_ZOOM_IN);
+                    break;
+                case DRAG_ZOOM_OUT:
+                    handleDragZoom(deviceForPlatform,channelId,rootElement,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,String channelId){
+        try {
+            cmder.iFrameCmd(device,channelId);
+        } catch (InvalidArgumentException | SipException | ParseException e) {
+            logger.error("[命令发送失败] 关键帧: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 处理重启命令
+     * @param device 设备信息
+     */
+    private void handleTeleBootCmd(Device device){
+        try {
+            cmder.teleBootCmd(device);
+        } 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,DeviceControlType type){
+        String cmdString = getText(rootElement,type.getVal());
+        StringBuffer cmdXml = new StringBuffer(200);
+        cmdXml.append("<" + type.getVal() + ">\r\n");
+        cmdXml.append(cmdString);
+        cmdXml.append("</" + type.getVal() + ">\r\n");
+        try {
+            cmder.dragZoomCmd(device,channelId,cmdXml.toString());
+        } catch (InvalidArgumentException | SipException | ParseException 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){
+        //获取整个消息主体,我们只需要修改请求头即可
+        String cmdString = getText(rootElement,type.getVal());
+        try {
+            cmder.homePositionCmd(device, channelId, cmdString,null,null,null,
+                    errorResult -> onError(request,errorResult),
+                    okResult -> onOk(request,okResult));
+        } catch (InvalidArgumentException | SipException | ParseException e) {
+            logger.error("[命令发送失败] 看守位设置: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 处理告警消息
+     * @param device 设备信息
+     * @param rootElement 根节点
+     * @param request 请求信息
+     */
+    private void handleAlarmCmd(Device device,Element rootElement,SIPRequest request){
+        //告警方法
+        String alarmMethod = "";
+        //告警类型
+        String alarmType = "";
+        Element info = rootElement.element("Info");
+        if (info !=null){
+            alarmMethod = getText(rootElement,"AlarmMethod");
+            alarmType = getText(rootElement,"AlarmType");
+        }
+        try {
+            cmder.alarmCmd(device, alarmMethod,alarmType,
+                    errorResult -> onError(request,errorResult));
+        } 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));
+        } 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));
+        } 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/vmanager/gb28181/device/DeviceControl.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
index 18618e74f..2a44eb540 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
@@ -268,13 +268,13 @@ public class DeviceControl {
 		String uuid = UUID.randomUUID().toString();
 		Device device = storager.queryVideoDevice(deviceId);
 		try {
-			cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> {
+			cmder.homePositionCmd(device, channelId,null, enabled, resetTime, presetIndex, event -> {
 				RequestMessage msg = new RequestMessage();
 				msg.setId(uuid);
 				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());

From e5b1876012fc76f7ea273fa35e1262b067891bac Mon Sep 17 00:00:00 2001
From: gaofw189 <gaofw189@chinatelecom.cn>
Date: Thu, 2 Feb 2023 18:24:32 +0800
Subject: [PATCH 2/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8DWVP=E4=BD=9C=E4=B8=BA?=
 =?UTF-8?q?=E4=B8=8B=E7=BA=A7=E5=B9=B3=E5=8F=B0=E6=8E=A5=E6=94=B6=E4=B8=8A?=
 =?UTF-8?q?=E7=BA=A7=E5=B9=B3=E5=8F=B0DeviceControl=E4=BF=A1=E4=BB=A4?=
 =?UTF-8?q?=E4=B8=8D=E5=81=9A=E5=A4=84=E7=90=86=E7=9A=84=E9=97=AE=E9=A2=98?=
 =?UTF-8?q?=E3=80=82-=E4=BF=AE=E6=94=B9=E6=97=A5=E5=BF=97=E5=A4=87?=
 =?UTF-8?q?=E6=B3=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../control/cmd/DeviceControlQueryMessageHandler.java       | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

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 e2c8fd9a9..46e8e9286 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
@@ -179,7 +179,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
         try {
             cmder.iFrameCmd(device,channelId);
         } catch (InvalidArgumentException | SipException | ParseException e) {
-            logger.error("[命令发送失败] 关键帧: {}", e.getMessage());
+            logger.error("[命令发送失败] 强制关键帧: {}", e.getMessage());
         }
     }
 
@@ -257,7 +257,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
             cmder.alarmCmd(device, alarmMethod,alarmType,
                     errorResult -> onError(request,errorResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
-            logger.error("[命令发送失败] 告警重置: {}", e.getMessage());
+            logger.error("[命令发送失败] 告警消息: {}", e.getMessage());
         }
     }
 
@@ -276,7 +276,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
             cmder.recordCmd(device, channelId,cmdString,
                     errorResult -> onError(request,errorResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
-            logger.error("[命令发送失败] 告警重置: {}", e.getMessage());
+            logger.error("[命令发送失败] 录像控制: {}", e.getMessage());
         }
     }
 

From 40ece192fe8b7c2df8599a71daeda422083c5a47 Mon Sep 17 00:00:00 2001
From: gaofw189 <gaofw189@chinatelecom.cn>
Date: Fri, 3 Feb 2023 14:35:44 +0800
Subject: [PATCH 3/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8DWVP=E4=BD=9C=E4=B8=BA?=
 =?UTF-8?q?=E4=B8=8B=E7=BA=A7=E5=B9=B3=E5=8F=B0=E6=8E=A5=E6=94=B6=E8=AE=BE?=
 =?UTF-8?q?=E5=A4=87=E5=91=8A=E8=AD=A6=E6=B6=88=E6=81=AF=E5=90=8E=E4=B8=8A?=
 =?UTF-8?q?=E6=8A=A5=E4=B8=8A=E7=BA=A7=E5=B9=B3=E5=8F=B0=E7=9A=84=E9=97=AE?=
 =?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../vmp/gb28181/bean/AlarmChannelMessage.java | 32 ++++---------------
 .../vmp/gb28181/bean/DeviceAlarmMethod.java   | 14 ++++++++
 .../notify/cmd/AlarmNotifyMessageHandler.java |  5 ++-
 .../redisMsg/RedisAlarmMsgListener.java       |  2 +-
 .../storager/impl/RedisCatchStorageImpl.java  |  2 +-
 5 files changed, 27 insertions(+), 28 deletions(-)

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 96d25c4eb..b87a32055 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,46 +1,28 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
+import lombok.Data;
+
 /**
  * 通过redis分发报警消息
  */
+@Data
 public class AlarmChannelMessage {
     /**
      * 国标编号
      */
     private String gbId;
-
     /**
      * 报警编号
      */
     private int alarmSn;
-
+    /**
+     * 告警类型
+     */
+    private int alarmType;
 
     /**
      * 报警描述
      */
     private String alarmDescription;
 
-    public String getGbId() {
-        return gbId;
-    }
-
-    public void setGbId(String gbId) {
-        this.gbId = gbId;
-    }
-
-    public int getAlarmSn() {
-        return alarmSn;
-    }
-
-    public void setAlarmSn(int alarmSn) {
-        this.alarmSn = alarmSn;
-    }
-
-    public String getAlarmDescription() {
-        return alarmDescription;
-    }
-
-    public void setAlarmDescription(String alarmDescription) {
-        this.alarmDescription = 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 ff8761eef..d1fb6db61 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 enum DeviceAlarmMethod {
     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/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 09a5ffc2c..0c1d5d6e4 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 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
                             }
                         }
                         logger.info("[收到报警通知]内容:{}", JSON.toJSONString(deviceAlarm));
-                        if ("7".equals(deviceAlarm.getAlarmMethod()) ) {
+                        if (DeviceAlarmMethod.typeOf(Integer.parseInt(deviceAlarm.getAlarmMethod())) !=null) {
                             // 发送给平台的报警信息。 发送redis通知
+                            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 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
             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/service/redisMsg/RedisAlarmMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java
index 9bb3bbd27..2e18db39d 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 @@ public class RedisAlarmMsgListener implements MessageListener {
                         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/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
index 8cf5293bc..2ab3e09c5 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
@@ -827,7 +827,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
 
     @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));
     }

From 25fca14e6224909811d96c348fc2427cf7fe13d1 Mon Sep 17 00:00:00 2001
From: gaofw189 <gaofw189@chinatelecom.cn>
Date: Mon, 6 Feb 2023 10:35:32 +0800
Subject: [PATCH 4/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8DWVP=E4=BD=9C=E4=B8=BA?=
 =?UTF-8?q?=E4=B8=8B=E7=BA=A7=E5=B9=B3=E5=8F=B0=E6=8E=A5=E5=8F=97deviceCon?=
 =?UTF-8?q?trol=E6=8C=87=E4=BB=A4=E7=9A=84=E9=97=AE=E9=A2=98-=E4=BF=AE?=
 =?UTF-8?q?=E5=A4=8D=E6=8C=87=E4=BB=A4=E5=93=8D=E5=BA=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../iot/vmp/gb28181/transmit/SIPSender.java   | 104 +++++++++---------
 .../gb28181/transmit/cmd/ISIPCommander.java   |   6 +-
 .../transmit/cmd/impl/SIPCommander.java       |  12 +-
 .../cmd/DeviceControlQueryMessageHandler.java |  27 +++--
 .../gb28181/device/DeviceControl.java         |   6 +-
 5 files changed, 82 insertions(+), 73 deletions(-)

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 0aff21d21..742b8bbbc 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 class SIPSender {
     }
 
     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, 使用默认的UDP方式处理数据");
-        }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, 使用默认的UDP方式处理数据");
+            }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("[发送信息失败] 未找到tcp://{}的监听信息", 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("[发送信息失败] 未找到udp://{}的监听信息", 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("[发送信息失败] 未找到tcp://{}的监听信息", 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("[发送信息失败] 未找到udp://{}的监听信息", 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 40571fe25..e9b203926 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 @@ public interface ISIPCommander {
 	 * @param channelId  	预览通道
 	 * @param recordCmdStr	录像命令:Record / 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 @@ public interface ISIPCommander {
 	 * 
 	 * @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 @@ public interface ISIPCommander {
 	 * @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;
 	
 	/**
 	 * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
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 47c798fb6..69376416c 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
@@ -664,7 +664,7 @@ public class SIPCommander implements ISIPCommander {
      * @param recordCmdStr 录像命令:Record / 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");
@@ -682,7 +682,7 @@ public class SIPCommander implements ISIPCommander {
         
 
         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);
     }
 
     /**
@@ -716,7 +716,7 @@ public class SIPCommander implements ISIPCommander {
      * @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();
@@ -729,7 +729,7 @@ public class SIPCommander implements ISIPCommander {
         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);
     }
 
     /**
@@ -738,7 +738,7 @@ public class SIPCommander implements ISIPCommander {
      * @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();
@@ -765,7 +765,7 @@ public class SIPCommander implements ISIPCommander {
         
 
         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 46e8e9286..fa54a0fd0 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
@@ -131,16 +131,16 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
                     handleRecordCmd(deviceForPlatform,channelId,rootElement,request,DeviceControlType.RECORD);
                     break;
                 case I_FRAME:
-                    handleIFameCmd(deviceForPlatform,channelId);
+                    handleIFameCmd(deviceForPlatform,request,channelId);
                     break;
                 case TELE_BOOT:
-                    handleTeleBootCmd(deviceForPlatform);
+                    handleTeleBootCmd(deviceForPlatform,request);
                     break;
                 case DRAG_ZOOM_IN:
-                    handleDragZoom(deviceForPlatform,channelId,rootElement,DeviceControlType.DRAG_ZOOM_IN);
+                    handleDragZoom(deviceForPlatform,channelId,rootElement,request,DeviceControlType.DRAG_ZOOM_IN);
                     break;
                 case DRAG_ZOOM_OUT:
-                    handleDragZoom(deviceForPlatform,channelId,rootElement,DeviceControlType.DRAG_ZOOM_OUT);
+                    handleDragZoom(deviceForPlatform,channelId,rootElement,request,DeviceControlType.DRAG_ZOOM_OUT);
                     break;
                 case HOME_POSITION:
                     handleHomePositionCmd(deviceForPlatform,channelId,rootElement,request,DeviceControlType.HOME_POSITION);
@@ -167,7 +167,6 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 云台/前端: {}", e.getMessage());
         }
-
     }
 
     /**
@@ -175,9 +174,10 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
      * @param device 设备
      * @param channelId 通道id
      */
-    private void handleIFameCmd(Device device,String channelId){
+    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());
         }
@@ -187,9 +187,10 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
      * 处理重启命令
      * @param device 设备信息
      */
-    private void handleTeleBootCmd(Device 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());
         }
@@ -203,7 +204,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
      * @param rootElement 根节点
      * @param type 消息类型
      */
-    private void handleDragZoom(Device device,String channelId,Element rootElement,DeviceControlType type){
+    private void handleDragZoom(Device device,String channelId,Element rootElement,SIPRequest request,DeviceControlType type){
         String cmdString = getText(rootElement,type.getVal());
         StringBuffer cmdXml = new StringBuffer(200);
         cmdXml.append("<" + type.getVal() + ">\r\n");
@@ -211,6 +212,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
         cmdXml.append("</" + type.getVal() + ">\r\n");
         try {
             cmder.dragZoomCmd(device,channelId,cmdXml.toString());
+            responseAck(request, Response.OK);
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 拉框控制: {}", e.getMessage());
         }
@@ -255,7 +257,8 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
         }
         try {
             cmder.alarmCmd(device, alarmMethod,alarmType,
-                    errorResult -> onError(request,errorResult));
+                    errorResult -> onError(request,errorResult),
+                    okResult -> onOk(request,okResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 告警消息: {}", e.getMessage());
         }
@@ -274,7 +277,8 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
         String cmdString = getText(rootElement,type.getVal());
         try {
             cmder.recordCmd(device, channelId,cmdString,
-                    errorResult -> onError(request,errorResult));
+                    errorResult -> onError(request,errorResult),
+                    okResult -> onOk(request,okResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 录像控制: {}", e.getMessage());
         }
@@ -292,7 +296,8 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
         String cmdString = getText(rootElement,type.getVal());
         try {
             cmder.guardCmd(device, cmdString,
-                    errorResult -> onError(request,errorResult));
+                    errorResult -> onError(request,errorResult),
+                    okResult -> onOk(request,okResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 布防/撤防命令: {}", e.getMessage());
         }
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 2a44eb540..3e1b423a3 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 @@ public class DeviceControl {
 				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 @@ public class DeviceControl {
 				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 @@ public class DeviceControl {
 				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());

From 55ee6f5f0d363faacdb04e7ff01ef9f23e0b9d7f Mon Sep 17 00:00:00 2001
From: gaofw189 <gaofw189@chinatelecom.cn>
Date: Tue, 7 Feb 2023 09:26:08 +0800
Subject: [PATCH 5/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8DWVP=E4=BD=9C=E4=B8=BA?=
 =?UTF-8?q?=E4=B8=8B=E7=BA=A7=E5=B9=B3=E5=8F=B0=E6=8E=A5=E5=8F=97devicecon?=
 =?UTF-8?q?trol=E5=91=BD=E4=BB=A4=E5=A4=84=E7=90=86-=E8=B0=83=E8=AF=95?=
 =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../vmp/common/enums/DeviceControlType.java   |   4 +-
 .../iot/vmp/gb28181/bean/DragZoomRequest.java |  70 +++++++
 .../vmp/gb28181/bean/HomePositionRequest.java |  50 +++++
 .../gb28181/transmit/cmd/ISIPCommander.java   |   2 +-
 .../transmit/cmd/impl/SIPCommander.java       |  31 ++-
 .../cmd/DeviceControlQueryMessageHandler.java | 188 ++++++++++--------
 .../iot/vmp/gb28181/utils/MessageElement.java |  17 ++
 .../iot/vmp/gb28181/utils/XmlUtil.java        |  79 +++++++-
 .../storager/dao/PlatformChannelMapper.java   |   3 +
 .../impl/VideoManagerStorageImpl.java         |   9 +
 .../gb28181/device/DeviceControl.java         |   2 +-
 11 files changed, 350 insertions(+), 105 deletions(-)
 create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java
 create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java
 create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/utils/MessageElement.java

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
index 3b801d294..5a046fac1 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java
@@ -1,5 +1,7 @@
 package com.genersoft.iot.vmp.common.enums;
 
+import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 import org.dom4j.Element;
@@ -60,7 +62,7 @@ public enum DeviceControlType {
 
     public static DeviceControlType typeOf(Element rootElement) {
         for (DeviceControlType item : DeviceControlType.values()) {
-            if (!ObjectUtils.isEmpty(getText(rootElement,item.val))) {
+            if (!ObjectUtils.isEmpty(rootElement.element(item.val)) || !ObjectUtils.isEmpty(rootElement.elements(item.val))) {
                 return item;
             }
         }
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 000000000..d8b76901d
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java
@@ -0,0 +1,70 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 设备信息查询响应
+ *
+ * @author Y.G
+ * @version 1.0
+ * @date 2022/6/28 14:55
+ */
+@Data
+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;
+
+    /**
+     * 基本参数
+     */
+    @Data
+    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;
+
+    }
+}
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 000000000..b0fff21c4
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java
@@ -0,0 +1,50 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
+import lombok.Data;
+
+/**
+ * 设备信息查询响应
+ *
+ * @author Y.G
+ * @version 1.0
+ * @date 2022/6/28 14:55
+ */
+@Data
+public class HomePositionRequest {
+    /**
+     * 序列号
+     */
+    @MessageElement("SN")
+    private String sn;
+
+    @MessageElement("DeviceID")
+    private String deviceId;
+
+    @MessageElement(value = "HomePosition")
+    private HomePosition homePosition;
+
+
+    /**
+     * 基本参数
+     */
+    @Data
+    public static class HomePosition {
+        /**
+         * 播放窗口长度像素值
+         */
+        @MessageElement("Enabled")
+        protected String enabled;
+        /**
+         * 播放窗口宽度像素值
+         */
+        @MessageElement("ResetTime")
+        protected String resetTime;
+        /**
+         * 拉框中心的横轴坐标像素值
+         */
+        @MessageElement("PresetIndex")
+        protected String presetIndex;
+
+    }
+}
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 e9b203926..1f1d10a65 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
@@ -226,7 +226,7 @@ public interface ISIPCommander {
 	 * @param resetTime   自动归位时间间隔,开启看守位时使用,单位:秒(s)
 	 * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
 	 */
-	void homePositionCmd(Device device, String channelId,String frontCmd, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) 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 69376416c..fbd9ececd 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
@@ -808,7 +808,7 @@ public class SIPCommander implements ISIPCommander {
      * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
      */
     @Override
-    public void homePositionCmd(Device device, String channelId,String frontCmd, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) 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();
@@ -822,26 +822,21 @@ public class SIPCommander implements ISIPCommander {
             cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
         }
         cmdXml.append("<HomePosition>\r\n");
-        if (StringUtils.hasText(frontCmd)){
-            cmdXml.append(frontCmd);
-        }else{
-            if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
-                cmdXml.append("<Enabled>1</Enabled>\r\n");
-                if (NumericUtil.isInteger(resetTime)) {
-                    cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
-                } else {
-                    cmdXml.append("<ResetTime>0</ResetTime>\r\n");
-                }
-                if (NumericUtil.isInteger(presetIndex)) {
-                    cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
-                } else {
-                    cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
-                }
+        if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
+            cmdXml.append("<Enabled>1</Enabled>\r\n");
+            if (NumericUtil.isInteger(resetTime)) {
+                cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
             } else {
-                cmdXml.append("<Enabled>0</Enabled>\r\n");
+                cmdXml.append("<ResetTime>0</ResetTime>\r\n");
             }
+            if (NumericUtil.isInteger(presetIndex)) {
+                cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
+            } else {
+                cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
+            }
+        } else {
+            cmdXml.append("<Enabled>0</Enabled>\r\n");
         }
-
         cmdXml.append("</HomePosition>\r\n");
         cmdXml.append("</Control>\r\n");
 
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 fa54a0fd0..4ac83de75 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
@@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.contro
 
 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;
@@ -20,18 +22,14 @@ import org.springframework.beans.factory.annotation.Qualifier;
 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.Objects;
+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 {
@@ -83,7 +81,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
                 } catch (InvalidArgumentException | ParseException | SipException e) {
                     logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
                 }
-                taskExecutor.execute(()->{
+                taskExecutor.execute(() -> {
                     // 远程启动
 //                    try {
 //                        Thread.sleep(3000);
@@ -106,7 +104,8 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
             }
         }
         DeviceControlType deviceControlType = DeviceControlType.typeOf(rootElement);
-        if (!ObjectUtils.isEmpty(deviceControlType) && !parentPlatform.getServerGBId().equals(targetGBId)){
+        logger.info("[接受deviceControl命令] 命令: {}", deviceControlType);
+        if (!ObjectUtils.isEmpty(deviceControlType) && !parentPlatform.getServerGBId().equals(targetGBId)) {
             //判断是否存在该通道
             Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
             if (deviceForPlatform == null) {
@@ -117,33 +116,33 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
                 }
                 return;
             }
-            switch (deviceControlType){
+            switch (deviceControlType) {
                 case PTZ:
-                    handlePtzCmd(deviceForPlatform,channelId,rootElement,request,DeviceControlType.PTZ);
+                    handlePtzCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.PTZ);
                     break;
                 case ALARM:
-                    handleAlarmCmd(deviceForPlatform,rootElement,request);
+                    handleAlarmCmd(deviceForPlatform, rootElement, request);
                     break;
                 case GUARD:
-                    handleGuardCmd(deviceForPlatform,rootElement,request,DeviceControlType.GUARD);
+                    handleGuardCmd(deviceForPlatform, rootElement, request, DeviceControlType.GUARD);
                     break;
                 case RECORD:
-                    handleRecordCmd(deviceForPlatform,channelId,rootElement,request,DeviceControlType.RECORD);
+                    handleRecordCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.RECORD);
                     break;
                 case I_FRAME:
-                    handleIFameCmd(deviceForPlatform,request,channelId);
+                    handleIFameCmd(deviceForPlatform, request, channelId);
                     break;
                 case TELE_BOOT:
-                    handleTeleBootCmd(deviceForPlatform,request);
+                    handleTeleBootCmd(deviceForPlatform, request);
                     break;
                 case DRAG_ZOOM_IN:
-                    handleDragZoom(deviceForPlatform,channelId,rootElement,request,DeviceControlType.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);
+                    handleDragZoom(deviceForPlatform, channelId, rootElement, request, DeviceControlType.DRAG_ZOOM_OUT);
                     break;
                 case HOME_POSITION:
-                    handleHomePositionCmd(deviceForPlatform,channelId,rootElement,request,DeviceControlType.HOME_POSITION);
+                    handleHomePositionCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.HOME_POSITION);
                     break;
                 default:
                     break;
@@ -153,17 +152,18 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
 
     /**
      * 处理云台指令
-     * @param device 设备
-     * @param channelId 通道id
+     *
+     * @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());
+    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));
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 云台/前端: {}", e.getMessage());
         }
@@ -171,12 +171,13 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
 
     /**
      * 处理强制关键帧
-     * @param device 设备
+     *
+     * @param device    设备
      * @param channelId 通道id
      */
-    private void handleIFameCmd(Device device,SIPRequest request,String channelId){
+    private void handleIFameCmd(Device device, SIPRequest request, String channelId) {
         try {
-            cmder.iFrameCmd(device,channelId);
+            cmder.iFrameCmd(device, channelId);
             responseAck(request, Response.OK);
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 强制关键帧: {}", e.getMessage());
@@ -185,9 +186,10 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
 
     /**
      * 处理重启命令
+     *
      * @param device 设备信息
      */
-    private void handleTeleBootCmd(Device device,SIPRequest request){
+    private void handleTeleBootCmd(Device device, SIPRequest request) {
         try {
             cmder.teleBootCmd(device);
             responseAck(request, Response.OK);
@@ -198,67 +200,82 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
     }
 
     /**
-     * 处理拉框控制
-     * @param device 设备信息
-     * @param channelId 通道id
+     * 处理拉框控制***
+     *
+     * @param device      设备信息
+     * @param channelId   通道id
      * @param rootElement 根节点
-     * @param type 消息类型
+     * @param type        消息类型
      */
-    private void handleDragZoom(Device device,String channelId,Element rootElement,SIPRequest request,DeviceControlType type){
-        String cmdString = getText(rootElement,type.getVal());
-        StringBuffer cmdXml = new StringBuffer(200);
-        cmdXml.append("<" + type.getVal() + ">\r\n");
-        cmdXml.append(cmdString);
-        cmdXml.append("</" + type.getVal() + ">\r\n");
+    private void handleDragZoom(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
         try {
-            cmder.dragZoomCmd(device,channelId,cmdXml.toString());
+            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 (InvalidArgumentException | SipException | ParseException e) {
+        } catch (Exception e) {
             logger.error("[命令发送失败] 拉框控制: {}", e.getMessage());
         }
 
     }
 
     /**
-     * 处理看守位命令
-     * @param device 设备信息
-     * @param channelId 通道id
+     * 处理看守位命令***
+     *
+     * @param device      设备信息
+     * @param channelId   通道id
      * @param rootElement 根节点
-     * @param request 请求信息
-     * @param type 消息类型
+     * @param request     请求信息
+     * @param type        消息类型
      */
-    private void handleHomePositionCmd(Device device,String channelId,Element rootElement,SIPRequest request,DeviceControlType type){
-        //获取整个消息主体,我们只需要修改请求头即可
-        String cmdString = getText(rootElement,type.getVal());
+    private void handleHomePositionCmd(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
         try {
-            cmder.homePositionCmd(device, channelId, cmdString,null,null,null,
-                    errorResult -> onError(request,errorResult),
-                    okResult -> onOk(request,okResult));
-        } catch (InvalidArgumentException | SipException | ParseException e) {
+            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 device      设备信息
      * @param rootElement 根节点
-     * @param request 请求信息
+     * @param request     请求信息
      */
-    private void handleAlarmCmd(Device device,Element rootElement,SIPRequest request){
+    private void handleAlarmCmd(Device device, Element rootElement, SIPRequest request) {
         //告警方法
         String alarmMethod = "";
         //告警类型
         String alarmType = "";
-        Element info = rootElement.element("Info");
-        if (info !=null){
-            alarmMethod = getText(rootElement,"AlarmMethod");
-            alarmType = getText(rootElement,"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));
+            cmder.alarmCmd(device, alarmMethod, alarmType,
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 告警消息: {}", e.getMessage());
         }
@@ -266,19 +283,20 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
 
     /**
      * 处理录像控制
-     * @param device 设备信息
-     * @param channelId 通道id
+     *
+     * @param device      设备信息
+     * @param channelId   通道id
      * @param rootElement 根节点
-     * @param request 请求信息
-     * @param type 消息类型
+     * @param request     请求信息
+     * @param type        消息类型
      */
-    private void handleRecordCmd(Device device,String channelId,Element rootElement,SIPRequest request,DeviceControlType type){
+    private void handleRecordCmd(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
         //获取整个消息主体,我们只需要修改请求头即可
-        String cmdString = getText(rootElement,type.getVal());
+        String cmdString = getText(rootElement, type.getVal());
         try {
-            cmder.recordCmd(device, channelId,cmdString,
-                    errorResult -> onError(request,errorResult),
-                    okResult -> onOk(request,okResult));
+            cmder.recordCmd(device, channelId, cmdString,
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 录像控制: {}", e.getMessage());
         }
@@ -286,18 +304,19 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
 
     /**
      * 处理报警布防/撤防命令
-     * @param device 设备信息
+     *
+     * @param device      设备信息
      * @param rootElement 根节点
-     * @param request 请求信息
-     * @param type 消息类型
+     * @param request     请求信息
+     * @param type        消息类型
      */
-    private void handleGuardCmd(Device device,Element rootElement,SIPRequest request,DeviceControlType type){
+    private void handleGuardCmd(Device device, Element rootElement, SIPRequest request, DeviceControlType type) {
         //获取整个消息主体,我们只需要修改请求头即可
-        String cmdString = getText(rootElement,type.getVal());
+        String cmdString = getText(rootElement, type.getVal());
         try {
             cmder.guardCmd(device, cmdString,
-                    errorResult -> onError(request,errorResult),
-                    okResult -> onOk(request,okResult));
+                    errorResult -> onError(request, errorResult),
+                    okResult -> onOk(request, okResult));
         } catch (InvalidArgumentException | SipException | ParseException e) {
             logger.error("[命令发送失败] 布防/撤防命令: {}", e.getMessage());
         }
@@ -306,10 +325,11 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
 
     /**
      * 错误响应处理
-     * @param request 请求
+     *
+     * @param request     请求
      * @param eventResult 响应结构
      */
-    private void onError(SIPRequest request, SipSubscribe.EventResult eventResult){
+    private void onError(SIPRequest request, SipSubscribe.EventResult eventResult) {
         // 失败的回复
         try {
             responseAck(request, eventResult.statusCode, eventResult.msg);
@@ -317,12 +337,14 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
             logger.error("[命令发送失败] 回复: {}", e.getMessage());
         }
     }
+
     /**
      * 成功响应处理
-     * @param request 请求
+     *
+     * @param request     请求
      * @param eventResult 响应结构
      */
-    private void onOk(SIPRequest request, SipSubscribe.EventResult eventResult){
+    private void onOk(SIPRequest request, SipSubscribe.EventResult eventResult) {
         // 成功的回复
         try {
             responseAck(request, eventResult.statusCode);
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 000000000..f94237cd8
--- /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 35d563d90..0ea6d8772 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.dom4j.io.SAXReader;
 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 @@ public class XmlUtil {
         }
         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/storager/dao/PlatformChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
index 35a42c572..ae130cf97 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 @@ public interface PlatformChannelMapper {
             "         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/VideoManagerStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
index 41cabad8c..35656ddf8 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 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
 					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 3e1b423a3..ff0d8b4f3 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
@@ -268,7 +268,7 @@ public class DeviceControl {
 		String uuid = UUID.randomUUID().toString();
 		Device device = storager.queryVideoDevice(deviceId);
 		try {
-			cmder.homePositionCmd(device, channelId,null, enabled, resetTime, presetIndex, event -> {
+			cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> {
 				RequestMessage msg = new RequestMessage();
 				msg.setId(uuid);
 				msg.setKey(key);

From c2e26291ceb940892b266852a671deda8f2cd952 Mon Sep 17 00:00:00 2001
From: gaofw189 <gaofw189@chinatelecom.cn>
Date: Tue, 7 Feb 2023 09:28:55 +0800
Subject: [PATCH 6/7] =?UTF-8?q?=E4=BF=AE=E5=A4=8DWVP=E4=BD=9C=E4=B8=BA?=
 =?UTF-8?q?=E4=B8=8B=E7=BA=A7=E5=B9=B3=E5=8F=B0=E6=8E=A5=E5=8F=97recordinf?=
 =?UTF-8?q?o=E6=8C=87=E4=BB=A4=E4=B8=8A=E6=8A=A5=E4=B8=8A=E7=BA=A7?=
 =?UTF-8?q?=E5=B9=B3=E5=8F=B0=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../iot/vmp/gb28181/bean/RecordInfo.java      |  5 +++
 .../event/record/RecordEndEventListener.java  | 37 +++++++++++++++----
 .../vmp/gb28181/session/RecordDataCatch.java  |  7 +++-
 .../cmd/RecordInfoResponseMessageHandler.java |  8 ++--
 4 files changed, 45 insertions(+), 12 deletions(-)

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 2121db7a5..04796eb8f 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,7 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
+import lombok.Data;
+
 import java.time.Instant;
 import java.util.List;
 
@@ -8,6 +10,7 @@ import java.util.List;
  * @author: swwheihei
  * @date:   2020年5月8日 下午2:05:56     
  */
+@Data
 public class RecordInfo {
 
 	private String deviceId;
@@ -20,6 +23,8 @@ public class RecordInfo {
 	
 	private int sumNum;
 
+	private int count;
+
 	private Instant lastTime;
 	
 	private List<RecordItem> recordList;
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 92a435170..cb4682304 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 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven
 
     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("录像查询完成事件触发,deviceId:{}, 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("录像查询完成事件触发,deviceId:{}, 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 1d2b34b0a..3f24dbee4 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 @@ public class RecordDataCatch {
 
     @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 @@ public class RecordDataCatch {
                 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/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 11d239ef3..8b4ae2e1c 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 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
                         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 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
                                     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);
                             }

From 5462b1f6c66eeb995af8202436bbae618111dc5e Mon Sep 17 00:00:00 2001
From: gaofw189 <gaofw189@chinatelecom.cn>
Date: Thu, 9 Feb 2023 09:20:46 +0800
Subject: [PATCH 7/7] =?UTF-8?q?=E5=8E=BB=E9=99=A4lombok=E4=BE=9D=E8=B5=96-?=
 =?UTF-8?q?=E5=90=8E=E7=BB=AD=E8=80=83=E8=99=91=E5=BC=95=E5=85=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                                       |  5 --
 .../vmp/common/enums/DeviceControlType.java   | 20 +++--
 .../vmp/gb28181/bean/AlarmChannelMessage.java | 33 ++++++-
 .../iot/vmp/gb28181/bean/DragZoomRequest.java | 85 +++++++++++++++++--
 .../vmp/gb28181/bean/HomePositionRequest.java | 50 ++++++++++-
 .../iot/vmp/gb28181/bean/RecordInfo.java      | 10 ++-
 6 files changed, 178 insertions(+), 25 deletions(-)

diff --git a/pom.xml b/pom.xml
index 9e369e0f4..c0c99004a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -57,11 +57,6 @@
 	</properties>
 
 	<dependencies>
-		<dependency>
-			<groupId>org.projectlombok</groupId>
-			<artifactId>lombok</artifactId>
-			<optional>true</optional>
-		</dependency>
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-data-redis</artifactId>
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
index 5a046fac1..02202d89c 100644
--- a/src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java
+++ b/src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java
@@ -1,21 +1,14 @@
 package com.genersoft.iot.vmp.common.enums;
 
-import com.alibaba.fastjson2.JSONObject;
-import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
 import org.dom4j.Element;
 import org.springframework.util.ObjectUtils;
 
-import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
 
 /**
  * @author gaofuwang
  * @date 2023/01/18/ 10:09:00
  * @since 1.0
  */
-@Getter
-@AllArgsConstructor
 public enum DeviceControlType {
 
     /**
@@ -60,6 +53,19 @@ public enum DeviceControlType {
 
     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))) {
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 b87a32055..7f50f4d37 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,11 +1,9 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
-import lombok.Data;
 
 /**
  * 通过redis分发报警消息
  */
-@Data
 public class AlarmChannelMessage {
     /**
      * 国标编号
@@ -25,4 +23,35 @@ public class AlarmChannelMessage {
      */
     private String alarmDescription;
 
+    public String getGbId() {
+        return gbId;
+    }
+
+    public void setGbId(String gbId) {
+        this.gbId = gbId;
+    }
+
+    public int getAlarmSn() {
+        return alarmSn;
+    }
+
+    public void setAlarmSn(int alarmSn) {
+        this.alarmSn = alarmSn;
+    }
+
+    public int getAlarmType() {
+        return alarmType;
+    }
+
+    public void setAlarmType(int alarmType) {
+        this.alarmType = alarmType;
+    }
+
+    public String getAlarmDescription() {
+        return alarmDescription;
+    }
+
+    public void setAlarmDescription(String alarmDescription) {
+        this.alarmDescription = alarmDescription;
+    }
 }
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
index d8b76901d..86fdb4d29 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java
@@ -1,10 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
 import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-import java.util.List;
 
 /**
  * 设备信息查询响应
@@ -13,7 +9,6 @@ import java.util.List;
  * @version 1.0
  * @date 2022/6/28 14:55
  */
-@Data
 public class DragZoomRequest {
     /**
      * 序列号
@@ -33,7 +28,6 @@ public class DragZoomRequest {
     /**
      * 基本参数
      */
-    @Data
     public static class DragZoom {
         /**
          * 播放窗口长度像素值
@@ -66,5 +60,84 @@ public class DragZoomRequest {
         @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
index b0fff21c4..2c20713bb 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java
@@ -1,7 +1,6 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
 import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
-import lombok.Data;
 
 /**
  * 设备信息查询响应
@@ -10,7 +9,6 @@ import lombok.Data;
  * @version 1.0
  * @date 2022/6/28 14:55
  */
-@Data
 public class HomePositionRequest {
     /**
      * 序列号
@@ -28,7 +26,6 @@ public class HomePositionRequest {
     /**
      * 基本参数
      */
-    @Data
     public static class HomePosition {
         /**
          * 播放窗口长度像素值
@@ -46,5 +43,52 @@ public class HomePositionRequest {
         @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 04796eb8f..41aebf5d9 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,6 +1,5 @@
 package com.genersoft.iot.vmp.gb28181.bean;
 
-import lombok.Data;
 
 import java.time.Instant;
 import java.util.List;
@@ -10,7 +9,6 @@ import java.util.List;
  * @author: swwheihei
  * @date:   2020年5月8日 下午2:05:56     
  */
-@Data
 public class RecordInfo {
 
 	private String deviceId;
@@ -84,4 +82,12 @@ public class RecordInfo {
 	public void setLastTime(Instant lastTime) {
 		this.lastTime = lastTime;
 	}
+
+	public int getCount() {
+		return count;
+	}
+
+	public void setCount(int count) {
+		this.count = count;
+	}
 }