Commit efc4a7bc8eb8a967198d70ff4d88670e71541164

Authored by 648540858
1 parent 3955e6ed

优化级联移动位置订阅位置更新

src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
... ... @@ -39,7 +39,7 @@ public class DynamicTask {
39 39 public void startCron(String key, Runnable task, int cycleForCatalog) {
40 40 stop(key);
41 41 // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔
42   - ScheduledFuture future = threadPoolTaskScheduler.scheduleWithFixedDelay(task, cycleForCatalog * 1000L);
  42 + ScheduledFuture future = threadPoolTaskScheduler.scheduleAtFixedRate(task, cycleForCatalog * 1000L);
43 43 futureMap.put(key, future);
44 44 runnableMap.put(key, task);
45 45 }
... ... @@ -78,4 +78,7 @@ public class DynamicTask {
78 78 return futureMap.keySet();
79 79 }
80 80  
  81 + public Runnable get(String key) {
  82 + return runnableMap.get(key);
  83 + }
81 84 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
... ... @@ -99,7 +99,10 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
99 99 storager.updateDevice(device);
100 100 // 上线添加订阅
101 101 if (device.getSubscribeCycleForCatalog() > 0) {
  102 + // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
102 103 deviceService.addCatalogSubscribe(device);
  104 + }
  105 + if (device.getSubscribeCycleForMobilePosition() > 0) {
103 106 deviceService.addMobilePositionSubscribe(device);
104 107 }
105 108 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
1 1 package com.genersoft.iot.vmp.gb28181.task;
2 2  
  3 +import javax.sip.DialogState;
  4 +
3 5 public interface ISubscribeTask extends Runnable{
4 6 void stop();
  7 +
  8 + DialogState getDialogState();
5 9 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
... ... @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
5 5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
6 6 import org.slf4j.Logger;
7 7 import org.slf4j.LoggerFactory;
  8 +import org.springframework.scheduling.annotation.Async;
8 9  
9 10 import javax.sip.Dialog;
10 11 import javax.sip.DialogState;
... ... @@ -45,6 +46,7 @@ public class CatalogSubscribeTask implements ISubscribeTask {
45 46 });
46 47 }
47 48  
  49 + @Async
48 50 @Override
49 51 public void stop() {
50 52 /**
... ... @@ -72,4 +74,10 @@ public class CatalogSubscribeTask implements ISubscribeTask {
72 74 });
73 75 }
74 76 }
  77 +
  78 + @Override
  79 + public DialogState getDialogState() {
  80 + if (dialog == null) return null;
  81 + return dialog.getState();
  82 + }
75 83 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
1 1 package com.genersoft.iot.vmp.gb28181.task.impl;
2 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.SubscribeHolder;
6   -import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
  3 +import com.genersoft.iot.vmp.gb28181.bean.*;
7 4 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
8 5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
9 6 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
10 7 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
11 8 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  9 +import org.slf4j.Logger;
  10 +import org.slf4j.LoggerFactory;
  11 +import org.springframework.scheduling.annotation.Async;
12 12  
13   -import java.text.SimpleDateFormat;
  13 +import javax.sip.DialogState;
14 14 import java.util.List;
15 15  
16 16 /**
... ... @@ -18,6 +18,8 @@ import java.util.List;
18 18 */
19 19 public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
20 20  
  21 + private Logger logger = LoggerFactory.getLogger(MobilePositionSubscribeHandlerTask.class);
  22 +
21 23 private IRedisCatchStorage redisCatchStorage;
22 24 private IVideoManagerStorage storager;
23 25 private ISIPCommanderForPlatform sipCommanderForPlatform;
... ... @@ -26,8 +28,6 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
26 28 private String sn;
27 29 private String key;
28 30  
29   - private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
30   -
31 31 public MobilePositionSubscribeHandlerTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorage storager, String platformId, String sn, String key, SubscribeHolder subscribeInfo) {
32 32 this.redisCatchStorage = redisCatchStorage;
33 33 this.storager = storager;
... ... @@ -38,40 +38,51 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
38 38 this.subscribeHolder = subscribeInfo;
39 39 }
40 40  
  41 + @Async
