Commit ddb36e54bd51761138c536ccca889d3f80182334

Authored by lin
1 parent 458e7d18

级联平台添加GPS订阅支持

Showing 18 changed files with 530 additions and 42 deletions
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
... ... @@ -58,6 +58,10 @@ public class VideoManagerConstants {
58 58  
59 59 public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_";
60 60  
  61 + public static final String SIP_SN_PREFIX = "VMP_SIP_SN_";
  62 +
  63 + public static final String SIP_SUBSCRIBE_PREFIX = "SIP_SUBSCRIBE_";
  64 +
61 65 //************************** redis 消息*********************************
62 66 public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_";
63 67 public static final String WVP_MSG_GPS_PREFIX = "WVP_MSG_GPS_";
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CmdType.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +public class CmdType {
  4 +
  5 + public static final String CATALOG = "Catalog";
  6 + public static final String ALARM = "Alarm";
  7 + public static final String MOBILE_POSITION = "MobilePosition";
  8 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import javax.sip.RequestEvent;
  4 +import javax.sip.header.*;
  5 +import javax.sip.message.Request;
  6 +
  7 +public class SubscribeInfo {
  8 +
  9 + public SubscribeInfo() {
  10 + }
  11 +
  12 + public SubscribeInfo(RequestEvent evt, String id) {
  13 + this.id = id;
  14 + Request request = evt.getRequest();
  15 + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
  16 + this.callId = callIdHeader.getCallId();
  17 + FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
  18 + this.fromTag = fromHeader.getTag();
  19 + ExpiresHeader expiresHeader = (ExpiresHeader)request.getHeader(ExpiresHeader.NAME);
  20 + this.expires = expiresHeader.getExpires();
  21 + this.event = (EventHeader)request.getHeader(EventHeader.NAME);
  22 + }
  23 +
  24 + private String id;
  25 + private int expires;
  26 + private String callId;
  27 + private EventHeader event;
  28 + private String fromTag;
  29 + private String toTag;
  30 +
  31 + public String getId() {
  32 + return id;
  33 + }
  34 +
  35 + public int getExpires() {
  36 + return expires;
  37 + }
  38 +
  39 + public String getCallId() {
  40 + return callId;
  41 + }
  42 +
  43 + public EventHeader getEvent() {
  44 + return event;
  45 + }
  46 +
  47 + public String getFromTag() {
  48 + return fromTag;
  49 + }
  50 +
  51 + public void setToTag(String toTag) {
  52 + this.toTag = toTag;
  53 + }
  54 +
  55 + public String getToTag() {
  56 + return toTag;
  57 + }
  58 +
  59 + public void setId(String id) {
  60 + this.id = id;
  61 + }
  62 +
  63 + public void setExpires(int expires) {
  64 + this.expires = expires;
  65 + }
  66 +
  67 + public void setCallId(String callId) {
  68 + this.callId = callId;
  69 + }
  70 +
  71 + public void setEvent(EventHeader event) {
  72 + this.event = event;
  73 + }
  74 +
  75 + public void setFromTag(String fromTag) {
  76 + this.fromTag = fromTag;
  77 + }
  78 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.event.subscribe;
  2 +
  3 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  4 +import com.genersoft.iot.vmp.conf.DynamicTask;
  5 +import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener;
  6 +import com.genersoft.iot.vmp.conf.UserSetup;
  7 +import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
  8 +import org.checkerframework.checker.units.qual.A;
  9 +import org.slf4j.Logger;
  10 +import org.slf4j.LoggerFactory;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +import org.springframework.data.redis.connection.Message;
  13 +import org.springframework.data.redis.listener.RedisMessageListenerContainer;
  14 +import org.springframework.stereotype.Component;
  15 +
  16 +/**
  17 + * 平台订阅到期事件
  18 + */
  19 +@Component
  20 +public class SubscribeListenerForPlatform extends RedisKeyExpirationEventMessageListener {
  21 +
  22 + private Logger logger = LoggerFactory.getLogger(SubscribeListenerForPlatform.class);
  23 +
  24 + @Autowired
  25 + private UserSetup userSetup;
  26 +
  27 + @Autowired
  28 + private DynamicTask dynamicTask;
  29 +
  30 + public SubscribeListenerForPlatform(RedisMessageListenerContainer listenerContainer, UserSetup userSetup) {
  31 + super(listenerContainer, userSetup);
  32 + }
  33 +
  34 +
  35 + /**
  36 + * 监听失效的key
  37 + * @param message
  38 + * @param pattern
  39 + */
  40 + @Override
  41 + public void onMessage(Message message, byte[] pattern) {
  42 + // 获取失效的key
  43 + String expiredKey = message.toString();
  44 + logger.debug(expiredKey);
  45 + // 订阅到期
  46 + String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_";
  47 + if (expiredKey.startsWith(PLATFORM_KEEPLIVEKEY_PREFIX)) {
  48 + // 取消定时任务
  49 + dynamicTask.stopCron(expiredKey);
  50 + }
  51 + }
  52 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.task;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.GbStream;
  4 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  5 +import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
  6 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
  7 +import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
  8 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  9 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  10 +
  11 +import java.text.SimpleDateFormat;
  12 +import java.util.List;
  13 +
  14 +public class GPSSubscribeTask implements Runnable{
  15 +
  16 + private IRedisCatchStorage redisCatchStorage;
  17 + private IVideoManagerStorager storager;
  18 + private ISIPCommanderForPlatform sipCommanderForPlatform;
  19 + private String platformId;
  20 + private String sn;
  21 + private String key;
  22 +
  23 + private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  24 +
  25 + public GPSSubscribeTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorager storager, String platformId, String sn, String key) {
  26 + this.redisCatchStorage = redisCatchStorage;
  27 + this.storager = storager;
  28 + this.platformId = platformId;
  29 + this.sn = sn;
  30 + this.key = key;
  31 + this.sipCommanderForPlatform = sipCommanderForPlatform;
  32 + }
  33 +
  34 + @Override
  35 + public void run() {
  36 +
  37 + SubscribeInfo subscribe = redisCatchStorage.getSubscribe(key);
  38 + if (subscribe != null) {
  39 + System.out.println("发送GPS消息");
  40 + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
  41 + if (parentPlatform == null || parentPlatform.isStatus()) {
  42 + // TODO 暂时只处理视频流的回复,后续增加对国标设备的支持
  43 + List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platformId);
  44 + if (gbStreams.size() > 0) {
  45 + for (GbStream gbStream : gbStreams) {
  46 + String gbId = gbStream.getGbId();
  47 + GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
  48 + if (gpsMsgInfo != null && gbStream.isStatus()) {
  49 + // 发送GPS消息
  50 + sipCommanderForPlatform.sendMobilePosition(parentPlatform, gpsMsgInfo, subscribe);
  51 + }
  52 + }
  53 + }
  54 + }
  55 + }
  56 +
  57 +
  58 + }
  59 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
... ... @@ -2,7 +2,9 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
4 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  5 +import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
5 6 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  7 +import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
6 8  
7 9 import javax.sip.header.WWWAuthenticateHeader;
8 10  
... ... @@ -61,4 +63,12 @@ public interface ISIPCommanderForPlatform {
61 63 */
62 64 boolean deviceStatusResponse(ParentPlatform parentPlatform, String sn, String fromTag);
63 65  
  66 + /**
  67 + * 向上级回复移动位置订阅消息
  68 + * @param parentPlatform 平台信息
  69 + * @param gpsMsgInfo GPS信息
  70 + * @param subscribeInfo 订阅相关的信息
  71 + * @return
  72 + */
  73 + boolean sendMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo);
64 74 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
... ... @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
2 2  
3 3 import com.genersoft.iot.vmp.conf.SipConfig;
4 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  5 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
5 6 import gov.nist.javax.sip.message.MessageFactoryImpl;
6 7 import org.springframework.beans.factory.annotation.Autowired;
7 8 import org.springframework.stereotype.Component;
... ... @@ -32,6 +33,9 @@ public class SIPRequestHeaderPlarformProvider {
32 33 @Autowired
33 34 private SipFactory sipFactory;
34 35  
  36 + @Autowired
  37 + private IRedisCatchStorage redisCatchStorage;
  38 +
35 39  
36 40 public Request createKeetpaliveMessageRequest(ParentPlatform parentPlatform, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
37 41 Request request = null;
... ... @@ -57,7 +61,7 @@ public class SIPRequestHeaderPlarformProvider {
57 61 // Forwards
58 62 MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
59 63 // ceq
60   - CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);
  64 + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.MESSAGE), Request.MESSAGE);
61 65  
62 66 request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
63 67 toHeader, viaHeaders, maxForwards);
... ... @@ -122,7 +126,7 @@ public class SIPRequestHeaderPlarformProvider {
122 126 String callId, WWWAuthenticateHeader www , CallIdHeader callIdHeader) throws ParseException, PeerUnavailableException, InvalidArgumentException {
123 127  
124 128  
125   - Request registerRequest = createRegisterRequest(parentPlatform, 2L, fromTag, viaTag, callIdHeader);
  129 + Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), fromTag, viaTag, callIdHeader);
126 130  
127 131 String realm = www.getRealm();
128 132 String nonce = www.getNonce();
... ... @@ -208,7 +212,7 @@ public class SIPRequestHeaderPlarformProvider {
208 212 // Forwards
209 213 MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
210 214 // ceq
211   - CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);
  215 + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.MESSAGE), Request.MESSAGE);
