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 131 /**
132 132 * 是否开启ssrc校验,默认关闭,开启可以防止串流
133 133 */
134   - private boolean ssrcCheck;
  134 + private boolean ssrcCheck = true;
135 135  
136 136 /**
137 137 * 地理坐标系, 目前支持 WGS84,GCJ02 TODO CGCS2000
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
... ... @@ -88,8 +88,8 @@ public class SipSubscribe {
88 88 this.type = "timeout";
89 89 this.msg = "消息超时未回复";
90 90 this.statusCode = -1024;
91   - this.callId = timeoutEvent.getClientTransaction().getDialog().getCallId().getCallId();
92 91 this.dialog = timeoutEvent.getClientTransaction().getDialog();
  92 + this.callId = this.dialog != null?timeoutEvent.getClientTransaction().getDialog().getCallId().getCallId(): null;
93 93 }else if (event instanceof TransactionTerminatedEvent) {
94 94 TransactionTerminatedEvent transactionTerminatedEvent = (TransactionTerminatedEvent)event;
95 95 this.type = "transactionTerminated";
... ... @@ -109,8 +109,8 @@ public class SipSubscribe {
109 109 this.type = "deviceNotFoundEvent";
110 110 this.msg = "设备未找到";
111 111 this.statusCode = -1024;
112   - this.callId = deviceNotFoundEvent.getDialog().getCallId().getCallId();
113 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 130 }
131 131  
132 132 public void removeErrorSubscribe(String key) {
  133 + if(key == null){
  134 + return;
  135 + }
133 136 errorSubscribes.remove(key);
134 137 errorTimeSubscribes.remove(key);
135 138 }
... ... @@ -139,6 +142,9 @@ public class SipSubscribe {
139 142 }
140 143  
141 144 public void removeOkSubscribe(String key) {
  145 + if(key == null){
  146 + return;
  147 + }
142 148 okSubscribes.remove(key);
143 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 143 * 回放倍速播放
144 144 */
145 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 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 1869 @Override
1833 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 82 deviceService.offline(device.getDeviceId());
83 83 }
84 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 86 msg.setData(json);
87 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 255 }else if (deviceChannel.getChannelId().length() == 20) {
256 256 if (Integer.parseInt(deviceChannel.getChannelId().substring(10, 13)) == 216) { // 虚拟组织
257 257 deviceChannel.setParentId(businessGroupID);
  258 + }else if (Integer.parseInt(device.getDeviceId().substring(10, 13) )== 118) {//NVR 如果上级设备编号是NVR则直接将NVR的编号设置给通道的上级编号
  259 + deviceChannel.setParentId(device.getDeviceId());
258 260 }else if (deviceChannel.getCivilCode() != null) {
259 261 // 设备, 无parentId的20位是使用CivilCode表示上级的设备,
260 262 // 注:215 业务分组是需要有parentId的
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
... ... @@ -342,6 +342,11 @@ public class DeviceQuery {
342 342 Device device = storager.queryVideoDevice(deviceId);
343 343 String uuid = UUID.randomUUID().toString();
344 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 350 cmder.deviceStatusQuery(device, event -> {
346 351 RequestMessage msg = new RequestMessage();
347 352 msg.setId(uuid);
... ... @@ -349,7 +354,6 @@ public class DeviceQuery {
349 354 msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg));
350 355 resultHolder.invokeResult(msg);
351 356 });
352   - DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(2*1000L);
353 357 result.onTimeout(()->{
354 358 logger.warn(String.format("获取设备状态超时"));
355 359 // 释放rtpserver
... ...