mk1990
2022-05-06 a2182b5a7ba0ffbba960e774e019a707b5bf26bb
Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0
65个文件已修改
2个文件已添加
1个文件已删除
1190 ■■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/ApiSaveConstant.java 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/ThreadPoolTaskConfig.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarmMethod.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformCycleRegisterEventLister.java 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 147 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 114 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/index.html 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/common/jessibuca.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/devicePosition.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/static/js/mapConfig.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
@@ -7,7 +7,6 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import springfox.documentation.oas.annotations.EnableOpenApi;
src/main/java/com/genersoft/iot/vmp/common/ApiSaveConstant.java
@@ -1,5 +1,9 @@
package com.genersoft.iot.vmp.common;
/**
 * 为API重命名, 方便向数据库记录数据的时候展示
 * @author lin
 */
public class ApiSaveConstant {
    public static String getVal(String key) {
@@ -35,35 +39,47 @@
                                    return "[设备控制] 强制关键帧";
                                case "home_position":
                                    return "[设备控制] 看守位控制";
                                default:
                                    return "";
                            }
                            break;
                            case "query":
                                if (keyItemArray.length <= 5) return null;
                                if (keyItemArray.length <= 5) {
                                    return null;
                                }
                                switch (keyItemArray[4]) {
                                    case "devices":
                                        if (keyItemArray.length < 7) return null;
                                        if (keyItemArray.length < 7) {
                                            return null;
                                        }
                                        switch (keyItemArray[6]) {
                                            case "sync":
                                                return "[设备查询] 同步设备通道";
                                            case "delete":
                                                return "[设备查询] 移除设备";
                                            default:
                                                return "";
                                        }
                                        break;
                                    case "channel":
                                        return "[设备查询] 更新通道信息";
                                    case "transport":
                                        return "[设备查询] 修改数据流传输模式";
                                    default:
                                        return "";
                                }
                                break;
                        default:
                            return "";
                            }
                    break;
                case "gbStream":
                    switch (keyItemArray[3]) {
                        case "del":
                            return "移除通道与国标的关联";
                        case "add":
                            return "添加通道与国标的关联";
                        default:
                            return "";
                    }
                    break;
                case "media":
                    break;
                case "position":
@@ -81,8 +97,9 @@
                            return "向上级平台添加国标通道";
                        case "del_channel_for_gb":
                            return "从上级平台移除国标通道";
                        default:
                            return "";
                    }
                    break;
                case "platform_gb_stream":
                    break;
                case "play":
@@ -97,32 +114,36 @@
                            return "结束转码";
                        case "broadcast":
                            return "语音广播";
                        default:
                            return "";
                    }
                    break;
                case "download":
                    switch (keyItemArray[3]) {
                        case "start":
                            return "开始历史媒体下载";
                        case "stop":
                            return "停止历史媒体下载";
                        default:
                            return "";
                    }
                    break;
                case "playback":
                    switch (keyItemArray[3]) {
                        case "start":
                            return "开始视频回放";
                        case "stop":
                            return "停止视频回放";
                        default:
                            return "";
                    }
                    break;
                case "ptz":
                    switch (keyItemArray[3]) {
                        case "control":
                            return "云台控制";
                        case "front_end_command":
                            return "通用前端控制命令";
                        default:
                            return "";
                    }
                    break;
                case "gb_record":
                    break;
                case "onvif":
@@ -142,16 +163,18 @@
                            return "启用代理";
                        case "stop":
                            return "停用代理";
                        default:
                            return "";
                    }
                    break;
                case "push":
                    switch (keyItemArray[3]) {
                        case "save_to_gb":
                            return "将推流添加到国标";
                        case "remove_form_gb":
                            return "将推流移出到国标";
                        default:
                            return "";
                    }
                    break;
                case "user":
                    switch (keyItemArray[3]) {
                        case "login":
@@ -162,8 +185,11 @@
                            return "添加用户";
                        case "delete":
                            return "删除用户";
                        default:
                            return "";
                    }
                    break;
                default:
                    return "";
            }
        }
        return null;
src/main/java/com/genersoft/iot/vmp/conf/ThreadPoolTaskConfig.java
@@ -7,6 +7,10 @@
import java.util.concurrent.ThreadPoolExecutor;
/**
 *  ThreadPoolTask 配置类
 * @author lin
 */
