Commit 03ee15ece2ff749be8f4c211e1ee6fd3a3a6066d

Authored by 648540858
Committed by GitHub
2 parents fdd73225 5462b1f6

Merge pull request #741 from gaofuwang/wvp-28181-2.0

修复WVP作为下级平台接收上级平台DeviceControl、RecordInfo信令处理问题和Alarm信令上报上级平台问题
Showing 21 changed files with 831 additions and 121 deletions
src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common.enums;
  2 +
  3 +import org.dom4j.Element;
  4 +import org.springframework.util.ObjectUtils;
  5 +
  6 +
  7 +/**
  8 + * @author gaofuwang
  9 + * @date 2023/01/18/ 10:09:00
  10 + * @since 1.0
  11 + */
  12 +public enum DeviceControlType {
  13 +
  14 + /**
  15 + * 云台控制
  16 + * 上下左右,预置位,扫描,辅助功能,巡航
  17 + */
  18 + PTZ("PTZCmd","云台控制"),
  19 + /**
  20 + * 远程启动
  21 + */
  22 + TELE_BOOT("TeleBoot","远程启动"),
  23 + /**
  24 + * 录像控制
  25 + */
  26 + RECORD("RecordCmd","录像控制"),
  27 + /**
  28 + * 布防撤防
  29 + */
  30 + GUARD("GuardCmd","布防撤防"),
  31 + /**
  32 + * 告警控制
  33 + */
  34 + ALARM("AlarmCmd","告警控制"),
  35 + /**
  36 + * 强制关键帧
  37 + */
  38 + I_FRAME("IFameCmd","强制关键帧"),
  39 + /**
  40 + * 拉框放大
  41 + */
  42 + DRAG_ZOOM_IN("DragZoomIn","拉框放大"),
  43 + /**
  44 + * 拉框缩小
  45 + */
  46 + DRAG_ZOOM_OUT("DragZoomOut","拉框缩小"),
  47 + /**
  48 + * 看守位
  49 + */
  50 + HOME_POSITION("HomePosition","看守位");
  51 +
  52 + private final String val;
  53 +
  54 + private final String desc;
  55 +
  56 + DeviceControlType(String val, String desc) {
  57 + this.val = val;
  58 + this.desc = desc;
  59 + }
  60 +
  61 + public String getVal() {
  62 + return val;
  63 + }
  64 +
  65 + public String getDesc() {
  66 + return desc;
  67 + }
  68 +
  69 + public static DeviceControlType typeOf(Element rootElement) {
  70 + for (DeviceControlType item : DeviceControlType.values()) {
  71 + if (!ObjectUtils.isEmpty(rootElement.element(item.val)) || !ObjectUtils.isEmpty(rootElement.elements(item.val))) {
  72 + return item;
  73 + }
  74 + }
  75 + return null;
  76 + }
  77 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/AlarmChannelMessage.java
1 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2  
  3 +
3 4 /**
4 5 * 通过redis分发报警消息
5 6 */
... ... @@ -8,12 +9,14 @@ public class AlarmChannelMessage {
8 9 * 国标编号
9 10 */
10 11 private String gbId;
11   -
12 12 /**
13 13 * 报警编号
14 14 */
15 15 private int alarmSn;
16   -
  16 + /**
  17 + * 告警类型
  18 + */
  19 + private int alarmType;
17 20  
18 21 /**
19 22 * 报警描述
... ... @@ -36,6 +39,14 @@ public class AlarmChannelMessage {
36 39 this.alarmSn = alarmSn;
37 40 }
38 41  
  42 + public int getAlarmType() {
  43 + return alarmType;
  44 + }
  45 +
  46 + public void setAlarmType(int alarmType) {
  47 + this.alarmType = alarmType;
  48 + }
  49 +
39 50 public String getAlarmDescription() {
40 51 return alarmDescription;
41 52 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarmMethod.java
... ... @@ -37,4 +37,18 @@ public enum DeviceAlarmMethod {
37 37 public int getVal() {
38 38 return val;
39 39 }
  40 +
  41 + /**
  42 + * 查询是否匹配类型
  43 + * @param code
  44 + * @return
  45 + */
  46 + public static DeviceAlarmMethod typeOf(int code) {
  47 + for (DeviceAlarmMethod item : DeviceAlarmMethod.values()) {
  48 + if (code==item.getVal()) {
  49 + return item;
  50 + }
  51 + }
  52 + return null;
  53 + }
40 54 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
  4 +
  5 +/**
  6 + * 设备信息查询响应
  7 + *
  8 + * @author Y.G
  9 + * @version 1.0
  10 + * @date 2022/6/28 14:55
  11 + */
  12 +public class DragZoomRequest {
  13 + /**
  14 + * 序列号
  15 + */
  16 + @MessageElement("SN")
  17 + private String sn;
  18 +
  19 + @MessageElement("DeviceID")
  20 + private String deviceId;
  21 +
  22 + @MessageElement(value = "DragZoomIn")
  23 + private DragZoom dragZoomIn;
  24 +
  25 + @MessageElement(value = "DragZoomOut")
  26 + private DragZoom dragZoomOut;
  27 +
  28 + /**
  29 + * 基本参数
  30 + */
  31 + public static class DragZoom {
  32 + /**
  33 + * 播放窗口长度像素值
  34 + */
  35 + @MessageElement("Length")
  36 + protected Integer length;
  37 + /**
  38 + * 播放窗口宽度像素值
  39 + */
  40 + @MessageElement("Width")
  41 + protected Integer width;
  42 + /**
  43 + * 拉框中心的横轴坐标像素值
  44 + */
  45 + @MessageElement("MidPointX")
  46 + protected Integer midPointX;
  47 + /**
  48 + * 拉框中心的纵轴坐标像素值
  49 + */
  50 + @MessageElement("MidPointY")
  51 + protected Integer midPointY;
  52 + /**
  53 + * 拉框长度像素值
  54 + */
  55 + @MessageElement("LengthX")
  56 + protected Integer lengthX;
  57 + /**
  58 + * 拉框宽度像素值
  59 + */
  60 + @MessageElement("LengthY")
  61 + protected Integer lengthY;
  62 +
  63 + public Integer getLength() {
  64 + return length;
  65 + }
  66 +
  67 + public void setLength(Integer length) {
  68 + this.length = length;
  69 + }
  70 +
  71 + public Integer getWidth() {
  72 + return width;
  73 + }
  74 +
  75 + public void setWidth(Integer width) {
  76 + this.width = width;
  77 + }
  78 +
  79 + public Integer getMidPointX() {
  80 + return midPointX;
  81 + }
  82 +
  83 + public void setMidPointX(Integer midPointX) {
  84 + this.midPointX = midPointX;
  85 + }
  86 +
  87 + public Integer getMidPointY() {
  88 + return midPointY;
  89 + }
  90 +
  91 + public void setMidPointY(Integer midPointY) {
  92 + this.midPointY = midPointY;
  93 + }
  94 +
  95 + public Integer getLengthX() {
  96 + return lengthX;
  97 + }
  98 +
  99 + public void setLengthX(Integer lengthX) {
  100 + this.lengthX = lengthX;
  101 + }
  102 +
  103 + public Integer getLengthY() {
  104 + return lengthY;
  105 + }
  106 +
  107 + public void setLengthY(Integer lengthY) {
  108 + this.lengthY = lengthY;
  109 + }
  110 + }
  111 +
  112 + public String getSn() {
  113 + return sn;
  114 + }
  115 +
  116 + public void setSn(String sn) {
  117 + this.sn = sn;
  118 + }
  119 +
  120 + public String getDeviceId() {
  121 + return deviceId;
  122 + }
  123 +
  124 + public void setDeviceId(String deviceId) {
  125 + this.deviceId = deviceId;
  126 + }
  127 +
  128 + public DragZoom getDragZoomIn() {
  129 + return dragZoomIn;
  130 + }
  131 +
  132 + public void setDragZoomIn(DragZoom dragZoomIn) {
  133 + this.dragZoomIn = dragZoomIn;
  134 + }
  135 +
  136 + public DragZoom getDragZoomOut() {
  137 + return dragZoomOut;
  138 + }
  139 +
  140 + public void setDragZoomOut(DragZoom dragZoomOut) {
  141 + this.dragZoomOut = dragZoomOut;
  142 + }
  143 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
  4 +
  5 +/**
  6 + * 设备信息查询响应
  7 + *
  8 + * @author Y.G
  9 + * @version 1.0
  10 + * @date 2022/6/28 14:55
  11 + */
  12 +public class HomePositionRequest {
  13 + /**
  14 + * 序列号
  15 + */
  16 + @MessageElement("SN")
  17 + private String sn;
  18 +
  19 + @MessageElement("DeviceID")
  20 + private String deviceId;
  21 +
  22 + @MessageElement(value = "HomePosition")
  23 + private HomePosition homePosition;
  24 +
  25 +
  26 + /**
  27 + * 基本参数
  28 + */
  29 + public static class HomePosition {
  30 + /**
  31 + * 播放窗口长度像素值
  32 + */
  33 + @MessageElement("Enabled")
  34 + protected String enabled;
  35 + /**
  36 + * 播放窗口宽度像素值
  37 + */
  38 + @MessageElement("ResetTime")
  39 + protected String resetTime;
  40 + /**
  41 + * 拉框中心的横轴坐标像素值
  42 + */
  43 + @MessageElement("PresetIndex")
  44 + protected String presetIndex;
  45 +
  46 + public String getEnabled() {
  47 + return enabled;
  48 + }
  49 +
  50 + public void setEnabled(String enabled) {
  51 + this.enabled = enabled;
  52 + }
  53 +
  54 + public String getResetTime() {
  55 + return resetTime;
  56 + }
  57 +
  58 + public void setResetTime(String resetTime) {
  59 + this.resetTime = resetTime;
  60 + }
  61 +
  62 + public String getPresetIndex() {
  63 + return presetIndex;
  64 + }
  65 +
  66 + public void setPresetIndex(String presetIndex) {
  67 + this.presetIndex = presetIndex;
  68 + }
  69 + }
  70 +
  71 + public String getSn() {
  72 + return sn;
  73 + }
  74 +
  75 + public void setSn(String sn) {
  76 + this.sn = sn;
  77 + }
  78 +
  79 + public String getDeviceId() {
  80 + return deviceId;
  81 + }
  82 +
  83 + public void setDeviceId(String deviceId) {
  84 + this.deviceId = deviceId;
  85 + }
  86 +
  87 + public HomePosition getHomePosition() {
  88 + return homePosition;
  89 + }
  90 +
  91 + public void setHomePosition(HomePosition homePosition) {
  92 + this.homePosition = homePosition;
  93 + }
  94 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
1 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2  
  3 +
3 4 import java.time.Instant;
4 5 import java.util.List;
5 6  
... ... @@ -20,6 +21,8 @@ public class RecordInfo {
20 21  
21 22 private int sumNum;
22 23  
  24 + private int count;
  25 +
23 26 private Instant lastTime;
24 27  
25 28 private List<RecordItem> recordList;
... ... @@ -79,4 +82,12 @@ public class RecordInfo {
79 82 public void setLastTime(Instant lastTime) {
80 83 this.lastTime = lastTime;
81 84 }
  85 +
  86 + public int getCount() {
  87 + return count;
  88 + }
  89 +
  90 + public void setCount(int count) {
  91 + this.count = count;
  92 + }
82 93 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
1 1 package com.genersoft.iot.vmp.gb28181.event.record;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
  4 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
4 5 import org.slf4j.Logger;
5 6 import org.slf4j.LoggerFactory;
  7 +import org.springframework.beans.factory.annotation.Autowired;
6 8 import org.springframework.context.ApplicationListener;
7 9 import org.springframework.stereotype.Component;
8 10  
... ... @@ -20,25 +22,46 @@ public class RecordEndEventListener implements ApplicationListener&lt;RecordEndEven
20 22  
21 23 private final static Logger logger = LoggerFactory.getLogger(RecordEndEventListener.class);
22 24  
  25 + private Map<String, RecordEndEventHandler> handlerMap = new ConcurrentHashMap<>();
23 26 public interface RecordEndEventHandler{
24 27 void handler(RecordInfo recordInfo);
25 28 }
26 29  
27   - private Map<String, RecordEndEventHandler> handlerMap = new ConcurrentHashMap<>();
28   -
29 30 @Override
30 31 public void onApplicationEvent(RecordEndEvent event) {
31   - logger.info("录像查询完成事件触发,deviceId:{}, channelId: {}, 录像数量{}条", event.getRecordInfo().getDeviceId(),
32   - event.getRecordInfo().getChannelId(), event.getRecordInfo().getSumNum() );
  32 + String deviceId = event.getRecordInfo().getDeviceId();
  33 + String channelId = event.getRecordInfo().getChannelId();
  34 + int count = event.getRecordInfo().getCount();
  35 + int sumNum = event.getRecordInfo().getSumNum();
  36 + logger.info("录像查询完成事件触发,deviceId:{}, channelId: {}, 录像数量{}/{}条", event.getRecordInfo().getDeviceId(),
  37 + event.getRecordInfo().getChannelId(), count,sumNum);
33 38 if (handlerMap.size() > 0) {
34   - for (RecordEndEventHandler recordEndEventHandler : handlerMap.values()) {
35   - recordEndEventHandler.handler(event.getRecordInfo());
  39 + RecordEndEventHandler handler = handlerMap.get(deviceId + channelId);
  40 + if (handler !=null){
  41 + handler.handler(event.getRecordInfo());
  42 + if (count ==sumNum){
  43 + handlerMap.remove(deviceId + channelId);
  44 + }
36 45 }
37 46 }
38   - handlerMap.clear();
39 47 }
40 48  
  49 + /**
  50 + * 添加
  51 + * @param device
  52 + * @param channelId
  53 + * @param recordEndEventHandler
  54 + */
41 55 public void addEndEventHandler(String device, String channelId, RecordEndEventHandler recordEndEventHandler) {
42 56 handlerMap.put(device + channelId, recordEndEventHandler);
43 57 }
  58 + /**
  59 + * 添加
  60 + * @param device
  61 + * @param channelId
  62 + */
  63 + public void delEndEventHandler(String device, String channelId) {
  64 + handlerMap.remove(device + channelId);
  65 + }
  66 +
44 67 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java
1 1 package com.genersoft.iot.vmp.gb28181.session;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.*;
  4 +import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEventListener;
4 5 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
5 6 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
6 7 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
... ... @@ -23,14 +24,17 @@ public class RecordDataCatch {
23 24  
24 25 @Autowired
25 26 private DeferredResultHolder deferredResultHolder;
  27 + @Autowired
  28 + private RecordEndEventListener recordEndEventListener;
26 29  
27 30  
28   - public int put(String deviceId, String sn, int sumNum, List<RecordItem> recordItems) {
  31 + public int put(String deviceId,String channelId, String sn, int sumNum, List<RecordItem> recordItems) {
29 32 String key = deviceId + sn;
30 33 RecordInfo recordInfo = data.get(key);
31 34 if (recordInfo == null) {
32 35 recordInfo = new RecordInfo();
33 36 recordInfo.setDeviceId(deviceId);
  37 + recordInfo.setChannelId(channelId);
34 38 recordInfo.setSn(sn.trim());
35 39 recordInfo.setSumNum(sumNum);
36 40 recordInfo.setRecordList(Collections.synchronizedList(new ArrayList<>()));
... ... @@ -67,6 +71,7 @@ public class RecordDataCatch {
67 71 msg.setKey(msgKey);
68 72 msg.setData(recordInfo);
69 73 deferredResultHolder.invokeAllResult(msg);
  74 + recordEndEventListener.delEndEventHandler(recordInfo.getDeviceId(),recordInfo.getChannelId());
70 75 data.remove(key);
71 76 }
72 77 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java
... ... @@ -47,61 +47,65 @@ public class SIPSender {
47 47 }
48 48  
49 49 public void transmitRequest(String ip, Message message, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, ParseException {
50   - ViaHeader viaHeader = (ViaHeader)message.getHeader(ViaHeader.NAME);
51   - String transport = "UDP";
52   - if (viaHeader == null) {
53   - logger.warn("[消息头缺失]: ViaHeader, 使用默认的UDP方式处理数据");
54   - }else {
55   - transport = viaHeader.getTransport();
56   - }
57   - if (message.getHeader(UserAgentHeader.NAME) == null) {
58   - try {
59   - message.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
60   - } catch (ParseException e) {
61   - logger.error("添加UserAgentHeader失败", e);
  50 + try {
  51 + ViaHeader viaHeader = (ViaHeader)message.getHeader(ViaHeader.NAME);
  52 + String transport = "UDP";
  53 + if (viaHeader == null) {
  54 + logger.warn("[消息头缺失]: ViaHeader, 使用默认的UDP方式处理数据");
  55 + }else {
  56 + transport = viaHeader.getTransport();
  57 + }
  58 + if (message.getHeader(UserAgentHeader.NAME) == null) {
  59 + try {
  60 + message.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
  61 + } catch (ParseException e) {
  62 + logger.error("添加UserAgentHeader失败", e);
  63 + }
62 64 }
63   - }
64 65  
65   - CallIdHeader callIdHeader = (CallIdHeader) message.getHeader(CallIdHeader.NAME);
66   - // 添加错误订阅
67   - if (errorEvent != null) {
68   - sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
69   - errorEvent.response(eventResult);
70   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
71   - sipSubscribe.removeOkSubscribe(eventResult.callId);
72   - }));
73   - }
74   - // 添加订阅
75   - if (okEvent != null) {
76   - sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
77   - okEvent.response(eventResult);
78   - sipSubscribe.removeOkSubscribe(eventResult.callId);
79   - sipSubscribe.removeErrorSubscribe(eventResult.callId);
80   - });
81   - }
82   - if ("TCP".equals(transport)) {
83   - SipProviderImpl tcpSipProvider = sipLayer.getTcpSipProvider(ip);
84   - if (tcpSipProvider == null) {
85   - logger.error("[发送信息失败] 未找到tcp://{}的监听信息", ip);
86   - return;
  66 + CallIdHeader callIdHeader = (CallIdHeader) message.getHeader(CallIdHeader.NAME);
  67 + // 添加错误订阅
  68 + if (errorEvent != null) {
  69 + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
  70 + errorEvent.response(eventResult);
  71 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  72 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  73 + }));
87 74 }
88   - if (message instanceof Request) {
89   - tcpSipProvider.sendRequest((Request)message);
90   - }else if (message instanceof Response) {
91   - tcpSipProvider.sendResponse((Response)message);
  75 + // 添加订阅
  76 + if (okEvent != null) {
  77 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
  78 + okEvent.response(eventResult);
  79 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  80 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  81 + });
92 82 }
  83 + if ("TCP".equals(transport)) {
  84 + SipProviderImpl tcpSipProvider = sipLayer.getTcpSipProvider(ip);
  85 + if (tcpSipProvider == null) {
  86 + logger.error("[发送信息失败] 未找到tcp://{}的监听信息", ip);
  87 + return;
  88 + }
  89 + if (message instanceof Request) {
  90 + tcpSipProvider.sendRequest((Request)message);
  91 + }else if (message instanceof Response) {
  92 + tcpSipProvider.sendResponse((Response)message);
  93 + }
93 94  
94   - } else if ("UDP".equals(transport)) {
95   - SipProviderImpl sipProvider = sipLayer.getUdpSipProvider(ip);
96   - if (sipProvider == null) {
97   - logger.error("[发送信息失败] 未找到udp://{}的监听信息", ip);
98   - return;
99   - }
100   - if (message instanceof Request) {
101   - sipProvider.sendRequest((Request)message);
102   - }else if (message instanceof Response) {
103   - sipProvider.sendResponse((Response)message);
  95 + } else if ("UDP".equals(transport)) {
  96 + SipProviderImpl sipProvider = sipLayer.getUdpSipProvider(ip);
  97 + if (sipProvider == null) {
  98 + logger.error("[发送信息失败] 未找到udp://{}的监听信息", ip);
  99 + return;
  100 + }
  101 + if (message instanceof Request) {
  102 + sipProvider.sendRequest((Request)message);
  103 + }else if (message instanceof Response) {
  104 + sipProvider.sendResponse((Response)message);
  105 + }
104 106 }
  107 + } finally {
  108 + logger.info("[SEND]:SUCCESS:{}", message);
105 109 }
106 110 }
107 111  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
... ... @@ -183,7 +183,7 @@ public interface ISIPCommander {
183 183 * @param channelId 预览通道
184 184 * @param recordCmdStr 录像命令:Record / StopRecord
185 185 */
186   - void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  186 + void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
187 187  
188 188 /**
189 189 * 远程启动控制命令
... ... @@ -197,7 +197,7 @@ public interface ISIPCommander {
197 197 *
198 198 * @param device 视频设备
199 199 */
200   - void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  200 + void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
201 201  
202 202 /**
203 203 * 报警复位命令
... ... @@ -206,7 +206,7 @@ public interface ISIPCommander {
206 206 * @param alarmMethod 报警方式(可选)
207 207 * @param alarmType 报警类型(可选)
208 208 */
209   - void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  209 + void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
210 210  
211 211 /**
212 212 * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
... ... @@ -215,17 +215,19 @@ public interface ISIPCommander {
215 215 * @param channelId 预览通道
216 216 */
217 217 void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException;
218   -
  218 +
219 219 /**
220 220 * 看守位控制命令
221   - *
222   - * @param device 视频设备
223   - * @param enabled 看守位使能:1 = 开启,0 = 关闭
224   - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
225   - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
226   - */
227   - void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
228   -
  221 + *
  222 + * @param device 视频设备
  223 + * @param channelId 通道id,非通道则是设备本身
  224 + * @param frontCmd 上级平台的指令,如果存在则直接下发
  225 + * @param enabled 看守位使能:1 = 开启,0 = 关闭
  226 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
  227 + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
  228 + */
  229 + void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  230 +
229 231 /**
230 232 * 设备配置命令
231 233 *
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -29,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired;
29 29 import org.springframework.context.annotation.DependsOn;
30 30 import org.springframework.stereotype.Component;
31 31 import org.springframework.util.ObjectUtils;
  32 +import org.springframework.util.StringUtils;
32 33  
33 34 import javax.sip.InvalidArgumentException;
34 35 import javax.sip.ResponseEvent;
... ... @@ -663,7 +664,7 @@ public class SIPCommander implements ISIPCommander {
663 664 * @param recordCmdStr 录像命令:Record / StopRecord
664 665 */
665 666 @Override
666   - public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  667 + public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
667 668 StringBuffer cmdXml = new StringBuffer(200);
668 669 String charset = device.getCharset();
669 670 cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
... ... @@ -681,7 +682,7 @@ public class SIPCommander implements ISIPCommander {
681 682  
682 683  
683 684 Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
684   - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  685 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
685 686 }
686 687  
687 688 /**
... ... @@ -715,7 +716,7 @@ public class SIPCommander implements ISIPCommander {
715 716 * @param guardCmdStr "SetGuard"/"ResetGuard"
716 717 */
717 718 @Override
718   - public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  719 + public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
719 720  
720 721 StringBuffer cmdXml = new StringBuffer(200);
721 722 String charset = device.getCharset();
... ... @@ -728,7 +729,7 @@ public class SIPCommander implements ISIPCommander {
728 729 cmdXml.append("</Control>\r\n");
729 730  
730 731 Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
731   - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  732 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
732 733 }
733 734  
734 735 /**
... ... @@ -737,7 +738,7 @@ public class SIPCommander implements ISIPCommander {
737 738 * @param device 视频设备
738 739 */
739 740 @Override
740   - public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  741 + public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
741 742  
742 743 StringBuffer cmdXml = new StringBuffer(200);
743 744 String charset = device.getCharset();
... ... @@ -764,7 +765,7 @@ public class SIPCommander implements ISIPCommander {
764 765  
765 766  
766 767 Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
767   - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  768 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
768 769 }
769 770  
770 771 /**
... ... @@ -800,12 +801,14 @@ public class SIPCommander implements ISIPCommander {
800 801 * 看守位控制命令
801 802 *
802 803 * @param device 视频设备
  804 + * @param channelId 通道id,非通道则是设备本身
  805 + * @param frontCmd 上级平台的指令,如果存在则直接下发
803 806 * @param enabled 看守位使能:1 = 开启,0 = 关闭
804 807 * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
805 808 * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
806 809 */
807 810 @Override
808   - public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  811 + public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
809 812  
810 813 StringBuffer cmdXml = new StringBuffer(200);
811 814 String charset = device.getCharset();
... ... @@ -840,7 +843,7 @@ public class SIPCommander implements ISIPCommander {
840 843  
841 844  
842 845 Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
843   - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  846 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
844 847 }
845 848  
846 849 /**
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control.cmd;
2 2  
3   -import com.genersoft.iot.vmp.VManageBootstrap;
  3 +import com.genersoft.iot.vmp.common.enums.DeviceControlType;
4 4 import com.genersoft.iot.vmp.gb28181.bean.Device;
  5 +import com.genersoft.iot.vmp.gb28181.bean.DragZoomRequest;
  6 +import com.genersoft.iot.vmp.gb28181.bean.HomePositionRequest;
5 7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  8 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
7 10 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
8 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
... ... @@ -19,17 +22,14 @@ import org.springframework.beans.factory.annotation.Qualifier;
19 22 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
20 23 import org.springframework.stereotype.Component;
21 24 import org.springframework.util.ObjectUtils;
22   -import org.springframework.util.StringUtils;
23 25  
24 26 import javax.sip.*;
25 27 import javax.sip.address.SipURI;
26   -import javax.sip.header.HeaderAddress;
27   -import javax.sip.header.ToHeader;
28 28 import javax.sip.message.Response;
29 29 import java.text.ParseException;
30   -import java.util.Iterator;
  30 +import java.util.List;
31 31  
32   -import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
  32 +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.*;
33 33  
34 34 @Component
35 35 public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
... ... @@ -81,7 +81,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
81 81 } catch (InvalidArgumentException | ParseException | SipException e) {
82 82 logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
83 83 }
84   - taskExecutor.execute(()->{
  84 + taskExecutor.execute(() -> {
85 85 // 远程启动
86 86 // try {
87 87 // Thread.sleep(3000);
... ... @@ -101,13 +101,12 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
101 101 // logger.error("[任务执行失败] 服务重启: {}", e.getMessage());
102 102 // }
103 103 });
104   - } else {
105   - // 远程启动指定设备
106 104 }
107 105 }
108   - // 云台/前端控制命令
109   - if (!ObjectUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) {
110   - String cmdString = getText(rootElement,"PTZCmd");
  106 + DeviceControlType deviceControlType = DeviceControlType.typeOf(rootElement);
  107 + logger.info("[接受deviceControl命令] 命令: {}", deviceControlType);
  108 + if (!ObjectUtils.isEmpty(deviceControlType) && !parentPlatform.getServerGBId().equals(targetGBId)) {
  109 + //判断是否存在该通道
111 110 Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
112 111 if (deviceForPlatform == null) {
113 112 try {
... ... @@ -117,25 +116,240 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
117 116 }
118 117 return;
119 118 }
120   - try {
121   - cmder.fronEndCmd(deviceForPlatform, channelId, cmdString, eventResult -> {
122   - // 失败的回复
123   - try {
124   - responseAck(request, eventResult.statusCode, eventResult.msg);
125   - } catch (SipException | InvalidArgumentException | ParseException e) {
126   - logger.error("[命令发送失败] 云台/前端回复: {}", e.getMessage());
127   - }
128   - }, eventResult -> {
129   - // 成功的回复
130   - try {
131   - responseAck(request, eventResult.statusCode);
132   - } catch (SipException | InvalidArgumentException | ParseException e) {
133   - logger.error("[命令发送失败] 云台/前端回复: {}", e.getMessage());
134   - }
135   - });
136   - } catch (InvalidArgumentException | SipException | ParseException e) {
137   - logger.error("[命令发送失败] 云台/前端: {}", e.getMessage());
  119 + switch (deviceControlType) {
  120 + case PTZ:
  121 + handlePtzCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.PTZ);
  122 + break;
  123 + case ALARM:
  124 + handleAlarmCmd(deviceForPlatform, rootElement, request);
  125 + break;
  126 + case GUARD:
  127 + handleGuardCmd(deviceForPlatform, rootElement, request, DeviceControlType.GUARD);
  128 + break;
  129 + case RECORD:
  130 + handleRecordCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.RECORD);
  131 + break;
  132 + case I_FRAME:
  133 + handleIFameCmd(deviceForPlatform, request, channelId);
  134 + break;
  135 + case TELE_BOOT:
  136 + handleTeleBootCmd(deviceForPlatform, request);
  137 + break;
  138 + case DRAG_ZOOM_IN:
  139 + handleDragZoom(deviceForPlatform, channelId, rootElement, request, DeviceControlType.DRAG_ZOOM_IN);
  140 + break;
  141 + case DRAG_ZOOM_OUT:
  142 + handleDragZoom(deviceForPlatform, channelId, rootElement, request, DeviceControlType.DRAG_ZOOM_OUT);
  143 + break;
  144 + case HOME_POSITION:
  145 + handleHomePositionCmd(deviceForPlatform, channelId, rootElement, request, DeviceControlType.HOME_POSITION);
  146 + break;
  147 + default:
  148 + break;
138 149 }
139 150 }
140 151 }
  152 +
  153 + /**
  154 + * 处理云台指令
  155 + *
  156 + * @param device 设备
  157 + * @param channelId 通道id
  158 + * @param rootElement
  159 + * @param request
  160 + */
  161 + private void handlePtzCmd(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
  162 + String cmdString = getText(rootElement, type.getVal());
  163 + try {
  164 + cmder.fronEndCmd(device, channelId, cmdString,
  165 + errorResult -> onError(request, errorResult),
  166 + okResult -> onOk(request, okResult));
  167 + } catch (InvalidArgumentException | SipException | ParseException e) {
  168 + logger.error("[命令发送失败] 云台/前端: {}", e.getMessage());
  169 + }
  170 + }
  171 +
  172 + /**
  173 + * 处理强制关键帧
  174 + *
  175 + * @param device 设备
  176 + * @param channelId 通道id
  177 + */
  178 + private void handleIFameCmd(Device device, SIPRequest request, String channelId) {
  179 + try {
  180 + cmder.iFrameCmd(device, channelId);
  181 + responseAck(request, Response.OK);
  182 + } catch (InvalidArgumentException | SipException | ParseException e) {
  183 + logger.error("[命令发送失败] 强制关键帧: {}", e.getMessage());
  184 + }
  185 + }
  186 +
  187 + /**
  188 + * 处理重启命令
  189 + *
  190 + * @param device 设备信息
  191 + */
  192 + private void handleTeleBootCmd(Device device, SIPRequest request) {
  193 + try {
  194 + cmder.teleBootCmd(device);
  195 + responseAck(request, Response.OK);
  196 + } catch (InvalidArgumentException | SipException | ParseException e) {
  197 + logger.error("[命令发送失败] 重启: {}", e.getMessage());
  198 + }
  199 +
  200 + }
  201 +
  202 + /**
  203 + * 处理拉框控制***
  204 + *
  205 + * @param device 设备信息
  206 + * @param channelId 通道id
  207 + * @param rootElement 根节点
  208 + * @param type 消息类型
  209 + */
  210 + private void handleDragZoom(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
  211 + try {
  212 + DragZoomRequest dragZoomRequest = loadElement(rootElement, DragZoomRequest.class);
  213 + DragZoomRequest.DragZoom dragZoom = dragZoomRequest.getDragZoomIn();
  214 + if (dragZoom == null) {
  215 + dragZoom = dragZoomRequest.getDragZoomOut();
  216 + }
  217 + StringBuffer cmdXml = new StringBuffer(200);
  218 + cmdXml.append("<" + type.getVal() + ">\r\n");
  219 + cmdXml.append("<Length>" + dragZoom.getLength() + "</Length>\r\n");
  220 + cmdXml.append("<Width>" + dragZoom.getWidth() + "</Width>\r\n");
  221 + cmdXml.append("<MidPointX>" + dragZoom.getMidPointX() + "</MidPointX>\r\n");
  222 + cmdXml.append("<MidPointY>" + dragZoom.getMidPointY() + "</MidPointY>\r\n");
  223 + cmdXml.append("<LengthX>" + dragZoom.getLengthX() + "</LengthX>\r\n");
  224 + cmdXml.append("<LengthY>" + dragZoom.getLengthY() + "</LengthY>\r\n");
  225 + cmdXml.append("</" + type.getVal() + ">\r\n");
  226 + cmder.dragZoomCmd(device, channelId, cmdXml.toString());
  227 + responseAck(request, Response.OK);
  228 + } catch (Exception e) {
  229 + logger.error("[命令发送失败] 拉框控制: {}", e.getMessage());
  230 + }
  231 +
  232 + }
  233 +
  234 + /**
  235 + * 处理看守位命令***
  236 + *
  237 + * @param device 设备信息
  238 + * @param channelId 通道id
  239 + * @param rootElement 根节点
  240 + * @param request 请求信息
  241 + * @param type 消息类型
  242 + */
  243 + private void handleHomePositionCmd(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
  244 + try {
  245 + HomePositionRequest homePosition = loadElement(rootElement, HomePositionRequest.class);
  246 + //获取整个消息主体,我们只需要修改请求头即可
  247 + HomePositionRequest.HomePosition info = homePosition.getHomePosition();
  248 + cmder.homePositionCmd(device, channelId, info.getEnabled(), info.getResetTime(), info.getPresetIndex(),
  249 + errorResult -> onError(request, errorResult),
  250 + okResult -> onOk(request, okResult));
  251 + } catch (Exception e) {
  252 + logger.error("[命令发送失败] 看守位设置: {}", e.getMessage());
  253 + }
  254 + }
  255 +
  256 + /**
  257 + * 处理告警消息***
  258 + *
  259 + * @param device 设备信息
  260 + * @param rootElement 根节点
  261 + * @param request 请求信息
  262 + */
  263 + private void handleAlarmCmd(Device device, Element rootElement, SIPRequest request) {
  264 + //告警方法
  265 + String alarmMethod = "";
  266 + //告警类型
  267 + String alarmType = "";
  268 + List<Element> info = rootElement.elements("Info");
  269 + if (info != null) {
  270 + for (Element element : info) {
  271 + alarmMethod = getText(element, "AlarmMethod");
  272 + alarmType = getText(element, "AlarmType");
  273 + }
  274 + }
  275 + try {
  276 + cmder.alarmCmd(device, alarmMethod, alarmType,
  277 + errorResult -> onError(request, errorResult),
  278 + okResult -> onOk(request, okResult));
  279 + } catch (InvalidArgumentException | SipException | ParseException e) {
  280 + logger.error("[命令发送失败] 告警消息: {}", e.getMessage());
  281 + }
  282 + }
  283 +
  284 + /**
  285 + * 处理录像控制
  286 + *
  287 + * @param device 设备信息
  288 + * @param channelId 通道id
  289 + * @param rootElement 根节点
  290 + * @param request 请求信息
  291 + * @param type 消息类型
  292 + */
  293 + private void handleRecordCmd(Device device, String channelId, Element rootElement, SIPRequest request, DeviceControlType type) {
  294 + //获取整个消息主体,我们只需要修改请求头即可
  295 + String cmdString = getText(rootElement, type.getVal());
  296 + try {
  297 + cmder.recordCmd(device, channelId, cmdString,
  298 + errorResult -> onError(request, errorResult),
  299 + okResult -> onOk(request, okResult));
  300 + } catch (InvalidArgumentException | SipException | ParseException e) {
  301 + logger.error("[命令发送失败] 录像控制: {}", e.getMessage());
  302 + }
  303 + }
  304 +
  305 + /**
  306 + * 处理报警布防/撤防命令
  307 + *
  308 + * @param device 设备信息
  309 + * @param rootElement 根节点
  310 + * @param request 请求信息
  311 + * @param type 消息类型
  312 + */
  313 + private void handleGuardCmd(Device device, Element rootElement, SIPRequest request, DeviceControlType type) {
  314 + //获取整个消息主体,我们只需要修改请求头即可
  315 + String cmdString = getText(rootElement, type.getVal());
  316 + try {
  317 + cmder.guardCmd(device, cmdString,
  318 + errorResult -> onError(request, errorResult),
  319 + okResult -> onOk(request, okResult));
  320 + } catch (InvalidArgumentException | SipException | ParseException e) {
  321 + logger.error("[命令发送失败] 布防/撤防命令: {}", e.getMessage());
  322 + }
  323 + }
  324 +
  325 +
  326 + /**
  327 + * 错误响应处理
  328 + *
  329 + * @param request 请求
  330 + * @param eventResult 响应结构
  331 + */
  332 + private void onError(SIPRequest request, SipSubscribe.EventResult eventResult) {
  333 + // 失败的回复
  334 + try {
  335 + responseAck(request, eventResult.statusCode, eventResult.msg);
  336 + } catch (SipException | InvalidArgumentException | ParseException e) {
  337 + logger.error("[命令发送失败] 回复: {}", e.getMessage());
  338 + }
  339 + }
  340 +
  341 + /**
  342 + * 成功响应处理
  343 + *
  344 + * @param request 请求
  345 + * @param eventResult 响应结构
  346 + */
  347 + private void onOk(SIPRequest request, SipSubscribe.EventResult eventResult) {
  348 + // 成功的回复
  349 + try {
  350 + responseAck(request, eventResult.statusCode);
  351 + } catch (SipException | InvalidArgumentException | ParseException e) {
  352 + logger.error("[命令发送失败] 回复: {}", e.getMessage());
  353 + }
  354 + }
141 355 }
... ...
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
181 181 }
182 182 }
183 183 logger.info("[收到报警通知]内容:{}", JSON.toJSONString(deviceAlarm));
184   - if ("7".equals(deviceAlarm.getAlarmMethod()) ) {
  184 + if (DeviceAlarmMethod.typeOf(Integer.parseInt(deviceAlarm.getAlarmMethod())) !=null) {
185 185 // 发送给平台的报警信息。 发送redis通知
  186 + logger.info("[发送给平台的报警信息]内容:{}", JSONObject.toJSONString(deviceAlarm));
186 187 AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage();
187 188 alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod()));
188 189 alarmChannelMessage.setAlarmDescription(deviceAlarm.getAlarmDescription());
  190 + alarmChannelMessage.setAlarmType(Integer.parseInt(deviceAlarm.getAlarmType()));
189 191 alarmChannelMessage.setGbId(channelId);
190 192 redisCatchStorage.sendAlarmMsg(alarmChannelMessage);
191 193 continue;
... ... @@ -264,6 +266,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
264 266 alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod()));
265 267 alarmChannelMessage.setAlarmDescription(deviceAlarm.getAlarmDescription());
266 268 alarmChannelMessage.setGbId(channelId);
  269 + alarmChannelMessage.setAlarmType(Integer.parseInt(deviceAlarm.getAlarmType()));
267 270 redisCatchStorage.sendAlarmMsg(alarmChannelMessage);
268 271 return;
269 272 }
... ...
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
102 102 Element recordListElement = rootElementForCharset.element("RecordList");
103 103 if (recordListElement == null || sumNum == 0) {
104 104 logger.info("无录像数据");
  105 + int count = recordDataCatch.put(take.getDevice().getDeviceId(),channelId, sn, sumNum, new ArrayList<>());
  106 + recordInfo.setCount(count);
105 107 eventPublisher.recordEndEventPush(recordInfo);
106   - recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, new ArrayList<>());
107 108 releaseRequest(take.getDevice().getDeviceId(), sn);
108 109 } else {
109 110 Iterator<Element> recordListIterator = recordListElement.elementIterator();
... ... @@ -137,12 +138,11 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
137 138 recordList.add(record);
138 139 }
139 140 recordInfo.setRecordList(recordList);
  141 + int count = recordDataCatch.put(take.getDevice().getDeviceId(),channelId, sn, sumNum, recordList);recordInfo.setCount(count);
  142 + logger.info("[国标录像], {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum);
140 143 // 发送消息,如果是上级查询此录像,则会通过这里通知给上级
141 144 eventPublisher.recordEndEventPush(recordInfo);
142   - int count = recordDataCatch.put(take.getDevice().getDeviceId(), sn, sumNum, recordList);
143   - logger.info("[国标录像], {}->{}: {}/{}", take.getDevice().getDeviceId(), sn, count, sumNum);
144 145 }
145   -
146 146 if (recordDataCatch.isComplete(take.getDevice().getDeviceId(), sn)){
147 147 releaseRequest(take.getDevice().getDeviceId(), sn);
148 148 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/utils/MessageElement.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.utils;
  2 +
  3 +import java.lang.annotation.*;
  4 +
  5 +/**
  6 + * @author gaofuwang
  7 + * @version 1.0
  8 + * @date 2022/6/28 14:58
  9 + */
  10 +@Target({ElementType.FIELD})
  11 +@Retention(RetentionPolicy.RUNTIME)
  12 +@Documented
  13 +public @interface MessageElement {
  14 + String value();
  15 +
  16 + String subVal() default "";
  17 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
1 1 package com.genersoft.iot.vmp.gb28181.utils;
2 2  
  3 +import com.alibaba.fastjson2.JSON;
3 4 import com.alibaba.fastjson2.JSONArray;
4 5 import com.alibaba.fastjson2.JSONObject;
5 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
... ... @@ -15,12 +16,16 @@ import org.dom4j.io.SAXReader;
15 16 import org.slf4j.Logger;
16 17 import org.slf4j.LoggerFactory;
17 18 import org.springframework.util.ObjectUtils;
18   -import org.springframework.util.StringUtils;
  19 +import org.springframework.util.ReflectionUtils;
19 20  
20 21 import javax.sip.RequestEvent;
21 22 import javax.sip.message.Request;
22 23 import java.io.ByteArrayInputStream;
23 24 import java.io.StringReader;
  25 +import java.lang.reflect.Field;
  26 +import java.lang.reflect.InvocationTargetException;
  27 +import java.lang.reflect.ParameterizedType;
  28 +import java.lang.reflect.Type;
24 29 import java.util.*;
25 30  
26 31 /**
... ... @@ -411,4 +416,76 @@ public class XmlUtil {
411 416 }
412 417 return deviceChannel;
413 418 }
  419 +
  420 + /**
  421 + * 新增方法支持内部嵌套
  422 + *
  423 + * @param element xmlElement
  424 + * @param clazz 结果类
  425 + * @param <T> 泛型
  426 + * @return 结果对象
  427 + * @throws NoSuchMethodException
  428 + * @throws InvocationTargetException
  429 + * @throws InstantiationException
  430 + * @throws IllegalAccessException
  431 + */
  432 + public static <T> T loadElement(Element element, Class<T> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
  433 + Field[] fields = clazz.getDeclaredFields();
  434 + T t = clazz.getDeclaredConstructor().newInstance();
  435 + for (Field field : fields) {
  436 + ReflectionUtils.makeAccessible(field);
  437 + MessageElement annotation = field.getAnnotation(MessageElement.class);
  438 + if (annotation == null) {
  439 + continue;
  440 + }
  441 + String value = annotation.value();
  442 + String subVal = annotation.subVal();
  443 + Element element1 = element.element(value);
  444 + if (element1 == null) {
  445 + continue;
  446 + }
  447 + if ("".equals(subVal)) {
  448 + // 无下级数据
  449 + Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType());
  450 + Object o = simpleTypeDeal(field.getType(), fieldVal);
  451 + ReflectionUtils.setField(field, t, o);
  452 + } else {
  453 + // 存在下级数据
  454 + ArrayList<Object> list = new ArrayList<>();
  455 + Type genericType = field.getGenericType();
  456 + if (!(genericType instanceof ParameterizedType)) {
  457 + continue;
  458 + }
  459 + Class<?> aClass = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
  460 + for (Element element2 : element1.elements(subVal)) {
  461 + list.add(loadElement(element2, aClass));
  462 + }
  463 + ReflectionUtils.setField(field, t, list);
  464 + }
  465 + }
  466 + return t;
  467 + }
  468 +
  469 + /**
  470 + * 简单类型处理
  471 + *
  472 + * @param tClass
  473 + * @param val
  474 + * @return
  475 + */
  476 + private static Object simpleTypeDeal(Class<?> tClass, Object val) {
  477 + if (tClass.equals(String.class)) {
  478 + return val.toString();
  479 + }
  480 + if (tClass.equals(Integer.class)) {
  481 + return Integer.valueOf(val.toString());
  482 + }
  483 + if (tClass.equals(Double.class)) {
  484 + return Double.valueOf(val.toString());
  485 + }
  486 + if (tClass.equals(Long.class)) {
  487 + return Long.valueOf(val.toString());
  488 + }
  489 + return val;
  490 + }
414 491 }
415 492 \ No newline at end of file
... ...
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java
... ... @@ -67,9 +67,9 @@ public class RedisAlarmMsgListener implements MessageListener {
67 67 deviceAlarm.setChannelId(gbId);
68 68 deviceAlarm.setAlarmDescription(alarmChannelMessage.getAlarmDescription());
69 69 deviceAlarm.setAlarmMethod("" + alarmChannelMessage.getAlarmSn());
  70 + deviceAlarm.setAlarmType("" + alarmChannelMessage.getAlarmType());
70 71 deviceAlarm.setAlarmPriority("1");
71 72 deviceAlarm.setAlarmTime(DateUtil.getNowForISO8601());
72   - deviceAlarm.setAlarmType("1");
73 73 deviceAlarm.setLongitude(0);
74 74 deviceAlarm.setLatitude(0);
75 75  
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
... ... @@ -114,4 +114,7 @@ public interface PlatformChannelMapper {
114 114 " left join device d on dc.deviceId = d.deviceId\n" +
115 115 "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}")
116 116 List<Device> queryDeviceInfoByPlatformIdAndChannelId(String platformId, String channelId);
  117 +
  118 + @Select("SELECT pgc.platformId FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId='${channelId}'")
  119 + List<String> queryParentPlatformByChannelId(String channelId);
117 120 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
... ... @@ -830,7 +830,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
830 830  
831 831 @Override
832 832 public void sendAlarmMsg(AlarmChannelMessage msg) {
833   - String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM;
  833 + String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE;
834 834 logger.info("[redis发送通知] 报警{}: {}", key, JSON.toJSON(msg));
835 835 RedisUtil.convertAndSend(key, (JSONObject)JSON.toJSON(msg));
836 836 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
... ... @@ -133,6 +133,15 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
133 133 if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
134 134 deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
135 135 deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
  136 + if (allChannelMap.get(deviceChannel.getChannelId()).getStatus() !=deviceChannel.getStatus()){
  137 + List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId());
  138 + if (!CollectionUtils.isEmpty(strings)){
  139 + strings.forEach(platformId->{
  140 + eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.getStatus()==1?CatalogEvent.ON:CatalogEvent.OFF);
  141 + });
  142 + }
  143 +
  144 + }
136 145 }
137 146 channels.add(deviceChannel);
138 147 if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
... ... @@ -110,7 +110,7 @@ public class DeviceControl {
110 110 msg.setKey(key);
111 111 msg.setData(String.format("开始/停止录像操作失败,错误码: %s, %s", event.statusCode, event.msg));
112 112 resultHolder.invokeAllResult(msg);
113   - });
  113 + },null);
