Commit 0da452293f15be019bf23923148691ca133e43b0

Authored by 648540858
2 parents c2faa8c3 59e07671

Merge remote-tracking branch 'origin/wvp-28181-2.0' into wvp-28181-2.0

src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -131,7 +131,7 @@ public class Device { @@ -131,7 +131,7 @@ public class Device {
131 /** 131 /**
132 * 是否开启ssrc校验,默认关闭,开启可以防止串流 132 * 是否开启ssrc校验,默认关闭,开启可以防止串流
133 */ 133 */
134 - private boolean ssrcCheck; 134 + private boolean ssrcCheck = true;
135 135
136 /** 136 /**
137 * 地理坐标系, 目前支持 WGS84,GCJ02 TODO CGCS2000 137 * 地理坐标系, 目前支持 WGS84,GCJ02 TODO CGCS2000
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
@@ -88,8 +88,8 @@ public class SipSubscribe { @@ -88,8 +88,8 @@ public class SipSubscribe {
88 this.type = "timeout"; 88 this.type = "timeout";
89 this.msg = "消息超时未回复"; 89 this.msg = "消息超时未回复";
90 this.statusCode = -1024; 90 this.statusCode = -1024;
91 - this.callId = timeoutEvent.getClientTransaction().getDialog().getCallId().getCallId();  
92 this.dialog = timeoutEvent.getClientTransaction().getDialog(); 91 this.dialog = timeoutEvent.getClientTransaction().getDialog();
  92 + this.callId = this.dialog != null?timeoutEvent.getClientTransaction().getDialog().getCallId().getCallId(): null;
93 }else if (event instanceof TransactionTerminatedEvent) { 93 }else if (event instanceof TransactionTerminatedEvent) {
94 TransactionTerminatedEvent transactionTerminatedEvent = (TransactionTerminatedEvent)event; 94 TransactionTerminatedEvent transactionTerminatedEvent = (TransactionTerminatedEvent)event;
95 this.type = "transactionTerminated"; 95 this.type = "transactionTerminated";
@@ -109,8 +109,8 @@ public class SipSubscribe { @@ -109,8 +109,8 @@ public class SipSubscribe {
109 this.type = "deviceNotFoundEvent"; 109 this.type = "deviceNotFoundEvent";
110 this.msg = "设备未找到"; 110 this.msg = "设备未找到";
111 this.statusCode = -1024; 111 this.statusCode = -1024;
112 - this.callId = deviceNotFoundEvent.getDialog().getCallId().getCallId();  
113 this.dialog = deviceNotFoundEvent.getDialog(); 112 this.dialog = deviceNotFoundEvent.getDialog();
  113 + this.callId = this.dialog != null ?deviceNotFoundEvent.getDialog().getCallId().getCallId() : null;
114 } 114 }
115 } 115 }
116 } 116 }
@@ -130,6 +130,9 @@ public class SipSubscribe { @@ -130,6 +130,9 @@ public class SipSubscribe {
130 } 130 }
131 131
132 public void removeErrorSubscribe(String key) { 132 public void removeErrorSubscribe(String key) {
  133 + if(key == null){
  134 + return;
  135 + }
133 errorSubscribes.remove(key); 136 errorSubscribes.remove(key);
134 errorTimeSubscribes.remove(key); 137 errorTimeSubscribes.remove(key);
135 } 138 }
@@ -139,6 +142,9 @@ public class SipSubscribe { @@ -139,6 +142,9 @@ public class SipSubscribe {
139 } 142 }
140 143
141 public void removeOkSubscribe(String key) { 144 public void removeOkSubscribe(String key) {
  145 + if(key == null){
  146 + return;
  147 + }
142 okSubscribes.remove(key); 148 okSubscribes.remove(key);
143 okTimeSubscribes.remove(key); 149 okTimeSubscribes.remove(key);
144 } 150 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -143,6 +143,14 @@ public interface ISIPCommander { @@ -143,6 +143,14 @@ public interface ISIPCommander {
143 * 回放倍速播放 143 * 回放倍速播放
144 */ 144 */
145 void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed); 145 void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed);
  146 +
  147 + /**
  148 + * 回放控制
  149 + * @param device
  150 + * @param streamInfo
  151 + * @param content
  152 + */
  153 + void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent);