41 42 @Override
42 43 public void run() {
43 44  
  45 + logger.info("执行MobilePositionSubscribeHandlerTask");
44 46 SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platformId);
45   -
46 47 if (subscribe != null) {
47 48 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
48   - if (parentPlatform == null || parentPlatform.isStatus()) {
49   - // TODO 暂时只处理视频流的回复,后续增加对国标设备的支持
50   - List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platformId);
51   - if (gbStreams.size() > 0) {
52   - for (GbStream gbStream : gbStreams) {
53   - String gbId = gbStream.getGbId();
54   - GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
55   - if (gpsMsgInfo != null) {
56   - // 发送GPS消息
57   - sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);
58   - }else {
59   - // 没有在redis找到新的消息就使用数据库的消息
60   - gpsMsgInfo = new GPSMsgInfo();
61   - gpsMsgInfo.setId(gbId);
62   - gpsMsgInfo.setLat(gbStream.getLongitude());
63   - gpsMsgInfo.setLng(gbStream.getLongitude());
64   - // 发送GPS消息
65   - sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);
66   - }
  49 + if (parentPlatform == null ) {
  50 + logger.info("发送订阅时未找到平台信息:{}", platformId);
  51 + return;
  52 + }
  53 + if (!parentPlatform.isStatus()) {
  54 + logger.info("发送订阅时发现平台已经离线:{}", platformId);
  55 + return;
  56 + }
  57 + // TODO 暂时只处理视频流的回复,后续增加对国标设备的支持
  58 + List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platformId);
  59 + if (gbStreams.size() == 0) {
  60 + logger.info("发送订阅时发现平台已经没有关联的直播流:{}", platformId);
  61 + return;
  62 + }
  63 + for (GbStream gbStream : gbStreams) {
  64 + String gbId = gbStream.getGbId();
  65 + GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
  66 + if (gpsMsgInfo != null) { // 无最新位置不发送
  67 + // 经纬度都为0不发送
  68 + if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) {
  69 + continue;
67 70 }
  71 + // 发送GPS消息
  72 + sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);
68 73 }
69 74 }
70 75 }
  76 + logger.info("结束执行MobilePositionSubscribeHandlerTask");
71 77 }
72 78  
73 79 @Override
74 80 public void stop() {
75 81  
76 82 }
  83 +
  84 + @Override
  85 + public DialogState getDialogState() {
  86 + return null;
  87 + }
77 88 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
... ... @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
6 6 import org.dom4j.Element;
7 7 import org.slf4j.Logger;
8 8 import org.slf4j.LoggerFactory;
  9 +import org.springframework.scheduling.annotation.Async;
9 10  
10 11 import javax.sip.Dialog;
11 12 import javax.sip.DialogState;
... ... @@ -25,6 +26,7 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
25 26 this.sipCommander = sipCommander;
26 27 }
27 28  
  29 + @Async
28 30 @Override
29 31 public void run() {
30 32 sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> {
... ... @@ -74,4 +76,9 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
74 76 });
75 77 }
76 78 }
  79 + @Override
  80 + public DialogState getDialogState() {
  81 + if (dialog == null) return null;
  82 + return dialog.getState();
  83 + }
77 84 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
... ... @@ -1566,17 +1566,28 @@ public class SIPCommander implements ISIPCommander {
1566 1566 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1567 1567 cmdXml.append("</Query>\r\n");
1568 1568  
1569   - String tm = Long.toString(System.currentTimeMillis());
1570 1569  
1571   - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
1572   - : udpSipProvider.getNewCallId();
  1570 + Request request;
  1571 + if (dialog != null) {
  1572 + logger.info("发送目录订阅消息时 dialog的状态为: {}", dialog.getState());
  1573 + request = dialog.createRequest(Request.SUBSCRIBE);
  1574 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  1575 + request.setContent(cmdXml.toString(), contentTypeHeader);
  1576 + ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForMobilePosition());
  1577 + request.addHeader(expireHeader);
  1578 + }else {
  1579 + String tm = Long.toString(System.currentTimeMillis());
1573 1580  
1574   - // 有效时间默认为60秒以上
1575   - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
1576   - "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
1577   - callIdHeader);
1578   - transmitRequest(device, request, errorEvent, okEvent);
  1581 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1582 + : udpSipProvider.getNewCallId();
  1583 +
  1584 + // 有效时间默认为60秒以上
  1585 + request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
  1586 + "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
  1587 + callIdHeader);
1579 1588  
  1589 + }
  1590 + transmitRequest(device, request, errorEvent, okEvent);
1580 1591 return true;
1581 1592  
1582 1593 } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
... ... @@ -405,7 +405,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
405 405 CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
406 406 : udpSipProvider.getNewCallId();
407 407 callIdHeader.setCallId(subscribeInfo.getCallId());
408   - logger.info("[发送Notify-MobilePosition] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat());
  408 + logger.info("[发送 移动位置订阅] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat());
409 409 sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> {
410 410 logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg);
411 411 }, null);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
... ... @@ -146,7 +146,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
146 146 } else {
147 147 mobilePosition.setAltitude(0.0);
148 148 }
149   - logger.info("[收到Notify-MobilePosition]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(),
  149 + logger.info("[收到 移动位置订阅]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(),
150 150 mobilePosition.getLongitude(), mobilePosition.getLatitude());
151 151 mobilePosition.setReportSource("Mobile Position");
152 152 BaiduPoint bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude()));
... ... @@ -281,7 +281,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
281 281 Element eventElement = itemDevice.element("Event");
282 282 DeviceChannel channel = XmlUtil.channelContentHander(itemDevice);
283 283 channel.setDeviceId(device.getDeviceId());
284   - logger.info("[收到Notify-Catalog]:{}/{}", device.getDeviceId(), channel.getChannelId());
  284 + logger.info("[收到 目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
285 285 switch (eventElement.getText().toUpperCase()) {
286 286 case CatalogEvent.ON: // 上线
287 287 logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
... ... @@ -150,7 +150,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
150 150 }
151 151 String sn = XmlUtil.getText(rootElement, "SN");
152 152 String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_MobilePosition_" + platformId;
153   - logger.info("[notify-MobilePosition]: {}", platformId);
  153 + logger.info("[回复 移动位置订阅]: {}", platformId);
154 154 StringBuilder resultXml = new StringBuilder(200);
155 155 resultXml.append("<?xml version=\"1.0\" ?>\r\n")
156 156 .append("<Response>\r\n")
... ... @@ -161,12 +161,21 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
161 161 .append("</Response>\r\n");
162 162  
163 163 if (subscribeInfo.getExpires() > 0) {
164   - if (subscribeHolder.getMobilePositionSubscribe(platformId) != null) {
165   - dynamicTask.stop(key);
  164 +
  165 + if (subscribeHolder.getMobilePositionSubscribe(platformId) == null ) {
  166 + String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔
  167 + subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
  168 + dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key, subscribeHolder), Integer.parseInt(interval));
  169 + }else {
  170 + if (subscribeHolder.getMobilePositionSubscribe(platformId).getDialog() != null
  171 + && subscribeHolder.getMobilePositionSubscribe(platformId).getDialog().getState() != null
  172 + && !subscribeHolder.getMobilePositionSubscribe(platformId).getDialog().getState().equals(DialogState.CONFIRMED)) {
  173 + dynamicTask.stop(key);
  174 + String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔
  175 + subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
  176 + dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key, subscribeHolder), Integer.parseInt(interval));
  177 + }