212 216 MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory();
213 217 // 设置编码, 防止中文乱码
214 218 messageFactory.setDefaultContentEncodingCharset("gb2312");
... ... @@ -223,4 +227,43 @@ public class SIPRequestHeaderPlarformProvider {
223 227 request.setContent(content, contentTypeHeader);
224 228 return request;
225 229 }
  230 +
  231 + public Request createNotifyRequest(ParentPlatform parentPlatform, String content, String fromTag, String toTag, CallIdHeader callIdHeader) throws PeerUnavailableException, ParseException, InvalidArgumentException {
  232 + Request request = null;
  233 + // sipuri
  234 + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP()+ ":" + parentPlatform.getServerPort());
  235 + // via
  236 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  237 + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(), Integer.parseInt(parentPlatform.getDevicePort()),
  238 + parentPlatform.getTransport(), null);
  239 + viaHeader.setRPort();
  240 + viaHeaders.add(viaHeader);
  241 + // from
  242 + SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(),
  243 + parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort());
  244 + Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
  245 + FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
  246 + // to
  247 + SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerGBDomain());
  248 + Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
  249 + ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
  250 +
  251 + // Forwards
  252 + MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
  253 + // ceq
  254 + CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(Request.NOTIFY), Request.NOTIFY);
  255 + MessageFactoryImpl messageFactory = (MessageFactoryImpl) sipFactory.createMessageFactory();
  256 + // 设置编码, 防止中文乱码
  257 + messageFactory.setDefaultContentEncodingCharset("gb2312");
  258 + request = messageFactory.createRequest(requestURI, Request.NOTIFY, callIdHeader, cSeqHeader, fromHeader,
  259 + toHeader, viaHeaders, maxForwards);
  260 + List<String> agentParam = new ArrayList<>();
  261 + agentParam.add("wvp-pro");
  262 + UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
  263 + request.addHeader(userAgentHeader);
  264 +
  265 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
  266 + request.setContent(content, contentTypeHeader);
  267 + return request;
  268 + }