@Configuration
@EnableAsync(proxyTargetClass = true)
public class ThreadPoolTaskConfig {
@@ -40,6 +44,10 @@
     */
    private static final String threadNamePrefix = "wvp-";
    /**
     *
     * @return
     */
    @Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.conf;
import io.swagger.models.auth.In;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@@ -19,7 +20,7 @@
    private Boolean seniorSdp = Boolean.FALSE;
    private Long playTimeout = 18000L;
    private Integer playTimeout = 18000;
    private int platformPlayTimeout = 60000;
@@ -55,7 +56,7 @@
        return seniorSdp;
    }
    public Long getPlayTimeout() {
    public Integer getPlayTimeout() {
        return playTimeout;
    }
@@ -83,7 +84,7 @@
        this.seniorSdp = seniorSdp;
    }
    public void setPlayTimeout(Long playTimeout) {
    public void setPlayTimeout(Integer playTimeout) {
        this.playTimeout = playTimeout;
    }
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
@@ -13,6 +13,7 @@
/**
 * 处理匿名用户访问逻辑
 * @author lin
 */
@Component
public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {
@@ -21,7 +22,6 @@
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
//        logger.debug("用户需要登录,访问[{}]失败,AuthenticationException=[{}]", request.getRequestURI(), e.getMessage());
        // 允许跨域
        response.setHeader("Access-Control-Allow-Origin", "*");
        // 允许自定义请求头token(允许head跨域)
@@ -30,7 +30,8 @@
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "-1");
        jsonObject.put("msg", "请登录后重新请求");
        if (request.getRequestURI().contains("api/user/login")){
        String logUri = "api/user/login";
        if (request.getRequestURI().contains(logUri)){
            jsonObject.put("msg", e.getMessage());
        }
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -8,6 +8,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
@@ -18,7 +19,7 @@
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Component
@Configuration
public class SipLayer{
    private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
@@ -35,7 +36,7 @@
    @Bean("sipFactory")
    private SipFactory createSipFactory() {
    SipFactory createSipFactory() {
        sipFactory = SipFactory.getInstance();
        sipFactory.setPathName("gov.nist");
        return sipFactory;
@@ -43,7 +44,7 @@
    
    @Bean("sipStack")
    @DependsOn({"sipFactory"})
    private SipStack createSipStack() throws PeerUnavailableException {
    SipStack createSipStack() throws PeerUnavailableException {
        Properties properties = new Properties();
        properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
        properties.setProperty("javax.sip.IP_ADDRESS", sipConfig.getMonitorIp());
@@ -64,7 +65,7 @@
    @Bean(name = "tcpSipProvider")
    @DependsOn("sipStack")
    private SipProviderImpl startTcpListener() {
    SipProviderImpl startTcpListener() {
        ListeningPoint tcpListeningPoint = null;
        SipProviderImpl tcpSipProvider  = null;
        try {
@@ -89,7 +90,7 @@
    
    @Bean(name = "udpSipProvider")
    @DependsOn("sipStack")
    private SipProviderImpl startUdpListener() {
    SipProviderImpl startUdpListener() {
        ListeningPoint udpListeningPoint = null;
        SipProviderImpl udpSipProvider = null;
        try {
src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
@@ -129,7 +129,9 @@
     */
    public boolean doAuthenticateHashedPassword(Request request, String hashedPassword) {
        AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        if ( authHeader == null ) return false;
        if ( authHeader == null ) {
            return false;
        }
        String realm = authHeader.getRealm();
        String username = authHeader.getUsername();
@@ -176,7 +178,9 @@
     */
    public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
        AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        if ( authHeader == null ) return false;
        if ( authHeader == null ) {
            return false;
        }
        String realm = authHeader.getRealm().trim();
        String username = authHeader.getUsername().trim();
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarmMethod.java
New file
@@ -0,0 +1,40 @@
package com.genersoft.iot.vmp.gb28181.bean;
/**
 * 报警方式
 * @author lin
 * 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,
 * 7其他报警;可以为直接组合如12为电话报警或 设备报警-
 */
public enum DeviceAlarmMethod {
    // 1为电话报警
    Telephone(1),
    // 2为设备报警
    Device(2),
    // 3为短信报警
    SMS(3),
    // 4为 GPS报警
    GPS(4),
    // 5为视频报警
    Video(5),
    // 6为设备故障报警
    DeviceFailure(6),
    // 7其他报警
    Other(7);
    private final int val;
    DeviceAlarmMethod(int val) {
        this.val=val;
    }
    public int getVal() {
        return val;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
@@ -25,6 +25,7 @@
        return gbStreamId;
    }
    @Override
    public void setGbStreamId(Integer gbStreamId) {
        this.gbStreamId = gbStreamId;
    }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
@@ -59,7 +59,9 @@
        mobilePositionMap.put(platformId, subscribeInfo);
        String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX +  "MobilePosition_" + platformId;
        // 添加任务处理GPS定时推送
        dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager,  platformId, subscribeInfo.getSn(), key, this), subscribeInfo.getGpsInterval());
        dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform,
                storager,  platformId, subscribeInfo.getSn(), key, this, dynamicTask),
                subscribeInfo.getGpsInterval());
        String taskOverdueKey = taskOverduePrefix +  "MobilePosition_" + platformId;
        dynamicTask.stop(taskOverdueKey);
        // 添加任务处理订阅过期
src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java
File was deleted
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
@@ -62,7 +62,9 @@
        logger.info("设备上线事件触发,deviceId:" + event.getDevice().getDeviceId() + ",from:" + event.getFrom());
        Device device = event.getDevice();
        if (device == null) return;
        if (device == null) {
            return;
        }
        String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetting.getServerId() + "_" + event.getDevice().getDeviceId();
        Device deviceInStore = storager.queryVideoDevice(device.getDeviceId());
        device.setOnline(1);
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformCycleRegisterEventLister.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
@@ -22,6 +23,8 @@
    private IVideoManagerStorage storager;
    @Autowired
    private ISIPCommanderForPlatform sipCommanderFroPlatform;
    @Autowired
    private DynamicTask dynamicTask;
    @Override
    public void onApplicationEvent(PlatformCycleRegisterEvent event) {
@@ -31,17 +34,13 @@
            logger.info("[ 平台未注册事件 ] 平台已经删除!!! 平台国标ID:" + event.getPlatformGbID());
            return;
        }
        Timer timer = new Timer();
        String taskKey = "platform-cycle-register" + parentPlatform.getServerGBId();;
        SipSubscribe.Event okEvent = (responseEvent)->{
            timer.cancel();
            dynamicTask.stop(taskKey);
        };
        sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                logger.info("[平台注册]再次向平台注册,平台国标ID:" + event.getPlatformGbID());
                sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
            }
        }, 15*1000 ,Long.parseLong(parentPlatform.getExpires())* 1000);
        dynamicTask.startCron(taskKey, ()->{
            logger.info("[平台注册]再次向平台注册,平台国标ID:" + event.getPlatformGbID());
            sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
        }, Integer.parseInt(parentPlatform.getExpires())* 1000);
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
@@ -46,6 +47,9 @@
    @Autowired
    private SipConfig config;
    @Autowired
    private DynamicTask dynamicTask;
    // @Autowired
    // private RedisUtil redis;
@@ -75,19 +79,13 @@
            }
        }
        Timer timer = new Timer();
        String taskKey = "platform-not-register-" + parentPlatform.getServerGBId();
        SipSubscribe.Event okEvent = (responseEvent)->{
            timer.cancel();
            dynamicTask.stop(taskKey);
        };
        logger.info("[平台注册]平台国标ID:" + event.getPlatformGbID());
        sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
        // 设置注册失败则每隔15秒发起一次注册
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                logger.info("[平台注册]再次向平台注册,平台国标ID:" + event.getPlatformGbID());
                sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
            }
        }, config.getRegisterTimeInterval()* 1000, config.getRegisterTimeInterval()* 1000);//十五秒后再次发起注册
        dynamicTask.startCron(taskKey, ()->{
            logger.info("[平台注册]再次向平台注册,平台国标ID:" + event.getPlatformGbID());
            sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
        }, config.getRegisterTimeInterval()* 1000);
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
@@ -60,7 +60,9 @@
        Map<String, List<ParentPlatform>> parentPlatformMap = new HashMap<>();
        if (event.getPlatformId() != null) {
            parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformId());
            if (parentPlatform != null && !parentPlatform.isStatus())return;
            if (parentPlatform != null && !parentPlatform.isStatus()) {
                return;
            }
            subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId());
            if (subscribe == null) {
@@ -80,7 +82,9 @@
            }else if (event.getGbStreams() != null) {
                if (platforms.size() > 0) {
                    for (GbStream gbStream : event.getGbStreams()) {
                        if (gbStream == null || StringUtils.isEmpty(gbStream.getGbId())) continue;
                        if (gbStream == null || StringUtils.isEmpty(gbStream.getGbId())) {
                            continue;
                        }
                        List<ParentPlatform> parentPlatformsForGB = storager.queryPlatFormListForStreamWithGBId(gbStream.getApp(),gbStream.getStream(), platforms);
                        parentPlatformMap.put(gbStream.getGbId(), parentPlatformsForGB);
                    }
@@ -113,7 +117,9 @@
                        if (parentPlatforms != null && parentPlatforms.size() > 0) {
                            for (ParentPlatform platform : parentPlatforms) {
                                SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId());
                                if (subscribeInfo == null) continue;
                                if (subscribeInfo == null) {
                                    continue;
                                }
                                logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId);
                                List<DeviceChannel> deviceChannelList = new ArrayList<>();
                                DeviceChannel deviceChannel = new DeviceChannel();
@@ -155,7 +161,9 @@
                        if (parentPlatforms != null && parentPlatforms.size() > 0) {
                            for (ParentPlatform platform : parentPlatforms) {
                                SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId());
                                if (subscribeInfo == null) continue;
                                if (subscribeInfo == null) {
                                    continue;
                                }
                                logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId);
                                List<DeviceChannel> deviceChannelList = new ArrayList<>();
                                DeviceChannel deviceChannel = storager.queryChannelInParentPlatform(platform.getServerGBId(), gbId);
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
@@ -65,19 +65,25 @@
    public List<DeviceChannel> get(String deviceId) {
        CatalogData catalogData = data.get(deviceId);
        if (catalogData == null) return null;
        if (catalogData == null) {
            return null;
        }
        return catalogData.getChannelList();
    }
    public int getTotal(String deviceId) {
        CatalogData catalogData = data.get(deviceId);
        if (catalogData == null) return 0;
        if (catalogData == null) {
            return 0;
        }
        return catalogData.getTotal();
    }
    public SyncStatus getSyncStatus(String deviceId) {
        CatalogData catalogData = data.get(deviceId);
        if (catalogData == null) return null;
        if (catalogData == null) {
            return null;
        }
        SyncStatus syncStatus = new SyncStatus();
        syncStatus.setCurrent(catalogData.getChannelList().size());
        syncStatus.setTotal(catalogData.getTotal());
@@ -87,7 +93,9 @@
    public boolean isSyncRunning(String deviceId) {
        CatalogData catalogData = data.get(deviceId);
        if (catalogData == null) return false;
        if (catalogData == null) {
            return false;
        }
        return !catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end);
    }
@@ -125,7 +133,9 @@
    public void setChannelSyncEnd(String deviceId, String errorMsg) {
        CatalogData catalogData = data.get(deviceId);
        if (catalogData == null)return;
        if (catalogData == null) {
            return;
        }
        catalogData.setStatus(CatalogData.CatalogDataStatus.end);
        catalogData.setErrorMsg(errorMsg);
    }
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
@@ -78,7 +78,9 @@
    
    public ClientTransaction getTransactionByStream(String deviceId, String channelId, String stream){
        SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
        if (ssrcTransaction == null) return null;
        if (ssrcTransaction == null) {
            return null;
        }
        byte[] transactionByteArray = ssrcTransaction.getTransaction();
        ClientTransaction clientTransaction = (ClientTransaction)SerializeUtils.deSerialize(transactionByteArray);
        return clientTransaction;
@@ -86,39 +88,63 @@
    public SIPDialog getDialogByStream(String deviceId, String channelId, String stream){
        SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
        if (ssrcTransaction == null) return null;
        if (ssrcTransaction == null) {
            return null;
        }
        byte[] dialogByteArray = ssrcTransaction.getDialog();
        if (dialogByteArray == null) return null;
        if (dialogByteArray == null) {
            return null;
        }
        SIPDialog dialog = (SIPDialog)SerializeUtils.deSerialize(dialogByteArray);
        return dialog;
    }
    public SIPDialog getDialogByCallId(String deviceId, String channelId, String callID){
        SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callID, null);
        if (ssrcTransaction == null) return null;
        if (ssrcTransaction == null) {
            return null;
        }
        byte[] dialogByteArray = ssrcTransaction.getDialog();
        if (dialogByteArray == null) return null;
        if (dialogByteArray == null) {
            return null;
        }
        SIPDialog dialog = (SIPDialog)SerializeUtils.deSerialize(dialogByteArray);
        return dialog;
    }
    public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){
        if (StringUtils.isEmpty(callId)) callId ="*";
        if (StringUtils.isEmpty(stream)) stream ="*";
        if (StringUtils.isEmpty(callId)) {
            callId ="*";
        }
        if (StringUtils.isEmpty(stream)) {
            stream ="*";
        }
        String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
        List<Object> scanResult = redisUtil.scan(key);
        if (scanResult.size() == 0) return null;
        if (scanResult.size() == 0) {
            return null;
        }
        return (SsrcTransaction)redisUtil.get((String) scanResult.get(0));
    }
    public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){
        if (StringUtils.isEmpty(deviceId)) deviceId ="*";
        if (StringUtils.isEmpty(channelId)) channelId ="*";
        if (StringUtils.isEmpty(callId)) callId ="*";
        if (StringUtils.isEmpty(stream)) stream ="*";
        if (StringUtils.isEmpty(deviceId)) {
            deviceId ="*";
        }
        if (StringUtils.isEmpty(channelId)) {
            channelId ="*";
        }
        if (StringUtils.isEmpty(callId)) {
            callId ="*";
        }
        if (StringUtils.isEmpty(stream)) {
            stream ="*";
        }
        String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
        List<Object> scanResult = redisUtil.scan(key);
        if (scanResult.size() == 0) return null;
        if (scanResult.size() == 0) {
            return null;
        }
        List<SsrcTransaction> result = new ArrayList<>();
        for (Object keyObj : scanResult) {
            result.add((SsrcTransaction)redisUtil.get((String) keyObj));
@@ -128,19 +154,25 @@
    public String getMediaServerId(String deviceId, String channelId, String stream){
        SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
        if (ssrcTransaction == null) return null;
        if (ssrcTransaction == null) {
            return null;
        }
        return ssrcTransaction.getMediaServerId();
    }
    public String getSSRC(String deviceId, String channelId, String stream){
        SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
        if (ssrcTransaction == null) return null;
        if (ssrcTransaction == null) {
            return null;
        }
        return ssrcTransaction.getSsrc();
    }
    
    public void remove(String deviceId, String channelId, String stream) {
        SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
        if (ssrcTransaction == null) return;
        if (ssrcTransaction == null) {
            return;
        }
        redisUtil.del(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_"
                +  deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream());
    }
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
@@ -2,6 +2,9 @@
import javax.sip.DialogState;
/**
 * @author lin
 */
public interface ISubscribeTask extends Runnable{
    void stop();
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
@@ -1,11 +1,13 @@
package com.genersoft.iot.vmp.gb28181.task.impl;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import javax.sip.Dialog;
import javax.sip.DialogState;
@@ -15,6 +17,7 @@
/**
 * 目录订阅任务
 * @author lin
 */
public class CatalogSubscribeTask implements ISubscribeTask {
    private final Logger logger = LoggerFactory.getLogger(CatalogSubscribeTask.class);
@@ -22,18 +25,21 @@
    private final ISIPCommander sipCommander;
    private Dialog dialog;
    private Timer timer ;
    private DynamicTask dynamicTask;
    public CatalogSubscribeTask(Device device, ISIPCommander sipCommander) {
    private String taskKey = "catalog-subscribe-timeout";
    public CatalogSubscribeTask(Device device, ISIPCommander sipCommander, DynamicTask dynamicTask) {
        this.device = device;
        this.sipCommander = sipCommander;
        this.dynamicTask = dynamicTask;
    }
    @Override
    public void run() {
        if (timer != null ) {
            timer.cancel();
            timer = null;
        if (dynamicTask.get(taskKey) != null) {
            dynamicTask.stop(taskKey);
        }
        sipCommander.catalogSubscribe(device, dialog, eventResult -> {
            if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) {
@@ -51,13 +57,7 @@
            dialog = null;
            // 失败
            logger.warn("[目录订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
            timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    CatalogSubscribeTask.this.run();
                }
            }, 2000);
            dynamicTask.startDelay(taskKey, CatalogSubscribeTask.this, 2000);
        });
    }
@@ -71,9 +71,8 @@
         * TERMINATED-> Terminated Dialog状态-终止
         */
        logger.info("取消目录订阅时dialog状态为{}", DialogState.CONFIRMED);
        if (timer != null ) {
            timer.cancel();
            timer = null;
        if (dynamicTask.get(taskKey) != null) {
            dynamicTask.stop(taskKey);
        }
        if (dialog != null && dialog.getState().equals(DialogState.CONFIRMED)) {
            device.setSubscribeCycleForCatalog(0);
@@ -95,7 +94,9 @@
    @Override
    public DialogState getDialogState() {
        if (dialog == null) return null;
        if (dialog == null) {
            return null;
        }
        return dialog.getState();
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.task.impl;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
@@ -15,6 +16,7 @@
/**
 * 向已经订阅(移动位置)的上级发送MobilePosition消息
 * @author lin
 */
public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
@@ -25,10 +27,18 @@
    private ISIPCommanderForPlatform sipCommanderForPlatform;
    private SubscribeHolder subscribeHolder;
    private ParentPlatform platform;
    private String sn;
    private String key;
    public MobilePositionSubscribeHandlerTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorage storager, String platformId, String sn, String key, SubscribeHolder subscribeInfo) {
    public MobilePositionSubscribeHandlerTask(IRedisCatchStorage redisCatchStorage,
                                              ISIPCommanderForPlatform sipCommanderForPlatform,
                                              IVideoManagerStorage storager,
                                              String platformId,
                                              String sn,
                                              String key,
                                              SubscribeHolder subscribeInfo,
                                              DynamicTask dynamicTask) {
        this.redisCatchStorage = redisCatchStorage;
        this.storager = storager;
        this.platform = storager.queryParentPlatByServerGBId(platformId);
@@ -41,7 +51,9 @@
    @Override
    public void run() {
        if (platform == null) return;
        if (platform == null) {
            return;
        }
        SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId());
        if (subscribe != null) {
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.gb28181.task.impl;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
@@ -16,25 +17,26 @@
/**
 * 移动位置订阅的定时更新
 * @author lin
 */
public class MobilePositionSubscribeTask implements ISubscribeTask {
    private final Logger logger = LoggerFactory.getLogger(MobilePositionSubscribeTask.class);
    private  Device device;
    private  ISIPCommander sipCommander;
    private Dialog dialog;
    private DynamicTask dynamicTask;
    private String taskKey = "mobile-position-subscribe-timeout";
    private Timer timer ;
    public MobilePositionSubscribeTask(Device device, ISIPCommander sipCommander) {
    public MobilePositionSubscribeTask(Device device, ISIPCommander sipCommander, DynamicTask dynamicTask) {
        this.device = device;
        this.sipCommander = sipCommander;
        this.dynamicTask = dynamicTask;
    }
    @Override
    public void run() {
        if (timer != null ) {
            timer.cancel();
            timer = null;
        if (dynamicTask.get(taskKey) != null) {
            dynamicTask.stop(taskKey);
        }
        sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> {
//            if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) {
@@ -52,13 +54,7 @@
            dialog = null;
            // 失败
            logger.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
            timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    MobilePositionSubscribeTask.this.run();
                }
            }, 2000);
            dynamicTask.startDelay(taskKey, MobilePositionSubscribeTask.this, 2000);
        });
    }
@@ -72,9 +68,8 @@
         * COMPLETED-> Completed Dialog状态-已完成
         * TERMINATED-> Terminated Dialog状态-终止
         */
        if (timer != null ) {
            timer.cancel();
            timer = null;
        if (dynamicTask.get(taskKey) != null) {
            dynamicTask.stop(taskKey);
        }
        if (dialog != null && dialog.getState().equals(DialogState.CONFIRMED)) {
            logger.info("取消移动订阅时dialog状态为{}", dialog.getState());
@@ -96,7 +91,9 @@
    }
    @Override
    public DialogState getDialogState() {
        if (dialog == null) return null;
        if (dialog == null) {
            return null;
        }
        return dialog.getState();
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
@@ -62,7 +62,7 @@
     * @param processor 处理程序
     */
    public void addTimeoutProcessor(ITimeoutProcessor processor) {
        this.timeoutProcessor = processor;
        timeoutProcessor = processor;
    }
    /**
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java
@@ -29,6 +29,7 @@
        this.recordInfo = recordInfo;
    }
    @Override
    public void run() {
        String cacheKey = this.key;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
@@ -65,12 +65,16 @@
    
    public DeferredResult get(String key, String id) {
        Map<String, DeferredResult> deferredResultMap = map.get(key);
        if (deferredResultMap == null) return null;
        if (deferredResultMap == null) {
            return null;
        }
        return deferredResultMap.get(id);
    }
    public boolean exist(String key, String id){
        if (key == null) return false;
        if (key == null) {
            return false;
        }
        Map<String, DeferredResult> deferredResultMap = map.get(key);
        if (id == null) {
            return deferredResultMap != null;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
@@ -68,9 +68,6 @@
                toHeader, viaHeaders, maxForwards);
        List<String> agentParam = new ArrayList<>();
        agentParam.add("wvp-pro");
        UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
        request.addHeader(userAgentHeader);
        ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
        request.setContent(content, contentTypeHeader);
@@ -115,10 +112,6 @@
        ExpiresHeader expires = sipFactory.createHeaderFactory().createExpiresHeader(Integer.parseInt(platform.getExpires()));
        request.addHeader(expires);
        List<String> agentParam = new ArrayList<>();
        agentParam.add("wvp-pro");
        UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
        request.addHeader(userAgentHeader);
        return request;
    }
@@ -226,10 +219,6 @@
        messageFactory.setDefaultContentEncodingCharset(parentPlatform.getCharacterSet());
        request = messageFactory.createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
                toHeader, viaHeaders, maxForwards);
        List<String> agentParam = new ArrayList<>();
        agentParam.add("wvp-pro");
        UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
        request.addHeader(userAgentHeader);
        ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
        request.setContent(content, contentTypeHeader);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
@@ -228,9 +228,13 @@
    public Request createInfoRequest(Device device, StreamInfo streamInfo, String content)
            throws PeerUnavailableException, ParseException, InvalidArgumentException {
        Request request = null;
        if (streamInfo == null) return null;
        if (streamInfo == null) {
            return null;
        }
        Dialog dialog = streamSession.getDialogByStream(streamInfo.getDeviceID(), streamInfo.getChannelId(), streamInfo.getStream());
        if (dialog == null) return null;
        if (dialog == null) {
            return null;
        }
        SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(),
                device.getHostAddress());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -27,6 +27,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringBootVersion;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@@ -37,7 +38,9 @@
import javax.sip.message.Request;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
/**    
 * @description:设备能力接口,用于定义设备的控制、查询能力   
@@ -49,7 +52,7 @@
public class SIPCommander implements ISIPCommander {
    private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
    @Autowired
    private SipConfig sipConfig;
@@ -340,13 +343,15 @@
      * @param channelId  预览通道
      * @param event hook订阅
      * @param errorEvent sip错误订阅
      */
    */
    @Override
    public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
                              ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
        String streamId = ssrcInfo.getStream();
        try {
            if (device == null) return;
            if (device == null) {
                return;
            }
            String streamMode = device.getStreamMode().toUpperCase();
            logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
@@ -694,7 +699,9 @@
            if (callId != null) {
                dialog = streamSession.getDialogByCallId(deviceId, channelId, callId);
            }else {
                if (stream == null) return;
                if (stream == null) {
                    return;
                }
                dialog = streamSession.getDialogByStream(deviceId, channelId, stream);
            }
            if (ssrcTransaction != null) {
@@ -1454,6 +1461,7 @@
     * @param device    视频设备
     * @return            true = 命令发送成功
     */
    @Override
    public boolean mobilePositionSubscribe(Device device, Dialog dialog, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) {
        try {
            StringBuffer subscribePostitionXml = new StringBuffer(200);
@@ -1505,6 +1513,7 @@
     * @param endTime        报警发生终止时间(可选)
     * @return                true = 命令发送成功
     */
    @Override
    public boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime) {
        try {
            StringBuffer cmdXml = new StringBuffer(200);
@@ -1637,7 +1646,18 @@
        } else if("UDP".equals(device.getTransport())) {
            clientTransaction = udpSipProvider.getNewClientTransaction(request);
        }
        if (request.getHeader(UserAgentHeader.NAME) == null) {
            List<String> agentParam = new ArrayList<>();
            agentParam.add("wvp-pro");
            // TODO 添加版本信息以及日期
            UserAgentHeader userAgentHeader = null;
            try {
                userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            request.addHeader(userAgentHeader);
        }
        CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
        // 添加错误订阅
        if (errorEvent != null) {
@@ -1701,7 +1721,9 @@
            content.append("CSeq: " + cseq + "\r\n");
            content.append("Range: npt=now-\r\n");
            Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
            if (request == null) return;
            if (request == null) {
                return;
            }
            logger.info(request.toString());
            ClientTransaction clientTransaction = null;
            if ("TCP".equals(device.getTransport())) {
@@ -1730,7 +1752,9 @@
            content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
            Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
            if (request == null) return;
            if (request == null) {
                return;
            }
            logger.info(request.toString());
            ClientTransaction clientTransaction = null;
            if ("TCP".equals(device.getTransport())) {
@@ -1758,7 +1782,9 @@
            content.append("CSeq: " + cseq + "\r\n");
            content.append("Scale: " + String.format("%.1f",speed) + "\r\n");
            Request request = headerProvider.createInfoRequest(device, streamInfo, content.toString());
            if (request == null) return;
            if (request == null) {
                return;
            }
            logger.info(request.toString());
            ClientTransaction clientTransaction = null;
            if ("TCP".equals(device.getTransport())) {
@@ -1824,7 +1850,9 @@
        // 设置编码, 防止中文乱码
        messageFactory.setDefaultContentEncodingCharset(characterSet);
        Dialog dialog  = subscribeInfo.getDialog();
        if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) return;
        if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) {
            return;
        }
        SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY);
        ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
        notifyRequest.setContent(catalogXmlContent, contentTypeHeader);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -529,7 +529,9 @@
         // 设置编码, 防止中文乱码
        messageFactory.setDefaultContentEncodingCharset(characterSet);
        Dialog dialog  = subscribeInfo.getDialog();
        if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) return;
        if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) {
            return;
        }
        SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY);
        ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
        notifyRequest.setContent(catalogXmlContent, contentTypeHeader);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
@@ -139,7 +139,9 @@
        serverTransaction.sendResponse(response);
        if (statusCode >= 200 && !"NOTIFY".equals(evt.getRequest().getMethod())) {
            if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
            if (serverTransaction.getDialog() != null) {
                serverTransaction.getDialog().delete();
            }
        }
    }
@@ -149,7 +151,9 @@
        ServerTransaction serverTransaction = getServerTransaction(evt);
        serverTransaction.sendResponse(response);
        if (statusCode >= 200 && !"NOTIFY".equals(evt.getRequest().getMethod())) {
            if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
            if (serverTransaction.getDialog() != null) {
                serverTransaction.getDialog().delete();
            }
        }
    }
@@ -215,7 +219,9 @@
        return getRootElement(evt, "gb2312");
    }
    public Element getRootElement(RequestEvent evt, String charset) throws DocumentException {
        if (charset == null) charset = "gb2312";
        if (charset == null) {
            charset = "gb2312";
        }
        Request request = evt.getRequest();
        SAXReader reader = new SAXReader();
        reader.setEncoding(charset);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -72,7 +72,9 @@
    public void process(RequestEvent evt) {
        Dialog dialog = evt.getDialog();
        CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
        if (dialog == null) return;
        if (dialog == null) {
            return;
        }
        if (dialog.getState()== DialogState.CONFIRMED) {
            String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
            logger.info("ACK请求: platformGbId->{}", platformGbId);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
@@ -81,7 +81,9 @@
            responseAck(evt, Response.OK);
            Dialog dialog = evt.getDialog();
            CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
            if (dialog == null) return;
            if (dialog == null) {
                return;
            }
            if (dialog.getState().equals(DialogState.TERMINATED)) {
                String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
                String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -321,7 +321,9 @@
                            response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());
                            ServerTransaction serverTransaction = getServerTransaction(evt);
                            serverTransaction.sendResponse(response);
                            if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
                            if (serverTransaction.getDialog() != null) {
                                serverTransaction.getDialog().delete();
                            }
                        } catch (ParseException | SipException | InvalidArgumentException e) {
                            e.printStackTrace();
                        }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -5,7 +5,6 @@
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
@@ -19,7 +18,6 @@
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.GpsUtil;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.dom4j.DocumentException;
import org.dom4j.Element;
@@ -64,10 +62,6 @@
    @Autowired
    private EventPublisher publisher;
    @Autowired
    private DeviceOffLineDetector offLineDetector;
    private String method = "NOTIFY";
@@ -240,7 +234,7 @@
            // 回复200 OK
            responseAck(evt, Response.OK);
            if (offLineDetector.isOnline(deviceId)) {
            if (redisCatchStorage.deviceIsOnline(deviceId)) {
                publisher.deviceAlarmEventPublish(deviceAlarm);
            }
        } catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
@@ -331,7 +325,7 @@
                }
                if (!offLineDetector.isOnline(deviceId)) {
                if (!redisCatchStorage.deviceIsOnline(deviceId)) {
                    publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
                }
            }
@@ -355,10 +349,6 @@
    }
    public void setDeferredResultHolder(DeferredResultHolder deferredResultHolder) {
    }
    public void setOffLineDetector(DeviceOffLineDetector offLineDetector) {
        this.offLineDetector = offLineDetector;
    }
    public IRedisCatchStorage getRedisCatchStorage() {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -130,7 +130,9 @@
                response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
                ServerTransaction serverTransaction = getServerTransaction(evt);
                serverTransaction.sendResponse(response);
                if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
                if (serverTransaction.getDialog() != null) {
                    serverTransaction.getDialog().delete();
                }
                return;
            }
            // 添加Contact头
@@ -195,7 +197,9 @@
            return;
        }
        serverTransaction.sendResponse(response);
        if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
        if (serverTransaction.getDialog() != null) {
            serverTransaction.getDialog().delete();
        }
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
@@ -35,21 +35,16 @@
/**
 * SIP命令类型: SUBSCRIBE请求
 * @author lin
 */
@Component
public class SubscribeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
    private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class);
    private String method = "SUBSCRIBE";
    private final Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class);
    private final String method = "SUBSCRIBE";
    @Autowired
    private SIPProcessorObserver sipProcessorObserver;
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
    @Autowired
    private ISIPCommanderForPlatform sipCommanderForPlatform;
    @Autowired
    private IVideoManagerStorage storager;
@@ -82,7 +77,7 @@
    /**   
     * 处理SUBSCRIBE请求  
     * 
     * @param evt
     * @param evt 事件
     */
    @Override
    public void process(RequestEvent evt) {
@@ -101,13 +96,12 @@
            } else {
                logger.info("接收到消息:" + cmd);
                Response response = null;
                response = getMessageFactory().createResponse(200, request);
                Response response = getMessageFactory().createResponse(200, request);
                if (response != null) {
                    ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30);
                    response.setExpires(expireHeader);
                }
                logger.info("response : " + response.toString());
                logger.info("response : " + response);
                ServerTransaction transaction = getServerTransaction(evt);
                if (transaction != null) {
                    transaction.sendResponse(response);
@@ -117,13 +111,7 @@
                    logger.info("processRequest serverTransactionId is null.");
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (SipException e) {
            e.printStackTrace();
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
        } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
            e.printStackTrace();
        }
@@ -134,14 +122,14 @@
     */
    private void processNotifyMobilePosition(RequestEvent evt, Element rootElement) throws SipException {
        String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
        String deviceID = XmlUtil.getText(rootElement, "DeviceID");
        String deviceId = XmlUtil.getText(rootElement, "DeviceID");
        ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
        SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId);
        if (platform == null) {
            return;
        }
        if (evt.getServerTransaction() == null) {
            ServerTransaction serverTransaction = platform.getTransport().equals("TCP") ? tcpSipProvider.getNewServerTransaction(evt.getRequest())
            ServerTransaction serverTransaction = "TCP".equals(platform.getTransport()) ? tcpSipProvider.getNewServerTransaction(evt.getRequest())
                    : udpSipProvider.getNewServerTransaction(evt.getRequest());
            subscribeInfo.setTransaction(serverTransaction);
            Dialog dialog = serverTransaction.getDialog();
@@ -154,13 +142,14 @@
        resultXml.append("<?xml version=\"1.0\" ?>\r\n")
                .append("<Response>\r\n")
                .append("<CmdType>MobilePosition</CmdType>\r\n")
                .append("<SN>" + sn + "</SN>\r\n")
                .append("<DeviceID>" + deviceID + "</DeviceID>\r\n")
                .append("<SN>").append(sn).append("</SN>\r\n")
                .append("<DeviceID>").append(deviceId).append("</DeviceID>\r\n")
                .append("<Result>OK</Result>\r\n")
                .append("</Response>\r\n");
        if (subscribeInfo.getExpires() > 0) {
            String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔
            // GPS上报时间间隔
            String interval = XmlUtil.getText(rootElement, "Interval");
            if (interval == null) {
                subscribeInfo.setGpsInterval(5);
            }else {
@@ -169,15 +158,7 @@
            subscribeInfo.setSn(sn);
            subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
//            if (subscribeHolder.getMobilePositionSubscribe(platformId) == null ) {
//                subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
//            }else {
//                if (subscribeHolder.getMobilePositionSubscribe(platformId).getDialog() != null
//                        && subscribeHolder.getMobilePositionSubscribe(platformId).getDialog().getState() != null
//                        && !subscribeHolder.getMobilePositionSubscribe(platformId).getDialog().getState().equals(DialogState.CONFIRMED)) {
//                    subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
//                }
//            }
        }else if (subscribeInfo.getExpires() == 0) {
            subscribeHolder.removeMobilePositionSubscribe(platformId);
        }
@@ -185,11 +166,7 @@
        try {
            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
            responseXmlAck(evt, resultXml.toString(), parentPlatform);
        } catch (SipException e) {
            e.printStackTrace();
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
        } catch (ParseException e) {
        } catch (SipException | InvalidArgumentException | ParseException e) {
            e.printStackTrace();
        }
    }
@@ -200,12 +177,14 @@
    private void processNotifyCatalogList(RequestEvent evt, Element rootElement) throws SipException {
        String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
        String deviceID = XmlUtil.getText(rootElement, "DeviceID");
        String deviceId = XmlUtil.getText(rootElement, "DeviceID");
        ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
        if (platform == null)return;
        if (platform == null){
            return;
        }
        SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId);
        if (evt.getServerTransaction() == null) {
            ServerTransaction serverTransaction = platform.getTransport().equals("TCP") ? tcpSipProvider.getNewServerTransaction(evt.getRequest())
            ServerTransaction serverTransaction = "TCP".equals(platform.getTransport()) ? tcpSipProvider.getNewServerTransaction(evt.getRequest())
                    : udpSipProvider.getNewServerTransaction(evt.getRequest());
            subscribeInfo.setTransaction(serverTransaction);
            Dialog dialog = serverTransaction.getDialog();
@@ -213,13 +192,13 @@
            subscribeInfo.setDialog(dialog);
        }
        String sn = XmlUtil.getText(rootElement, "SN");
        logger.info("[回复 目录订阅]: {}/{}", platformId, deviceID);
        logger.info("[回复 目录订阅]: {}/{}", platformId, deviceId);
        StringBuilder resultXml = new StringBuilder(200);
        resultXml.append("<?xml version=\"1.0\" ?>\r\n")
                .append("<Response>\r\n")
                .append("<CmdType>Catalog</CmdType>\r\n")
                .append("<SN>" + sn + "</SN>\r\n")
                .append("<DeviceID>" + deviceID + "</DeviceID>\r\n")
                .append("<SN>").append(sn).append("</SN>\r\n")
                .append("<DeviceID>").append(deviceId).append("</DeviceID>\r\n")
                .append("<Result>OK</Result>\r\n")
                .append("</Response>\r\n");
@@ -232,11 +211,7 @@
        try {
            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);
            responseXmlAck(evt, resultXml.toString(), parentPlatform);
        } catch (SipException e) {
            e.printStackTrace();
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
        } catch (ParseException e) {
        } catch (SipException | InvalidArgumentException | ParseException e) {
            e.printStackTrace();
        }
    }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
@@ -1,10 +1,8 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.alibaba.fastjson.JSON;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
@@ -14,7 +12,6 @@
import com.genersoft.iot.vmp.service.IDeviceAlarmService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.GpsUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,7 +32,7 @@
@Component
public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
    private Logger logger = LoggerFactory.getLogger(AlarmNotifyMessageHandler.class);
    private final Logger logger = LoggerFactory.getLogger(AlarmNotifyMessageHandler.class);
    private final String cmdType = "Alarm";
    @Autowired
@@ -58,9 +55,6 @@
    @Autowired
    private IDeviceAlarmService deviceAlarmService;
    @Autowired
    private DeviceOffLineDetector offLineDetector;
    @Override
    public void afterPropertiesSet() throws Exception {
@@ -91,24 +85,27 @@
        deviceAlarm.setAlarmPriority(getText(rootElement, "AlarmPriority"));
        deviceAlarm.setAlarmMethod(getText(rootElement, "AlarmMethod"));
        deviceAlarm.setAlarmTime(getText(rootElement, "AlarmTime"));
        if (getText(rootElement, "AlarmDescription") == null) {
        String alarmDescription = getText(rootElement, "AlarmDescription");
        if (alarmDescription == null) {
            deviceAlarm.setAlarmDescription("");
        } else {
            deviceAlarm.setAlarmDescription(getText(rootElement, "AlarmDescription"));
            deviceAlarm.setAlarmDescription(alarmDescription);
        }
        if (NumericUtil.isDouble(getText(rootElement, "Longitude"))) {
            deviceAlarm.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
        String longitude = getText(rootElement, "Longitude");
        if (longitude != null && NumericUtil.isDouble(longitude)) {
            deviceAlarm.setLongitude(Double.parseDouble(longitude));
        } else {
            deviceAlarm.setLongitude(0.00);
        }
        if (NumericUtil.isDouble(getText(rootElement, "Latitude"))) {
            deviceAlarm.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
        String latitude = getText(rootElement, "Latitude");
        if (latitude != null && NumericUtil.isDouble(latitude)) {
            deviceAlarm.setLatitude(Double.parseDouble(latitude));
        } else {
            deviceAlarm.setLatitude(0.00);
        }
        if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
            if ( deviceAlarm.getAlarmMethod().equals("4")) {
            if ( deviceAlarm.getAlarmMethod().contains(DeviceAlarmMethod.GPS.getVal() + "")) {
                MobilePosition mobilePosition = new MobilePosition();
                mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
                mobilePosition.setTime(deviceAlarm.getAlarmTime());
@@ -128,7 +125,7 @@
            }
        }
        if (!StringUtils.isEmpty(deviceAlarm.getDeviceId())) {
            if (deviceAlarm.getAlarmMethod().equals("5")) {
            if (deviceAlarm.getAlarmMethod().contains(DeviceAlarmMethod.Video.getVal() + "")) {
                deviceAlarm.setAlarmType(getText(rootElement.element("Info"), "AlarmType"));
            }
        }
@@ -151,7 +148,7 @@
        }
        if (offLineDetector.isOnline(device.getDeviceId())) {
        if (redisCatchStorage.deviceIsOnline(device.getDeviceId())) {
            publisher.deviceAlarmEventPublish(deviceAlarm);
        }
    }
@@ -179,25 +176,28 @@
        deviceAlarm.setAlarmPriority(getText(rootElement, "AlarmPriority"));
        deviceAlarm.setAlarmMethod(getText(rootElement, "AlarmMethod"));
        deviceAlarm.setAlarmTime(getText(rootElement, "AlarmTime"));
        if (getText(rootElement, "AlarmDescription") == null) {
        String alarmDescription = getText(rootElement, "AlarmDescription");
        if (alarmDescription == null) {
            deviceAlarm.setAlarmDescription("");
        } else {
            deviceAlarm.setAlarmDescription(getText(rootElement, "AlarmDescription"));
            deviceAlarm.setAlarmDescription(alarmDescription);
        }
        if (NumericUtil.isDouble(getText(rootElement, "Longitude"))) {
            deviceAlarm.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
        String longitude = getText(rootElement, "Longitude");
        if (longitude != null && NumericUtil.isDouble(longitude)) {
            deviceAlarm.setLongitude(Double.parseDouble(longitude));
        } else {
            deviceAlarm.setLongitude(0.00);
        }
        if (NumericUtil.isDouble(getText(rootElement, "Latitude"))) {
            deviceAlarm.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
        String latitude = getText(rootElement, "Latitude");
        if (latitude != null && NumericUtil.isDouble(latitude)) {
            deviceAlarm.setLatitude(Double.parseDouble(latitude));
        } else {
            deviceAlarm.setLatitude(0.00);
        }
        if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
            if (deviceAlarm.getAlarmMethod().equals("5")) {
            if (deviceAlarm.getAlarmMethod().contains(DeviceAlarmMethod.Video.getVal() + "")) {
                deviceAlarm.setAlarmType(getText(rootElement.element("Info"), "AlarmType"));
            }
        }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -70,7 +70,9 @@
                    videoManagerStorager.updateDevice(device);
                    redisCatchStorage.updateDevice(device);
                }
                publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
                if (!redisCatchStorage.deviceIsOnline(device.getDeviceId())) {
                    publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
                }
            }
        } catch (SipException e) {
            e.printStackTrace();
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
@@ -1,14 +1,11 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.session.CatalogDataCatch;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
@@ -17,8 +14,6 @@
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.GpsUtil;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
@@ -57,9 +52,6 @@
    @Autowired
    private CatalogDataCatch catalogDataCatch;
    @Autowired
    private DeviceOffLineDetector offLineDetector;
    @Autowired
    private SipConfig config;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
@@ -4,13 +4,13 @@
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import org.dom4j.DocumentException;
import org.dom4j.Element;
@@ -42,10 +42,10 @@
    private IVideoManagerStorage storager;
    @Autowired
    private DeferredResultHolder deferredResultHolder;
    private IRedisCatchStorage redisCatchStorage;
    @Autowired
    private DeviceOffLineDetector offLineDetector;
    private DeferredResultHolder deferredResultHolder;
    @Autowired
    private SipConfig config;
@@ -82,7 +82,7 @@
            deferredResultHolder.invokeAllResult(msg);
            // 回复200 OK
            responseAck(evt, Response.OK);
            if (offLineDetector.isOnline(device.getDeviceId())) {
            if (redisCatchStorage.deviceIsOnline(device.getDeviceId())) {
                publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
            }
        } catch (DocumentException e) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java
@@ -4,7 +4,6 @@
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
@@ -12,6 +11,7 @@
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -34,14 +34,15 @@
    @Autowired
    private ResponseMessageHandler responseMessageHandler;
    @Autowired
    private DeviceOffLineDetector offLineDetector;
    @Autowired
    private DeferredResultHolder deferredResultHolder;
    @Autowired
    private EventPublisher publisher;
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
    @Override
    public void afterPropertiesSet() throws Exception {
@@ -74,10 +75,8 @@
        msg.setData(json);
        deferredResultHolder.invokeAllResult(msg);
        if (offLineDetector.isOnline(device.getDeviceId())) {
        if (redisCatchStorage.deviceIsOnline(device.getDeviceId())) {
            publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
        } else {
        }
    }
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
@@ -25,7 +25,9 @@
     * */
    public static String getChannelIdFromHeader(Request request) {
        Header subject = request.getHeader("subject");
        if (subject == null) return null;
        if (subject == null) {
            return null;
        }
        return ((Subject) subject).getSubject().split(":")[0];
    }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
@@ -85,7 +85,9 @@
                    if (result == null) {
                        result = key.getString(s).equals(hookResponse.getString(s));
                    }else {
                        if (key.getString(s) == null) continue;
                        if (key.getString(s) == null) {
                            continue;
                        }
                        result = result && key.getString(s).equals(hookResponse.getString(s));
                    }
                }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
@@ -67,7 +67,9 @@
        // 使用异步的当时更新媒体流列表
        zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{
            if (mediaList == null) return;
            if (mediaList == null) {
                return;
            }
            String dataStr = mediaList.getString("data");
            Integer code = mediaList.getInteger("code");
@@ -176,7 +178,9 @@
        //使用异步更新推流
        zlmresTfulUtils.getMediaList(mediaServerItem, app, streamId, "rtmp", json->{
            if (json == null) return;
            if (json == null) {
                return;
            }
            String dataStr = json.getString("data");
            Integer code = json.getInteger("code");
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -23,7 +23,9 @@
    private int[] portRangeArray = new int[2];
    public int getFreePort(MediaServerItem mediaServerItem, int startPort, int endPort, List<Integer> usedFreelist) {
        if (endPort <= startPort) return -1;
        if (endPort <= startPort) {
            return -1;
        }
        if (usedFreelist == null) {
            usedFreelist = new ArrayList<>();
        }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -3,6 +3,7 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
@@ -51,6 +52,9 @@
    @Autowired
    private MediaConfig mediaConfig;
    @Autowired
    private DynamicTask dynamicTask;
    @Qualifier("taskExecutor")
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
@@ -97,27 +101,25 @@
            all.add(mediaConfig.getMediaSerItem());
        }
        for (MediaServerItem mediaServerItem : all) {
            if (startGetMedia == null) startGetMedia = new HashMap<>();
            if (startGetMedia == null) {
                startGetMedia = new HashMap<>();
            }
            startGetMedia.put(mediaServerItem.getId(), true);
            taskExecutor.execute(()->{
                connectZlmServer(mediaServerItem);
            });
        }
        Timer timer = new Timer();
        // 10分钟后未连接到则不再去主动连接, TODO 并对重启前使用此在zlm的通道发送bye
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
        String taskKey = "zlm-connect-timeout";
        dynamicTask.startDelay(taskKey, ()->{
            if (startGetMedia != null) {
                Set<String> allZlmId = startGetMedia.keySet();
                for (String id : allZlmId) {
                    logger.error("[ {} ]]主动连接失败,不再主动连接", id);
                    logger.error("[ {} ]]主动连接失败,不再尝试连接", id);
                }
                startGetMedia = null;
            }
            //  TODO 清理数据库中与redis不匹配的zlm
            }
        }, 60 * 1000 * 10);
        //  TODO 清理数据库中与redis不匹配的zlm
        }, 6 * 1000 );
    }
    @Async
@@ -139,12 +141,12 @@
        if ( startGetMedia.get(mediaServerItem.getId()) == null || !startGetMedia.get(mediaServerItem.getId())) {
            return null;
        }
        JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
        ZLMServerConfig ZLMServerConfig = null;
        if (responseJSON != null) {
            JSONArray data = responseJSON.getJSONArray("data");
        JSONObject responseJson = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
        ZLMServerConfig zlmServerConfig = null;
        if (responseJson != null) {
            JSONArray data = responseJson.getJSONArray("data");
            if (data != null && data.size() > 0) {
                ZLMServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
                zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
            }
        } else {
            logger.error("[ {} ]-[ {}:{} ]第{}次主动连接失败, 2s后重试",
@@ -159,9 +161,9 @@
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ZLMServerConfig = getMediaServerConfig(mediaServerItem, index += 1);
            zlmServerConfig = getMediaServerConfig(mediaServerItem, index += 1);
        }
        return ZLMServerConfig;
        return zlmServerConfig;
    }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
@@ -29,18 +29,22 @@
        this.type = type;
    }
    @Override
    public String getApp() {
        return app;
    }
    @Override
    public void setApp(String app) {
        this.app = app;
    }
    @Override
    public String getStream() {
        return stream;
    }
    @Override
    public void setStream(String stream) {
        this.stream = stream;
    }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
@@ -124,18 +124,22 @@
        this.id = id;
    }
    @Override
    public String getApp() {
        return app;
    }
    @Override
    public void setApp(String app) {
        this.app = app;
    }
    @Override
    public String getStream() {
        return stream;
    }
    @Override
    public void setStream(String stream) {
        this.stream = stream;
    }
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -12,6 +12,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import javax.sip.DialogState;
@@ -43,7 +45,7 @@
        }
        logger.info("[添加目录订阅] 设备{}", device.getDeviceId());
        // 添加目录订阅
        CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander);
        CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander, dynamicTask);
        // 提前开始刷新订阅
        int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30);
        // 设置最小值为30
@@ -68,10 +70,10 @@
        }
        logger.info("[添加移动位置订阅] 设备{}", device.getDeviceId());
        // 添加目录订阅
        MobilePositionSubscribeTask mobilePositionSubscribeTask = new MobilePositionSubscribeTask(device, sipCommander);
        // 提前开始刷新订阅
        MobilePositionSubscribeTask mobilePositionSubscribeTask = new MobilePositionSubscribeTask(device, sipCommander, dynamicTask);
        // 设置最小值为30
        int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30);
        // 提前开始刷新订阅
        dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog -1 );
        return true;
    }
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
@@ -70,7 +70,9 @@
        boolean result = false;
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        ParentPlatform parentPlatform = platformMapper.getParentPlatByServerGBId(platformId);
        if (catalogId == null) catalogId = parentPlatform.getCatalogId();
        if (catalogId == null) {
            catalogId = parentPlatform.getCatalogId();
        }
        try {
            List<DeviceChannel> deviceChannelList = new ArrayList<>();
            for (GbStream gbStream : gbStreams) {
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -54,7 +54,9 @@
        if (mediaList != null) {
            if (mediaList.getInteger("code") == 0) {
                JSONArray data = mediaList.getJSONArray("data");
                if (data == null) return null;
                if (data == null) {
                    return null;
                }
                JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
                JSONArray tracks = mediaJSON.getJSONArray("tracks");
                streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks);
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -4,6 +4,7 @@
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
@@ -86,6 +87,9 @@
    @Autowired
    private UserSetting userSetting;
    @Autowired
    private DynamicTask dynamicTask;
@@ -100,7 +104,7 @@
        String uuid = UUID.randomUUID().toString();
        msg.setId(uuid);
        playResult.setUuid(uuid);
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(userSetting.getPlayTimeout());
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
        playResult.setResult(result);
        // 录像查询以channelId作为deviceId查询
        resultHolder.put(key, uuid, result);
@@ -237,30 +241,27 @@
        }
        // 超时处理
        Timer timer = new Timer();
        String timeOutTaskKey = UUID.randomUUID().toString();
        SSRCInfo finalSsrcInfo = ssrcInfo;
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", device.getDeviceId(), channelId));
        dynamicTask.startDelay( timeOutTaskKey,()->{
            logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", device.getDeviceId(), channelId));
                SIPDialog dialog = streamSession.getDialogByStream(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
                if (dialog != null) {
                    timeoutCallback.run(1, "收流超时");
                    // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
                    cmder.streamByeCmd(device.getDeviceId(), channelId, finalSsrcInfo.getStream(), null);
                }else {
                    timeoutCallback.run(0, "点播超时");
                    mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
                    mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
                    streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
                }
            SIPDialog dialog = streamSession.getDialogByStream(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
            if (dialog != null) {
                timeoutCallback.run(1, "收流超时");
                // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
                cmder.streamByeCmd(device.getDeviceId(), channelId, finalSsrcInfo.getStream(), null);
            }else {
                timeoutCallback.run(0, "点播超时");
                mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
                mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
                streamSession.remove(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
            }
        }, userSetting.getPlayTimeout());
        }, userSetting.getPlayTimeout()*1000);
        final String ssrc = ssrcInfo.getSsrc();
        cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
            logger.info("收到订阅消息: " + response.toJSONString());
            timer.cancel();
            dynamicTask.stop(timeOutTaskKey);
            // hook响应
            onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId, uuid);
            hookEvent.response(mediaServerItemInuse, response);
@@ -292,7 +293,7 @@
                }
            }
        }, (event) -> {
            timer.cancel();
            dynamicTask.stop(timeOutTaskKey);
            mediaServerService.closeRTPServer(device.getDeviceId(), channelId, finalSsrcInfo.getStream());
            // 释放ssrc
            mediaServerService.releaseSsrc(mediaServerItem.getId(), finalSsrcInfo.getSsrc());
@@ -334,7 +335,9 @@
    @Override
    public MediaServerItem getNewMediaServerItem(Device device) {
        if (device == null) return null;
        if (device == null) {
            return null;
        }
        String mediaServerId = device.getMediaServerId();
        MediaServerItem mediaServerItem;
        if (mediaServerId == null) {
@@ -353,7 +356,9 @@
                                                           String endTime,InviteStreamCallback inviteStreamCallback,
                                                           PlayBackCallback callback) {
        Device device = storager.queryVideoDevice(deviceId);
        if (device == null) return null;
        if (device == null) {
            return null;
        }
        MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
@@ -365,7 +370,9 @@
                                                           String deviceId, String channelId, String startTime,
                                                           String endTime, InviteStreamCallback infoCallBack,
                                                           PlayBackCallback playBackCallback) {
        if (mediaServerItem == null || ssrcInfo == null) return null;
        if (mediaServerItem == null || ssrcInfo == null) {
            return null;
        }
        String uuid = UUID.randomUUID().toString();
        String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L);
@@ -380,34 +387,31 @@
        msg.setId(uuid);
        msg.setKey(key);
        PlayBackResult<RequestMessage> playBackResult = new PlayBackResult<>();
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
                playBackResult.setCode(-1);
                playBackResult.setData(msg);
                playBackCallback.call(playBackResult);
                SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
        String  playBackTimeOutTaskKey = UUID.randomUUID().toString();
        dynamicTask.startDelay(playBackTimeOutTaskKey, ()->{
            logger.warn(String.format("设备回放超时,deviceId:%s ,channelId:%s", deviceId, channelId));
            playBackResult.setCode(-1);
            playBackResult.setData(msg);
            playBackCallback.call(playBackResult);
            SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
            // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
            if (dialog != null) {
                // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
                if (dialog != null) {
                    // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
                    cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
                }else {
                    mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
                    mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream());
                    streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
                }
                cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
                // 回复之前所有的点播请求
                playBackCallback.call(playBackResult);
            }else {
                mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
                mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream());
                streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
            }
        }, userSetting.getPlayTimeout());
            cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
            // 回复之前所有的点播请求
            playBackCallback.call(playBackResult);
        }, userSetting.getPlayTimeout()*1000);
        cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack,
                (InviteStreamInfo inviteStreamInfo) -> {
                    logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
                    timer.cancel();
                    dynamicTask.stop(playBackTimeOutTaskKey);
                    StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
                    if (streamInfo == null) {
                        logger.warn("设备回放API调用失败!");
@@ -425,7 +429,7 @@
                    playBackResult.setResponse(inviteStreamInfo.getResponse());
                    playBackCallback.call(playBackResult);
                }, event -> {
                    timer.cancel();
                    dynamicTask.stop(playBackTimeOutTaskKey);
                    msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
                    playBackResult.setCode(-1);
                    playBackResult.setData(msg);
@@ -439,7 +443,9 @@
    @Override
    public DeferredResult<ResponseEntity<String>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
        Device device = storager.queryVideoDevice(deviceId);
        if (device == null) return null;
        if (device == null) {
            return null;
        }
        MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
@@ -448,7 +454,9 @@
    @Override
    public DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
        if (mediaServerItem == null || ssrcInfo == null) return null;
        if (mediaServerItem == null || ssrcInfo == null) {
            return null;
        }
        String uuid = UUID.randomUUID().toString();
        String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L);
@@ -467,34 +475,31 @@
        PlayBackResult<RequestMessage> downloadResult = new PlayBackResult<>();
        downloadResult.setData(msg);
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
                wvpResult.setCode(-1);
                wvpResult.setMsg("录像下载请求超时");
                downloadResult.setCode(-1);
                hookCallBack.call(downloadResult);
                SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
        String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
        dynamicTask.startDelay(downLoadTimeOutTaskKey, ()->{
            logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
            wvpResult.setCode(-1);
            wvpResult.setMsg("录像下载请求超时");
            downloadResult.setCode(-1);
            hookCallBack.call(downloadResult);
            SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
            // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
            if (dialog != null) {
                // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
                if (dialog != null) {
                    // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
                    cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
                }else {
                    mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
                    mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream());
                    streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
                }
                cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
                // 回复之前所有的点播请求
                hookCallBack.call(downloadResult);
            }else {
                mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
                mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream());
                streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
            }
        }, userSetting.getPlayTimeout());
            cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
            // 回复之前所有的点播请求
            hookCallBack.call(downloadResult);
        }, userSetting.getPlayTimeout()*1000);
        cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack,
                inviteStreamInfo -> {
                    logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
                    timer.cancel();
                    dynamicTask.stop(downLoadTimeOutTaskKey);
                    StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
                    streamInfo.setStartTime(startTime);
                    streamInfo.setEndTime(endTime);
@@ -515,7 +520,7 @@
                    downloadResult.setResponse(inviteStreamInfo.getResponse());
                    hookCallBack.call(downloadResult);
                }, event -> {
                    timer.cancel();
                    dynamicTask.stop(downLoadTimeOutTaskKey);
                    downloadResult.setCode(-1);
                    wvpResult.setCode(-1);
                    wvpResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg));
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -194,7 +194,9 @@
    @Override
    public JSONObject removeStreamProxyFromZlm(StreamProxyItem param) {
        if (param ==null) return null;
        if (param ==null) {
            return null;
        }
        MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId());
        JSONObject result = zlmresTfulUtils.closeStreams(mediaServerItem, param.getApp(), param.getStream());
        return result;