114 114 } catch (InvalidArgumentException | SipException | ParseException e) {
115 115 logger.error("[命令发送失败] 开始/停止录像: {}", e.getMessage());
116 116 throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
... ... @@ -143,7 +143,7 @@ public class DeviceControl {
143 143 msg.setKey(key);
144 144 msg.setData(String.format("布防/撤防操作失败,错误码: %s, %s", event.statusCode, event.msg));
145 145 resultHolder.invokeResult(msg);
146   - });
  146 + },null);
147 147 } catch (InvalidArgumentException | SipException | ParseException e) {
148 148 logger.error("[命令发送失败] 布防/撤防操作: {}", e.getMessage());
149 149 throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage());
... ... @@ -192,7 +192,7 @@ public class DeviceControl {
192 192 msg.setKey(key);
193 193 msg.setData(String.format("报警复位操作失败,错误码: %s, %s", event.statusCode, event.msg));
194 194 resultHolder.invokeResult(msg);
195   - });
  195 + },null);
196 196 } catch (InvalidArgumentException | SipException | ParseException e) {
197 197 logger.error("[命令发送失败] 报警复位: {}", e.getMessage());
198 198 throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
... ... @@ -274,7 +274,7 @@ public class DeviceControl {
274 274 msg.setKey(key);
275 275 msg.setData(String.format("看守位控制操作失败,错误码: %s, %s", event.statusCode, event.msg));
276 276 resultHolder.invokeResult(msg);
277   - });
  277 + },null);
278 278 } catch (InvalidArgumentException | SipException | ParseException e) {
279 279 logger.error("[命令发送失败] 看守位控制: {}", e.getMessage());
280 280 throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
... ...