226 269 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
... ... @@ -3,9 +3,11 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
3 3 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
4 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
5 5 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  6 +import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
6 7 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
7 8 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
8 9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
  10 +import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
9 11 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10 12 import org.slf4j.Logger;
11 13 import org.slf4j.LoggerFactory;
... ... @@ -92,7 +94,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
92 94 callIdHeader = udpSipProvider.getNewCallId();
93 95 }
94 96  
95   - request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, 1L, "FromRegister" + tm, null, callIdHeader);
  97 + request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(Request.REGISTER), "FromRegister" + tm, null, callIdHeader);
96 98 // 将 callid 写入缓存, 等注册成功可以更新状态
97 99 redisCatchStorage.updatePlatformRegisterInfo(callIdHeader.getCallId(), parentPlatform.getServerGBId());
98 100  
... ... @@ -325,4 +327,41 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
325 327 }
326 328 return true;
327 329 }
  330 +
  331 + @Override
  332 + public boolean sendMobilePosition(ParentPlatform parentPlatform, GPSMsgInfo gpsMsgInfo, SubscribeInfo subscribeInfo) {
  333 + if (parentPlatform == null) {
  334 + return false;
  335 + }
  336 +
  337 + try {
  338 + StringBuffer deviceStatusXml = new StringBuffer(600);
  339 + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
  340 + deviceStatusXml.append("<Notify>\r\n");
  341 + deviceStatusXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  342 + deviceStatusXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
  343 + deviceStatusXml.append("<DeviceID>" + gpsMsgInfo.getId() + "</DeviceID>\r\n");
  344 + deviceStatusXml.append("<Time>" + gpsMsgInfo.getTime() + "</Time>\r\n");
  345 + deviceStatusXml.append("<Longitude>" + gpsMsgInfo.getLng() + "</Longitude>\r\n");
  346 + deviceStatusXml.append("<Latitude>" + gpsMsgInfo.getLat() + "</Latitude>\r\n");
  347 + deviceStatusXml.append("<Speed>" + gpsMsgInfo.getSpeed() + "</Speed>\r\n");
  348 + deviceStatusXml.append("<Direction>" + gpsMsgInfo.getDirection() + "</Direction>\r\n");
  349 + deviceStatusXml.append("<Altitude>" + gpsMsgInfo.getAltitude() + "</Altitude>\r\n");
  350 + deviceStatusXml.append("</Notify>\r\n");
  351 +
  352 + CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  353 + : udpSipProvider.getNewCallId();
  354 + callIdHeader.setCallId(subscribeInfo.getCallId());
  355 +
  356 + String tm = Long.toString(System.currentTimeMillis());
  357 +
  358 + Request request = headerProviderPlarformProvider.createNotifyRequest(parentPlatform, deviceStatusXml.toString(), subscribeInfo.getToTag(), subscribeInfo.getFromTag(), callIdHeader);
  359 + transmitRequest(parentPlatform, request);
  360 +
  361 + } catch (SipException | ParseException | InvalidArgumentException e) {
  362 + e.printStackTrace();
  363 + return false;
  364 + }
  365 + return true;
  366 + }
