Commit f10b458fc919fbcadc4936bf3a7886088e20ac71
1 parent
f1c8ca60
优化订阅信息的发送与取消订阅
Showing
14 changed files
with
174 additions
and
56 deletions
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; | |
| 3 | 4 | import org.springframework.beans.factory.annotation.Autowired; |
| 4 | 5 | import org.springframework.context.annotation.Bean; |
| 5 | 6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
| ... | ... | @@ -21,6 +22,7 @@ public class DynamicTask { |
| 21 | 22 | private ThreadPoolTaskScheduler threadPoolTaskScheduler; |
| 22 | 23 | |
| 23 | 24 | private Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>(); |
| 25 | + private Map<String, Runnable> runnableMap = new ConcurrentHashMap<>(); | |
| 24 | 26 | |
| 25 | 27 | @Bean |
| 26 | 28 | public ThreadPoolTaskScheduler threadPoolTaskScheduler() { |
| ... | ... | @@ -34,12 +36,12 @@ public class DynamicTask { |
| 34 | 36 | * @param cycleForCatalog 间隔 |
| 35 | 37 | * @return |
| 36 | 38 | */ |
| 37 | - public String startCron(String key, Runnable task, int cycleForCatalog) { | |
| 39 | + public void startCron(String key, Runnable task, int cycleForCatalog) { | |
| 38 | 40 | stop(key); |
| 39 | 41 | // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 |
| 40 | 42 | ScheduledFuture future = threadPoolTaskScheduler.scheduleWithFixedDelay(task, cycleForCatalog * 1000L); |
| 41 | 43 | futureMap.put(key, future); |
| 42 | - return "startCron"; | |
| 44 | + runnableMap.put(key, task); | |
| 43 | 45 | } |
| 44 | 46 | |
| 45 | 47 | /** |
| ... | ... | @@ -49,18 +51,22 @@ public class DynamicTask { |
| 49 | 51 | * @param delay 延时 /毫秒 |
| 50 | 52 | * @return |
| 51 | 53 | */ |
| 52 | - public String startDelay(String key, Runnable task, int delay) { | |
| 54 | + public void startDelay(String key, Runnable task, int delay) { | |
| 53 | 55 | stop(key); |
| 54 | 56 | Date starTime = new Date(System.currentTimeMillis() + delay); |
| 55 | 57 | // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 |
| 56 | 58 | ScheduledFuture future = threadPoolTaskScheduler.schedule(task, starTime); |
| 57 | 59 | futureMap.put(key, future); |
| 58 | - return "startCron"; | |
| 59 | 60 | } |
| 60 | 61 | |
| 61 | 62 | public void stop(String key) { |
| 62 | 63 | if (futureMap.get(key) != null && !futureMap.get(key).isCancelled()) { |
| 63 | 64 | futureMap.get(key).cancel(true); |
| 65 | + Runnable runnable = runnableMap.get(key); | |
| 66 | + if (runnable instanceof ISubscribeTask) { | |
| 67 | + ISubscribeTask subscribeTask = (ISubscribeTask) runnable; | |
| 68 | + subscribeTask.stop(); | |
| 69 | + } | |
| 64 | 70 | } |
| 65 | 71 | } |
| 66 | 72 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/runner/SipDeviceRunner.java
| ... | ... | @@ -14,7 +14,7 @@ import java.util.List; |
| 14 | 14 | |
| 15 | 15 | |
| 16 | 16 | /** |
| 17 | - * 系统启动时控制设备离线 | |
| 17 | + * 系统启动时控制设备 | |
| 18 | 18 | */ |
| 19 | 19 | @Component |
| 20 | 20 | @Order(value=4) |
| ... | ... | @@ -41,10 +41,14 @@ public class SipDeviceRunner implements CommandLineRunner { |
| 41 | 41 | for (String deviceId : onlineForAll) { |
| 42 | 42 | storager.online(deviceId); |
| 43 | 43 | Device device = redisCatchStorage.getDevice(deviceId); |
| 44 | - if (device != null && device.getSubscribeCycleForCatalog() > 0) { | |
| 45 | - // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | |
| 46 | - deviceService.addCatalogSubscribe(device); | |
| 47 | - deviceService.addMobilePositionSubscribe(device); | |
| 44 | + if (device != null ) { | |
| 45 | + if (device.getSubscribeCycleForCatalog() > 0) { | |
| 46 | + // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | |
| 47 | + deviceService.addCatalogSubscribe(device); | |
| 48 | + } | |
| 49 | + if (device.getSubscribeCycleForMobilePosition() > 0) { | |
| 50 | + deviceService.addMobilePositionSubscribe(device); | |
| 51 | + } | |
| 48 | 52 | } |
| 49 | 53 | } |
| 50 | 54 | // 重置cseq计数 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
0 → 100644
src/main/java/com/genersoft/iot/vmp/service/bean/CatalogSubscribeTask.java renamed to src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
| 1 | -package com.genersoft.iot.vmp.service.bean; | |
| 1 | +package com.genersoft.iot.vmp.gb28181.task.impl; | |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 4 | +import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; | |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 5 | -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; | |
| 6 | -import org.dom4j.DocumentException; | |
| 7 | -import org.dom4j.Element; | |
| 8 | 6 | import org.slf4j.Logger; |
| 9 | 7 | import org.slf4j.LoggerFactory; |
| 10 | 8 | |
| 9 | +import javax.sip.Dialog; | |
| 10 | +import javax.sip.DialogState; | |
| 11 | 11 | import javax.sip.ResponseEvent; |
| 12 | 12 | |
| 13 | 13 | /** |
| 14 | 14 | * 目录订阅任务 |
| 15 | 15 | */ |
| 16 | -public class CatalogSubscribeTask implements Runnable{ | |
| 16 | +public class CatalogSubscribeTask implements ISubscribeTask { | |
| 17 | 17 | private final Logger logger = LoggerFactory.getLogger(CatalogSubscribeTask.class); |
| 18 | - private Device device; | |
| 19 | - private ISIPCommander sipCommander; | |
| 18 | + private Device device; | |
| 19 | + private final ISIPCommander sipCommander; | |
| 20 | + private Dialog dialog; | |
| 20 | 21 | |
| 21 | 22 | public CatalogSubscribeTask(Device device, ISIPCommander sipCommander) { |
| 22 | 23 | this.device = device; |
| ... | ... | @@ -25,7 +26,10 @@ public class CatalogSubscribeTask implements Runnable{ |
| 25 | 26 | |
| 26 | 27 | @Override |
| 27 | 28 | public void run() { |
| 28 | - sipCommander.catalogSubscribe(device, eventResult -> { | |
| 29 | + sipCommander.catalogSubscribe(device, dialog, eventResult -> { | |
| 30 | + if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) { | |
| 31 | + dialog = eventResult.dialog; | |
| 32 | + } | |
| 29 | 33 | ResponseEvent event = (ResponseEvent) eventResult.event; |
| 30 | 34 | if (event.getResponse().getRawContent() != null) { |
| 31 | 35 | // 成功 |
| ... | ... | @@ -35,8 +39,37 @@ public class CatalogSubscribeTask implements Runnable{ |
| 35 | 39 | logger.info("[目录订阅]成功: {}", device.getDeviceId()); |
| 36 | 40 | } |
| 37 | 41 | },eventResult -> { |
| 42 | + dialog = null; | |
| 38 | 43 | // 失败 |
| 39 | 44 | logger.warn("[目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); |
| 40 | 45 | }); |
| 41 | 46 | } |
| 47 | + | |
| 48 | + @Override | |
| 49 | + public void stop() { | |
| 50 | + /** | |
| 51 | + * dialog 的各个状态 | |
| 52 | + * EARLY-> Early state状态-初始请求发送以后,收到了一个临时响应消息 | |
| 53 | + * CONFIRMED-> Confirmed Dialog状态-已确认 | |
| 54 | + * COMPLETED-> Completed Dialog状态-已完成 | |
| 55 | + * TERMINATED-> Terminated Dialog状态-终止 | |
| 56 | + */ | |
| 57 | + logger.info("取消目录订阅时dialog状态为{}", DialogState.CONFIRMED); | |
| 58 | + if (dialog != null && dialog.getState().equals(DialogState.CONFIRMED)) { | |
| 59 | + device.setSubscribeCycleForCatalog(0); | |
| 60 | + sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> { | |
| 61 | + ResponseEvent event = (ResponseEvent) eventResult.event; | |
| 62 | + if (event.getResponse().getRawContent() != null) { | |
| 63 | + // 成功 | |
| 64 | + logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId()); | |
| 65 | + }else { | |
| 66 | + // 成功 | |
| 67 | + logger.info("[取消目录订阅订阅]成功: {}", device.getDeviceId()); | |
| 68 | + } | |
| 69 | + },eventResult -> { | |
| 70 | + // 失败 | |
| 71 | + logger.warn("[取消目录订阅订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); | |
| 72 | + }); | |
| 73 | + } | |
| 74 | + } | |
| 42 | 75 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/task/GPSSubscribeTask.java renamed to src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
| 1 | -package com.genersoft.iot.vmp.gb28181.task; | |
| 1 | +package com.genersoft.iot.vmp.gb28181.task.impl; | |
| 2 | 2 | |
| 3 | -import com.alibaba.fastjson.JSON; | |
| 4 | 3 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 5 | 4 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 6 | 5 | import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; |
| 7 | 6 | import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; |
| 7 | +import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; | |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 9 | 9 | import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; |
| 10 | 10 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| ... | ... | @@ -13,7 +13,10 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 13 | 13 | import java.text.SimpleDateFormat; |
| 14 | 14 | import java.util.List; |
| 15 | 15 | |
| 16 | -public class GPSSubscribeTask implements Runnable{ | |
| 16 | +/** | |
| 17 | + * 向已经订阅(移动位置)的上级发送MobilePosition消息 | |
| 18 | + */ | |
| 19 | +public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { | |
| 17 | 20 | |
| 18 | 21 | private IRedisCatchStorage redisCatchStorage; |
| 19 | 22 | private IVideoManagerStorage storager; |
| ... | ... | @@ -25,7 +28,7 @@ public class GPSSubscribeTask implements Runnable{ |
| 25 | 28 | |
| 26 | 29 | private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| 27 | 30 | |
| 28 | - public GPSSubscribeTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorage storager, String platformId, String sn, String key, SubscribeHolder subscribeInfo) { | |
| 31 | + public MobilePositionSubscribeHandlerTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorage storager, String platformId, String sn, String key, SubscribeHolder subscribeInfo) { | |
| 29 | 32 | this.redisCatchStorage = redisCatchStorage; |
| 30 | 33 | this.storager = storager; |
| 31 | 34 | this.platformId = platformId; |
| ... | ... | @@ -66,4 +69,9 @@ public class GPSSubscribeTask implements Runnable{ |
| 66 | 69 | } |
| 67 | 70 | } |
| 68 | 71 | } |
| 72 | + | |
| 73 | + @Override | |
| 74 | + public void stop() { | |
| 75 | + | |
| 76 | + } | |
| 69 | 77 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/bean/MobilePositionSubscribeTask.java renamed to src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
| 1 | -package com.genersoft.iot.vmp.service.bean; | |
| 1 | +package com.genersoft.iot.vmp.gb28181.task.impl; | |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 4 | +import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; | |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 5 | 6 | import org.dom4j.Element; |
| 6 | 7 | import org.slf4j.Logger; |
| 7 | 8 | import org.slf4j.LoggerFactory; |
| 8 | 9 | |
| 10 | +import javax.sip.Dialog; | |
| 11 | +import javax.sip.DialogState; | |
| 9 | 12 | import javax.sip.ResponseEvent; |
| 10 | 13 | |
| 11 | -public class MobilePositionSubscribeTask implements Runnable{ | |
| 14 | +/** | |
| 15 | + * 移动位置订阅的定时更新 | |
| 16 | + */ | |
| 17 | +public class MobilePositionSubscribeTask implements ISubscribeTask { | |
| 12 | 18 | private final Logger logger = LoggerFactory.getLogger(MobilePositionSubscribeTask.class); |
| 13 | 19 | private Device device; |
| 14 | 20 | private ISIPCommander sipCommander; |
| 21 | + private Dialog dialog; | |
| 15 | 22 | |
| 16 | 23 | public MobilePositionSubscribeTask(Device device, ISIPCommander sipCommander) { |
| 17 | 24 | this.device = device; |
| ... | ... | @@ -20,9 +27,11 @@ public class MobilePositionSubscribeTask implements Runnable{ |
| 20 | 27 | |
| 21 | 28 | @Override |
| 22 | 29 | public void run() { |
| 23 | - sipCommander.mobilePositionSubscribe(device, eventResult -> { | |
| 30 | + sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> { | |
| 31 | + if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) { | |
| 32 | + dialog = eventResult.dialog; | |
| 33 | + } | |
| 24 | 34 | ResponseEvent event = (ResponseEvent) eventResult.event; |
| 25 | - Element rootElement = null; | |
| 26 | 35 | if (event.getResponse().getRawContent() != null) { |
| 27 | 36 | // 成功 |
| 28 | 37 | logger.info("[移动位置订阅]成功: {}", device.getDeviceId()); |
| ... | ... | @@ -31,8 +40,38 @@ public class MobilePositionSubscribeTask implements Runnable{ |
| 31 | 40 | logger.info("[移动位置订阅]成功: {}", device.getDeviceId()); |
| 32 | 41 | } |
| 33 | 42 | },eventResult -> { |
| 43 | + dialog = null; | |
| 34 | 44 | // 失败 |
| 35 | 45 | logger.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); |
| 36 | 46 | }); |
| 47 | + | |
| 48 | + } | |
| 49 | + | |
| 50 | + @Override | |
| 51 | + public void stop() { | |
| 52 | + /** | |
| 53 | + * dialog 的各个状态 | |
| 54 | + * EARLY-> Early state状态-初始请求发送以后,收到了一个临时响应消息 | |
| 55 | + * CONFIRMED-> Confirmed Dialog状态-已确认 | |
| 56 | + * COMPLETED-> Completed Dialog状态-已完成 | |
| 57 | + * TERMINATED-> Terminated Dialog状态-终止 | |
| 58 | + */ | |
| 59 | + logger.info("取消移动订阅时dialog状态为{}", dialog.getState()); | |
| 60 | + if (dialog != null && dialog.getState().equals(DialogState.CONFIRMED)) { | |
| 61 | + device.setSubscribeCycleForMobilePosition(0); | |
| 62 | + sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> { | |
| 63 | + ResponseEvent event = (ResponseEvent) eventResult.event; | |
| 64 | + if (event.getResponse().getRawContent() != null) { | |
| 65 | + // 成功 | |
| 66 | + logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); | |
| 67 | + }else { | |
| 68 | + // 成功 | |
| 69 | + logger.info("[取消移动位置订阅]成功: {}", device.getDeviceId()); | |
| 70 | + } | |
| 71 | + },eventResult -> { | |
| 72 | + // 失败 | |
| 73 | + logger.warn("[取消移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); | |
| 74 | + }); | |
| 75 | + } | |
| 37 | 76 | } |
| 38 | 77 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
| ... | ... | @@ -8,6 +8,8 @@ import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| 8 | 8 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 9 | 9 | import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 10 | 10 | |
| 11 | +import javax.sip.Dialog; | |
| 12 | + | |
| 11 | 13 | /** |
| 12 | 14 | * @description:设备能力接口,用于定义设备的控制、查询能力 |
| 13 | 15 | * @author: swwheihei |
| ... | ... | @@ -304,7 +306,7 @@ public interface ISIPCommander { |
| 304 | 306 | * @param device 视频设备 |
| 305 | 307 | * @return true = 命令发送成功 |
| 306 | 308 | */ |
| 307 | - boolean mobilePositionSubscribe(Device device, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent); | |
| 309 | + boolean mobilePositionSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent); | |
| 308 | 310 | |
| 309 | 311 | /** |
| 310 | 312 | * 订阅、取消订阅报警信息 |
| ... | ... | @@ -324,7 +326,7 @@ public interface ISIPCommander { |
| 324 | 326 | * @param device 视频设备 |
| 325 | 327 | * @return true = 命令发送成功 |
| 326 | 328 | */ |
| 327 | - boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent); | |
| 329 | + boolean catalogSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent); | |
| 328 | 330 | |
| 329 | 331 | /** |
| 330 | 332 | * 拉框控制命令 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -36,6 +36,8 @@ import org.springframework.util.StringUtils; |
| 36 | 36 | import javax.sip.*; |
| 37 | 37 | import javax.sip.address.SipURI; |
| 38 | 38 | import javax.sip.header.CallIdHeader; |
| 39 | +import javax.sip.header.ContentTypeHeader; | |
| 40 | +import javax.sip.header.ExpiresHeader; | |
| 39 | 41 | import javax.sip.header.ViaHeader; |
| 40 | 42 | import javax.sip.message.Request; |
| 41 | 43 | import java.lang.reflect.Field; |
| ... | ... | @@ -57,6 +59,9 @@ public class SIPCommander implements ISIPCommander { |
| 57 | 59 | private SipConfig sipConfig; |
| 58 | 60 | |
| 59 | 61 | @Autowired |
| 62 | + private SipFactory sipFactory; | |
| 63 | + | |
| 64 | + @Autowired | |
| 60 | 65 | @Qualifier(value="tcpSipProvider") |
| 61 | 66 | private SipProviderImpl tcpSipProvider; |
| 62 | 67 | |
| ... | ... | @@ -1453,7 +1458,7 @@ public class SIPCommander implements ISIPCommander { |
| 1453 | 1458 | * @param device 视频设备 |
| 1454 | 1459 | * @return true = 命令发送成功 |
| 1455 | 1460 | */ |
| 1456 | - public boolean mobilePositionSubscribe(Device device, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) { | |
| 1461 | + public boolean mobilePositionSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) { | |
| 1457 | 1462 | try { |
| 1458 | 1463 | StringBuffer subscribePostitionXml = new StringBuffer(200); |
| 1459 | 1464 | String charset = device.getCharset(); |
| ... | ... | @@ -1467,12 +1472,20 @@ public class SIPCommander implements ISIPCommander { |
| 1467 | 1472 | } |
| 1468 | 1473 | subscribePostitionXml.append("</Query>\r\n"); |
| 1469 | 1474 | |
| 1470 | - String tm = Long.toString(System.currentTimeMillis()); | |
| 1471 | - | |
| 1472 | - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() | |
| 1473 | - : udpSipProvider.getNewCallId(); | |
| 1474 | - | |
| 1475 | - Request request = headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForMobilePosition(), "presence" ,callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); | |
| 1475 | + Request request; | |
| 1476 | + if (dialog != null) { | |
| 1477 | + logger.info("发送移动位置订阅消息时 dialog的状态为: {}", dialog.getState()); | |
| 1478 | + request = dialog.createRequest(Request.SUBSCRIBE); | |
| 1479 | + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); | |
| 1480 | + request.setContent(subscribePostitionXml.toString(), contentTypeHeader); | |
| 1481 | + ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForMobilePosition()); | |
| 1482 | + request.addHeader(expireHeader); | |
| 1483 | + }else { | |
| 1484 | + String tm = Long.toString(System.currentTimeMillis()); | |
| 1485 | + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() | |
| 1486 | + : udpSipProvider.getNewCallId(); | |
| 1487 | + request = headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForMobilePosition(), "presence" ,callIdHeader); //Position;id=" + tm.substring(tm.length() - 4)); | |
| 1488 | + } | |
| 1476 | 1489 | transmitRequest(device, request, errorEvent, okEvent); |
| 1477 | 1490 | |
| 1478 | 1491 | return true; |
| ... | ... | @@ -1542,7 +1555,7 @@ public class SIPCommander implements ISIPCommander { |
| 1542 | 1555 | } |
| 1543 | 1556 | |
| 1544 | 1557 | @Override |
| 1545 | - public boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { | |
| 1558 | + public boolean catalogSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { | |
| 1546 | 1559 | try { |
| 1547 | 1560 | StringBuffer cmdXml = new StringBuffer(200); |
| 1548 | 1561 | String charset = device.getCharset(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
| ... | ... | @@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.gb28181.bean.CmdType; |
| 7 | 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; |
| 10 | -import com.genersoft.iot.vmp.gb28181.task.GPSSubscribeTask; | |
| 10 | +import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask; | |
| 11 | 11 | import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; |
| 12 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 13 | 13 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; |
| ... | ... | @@ -147,7 +147,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 147 | 147 | } |
| 148 | 148 | String sn = XmlUtil.getText(rootElement, "SN"); |
| 149 | 149 | String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_MobilePosition_" + platformId; |
| 150 | - logger.info("接收到{}的MobilePosition订阅", platformId); | |
| 150 | + logger.info("[notify-MobilePosition]: {}", platformId); | |
| 151 | 151 | StringBuilder resultXml = new StringBuilder(200); |
| 152 | 152 | resultXml.append("<?xml version=\"1.0\" ?>\r\n") |
| 153 | 153 | .append("<Response>\r\n") |
| ... | ... | @@ -162,7 +162,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 162 | 162 | dynamicTask.stop(key); |
| 163 | 163 | } |
| 164 | 164 | String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔 |
| 165 | - dynamicTask.startCron(key, new GPSSubscribeTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key, subscribeHolder), Integer.parseInt(interval)); | |
| 165 | + dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key, subscribeHolder), Integer.parseInt(interval) -1 ); | |
| 166 | 166 | subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo); |
| 167 | 167 | }else if (subscribeInfo.getExpires() == 0) { |
| 168 | 168 | dynamicTask.stop(key); |
| ... | ... | @@ -200,7 +200,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 200 | 200 | } |
| 201 | 201 | String sn = XmlUtil.getText(rootElement, "SN"); |
| 202 | 202 | String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_Catalog_" + platformId; |
| 203 | - logger.info("接收到{}的Catalog订阅", platformId); | |
| 203 | + logger.info("[notify-Catalog]: {}", platformId); | |
| 204 | 204 | StringBuilder resultXml = new StringBuilder(200); |
| 205 | 205 | resultXml.append("<?xml version=\"1.0\" ?>\r\n") |
| 206 | 206 | .append("<Response>\r\n") | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
| ... | ... | @@ -81,7 +81,7 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract { |
| 81 | 81 | } |
| 82 | 82 | requestURI.setPort(event.getRemotePort()); |
| 83 | 83 | reqAck.setRequestURI(requestURI); |
| 84 | - logger.info("向 " + event.getRemoteIpAddress() + ":" + event.getRemotePort() + "回复ack"); | |
| 84 | + logger.info("[回复ack] {}-> {}:{} ",requestURI, event.getRemoteIpAddress(), event.getRemotePort()); | |
| 85 | 85 | |
| 86 | 86 | dialog.sendAck(reqAck); |
| 87 | 87 | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
| ... | ... | @@ -82,9 +82,14 @@ public class ZLMRTPServerFactory { |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | public int createRTPServer(MediaServerItem mediaServerItem, String streamId) { |
| 85 | - | |
| 86 | - Map<String, Object> param = new HashMap<>(); | |
| 87 | 85 | int result = -1; |
| 86 | + // 查询此rtp server 是否已经存在 | |
| 87 | + JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId); | |
| 88 | + if (rtpInfo.getInteger("code ") == 0 && rtpInfo.getBoolean("exist")) { | |
| 89 | + result = rtpInfo.getInteger("local_port"); | |
| 90 | + return result; | |
| 91 | + } | |
| 92 | + Map<String, Object> param = new HashMap<>(); | |
| 88 | 93 | // 推流端口设置0则使用随机端口 |
| 89 | 94 | param.put("enable_tcp", 1); |
| 90 | 95 | param.put("stream_id", streamId); |
| ... | ... | @@ -301,7 +306,7 @@ public class ZLMRTPServerFactory { |
| 301 | 306 | result= true; |
| 302 | 307 | logger.info("停止RTP推流成功"); |
| 303 | 308 | } else { |
| 304 | - logger.error("RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"),JSONObject.toJSON(param)); | |
| 309 | + logger.error("停止RTP推流失败: {}, 参数:{}",jsonObject.getString("msg"),JSONObject.toJSON(param)); | |
| 305 | 310 | } |
| 306 | 311 | return result; |
| 307 | 312 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| ... | ... | @@ -4,8 +4,8 @@ import com.genersoft.iot.vmp.conf.DynamicTask; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 6 | 6 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 7 | -import com.genersoft.iot.vmp.service.bean.CatalogSubscribeTask; | |
| 8 | -import com.genersoft.iot.vmp.service.bean.MobilePositionSubscribeTask; | |
| 7 | +import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; | |
| 9 | 9 | import org.slf4j.Logger; |
| 10 | 10 | import org.slf4j.LoggerFactory; |
| 11 | 11 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -42,7 +42,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 42 | 42 | int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog(); |
| 43 | 43 | // 设置最小值为30 |
| 44 | 44 | subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30); |
| 45 | - dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, subscribeCycleForCatalog - 5); | |
| 45 | + dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, subscribeCycleForCatalog); | |
| 46 | 46 | return true; |
| 47 | 47 | } |
| 48 | 48 | |
| ... | ... | @@ -53,8 +53,6 @@ public class DeviceServiceImpl implements IDeviceService { |
| 53 | 53 | } |
| 54 | 54 | logger.info("移除目录订阅: {}", device.getDeviceId()); |
| 55 | 55 | dynamicTask.stop(device.getDeviceId() + "catalog"); |
| 56 | - device.setSubscribeCycleForCatalog(0); | |
| 57 | - sipCommander.catalogSubscribe(device, null, null); | |
| 58 | 56 | return true; |
| 59 | 57 | } |
| 60 | 58 | |
| ... | ... | @@ -75,7 +73,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 75 | 73 | int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog(); |
| 76 | 74 | // 设置最小值为30 |
| 77 | 75 | subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30); |
| 78 | - dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog - 5); | |
| 76 | + dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog -1 ); | |
| 79 | 77 | return true; |
| 80 | 78 | } |
| 81 | 79 | |
| ... | ... | @@ -86,8 +84,6 @@ public class DeviceServiceImpl implements IDeviceService { |
| 86 | 84 | } |
| 87 | 85 | logger.info("移除移动位置订阅: {}", device.getDeviceId()); |
| 88 | 86 | dynamicTask.stop(device.getDeviceId() + "mobile_position"); |
| 89 | - device.setSubscribeCycleForCatalog(0); | |
| 90 | - sipCommander.mobilePositionSubscribe(device, null, null); | |
| 91 | 87 | return true; |
| 92 | 88 | } |
| 93 | 89 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
| ... | ... | @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 10 | 10 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 11 | +import com.genersoft.iot.vmp.service.IDeviceService; | |
| 11 | 12 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 12 | 13 | import com.github.pagehelper.util.StringUtil; |
| 13 | 14 | |
| ... | ... | @@ -48,6 +49,9 @@ public class MobilePositionController { |
| 48 | 49 | @Autowired |
| 49 | 50 | private DeferredResultHolder resultHolder; |
| 50 | 51 | |
| 52 | + @Autowired | |
| 53 | + private IDeviceService deviceService; | |
| 54 | + | |
| 51 | 55 | /** |
| 52 | 56 | * 查询历史轨迹 |
| 53 | 57 | * @param deviceId 设备ID |
| ... | ... | @@ -163,7 +167,7 @@ public class MobilePositionController { |
| 163 | 167 | device.setMobilePositionSubmissionInterval(Integer.parseInt(interval)); |
| 164 | 168 | storager.updateDevice(device); |
| 165 | 169 | String result = msg; |
| 166 | - if (cmder.mobilePositionSubscribe(device, null, null)) { | |
| 170 | + if (deviceService.removeMobilePositionSubscribe(device)) { | |
| 167 | 171 | result += ",成功"; |
| 168 | 172 | } else { |
| 169 | 173 | result += ",失败"; | ... | ... |
web_src/src/components/dialog/deviceEdit.vue
| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | @close="close()" |
| 11 | 11 | > |
| 12 | 12 | <div id="shared" style="margin-top: 1rem;margin-right: 100px;"> |
| 13 | - <el-form ref="form" :rules="rules" :model="form" label-width="240px" > | |
| 13 | + <el-form ref="form" :rules="rules" :model="form" label-width="200px" > | |
| 14 | 14 | <el-form-item label="设备编号" > |
| 15 | 15 | <el-input v-model="form.deviceId" disabled></el-input> |
| 16 | 16 | </el-form-item> |
| ... | ... | @@ -36,13 +36,13 @@ |
| 36 | 36 | <el-option key="UTF-8" label="UTF-8" value="utf-8"></el-option> |
| 37 | 37 | </el-select> |
| 38 | 38 | </el-form-item> |
| 39 | - <el-form-item label="目录订阅周期(0为停用订阅)" prop="subscribeCycleForCatalog" > | |
| 39 | + <el-form-item label="目录订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" > | |
| 40 | 40 | <el-input v-model="form.subscribeCycleForCatalog" clearable ></el-input> |
| 41 | 41 | </el-form-item> |
| 42 | - <el-form-item label="移动位置订阅周期(0为停用订阅)" prop="subscribeCycleForCatalog" > | |
| 42 | + <el-form-item label="移动位置订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" > | |
| 43 | 43 | <el-input v-model="form.subscribeCycleForMobilePosition" clearable ></el-input> |
| 44 | 44 | </el-form-item> |
| 45 | - <el-form-item label="移动位置报送间隔" prop="subscribeCycleForCatalog" > | |
| 45 | + <el-form-item v-if="form.subscribeCycleForMobilePosition > 0" label="移动位置报送间隔" prop="subscribeCycleForCatalog" > | |
| 46 | 46 | <el-input v-model="form.mobilePositionSubmissionInterval" clearable ></el-input> |
| 47 | 47 | </el-form-item> |
| 48 | 48 | <el-form-item> |
| ... | ... | @@ -98,6 +98,9 @@ export default { |
| 98 | 98 | onSubmit: function () { |
| 99 | 99 | console.log("onSubmit"); |
| 100 | 100 | console.log(this.form); |
| 101 | + this.form.subscribeCycleForCatalog = this.form.subscribeCycleForCatalog||0 | |
| 102 | + this.form.subscribeCycleForMobilePosition = this.form.subscribeCycleForMobilePosition||0 | |
| 103 | + this.form.mobilePositionSubmissionInterval = this.form.mobilePositionSubmissionInterval||0 | |
| 101 | 104 | this.$axios({ |
| 102 | 105 | method: 'post', |
| 103 | 106 | url:`/api/device/query/device/update/`, | ... | ... |