166 178 }
167   - String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔
168   - dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key, subscribeHolder), Integer.parseInt(interval) -1 );
169   - subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
170 179 }else if (subscribeInfo.getExpires() == 0) {
171 180 dynamicTask.stop(key);
172 181 subscribeHolder.removeMobilePositionSubscribe(platformId);
... ... @@ -203,7 +212,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
203 212 }
204 213 String sn = XmlUtil.getText(rootElement, "SN");
205 214 String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_Catalog_" + platformId;
206   - logger.info("[notify-Catalog]: {}", platformId);
  215 + logger.info("[回复 目录订阅]: {}/{}", platformId, deviceID);
207 216 StringBuilder resultXml = new StringBuilder(200);
208 217 resultXml.append("<?xml version=\"1.0\" ?>\r\n")
209 218 .append("<Response>\r\n")
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
... ... @@ -4,8 +4,13 @@ import com.alibaba.fastjson.JSONObject;
4 4 import com.genersoft.iot.vmp.conf.DynamicTask;
5 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  7 +import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
7 8 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
8 9 import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
  10 +import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
  11 +import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
  12 +import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask;
  13 +import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
9 14 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
10 15 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
11 16 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
... ... @@ -29,9 +34,8 @@ import org.springframework.util.StringUtils;
29 34 import org.springframework.web.bind.annotation.*;
30 35 import org.springframework.web.context.request.async.DeferredResult;
31 36  
32   -import java.util.List;
33   -import java.util.Set;
34   -import java.util.UUID;
  37 +import javax.sip.DialogState;
  38 +import java.util.*;
35 39  
36 40 @Api(tags = "国标设备查询", value = "国标设备查询")
37 41 @SuppressWarnings("rawtypes")
... ... @@ -63,6 +67,9 @@ public class DeviceQuery {
63 67 @Autowired
64 68 private DynamicTask dynamicTask;
65 69  
  70 + @Autowired
  71 + private SubscribeHolder subscribeHolder;
  72 +
66 73 /**
67 74 * 使用ID查询国标设备
68 75 * @param deviceId 国标ID
... ... @@ -469,4 +476,29 @@ public class DeviceQuery {
469 476 }
470 477 return wvpResult;
471 478 }
  479 +
  480 + @GetMapping("/{deviceId}/subscribe_info")
  481 + @ApiOperation(value = "获取设备的订阅状态", notes = "获取设备的订阅状态")
  482 + public WVPResult<Map<String, String>> getSubscribeInfo(@PathVariable String deviceId) {
  483 + Set<String> allKeys = dynamicTask.getAllKeys();
  484 + Map<String, String> dialogStateMap = new HashMap<>();
  485 + for (String key : allKeys) {
  486 + if (key.startsWith(deviceId)) {
  487 + ISubscribeTask subscribeTask = (ISubscribeTask)dynamicTask.get(key);
  488 + DialogState dialogState = subscribeTask.getDialogState();
  489 + if (dialogState == null) {
  490 + continue;
  491 + }
  492 + if (subscribeTask instanceof CatalogSubscribeTask) {
  493 + dialogStateMap.put("catalog", dialogState.toString());
  494 + }else if (subscribeTask instanceof MobilePositionSubscribeTask) {
  495 + dialogStateMap.put("mobilePosition", dialogState.toString());
  496 + }
  497 + }
  498 + }
  499 + WVPResult<Map<String, String>> wvpResult = new WVPResult<>();
  500 + wvpResult.setCode(0);
  501 + wvpResult.setData(dialogStateMap);
  502 + return wvpResult;
  503 + }
472 504 }
... ...