328 367 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
... ... @@ -18,6 +18,7 @@ import javax.sip.address.Address;
18 18 import javax.sip.address.AddressFactory;
19 19 import javax.sip.address.SipURI;
20 20 import javax.sip.header.ContentTypeHeader;
  21 +import javax.sip.header.ExpiresHeader;
21 22 import javax.sip.header.HeaderFactory;
22 23 import javax.sip.header.ViaHeader;
23 24 import javax.sip.message.MessageFactory;
... ... @@ -153,7 +154,7 @@ public abstract class SIPRequestProcessorParent {
153 154 * @throws InvalidArgumentException
154 155 * @throws ParseException
155 156 */
156   - public void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
  157 + public void responseSdpAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
157 158 Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
158 159 SipFactory sipFactory = SipFactory.getInstance();
159 160 ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
... ... @@ -168,6 +169,31 @@ public abstract class SIPRequestProcessorParent {
168 169 getServerTransaction(evt).sendResponse(response);
169 170 }
170 171  
  172 + /**
  173 + * 回复带xml的200
  174 + * @param evt
  175 + * @param xml
  176 + * @throws SipException
  177 + * @throws InvalidArgumentException
  178 + * @throws ParseException
  179 + */
  180 + public Response responseXmlAck(RequestEvent evt, String xml) throws SipException, InvalidArgumentException, ParseException {
  181 + Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
  182 + SipFactory sipFactory = SipFactory.getInstance();
  183 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
  184 + response.setContent(xml, contentTypeHeader);
  185 +
  186 + SipURI sipURI = (SipURI)evt.getRequest().getRequestURI();
  187 +
  188 + Address concatAddress = sipFactory.createAddressFactory().createAddress(
  189 + sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort()
  190 + ));
  191 + response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
  192 + response.addHeader(evt.getRequest().getHeader(ExpiresHeader.NAME));
  193 + getServerTransaction(evt).sendResponse(response);
  194 + return response;
  195 + }
  196 +