@@ -230,7 +232,9 @@
        StreamProxyItem streamProxy = videoManagerStorager.queryStreamProxy(app, stream);
        if (!streamProxy.isEnable() &&  streamProxy != null) {
            JSONObject jsonObject = addStreamProxyToZlm(streamProxy);
            if (jsonObject == null) return false;
            if (jsonObject == null) {
                return false;
            }
            if (jsonObject.getInteger("code") == 0) {
                result = true;
                streamProxy.setEnable(true);
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
@@ -66,7 +66,9 @@
    @Override
    public List<StreamPushItem> handleJSON(String jsonData, MediaServerItem mediaServerItem) {
        if (jsonData == null) return null;
        if (jsonData == null) {
            return null;
        }
        Map<String, StreamPushItem> result = new HashMap<>();
@@ -219,7 +221,9 @@
            }
        }
        zlmresTfulUtils.getMediaList(mediaServerItem, (mediaList ->{
            if (mediaList == null) return;
            if (mediaList == null) {
                return;
            }
            String dataStr = mediaList.getString("data");
            Integer code = mediaList.getInteger("code");
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
@@ -34,7 +34,9 @@
    @Override
    public int addUser(User user) {
        User userByUsername = userMapper.getUserByUsername(user.getUsername());
        if (userByUsername != null) return 0;
        if (userByUsername != null) {
            return 0;
        }
        return userMapper.add(user);
    }
    @Override
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -223,4 +223,11 @@
    void sendStreamPushRequestedMsg(MessageForPushChannel messageForPushChannel);
    /**
     * 判断设备状态
     * @param deviceId 设备ID
     * @return
     */
    public boolean deviceIsOnline(String deviceId);
}
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -103,7 +103,9 @@
     */
    @Override
    public boolean stopPlay(StreamInfo streamInfo) {
        if (streamInfo == null) return false;
        if (streamInfo == null) {
            return false;
        }
        return redis.del(String.format("%S_%s_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
                userSetting.getServerId(),
                streamInfo.getStream(),
@@ -127,7 +129,9 @@
    @Override
    public StreamInfo queryPlayByStreamId(String streamId) {
        List<Object> playLeys = redis.scan(String.format("%S_%s_%s_*", VideoManagerConstants.PLAYER_PREFIX, userSetting.getServerId(), streamId));
        if (playLeys == null || playLeys.size() == 0) return null;
        if (playLeys == null || playLeys.size() == 0) {
            return null;
        }
        return (StreamInfo)redis.get(playLeys.get(0).toString());
    }
@@ -137,7 +141,9 @@
                userSetting.getServerId(),
                deviceId,
                channelId));
        if (playLeys == null || playLeys.size() == 0) return null;
        if (playLeys == null || playLeys.size() == 0) {
            return null;
        }
        return (StreamInfo)redis.get(playLeys.get(0).toString());
    }
@@ -146,7 +152,9 @@
        Map<String, StreamInfo> streamInfos = new HashMap<>();
//        List<Object> playLeys = redis.keys(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
        List<Object> players = redis.scan(String.format("%S_%s_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, userSetting.getServerId(),deviceId));
        if (players.size() == 0) return streamInfos;
        if (players.size() == 0) {
            return streamInfos;
        }
        for (Object player : players) {
            String key = (String) player;
            StreamInfo streamInfo = (StreamInfo) redis.get(key);
@@ -182,10 +190,18 @@
            deviceChannel.setDeviceId(deviceId);
            deviceChannelMapper.update(deviceChannel);
        }
        if (deviceId == null) deviceId = "*";
        if (channelId == null) channelId = "*";
        if (stream == null) stream = "*";
        if (callId == null) callId = "*";
        if (deviceId == null) {
            deviceId = "*";
        }
        if (channelId == null) {
            channelId = "*";
        }
        if (stream == null) {
            stream = "*";
        }
        if (callId == null) {
            callId = "*";
        }
        String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
                userSetting.getServerId(),
                deviceId,
@@ -210,10 +226,18 @@
            deviceChannel.setDeviceId(deviceId);
            deviceChannelMapper.update(deviceChannel);
        }
        if (deviceId == null) deviceId = "*";
        if (channelId == null) channelId = "*";
        if (stream == null) stream = "*";
        if (callId == null) callId = "*";
        if (deviceId == null) {
            deviceId = "*";
        }
        if (channelId == null) {
            channelId = "*";
        }
        if (stream == null) {
            stream = "*";
        }
        if (callId == null) {
            callId = "*";
        }
        String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
                userSetting.getServerId(),
                deviceId,
@@ -235,10 +259,18 @@
        if (stream == null && callId == null) {
            return null;
        }
        if (deviceId == null) deviceId = "*";
        if (channelId == null) channelId = "*";
        if (stream == null) stream = "*";
        if (callId == null) callId = "*";
        if (deviceId == null) {
            deviceId = "*";
        }
        if (channelId == null) {
            channelId = "*";
        }
        if (stream == null) {
            stream = "*";
        }
        if (callId == null) {
            callId = "*";
        }
        String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
                userSetting.getServerId(),
                deviceId,
@@ -328,10 +360,18 @@
    @Override
    public SendRtpItem querySendRTPServer(String platformGbId, String channelId, String streamId, String callId) {
        if (platformGbId == null) platformGbId = "*";
        if (channelId == null) channelId = "*";
        if (streamId == null) streamId = "*";
        if (callId == null) callId = "*";
        if (platformGbId == null) {
            platformGbId = "*";
        }
        if (channelId == null) {
            channelId = "*";
        }
        if (streamId == null) {
            streamId = "*";
        }
        if (callId == null) {
            callId = "*";
        }
        String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + userSetting.getServerId() + "_" + platformGbId
                + "_" + channelId + "_" + streamId + "_" + callId;
        List<Object> scan = redis.scan(key);
@@ -344,7 +384,9 @@
    @Override
    public List<SendRtpItem> querySendRTPServer(String platformGbId) {
        if (platformGbId == null) platformGbId = "*";
        if (platformGbId == null) {
            platformGbId = "*";
        }
        String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + userSetting.getServerId() + "_" + platformGbId + "_*" + "_*" + "_*";
        List<Object> queryResult = redis.scan(key);
        List<SendRtpItem> result= new ArrayList<>();
@@ -364,8 +406,12 @@
     */
    @Override
    public void deleteSendRTPServer(String platformGbId, String channelId, String callId, String streamId) {
        if (streamId == null) streamId = "*";
        if (callId == null) callId = "*";
        if (streamId == null) {
            streamId = "*";
        }
        if (callId == null) {
            callId = "*";
        }
        String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + userSetting.getServerId() + "_" + platformGbId
                + "_" + channelId + "_" + streamId + "_" + callId;
        List<Object> scan = redis.scan(key);
@@ -473,10 +519,18 @@
        if (stream == null && callId == null) {
            return null;
        }
        if (deviceId == null) deviceId = "*";
        if (channelId == null) channelId = "*";
        if (stream == null) stream = "*";
        if (callId == null) callId = "*";
        if (deviceId == null) {
            deviceId = "*";
        }
        if (channelId == null) {
            channelId = "*";
        }
        if (stream == null) {
            stream = "*";
        }
        if (callId == null) {
            callId = "*";
        }
        String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
                userSetting.getServerId(),
                deviceId,
@@ -645,4 +699,10 @@
        logger.info("[redis 报警通知] {}: {}", key, JSON.toJSON(msg));
        redis.convertAndSend(key, (JSONObject)JSON.toJSON(msg));
    }
    @Override
    public boolean deviceIsOnline(String deviceId) {
        String key = VideoManagerConstants.KEEPLIVEKEY_PREFIX + userSetting.getServerId() + "_" + deviceId;
        return redis.hasKey(key);
    }
}
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -460,7 +460,9 @@
    public synchronized boolean outline(String deviceId) {
        logger.info("更新设备离线: " + deviceId);
        Device device = deviceMapper.getDeviceByDeviceId(deviceId);
        if (device == null) return false;
        if (device == null) {
            return false;
        }
        device.setOnline(0);
        redisCatchStorage.updateDevice(device);
        return deviceMapper.update(device) > 0;
@@ -714,6 +716,7 @@
     * 删除指定设备的所有移动位置
     * @param deviceId
     */
    @Override
    public int clearMobilePositionsByDeviceId(String deviceId) {
        return deviceMobilePositionMapper.clearMobilePositionsByDeviceId(deviceId);
    }
@@ -859,7 +862,9 @@
    @Override
    public void updateMediaList(List<StreamPushItem> streamPushItems) {
        if (streamPushItems == null || streamPushItems.size() == 0) return;
        if (streamPushItems == null || streamPushItems.size() == 0) {
            return;
        }
        logger.info("updateMediaList:  " + streamPushItems.size());
        streamPushMapper.addAll(streamPushItems);
        // TODO 待优化
src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java
@@ -34,7 +34,9 @@
     * 获取对象 这里重写了bean方法,起主要作用
     */
    public static Object getBean(String beanId) throws BeansException {
        if (applicationContext == null) return null;
        if (applicationContext == null) {
            return null;
        }
        return applicationContext.getBean(beanId);
    }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java
@@ -85,16 +85,30 @@
                                             @RequestParam(required = false) String startTime,
                                             @RequestParam(required = false) String endTime
                                             ) {
        if (StringUtils.isEmpty(alarmPriority)) alarmPriority = null;
        if (StringUtils.isEmpty(alarmMethod)) alarmMethod = null;
        if (StringUtils.isEmpty(alarmType)) alarmType = null;
        if (StringUtils.isEmpty(startTime)) startTime = null;
        if (StringUtils.isEmpty(endTime)) endTime = null;
        if (StringUtils.isEmpty(alarmPriority)) {
            alarmPriority = null;
        }
        if (StringUtils.isEmpty(alarmMethod)) {
            alarmMethod = null;
        }
        if (StringUtils.isEmpty(alarmType)) {
            alarmType = null;
        }
        if (StringUtils.isEmpty(startTime)) {
            startTime = null;
        }
        if (StringUtils.isEmpty(endTime)) {
            endTime = null;
        }
        try {
            if (startTime != null)  format.parse(startTime);
            if (endTime != null)  format.parse(endTime);
            if (startTime != null) {
                format.parse(startTime);
            }
            if (endTime != null) {
                format.parse(endTime);
            }
        } catch (ParseException e) {
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }
@@ -125,9 +139,15 @@
                                              @RequestParam(required = false) String deviceIds,
                                              @RequestParam(required = false) String time
    ) {
        if (StringUtils.isEmpty(id)) id = null;
        if (StringUtils.isEmpty(deviceIds)) deviceIds = null;
        if (StringUtils.isEmpty(time)) time = null;
        if (StringUtils.isEmpty(id)) {
            id = null;
        }
        if (StringUtils.isEmpty(deviceIds)) {
            deviceIds = null;
        }
        if (StringUtils.isEmpty(time)) {
            time = null;
        }
        try {
            if (time != null) {
                format.parse(time);
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -6,7 +6,6 @@
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
@@ -54,9 +53,6 @@
    
    @Autowired
    private DeferredResultHolder resultHolder;
    @Autowired
    private DeviceOffLineDetector offLineDetector;
    @Autowired
    private IDeviceService deviceService;
@@ -310,9 +306,15 @@
        if (device != null && device.getDeviceId() != null) {
            Device deviceInStore = storager.queryVideoDevice(device.getDeviceId());
            if (!StringUtils.isEmpty(device.getName())) deviceInStore.setName(device.getName());
            if (!StringUtils.isEmpty(device.getCharset())) deviceInStore.setCharset(device.getCharset());
            if (!StringUtils.isEmpty(device.getMediaServerId())) deviceInStore.setMediaServerId(device.getMediaServerId());
            if (!StringUtils.isEmpty(device.getName())) {
                deviceInStore.setName(device.getName());
            }
            if (!StringUtils.isEmpty(device.getCharset())) {
                deviceInStore.setCharset(device.getCharset());
            }
            if (!StringUtils.isEmpty(device.getMediaServerId())) {
                deviceInStore.setMediaServerId(device.getMediaServerId());
            }
            //  目录订阅相关的信息
            if (device.getSubscribeCycleForCatalog() > 0) {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
@@ -286,7 +286,9 @@
            return new ResponseEntity<>("missing parameters", HttpStatus.BAD_REQUEST);
        }
        ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(serverGBId);
        if (parentPlatform == null) return new ResponseEntity<>("fail", HttpStatus.OK);
        if (parentPlatform == null) {
            return new ResponseEntity<>("fail", HttpStatus.OK);
        }
        // 发送离线消息,无论是否成功都删除缓存
        commanderForPlatform.unregister(parentPlatform, (event -> {
            // 清空redis缓存
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java
@@ -65,16 +65,26 @@
            @RequestParam(required = false) String startTime,
            @RequestParam(required = false) String endTime
    ) {
        if (StringUtils.isEmpty(query)) query = null;
        if (StringUtils.isEmpty(startTime)) startTime = null;
        if (StringUtils.isEmpty(endTime)) endTime = null;
        if (StringUtils.isEmpty(query)) {
            query = null;
        }
        if (StringUtils.isEmpty(startTime)) {
            startTime = null;
        }
        if (StringUtils.isEmpty(endTime)) {
            endTime = null;
        }
        if (!userSetting.getLogInDatebase()) {
            logger.warn("自动记录日志功能已关闭,查询结果可能不完整。");
        }
        try {
            if (startTime != null)  format.parse(startTime);
            if (endTime != null)  format.parse(endTime);
            if (startTime != null) {
                format.parse(startTime);
            }
            if (endTime != null) {
                format.parse(endTime);
            }
        } catch (ParseException e) {
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        }
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
@@ -69,9 +69,15 @@
    @ResponseBody
    public WVPResult save(@RequestBody StreamProxyItem param){
        logger.info("添加代理: " + JSONObject.toJSONString(param));
        if (StringUtils.isEmpty(param.getMediaServerId())) param.setMediaServerId("auto");
        if (StringUtils.isEmpty(param.getType())) param.setType("default");
        if (StringUtils.isEmpty(param.getGbId())) param.setGbId(null);
        if (StringUtils.isEmpty(param.getMediaServerId())) {
            param.setMediaServerId("auto");
        }
        if (StringUtils.isEmpty(param.getType())) {
            param.setType("default");
        }
        if (StringUtils.isEmpty(param.getGbId())) {
            param.setGbId(null);
        }
        WVPResult<StreamInfo> result = streamProxyService.save(param);
        return result;
    }
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
@@ -68,7 +68,7 @@
                                             @RequestParam(required = false)String timeout
    ){
        DeferredResult<JSONObject> resultDeferredResult = new DeferredResult<>(userSetting.getPlayTimeout() + 10);
        DeferredResult<JSONObject> resultDeferredResult = new DeferredResult<>(userSetting.getPlayTimeout().longValue() + 10);
        Device device = storager.queryVideoDevice(serial);
        if (device == null ) {
            JSONObject result = new JSONObject();
web_src/index.html
@@ -12,26 +12,7 @@
    <script type="text/javascript" src="./static/js/jessibuca/jessibuca.js"></script>
    <script type="text/javascript" src="./static/js/EasyWasmPlayer.js"></script>
    <script type="text/javascript" src="./static/js/ZLMRTCClient.js"></script>
    <script type="text/javascript" src="./static/js/mapConfig.js"></script>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script>
      // map组件全局参数, 注释此内容可以关闭地图功能
      window.mapParam = {
        // 坐标系 GCJ-02 WGS-84,
        coordinateSystem: "GCJ-02",
        // 地图瓦片地址
        tilesUrl: "http://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
        // 瓦片大小
        tileSize: 256,
        // 默认层级
        zoom:10,
        // 默认地图中心点
        center:[116.41020, 39.915119],
        // 地图最大层级
        maxZoom:18,
        // 地图最小层级
        minZoom: 3
      }
    </script>
  </body>
</html>
web_src/src/components/common/jessibuca.vue
@@ -1,5 +1,5 @@
<template>
  <div ref="container" @dblclick="fullscreenSwich" style="width:100%;height:100%;background-color: #eee;margin:0 auto;">
  <div ref="container" @dblclick="fullscreenSwich" style="width:100%;height:100%;background-color: #000000;margin:0 auto;">
    <div class="buttons-box" id="buttonsBox">
      <div class="buttons-box-left">
        <i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i>
web_src/src/components/devicePosition.vue
@@ -59,7 +59,7 @@
  },
  data() {
    return {
      onOff: typeof window.mapParam !== "undefined",
      onOff: typeof window.mapParam !== "undefined" && window.mapParam.enable,
      deviceService: new DeviceService(),
      layer: null,
      lineLayer: null,
web_src/static/js/mapConfig.js
New file
@@ -0,0 +1,19 @@
// map组件全局参数, 注释此内容可以关闭地图功能
window.mapParam = {
  // 开启/关闭地图功能
  enable: true,
  // 坐标系 GCJ-02 WGS-84,
  coordinateSystem: "GCJ-02",
  // 地图瓦片地址
  tilesUrl: "http://webrd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
  // 瓦片大小
  tileSize: 256,
  // 默认层级
  zoom:10,
  // 默认地图中心点
  center:[116.41020, 39.915119],
  // 地图最大层级
  maxZoom:18,
  // 地图最小层级
  minZoom: 3
}