146 154
147 /** 155 /**
148 * 语音广播 156 * 语音广播
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -1828,6 +1828,43 @@ public class SIPCommander implements ISIPCommander { @@ -1828,6 +1828,43 @@ public class SIPCommander implements ISIPCommander {
1828 e.printStackTrace(); 1828 e.printStackTrace();
1829 } 1829 }
1830 } 1830 }
  1831 +
  1832 + @Override
  1833 + public void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) {
  1834 + try {
  1835 + Request request = headerProvider.createInfoRequest(device, streamInfo, content);
  1836 + if (request == null) {
  1837 + return;
  1838 + }
  1839 + logger.info(request.toString());
  1840 + ClientTransaction clientTransaction = null;
  1841 + if ("TCP".equals(device.getTransport())) {
  1842 + clientTransaction = tcpSipProvider.getNewClientTransaction(request);
  1843 + } else if ("UDP".equals(device.getTransport())) {
  1844 + clientTransaction = udpSipProvider.getNewClientTransaction(request);
  1845 + }
  1846 + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
  1847 + if(errorEvent != null) {
  1848 + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
  1849 + errorEvent.response(eventResult);
  1850 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1851 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  1852 + }));
  1853 + }
  1854 +
  1855 + if(okEvent != null) {
  1856 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
  1857 + okEvent.response(eventResult);
  1858 + sipSubscribe.removeOkSubscribe(eventResult.callId);
  1859 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1860 + });
  1861 + }
  1862 + clientTransaction.sendRequest();
  1863 +
  1864 + } catch (SipException | ParseException | InvalidArgumentException e) {
  1865 + e.printStackTrace();
  1866 + }
  1867 + }
1831 1868
1832 @Override 1869 @Override
1833 public boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) { 1870 public boolean sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info;
  2 +
  3 +import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.gb28181.bean.*;
  5 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  6 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  7 +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
  8 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
  10 +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
  11 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  12 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  13 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  14 +import gov.nist.javax.sip.message.SIPRequest;
  15 +import org.slf4j.Logger;
  16 +import org.slf4j.LoggerFactory;
  17 +import org.springframework.beans.factory.InitializingBean;
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.stereotype.Component;
  20 +import javax.sip.InvalidArgumentException;
  21 +import javax.sip.RequestEvent;
  22 +import javax.sip.SipException;
  23 +import javax.sip.header.*;
  24 +import javax.sip.message.Response;
  25 +import java.text.ParseException;
  26 +
  27 +@Component
  28 +public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
  29 +
  30 + private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class);
  31 +
  32 + private final String method = "INFO";
  33 +
  34 + @Autowired
  35 + private SIPProcessorObserver sipProcessorObserver;
  36 +
  37 + @Autowired
  38 + private IVideoManagerStorage storage;
  39 +
  40 + @Autowired
  41 + private SipSubscribe sipSubscribe;
  42 +
  43 + @Autowired
  44 + private IRedisCatchStorage redisCatchStorage;
  45 +
  46 + @Autowired
  47 + private IVideoManagerStorage storager;
  48 +
  49 + @Autowired
  50 + private SIPCommander cmder;
  51 +
  52 + @Autowired
  53 + private VideoStreamSessionManager sessionManager;
  54 +
  55 + @Override
  56 + public void afterPropertiesSet() throws Exception {
  57 + // 添加消息处理的订阅
  58 + sipProcessorObserver.addRequestProcessor(method, this);
  59 + }
  60 +
  61 + @Override
  62 + public void process(RequestEvent evt) {
  63 + logger.debug("接收到消息:" + evt.getRequest());
  64 + String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
  65 + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
  66 + // 先从会话内查找
  67 + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
  68 + if (ssrcTransaction != null) { // 兼容海康 媒体通知 消息from字段不是设备ID的问题
  69 + deviceId = ssrcTransaction.getDeviceId();
  70 + }
  71 + // 查询设备是否存在
  72 + Device device = redisCatchStorage.getDevice(deviceId);
  73 + // 查询上级平台是否存在
  74 + ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
  75 + try {
  76 + if (device != null && parentPlatform != null) {
  77 + logger.warn("[重复]平台与设备编号重复:{}", deviceId);
  78 + SIPRequest request = (SIPRequest) evt.getRequest();
  79 + String hostAddress = request.getRemoteAddress().getHostAddress();
  80 + int remotePort = request.getRemotePort();
  81 + if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) {
  82 + parentPlatform = null;
  83 + }else {
  84 + device = null;
  85 + }
  86 + }
  87 + if (device == null && parentPlatform == null) {
  88 + // 不存在则回复404
  89 + responseAck(evt, Response.NOT_FOUND, "device "+ deviceId +" not found");
  90 + logger.warn("[设备未找到 ]: {}", deviceId);
  91 + if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){
  92 + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new DeviceNotFoundEvent(evt.getDialog()));
  93 + sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
  94 + };
  95 + }else {
  96 + ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME);
  97 + String contentType = header.getContentType();
  98 + String contentSubType = header.getContentSubType();
  99 + if ("Application".equals(contentType) && "MANSRTSP".equals(contentSubType)) {
  100 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
  101 + String streamId = sendRtpItem.getStreamId();
  102 + StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
  103 + if (null == streamInfo) {
  104 + responseAck(evt, Response.NOT_FOUND, "stream " + streamId + " not found");
  105 + return;
  106 + }
  107 + Device device1 = storager.queryVideoDevice(streamInfo.getDeviceID());
  108 + cmder.playbackControlCmd(device1,streamInfo,new String(evt.getRequest().getRawContent()),eventResult -> {
  109 + // 失败的回复
  110 + try {
  111 + responseAck(evt, eventResult.statusCode, eventResult.msg);
  112 + } catch (SipException e) {
  113 + e.printStackTrace();
  114 + } catch (InvalidArgumentException e) {
  115 + e.printStackTrace();
  116 + } catch (ParseException e) {
  117 + e.printStackTrace();
  118 + }
  119 + }, eventResult -> {
  120 + // 成功的回复
  121 + try {
  122 + responseAck(evt, eventResult.statusCode);
  123 + } catch (SipException e) {
  124 + e.printStackTrace();
  125 + } catch (InvalidArgumentException e) {
  126 + e.printStackTrace();
  127 + } catch (ParseException e) {
  128 + e.printStackTrace();
  129 + }
  130 + });
  131 + }
  132 + }
  133 + } catch (SipException e) {
  134 + logger.warn("SIP 回复错误", e);
  135 + } catch (InvalidArgumentException e) {
  136 + logger.warn("参数无效", e);
  137 + } catch (ParseException e) {
  138 + logger.warn("SIP回复时解析异常", e);
  139 + }
  140 + }
  141 +
  142 +
  143 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java
@@ -82,7 +82,7 @@ public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParen @@ -82,7 +82,7 @@ public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParen
82 deviceService.offline(device.getDeviceId()); 82 deviceService.offline(device.getDeviceId());
83 } 83 }
84 RequestMessage msg = new RequestMessage(); 84 RequestMessage msg = new RequestMessage();
85 - msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + device.getDeviceId() + channelId); 85 + msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + device.getDeviceId());
86 msg.setData(json); 86 msg.setData(json);
87 deferredResultHolder.invokeAllResult(msg); 87 deferredResultHolder.invokeAllResult(msg);
88 } 88 }
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -255,6 +255,8 @@ public class XmlUtil { @@ -255,6 +255,8 @@ public class XmlUtil {
255 }else if (deviceChannel.getChannelId().length() == 20) { 255 }else if (deviceChannel.getChannelId().length() == 20) {
256 if (Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 216) { // 虚拟组织 256 if (Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 216) { // 虚拟组织
257 deviceChannel.setParentId(businessGroupID); 257 deviceChannel.setParentId(businessGroupID);
  258 + }else if (Integer.parseInt(device.getDeviceId().substring(10, 13) )== 118) {//NVR 如果上级设备编号是NVR则直接将NVR的编号设置给通道的上级编号
  259 + deviceChannel.setParentId(device.getDeviceId());
258 }else if (deviceChannel.getCivilCode() != null) { 260 }else if (deviceChannel.getCivilCode() != null) {
259 // 设备, 无parentId的20位是使用CivilCode表示上级的设备, 261 // 设备, 无parentId的20位是使用CivilCode表示上级的设备,
260 // 注:215 业务分组是需要有parentId的 262 // 注:215 业务分组是需要有parentId的
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -342,6 +342,11 @@ public class DeviceQuery { @@ -342,6 +342,11 @@ public class DeviceQuery {
342 Device device = storager.queryVideoDevice(deviceId); 342 Device device = storager.queryVideoDevice(deviceId);
343 String uuid = UUID.randomUUID().toString(); 343 String uuid = UUID.randomUUID().toString();
344 String key = DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId; 344 String key = DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId;
  345 + DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(2*1000L);
  346 + if(device == null) {
  347 + result.setResult(new ResponseEntity(String.format("设备%s不存在", deviceId),HttpStatus.OK));
  348 + return result;
  349 + }
345 cmder.deviceStatusQuery(device, event -> { 350 cmder.deviceStatusQuery(device, event -> {
346 RequestMessage msg = new RequestMessage(); 351 RequestMessage msg = new RequestMessage();
347 msg.setId(uuid); 352 msg.setId(uuid);
@@ -349,7 +354,6 @@ public class DeviceQuery { @@ -349,7 +354,6 @@ public class DeviceQuery {
349 msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg)); 354 msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg));
350 resultHolder.invokeResult(msg); 355 resultHolder.invokeResult(msg);
351 }); 356 });
352 - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(2*1000L);  
353 result.onTimeout(()->{ 357 result.onTimeout(()->{
354 logger.warn(String.format("获取设备状态超时")); 358 logger.warn(String.format("获取设备状态超时"));
355 // 释放rtpserver 359 // 释放rtpserver