171 197 public Element getRootElement(RequestEvent evt) throws DocumentException {
172 198 return getRootElement(evt, "gb2312");
173 199 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -253,7 +253,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
253 253 content.append("f=\r\n");
254 254  
255 255 try {
256   - responseAck(evt, content.toString());
  256 + responseSdpAck(evt, content.toString());
257 257 } catch (SipException e) {
258 258 e.printStackTrace();
259 259 } catch (InvalidArgumentException e) {
... ... @@ -310,7 +310,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
310 310 content.append("f=\r\n");
311 311  
312 312 try {
313   - responseAck(evt, content.toString());
  313 + responseSdpAck(evt, content.toString());
314 314 } catch (SipException e) {
315 315 e.printStackTrace();
316 316 } catch (InvalidArgumentException e) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
... ... @@ -62,9 +62,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
62 62 @Autowired
63 63 private DeviceOffLineDetector offLineDetector;
64 64  
65   - private static final String NOTIFY_CATALOG = "Catalog";
66   - private static final String NOTIFY_ALARM = "Alarm";
67   - private static final String NOTIFY_MOBILE_POSITION = "MobilePosition";
  65 +
68 66 private String method = "NOTIFY";
69 67  
70 68 @Autowired
... ... @@ -82,13 +80,13 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
82 80 Element rootElement = getRootElement(evt);
83 81 String cmd = XmlUtil.getText(rootElement, "CmdType");
84 82  
85   - if (NOTIFY_CATALOG.equals(cmd)) {
  83 + if (CmdType.CATALOG.equals(cmd)) {
86 84 logger.info("接收到Catalog通知");
87 85 processNotifyCatalogList(evt);
88   - } else if (NOTIFY_ALARM.equals(cmd)) {
  86 + } else if (CmdType.ALARM.equals(cmd)) {
89 87 logger.info("接收到Alarm通知");
90 88 processNotifyAlarm(evt);
91   - } else if (NOTIFY_MOBILE_POSITION.equals(cmd)) {
  89 + } else if (CmdType.MOBILE_POSITION.equals(cmd)) {
92 90 logger.info("接收到MobilePosition通知");
93 91 processNotifyMobilePosition(evt);
94 92 } else {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2  
  3 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  4 +import com.genersoft.iot.vmp.conf.DynamicTask;
  5 +import com.genersoft.iot.vmp.conf.UserSetup;
  6 +import com.genersoft.iot.vmp.gb28181.bean.CmdType;
  7 +import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
  8 +import com.genersoft.iot.vmp.gb28181.task.GPSSubscribeTask;
3 9 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
  10 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
4 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
5 12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
  13 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  14 +import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
  15 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  16 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  17 +import org.dom4j.DocumentException;
  18 +import org.dom4j.Element;
6 19 import org.slf4j.Logger;
7 20 import org.slf4j.LoggerFactory;
8 21 import org.springframework.beans.factory.InitializingBean;
... ... @@ -13,7 +26,10 @@ import javax.sip.InvalidArgumentException;
13 26 import javax.sip.RequestEvent;
14 27 import javax.sip.ServerTransaction;
15 28 import javax.sip.SipException;
  29 +import javax.sip.header.CallIdHeader;
16 30 import javax.sip.header.ExpiresHeader;
  31 +import javax.sip.header.Header;
  32 +import javax.sip.header.ToHeader;
17 33 import javax.sip.message.Request;
18 34 import javax.sip.message.Response;
19 35 import java.text.ParseException;
... ... @@ -30,6 +46,21 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
30 46 @Autowired
31 47 private SIPProcessorObserver sipProcessorObserver;
32 48  
  49 + @Autowired
  50 + private IRedisCatchStorage redisCatchStorage;
  51 +
  52 + @Autowired
  53 + private ISIPCommanderForPlatform sipCommanderForPlatform;
  54 +
  55 + @Autowired
  56 + private IVideoManagerStorager storager;
  57 +
  58 + @Autowired
  59 + private DynamicTask dynamicTask;
  60 +
  61 + @Autowired
  62 + private UserSetup userSetup;
  63 +
33 64 @Override
34 65 public void afterPropertiesSet() throws Exception {
35 66 // 添加消息处理的订阅
... ... @@ -46,30 +77,107 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
46 77 Request request = evt.getRequest();
47 78  
48 79 try {
49   - Response response = null;
50   - response = getMessageFactory().createResponse(200, request);
51   - if (response != null) {
52   - ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30);
53   - response.setExpires(expireHeader);
54   - }
55   - logger.info("response : " + response.toString());
56   - ServerTransaction transaction = getServerTransaction(evt);
57   - if (transaction != null) {
58   - transaction.sendResponse(response);
59   - transaction.getDialog().delete();
60   - transaction.terminate();
  80 + Element rootElement = getRootElement(evt);
  81 + String cmd = XmlUtil.getText(rootElement, "CmdType");
  82 + if (CmdType.MOBILE_POSITION.equals(cmd)) {
  83 + logger.info("接收到MobilePosition订阅");
  84 + processNotifyMobilePosition(evt, rootElement);
  85 +// } else if (CmdType.ALARM.equals(cmd)) {
  86 +// logger.info("接收到Alarm订阅");
  87 +// processNotifyAlarm(evt, rootElement);
  88 +// } else if (CmdType.CATALOG.equals(cmd)) {
  89 +// logger.info("接收到Catalog订阅");
  90 +// processNotifyCatalogList(evt, rootElement);
61 91 } else {
62   - logger.info("processRequest serverTransactionId is null.");
  92 + logger.info("接收到消息:" + cmd);
  93 +// responseAck(evt, Response.OK);
  94 +
  95 + Response response = null;
  96 + response = getMessageFactory().createResponse(200, request);
  97 + if (response != null) {
  98 + ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30);
  99 + response.setExpires(expireHeader);
  100 + }
  101 + logger.info("response : " + response.toString());
  102 + ServerTransaction transaction = getServerTransaction(evt);
  103 + if (transaction != null) {
  104 + transaction.sendResponse(response);
  105 + transaction.getDialog().delete();
  106 + transaction.terminate();
  107 + } else {
  108 + logger.info("processRequest serverTransactionId is null.");
  109 + }
63 110 }
64 111  
  112 +
  113 +
65 114 } catch (ParseException e) {
66 115 e.printStackTrace();
67 116 } catch (SipException e) {
68 117 e.printStackTrace();
69 118 } catch (InvalidArgumentException e) {
70 119 e.printStackTrace();
  120 + } catch (DocumentException e) {
  121 + e.printStackTrace();
  122 + }
  123 +
  124 + }
  125 +
  126 + /**
  127 + * 处理移动位置订阅消息
  128 + */
  129 + private void processNotifyMobilePosition(RequestEvent evt, Element rootElement) {
  130 + String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
  131 + String deviceID = XmlUtil.getText(rootElement, "DeviceID");
  132 + SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId);
  133 + String sn = XmlUtil.getText(rootElement, "SN");
  134 + String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_MobilePosition_" + platformId;
  135 +
  136 + StringBuilder resultXml = new StringBuilder(200);
  137 + resultXml.append("<?xml version=\"1.0\" ?>\r\n")
  138 + .append("<Response>\r\n")
  139 + .append("<CmdType>MobilePosition</CmdType>\r\n")
  140 + .append("<SN>" + sn + "</SN>\r\n")
  141 + .append("<DeviceID>" + deviceID + "</DeviceID>\r\n")
  142 + .append("<Result>OK</Result>\r\n")
  143 + .append("</Response>\r\n");
  144 +
  145 + if (subscribeInfo.getExpires() > 0) {
  146 + if (redisCatchStorage.getSubscribe(key) != null) {
  147 + dynamicTask.stopCron(key);
  148 + }
  149 + String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔
  150 + dynamicTask.startCron(key, new GPSSubscribeTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key), Integer.parseInt(interval));
  151 +
  152 + redisCatchStorage.updateSubscribe(key, subscribeInfo);
  153 + }else if (subscribeInfo.getExpires() == 0) {
  154 + dynamicTask.stopCron(key);
  155 + redisCatchStorage.delSubscribe(key);
  156 + }
  157 +
  158 +
  159 +
  160 + try {
  161 + Response response = responseXmlAck(evt, resultXml.toString());
  162 + ToHeader toHeader = (ToHeader)response.getHeader(ToHeader.NAME);
  163 + subscribeInfo.setToTag(toHeader.getTag());
  164 + redisCatchStorage.updateSubscribe(key, subscribeInfo);
  165 +
  166 + } catch (SipException e) {
  167 + e.printStackTrace();
  168 + } catch (InvalidArgumentException e) {
  169 + e.printStackTrace();
  170 + } catch (ParseException e) {
  171 + e.printStackTrace();
71 172 }
72   -
  173 + }
  174 +
  175 + private void processNotifyAlarm(RequestEvent evt, Element rootElement) {
  176 +
  177 + }
  178 +
  179 + private void processNotifyCatalogList(RequestEvent evt, Element rootElement) {
  180 +
73 181 }
74 182  
75 183 }
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java
... ... @@ -23,7 +23,7 @@ public class GPSMsgInfo {
23 23 private double speed;
24 24  
25 25 /**
26   - * 产生通知时间,
  26 + * 产生通知时间, 时间格式: 2020-01-14T14:32:12
27 27 */
28 28 private String time;
29 29  
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGPSMsgListener.java
... ... @@ -17,6 +17,7 @@ public class RedisGPSMsgListener implements MessageListener {
17 17 @Override
18 18 public void onMessage(Message message, byte[] bytes) {
19 19 GPSMsgInfo gpsMsgInfo = JSON.parseObject(message.getBody(), GPSMsgInfo.class);
  20 + System.out.println(JSON.toJSON(gpsMsgInfo));
20 21 redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo);
21 22 }
22 23 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
... ... @@ -2,10 +2,7 @@ package com.genersoft.iot.vmp.storager;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
4 4 import com.genersoft.iot.vmp.common.StreamInfo;
5   -import com.genersoft.iot.vmp.gb28181.bean.Device;
6   -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7   -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
8   -import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
  5 +import com.genersoft.iot.vmp.gb28181.bean.*;
9 6 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
10 7 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
11 8 import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
... ... @@ -196,4 +193,16 @@ public interface IRedisCatchStorage {
196 193 void resetAllCSEQ();
197 194  
198 195 void updateGpsMsgInfo(GPSMsgInfo gpsMsgInfo);
  196 +
  197 + GPSMsgInfo getGpsMsgInfo(String gbId);
  198 +
  199 + Long getSN(String method);
  200 +
  201 + void resetAllSN();
  202 +
  203 + void updateSubscribe(String key, SubscribeInfo subscribeInfo);
  204 +
  205 + SubscribeInfo getSubscribe(String key);
  206 +
  207 + void delSubscribe(String key);
199 208 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
... ... @@ -54,6 +54,11 @@ public interface GbStreamMapper {
54 54 "WHERE pgs.platformId = '${platformId}'")
55 55 List<GbStream> queryGbStreamListInPlatform(String platformId);
56 56  
  57 +
  58 + @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs LEFT JOIN platform_gb_stream pgs " +
  59 + "ON gs.app = pgs.app and gs.stream = pgs.stream WHERE pgs.app is NULL and pgs.stream is NULL")
  60 + List<GbStream> queryStreamNotInPlatform();
  61 +
57 62 @Update("UPDATE gb_stream " +
58 63 "SET status=${status} " +
59 64 "WHERE app=#{app} AND stream=#{stream}")
... ... @@ -87,4 +92,6 @@ public interface GbStreamMapper {
87 92 "</foreach> " +
88 93 "</script>")
89 94 void batchAdd(List<StreamPushItem> subList);
  95 +
  96 +
90 97 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
... ... @@ -50,6 +50,18 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
50 50 }
51 51  
52 52 @Override
  53 + public Long getSN(String method) {
  54 + String key = VideoManagerConstants.SIP_SN_PREFIX + userSetup.getServerId() + "_" + method;
  55 +
  56 + long result = redis.incr(key, 1L);
  57 + if (result > Integer.MAX_VALUE) {
  58 + redis.set(key, 1);
  59 + result = 1;
  60 + }
  61 + return result;
  62 + }
  63 +
  64 + @Override
53 65 public void resetAllCSEQ() {
54 66 String scanKey = VideoManagerConstants.SIP_CSEQ_PREFIX + userSetup.getServerId() + "_*";
55 67 List<Object> keys = redis.scan(scanKey);
... ... @@ -59,6 +71,16 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
59 71 }
60 72 }
61 73  
  74 + @Override
  75 + public void resetAllSN() {
  76 + String scanKey = VideoManagerConstants.SIP_SN_PREFIX + userSetup.getServerId() + "_*";
  77 + List<Object> keys = redis.scan(scanKey);
  78 + for (int i = 0; i < keys.size(); i++) {
  79 + String key = (String) keys.get(i);
  80 + redis.set(key, 1);
  81 + }
  82 + }
  83 +
62 84 /**
63 85 * 开始播放时将流存入redis
64 86 *
... ... @@ -433,4 +455,25 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
433 455 String key = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetup.getServerId() + "_" + gpsMsgInfo.getId();
434 456 redis.set(key, gpsMsgInfo);
435 457 }
  458 +
  459 + @Override
  460 + public GPSMsgInfo getGpsMsgInfo(String gbId) {
  461 + String key = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetup.getServerId() + "_" + gbId;
  462 + return (GPSMsgInfo)redis.get(key);
  463 + }
  464 +
  465 + @Override
  466 + public void updateSubscribe(String key, SubscribeInfo subscribeInfo) {
  467 + redis.set(key, subscribeInfo, subscribeInfo.getExpires());
  468 + }
  469 +
  470 + @Override
  471 + public SubscribeInfo getSubscribe(String key) {
  472 + return (SubscribeInfo)redis.get(key);
  473 + }
  474 +
  475 + @Override
  476 + public void delSubscribe(String key) {
  477 + redis.del(key);
  478 + }
436 479 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
... ... @@ -486,18 +486,21 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
486 486 // 更新缓存
487 487 parentPlatformCatch.setParentPlatform(parentPlatform);
488 488 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
489   - // 共享所有视频流,需要将现有视频流添加到此平台
490   - List<GbStream> gbStreams = gbStreamMapper.selectAll();
491   - if (gbStreams.size() > 0) {
492   - for (GbStream gbStream : gbStreams) {
493   - gbStream.setCatalogId(parentPlatform.getCatalogId());
494   - }
495   - if (parentPlatform.isShareAllLiveStream()) {
496   - gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId(), parentPlatform.getCatalogId());
497   - }else {
498   - gbStreamService.delPlatformInfo(gbStreams);
  489 + if (parentPlatform.isEnable()) {
  490 + // 共享所有视频流,需要将现有视频流添加到此平台
  491 + List<GbStream> gbStreams = gbStreamMapper.queryStreamNotInPlatform();
  492 + if (gbStreams.size() > 0) {
  493 + for (GbStream gbStream : gbStreams) {
  494 + gbStream.setCatalogId(parentPlatform.getCatalogId());
  495 + }
  496 + if (parentPlatform.isShareAllLiveStream()) {
  497 + gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId(), parentPlatform.getCatalogId());
  498 + }else {
  499 + gbStreamService.delPlatformInfo(gbStreams);
  500 + }
499 501 }
500 502 }
  503 +
501 504 return result > 0;
502 505 }
503 506  
... ...