648540858
2022-08-21 5461b8ebf2f8bf66a9d34351eb8783484304958a
支持全局异常和统一返回结果,未完待续
69个文件已修改
4个文件已添加
1 文件已重命名
16241 ■■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/conf/GlobalExceptionHandler.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/GlobalResponseAdvice.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/exception/ControllerException.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java 81 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/bean/PlayTypeEnum.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/PlayResult.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java 92 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java 187 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/user/RoleController.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/package-lock.json 14432 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/CloudRecord.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/CloudRecordDetail.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/DeviceList.vue 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/Login.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/ParentPlatformList.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/PushVideoList.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/channelList.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/chooseChannelForGb.vue 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/devicePlayer.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/platformEdit.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/live.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/GlobalExceptionHandler.java
New file
@@ -0,0 +1,56 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
 * 全局异常处理
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    private final static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    /**
     * 默认异常处理
     * @param e 异常
     * @return 统一返回结果
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public WVPResult<String> exceptionHandler(Exception e) {
        logger.error("[全局异常]: ", e);
        return WVPResult.fail(ErrorCode.ERROR500.getCode(), e.getMessage());
    }
    /**
     * 自定义异常处理, 处理controller中返回的错误
     * @param e 异常
     * @return 统一返回结果
     */
    @ExceptionHandler(ControllerException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public WVPResult<String> exceptionHandler(ControllerException e) {
        return WVPResult.fail(e.getCode(), e.getMsg());
    }
    /**
     * 登陆失败
     * @param e 异常
     * @return 统一返回结果
     */
    @ExceptionHandler(BadCredentialsException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public WVPResult<String> exceptionHandler(BadCredentialsException e) {
        return WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMessage());
    }
}
src/main/java/com/genersoft/iot/vmp/conf/GlobalResponseAdvice.java
New file
@@ -0,0 +1,51 @@
package com.genersoft.iot.vmp.conf;
import com.alibaba.fastjson.JSON;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
 * 全局统一返回结果
 */
@RestControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 排除api文档的接口,这个接口不需要统一
        String[] excludePath = {"/v3/api-docs","/api/v1"};
        for (String path : excludePath) {
            if (request.getURI().getPath().startsWith(path)) {
                return body;
            }
        }
        if (body instanceof WVPResult) {
            return body;
        }
        if (body instanceof ErrorCode) {
            ErrorCode errorCode = (ErrorCode) body;
            return new WVPResult<>(errorCode.getCode(), errorCode.getMsg(), null);
        }
        if (body instanceof String) {
            return JSON.toJSON(WVPResult.success(body));
        }
        return WVPResult.success(body);
    }
}
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
@@ -4,6 +4,7 @@
import com.genersoft.iot.vmp.utils.DateUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.net.InetAddress;
@@ -88,7 +89,7 @@
    }
    public String getHookIp() {
        if (StringUtils.isEmpty(hookIp)){
        if (ObjectUtils.isEmpty(hookIp)){
            return sipIp;
        }else {
            return hookIp;
@@ -162,7 +163,7 @@
    }
    public String getSdpIp() {
        if (StringUtils.isEmpty(sdpIp)){
        if (ObjectUtils.isEmpty(sdpIp)){
            return ip;
        }else {
            if (isValidIPAddress(sdpIp)) {
@@ -181,7 +182,7 @@
    }
    public String getStreamIp() {
        if (StringUtils.isEmpty(streamIp)){
        if (ObjectUtils.isEmpty(streamIp)){
            return ip;
        }else {
            return streamIp;
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
@@ -14,6 +14,7 @@
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.servlet.ServletException;
@@ -55,7 +56,7 @@
            String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
            MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
            if (mediaInfo != null) {
                if (!StringUtils.isEmpty(queryStr)) {
                if (!ObjectUtils.isEmpty(queryStr)) {
                    queryStr += "&secret=" + mediaInfo.getSecret();
                }else {
                    queryStr = "secret=" + mediaInfo.getSecret();
@@ -146,7 +147,7 @@
                logger.error("[ZLM服务访问代理],错误:处理url信息时未找到流媒体信息=>{}", requestURI);
                return  url;
            }
            if (!StringUtils.isEmpty(mediaInfo.getId())) {
            if (!ObjectUtils.isEmpty(mediaInfo.getId())) {
                url = url.replace(mediaInfo.getId() + "/", "");
            }
            return url.replace("default/", "");
@@ -173,7 +174,7 @@
            MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
            String remoteHost = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getHttpPort());
            if (mediaInfo != null) {
                if (!StringUtils.isEmpty(queryStr)) {
                if (!ObjectUtils.isEmpty(queryStr)) {
                    queryStr += "&remoteHost=" + remoteHost;
                }else {
                    queryStr = "remoteHost=" + remoteHost;
@@ -265,7 +266,7 @@
                logger.error("[录像服务访问代理],错误:处理url信息时未找到流媒体信息=>{}", requestURI);
                return  url;
            }
            if (!StringUtils.isEmpty(mediaInfo.getId())) {
            if (!ObjectUtils.isEmpty(mediaInfo.getId())) {
                url = url.replace(mediaInfo.getId() + "/", "");
            }
            return url.replace("default/", "");
src/main/java/com/genersoft/iot/vmp/conf/exception/ControllerException.java
New file
@@ -0,0 +1,37 @@
package com.genersoft.iot.vmp.conf.exception;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
/**
 * 自定义异常,controller出现错误时直接抛出异常由全局异常捕获并返回结果
 */
public class ControllerException extends RuntimeException{
    private int code;
    private String msg;
    public ControllerException(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public ControllerException(ErrorCode errorCode) {
        this.code = errorCode.getCode();
        this.msg = errorCode.getMsg();
    }
    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -91,6 +91,7 @@
                    .antMatchers("/webjars/**")
                    .antMatchers("/swagger-resources/**")
                    .antMatchers("/v3/api-docs/**")
                    .antMatchers("/favicon.ico")
                    .antMatchers("/js/**");
            List<String> interfaceAuthenticationExcludes = userSetting.getInterfaceAuthenticationExcludes();
            for (String interfaceAuthenticationExclude : interfaceAuthenticationExcludes) {
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
@@ -15,6 +15,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.*;
@@ -58,7 +59,7 @@
        ParentPlatform parentPlatform = null;
        Map<String, List<ParentPlatform>> parentPlatformMap = new HashMap<>();
        if (!StringUtils.isEmpty(event.getPlatformId())) {
        if (!ObjectUtils.isEmpty(event.getPlatformId())) {
            subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId());
            if (subscribe == null) {
                return;
@@ -81,7 +82,7 @@
            }else if (event.getGbStreams() != null) {
                if (platforms.size() > 0) {
                    for (GbStream gbStream : event.getGbStreams()) {
                        if (gbStream == null || StringUtils.isEmpty(gbStream.getGbId())) {
                        if (gbStream == null || ObjectUtils.isEmpty(gbStream.getGbId())) {
                            continue;
                        }
                        List<ParentPlatform> parentPlatformsForGB = storager.queryPlatFormListForStreamWithGBId(gbStream.getApp(),gbStream.getStream(), platforms);
src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java
@@ -60,16 +60,12 @@
                // 处理录像数据, 返回给前端
                String msgKey = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getSn();
                WVPResult<RecordInfo> wvpResult = new WVPResult<>();
                wvpResult.setCode(0);
                wvpResult.setMsg("success");
                // 对数据进行排序
                Collections.sort(recordInfo.getRecordList());
                wvpResult.setData(recordInfo);
                RequestMessage msg = new RequestMessage();
                msg.setKey(msgKey);
                msg.setData(wvpResult);
                msg.setData(recordInfo);
                deferredResultHolder.invokeAllResult(msg);
                data.remove(key);
            }
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
@@ -14,6 +14,7 @@
import gov.nist.javax.sip.stack.SIPDialog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**    
@@ -110,16 +111,16 @@
    public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){
        if (StringUtils.isEmpty(deviceId)) {
        if (ObjectUtils.isEmpty(deviceId)) {
            deviceId ="*";
        }
        if (StringUtils.isEmpty(channelId)) {
        if (ObjectUtils.isEmpty(channelId)) {
            channelId ="*";
        }
        if (StringUtils.isEmpty(callId)) {
        if (ObjectUtils.isEmpty(callId)) {
            callId ="*";
        }
        if (StringUtils.isEmpty(stream)) {
        if (ObjectUtils.isEmpty(stream)) {
            stream ="*";
        }
        String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
@@ -131,16 +132,16 @@
    }
    public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){
        if (StringUtils.isEmpty(deviceId)) {
        if (ObjectUtils.isEmpty(deviceId)) {
            deviceId ="*";
        }
        if (StringUtils.isEmpty(channelId)) {
        if (ObjectUtils.isEmpty(channelId)) {
            channelId ="*";
        }
        if (StringUtils.isEmpty(callId)) {
        if (ObjectUtils.isEmpty(callId)) {
            callId ="*";
        }
        if (StringUtils.isEmpty(stream)) {
        if (ObjectUtils.isEmpty(stream)) {
            stream ="*";
        }
        String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
@@ -3,8 +3,6 @@
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd.KeepaliveNotifyMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.response.ISIPResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor;
import org.slf4j.Logger;
@@ -14,13 +12,10 @@
import org.springframework.stereotype.Component;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.address.URI;
import javax.sip.header.*;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -42,9 +37,6 @@
    @Autowired
    private EventPublisher eventPublisher;
    /**
     * 添加 request订阅
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
@@ -96,7 +96,7 @@
        if (result == null) {
            return;
        }
        result.setResult(new ResponseEntity<>(msg.getData(),HttpStatus.OK));
        result.setResult(msg.getData());
        deferredResultMap.remove(msg.getId());
        if (deferredResultMap.size() == 0) {
            map.remove(msg.getKey());
@@ -118,9 +118,8 @@
            if (result == null) {
                return;
            }
            result.setResult(ResponseEntity.ok().body(msg.getData()));
            result.setResult(msg.getData());
        }
        map.remove(msg.getKey());
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -32,6 +32,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.*;
@@ -856,7 +857,7 @@
            cmdXml.append("<Control>\r\n");
            cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            if (StringUtils.isEmpty(channelId)) {
            if (ObjectUtils.isEmpty(channelId)) {
                cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            } else {
                cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -959,16 +960,16 @@
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
            if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
            if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
                cmdXml.append("<Info>\r\n");
            }
            if (!StringUtils.isEmpty(alarmMethod)) {
            if (!ObjectUtils.isEmpty(alarmMethod)) {
                cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
            }
            if (!StringUtils.isEmpty(alarmType)) {
            if (!ObjectUtils.isEmpty(alarmType)) {
                cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
            }
            if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
            if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
                cmdXml.append("</Info>\r\n");
            }
            cmdXml.append("</Control>\r\n");
@@ -1002,7 +1003,7 @@
            cmdXml.append("<Control>\r\n");
            cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            if (StringUtils.isEmpty(channelId)) {
            if (ObjectUtils.isEmpty(channelId)) {
                cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            } else {
                cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -1041,7 +1042,7 @@
            cmdXml.append("<Control>\r\n");
            cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            if (StringUtils.isEmpty(channelId)) {
            if (ObjectUtils.isEmpty(channelId)) {
                cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            } else {
                cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -1110,13 +1111,13 @@
            cmdXml.append("<Control>\r\n");
            cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            if (StringUtils.isEmpty(channelId)) {
            if (ObjectUtils.isEmpty(channelId)) {
                cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            } else {
                cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
            }
            cmdXml.append("<BasicParam>\r\n");
            if (!StringUtils.isEmpty(name)) {
            if (!ObjectUtils.isEmpty(name)) {
                cmdXml.append("<Name>" + name + "</Name>\r\n");
            }
            if (NumericUtil.isInteger(expiration)) {
@@ -1326,22 +1327,22 @@
            cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            if (!StringUtils.isEmpty(startPriority)) {
            if (!ObjectUtils.isEmpty(startPriority)) {
                cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
            }
            if (!StringUtils.isEmpty(endPriority)) {
            if (!ObjectUtils.isEmpty(endPriority)) {
                cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
            }
            if (!StringUtils.isEmpty(alarmMethod)) {
            if (!ObjectUtils.isEmpty(alarmMethod)) {
                cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
            }
            if (!StringUtils.isEmpty(alarmType)) {
            if (!ObjectUtils.isEmpty(alarmType)) {
                cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
            }
            if (!StringUtils.isEmpty(startTime)) {
            if (!ObjectUtils.isEmpty(startTime)) {
                cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
            }
            if (!StringUtils.isEmpty(endTime)) {
            if (!ObjectUtils.isEmpty(endTime)) {
                cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
            }
            cmdXml.append("</Query>\r\n");
@@ -1376,7 +1377,7 @@
            cmdXml.append("<Query>\r\n");
            cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            if (StringUtils.isEmpty(channelId)) {
            if (ObjectUtils.isEmpty(channelId)) {
                cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            } else {
                cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -1412,7 +1413,7 @@
            cmdXml.append("<Query>\r\n");
            cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            if (StringUtils.isEmpty(channelId)) {
            if (ObjectUtils.isEmpty(channelId)) {
                cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            } else {
                cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@@ -1543,22 +1544,22 @@
            cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
            cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
            cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            if (!StringUtils.isEmpty(startPriority)) {
            if (!ObjectUtils.isEmpty(startPriority)) {
                cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
            }
            if (!StringUtils.isEmpty(endPriority)) {
            if (!ObjectUtils.isEmpty(endPriority)) {
                cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
            }
            if (!StringUtils.isEmpty(alarmMethod)) {
            if (!ObjectUtils.isEmpty(alarmMethod)) {
                cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
            }
            if (!StringUtils.isEmpty(alarmType)) {
            if (!ObjectUtils.isEmpty(alarmType)) {
                cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
            }
            if (!StringUtils.isEmpty(startTime)) {
            if (!ObjectUtils.isEmpty(startTime)) {
                cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
            }
            if (!StringUtils.isEmpty(endTime)) {
            if (!ObjectUtils.isEmpty(endTime)) {
                cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
            }
            cmdXml.append("</Query>\r\n");
@@ -1639,7 +1640,7 @@
            dragXml.append("<Control>\r\n");
            dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
            dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
            if (StringUtils.isEmpty(channelId)) {
            if (ObjectUtils.isEmpty(channelId)) {
                dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
            } else {
                dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -24,6 +24,7 @@
import org.springframework.context.annotation.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.*;
@@ -728,10 +729,10 @@
                            recordXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(recordItem.getEndTime()) + "</EndTime>\r\n");
                            recordXml.append("<Secrecy>" + recordItem.getSecrecy() + "</Secrecy>\r\n");
                            recordXml.append("<Type>" + recordItem.getType() + "</Type>\r\n");
                            if (!StringUtils.isEmpty(recordItem.getFileSize())) {
                            if (!ObjectUtils.isEmpty(recordItem.getFileSize())) {
                                recordXml.append("<FileSize>" + recordItem.getFileSize() + "</FileSize>\r\n");
                            }
                            if (!StringUtils.isEmpty(recordItem.getFilePath())) {
                            if (!ObjectUtils.isEmpty(recordItem.getFilePath())) {
                                recordXml.append("<FilePath>" + recordItem.getFilePath() + "</FilePath>\r\n");
                            }
                        }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -29,6 +29,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
@@ -157,7 +158,7 @@
            String channelId = deviceIdElement.getTextTrim().toString();
            Device device = redisCatchStorage.getDevice(deviceId);
            if (device != null) {
                if (!StringUtils.isEmpty(device.getName())) {
                if (!ObjectUtils.isEmpty(device.getName())) {
                    mobilePosition.setDeviceName(device.getName());
                }
            }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -19,6 +19,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
@@ -81,7 +82,7 @@
            String deviceId = uri.getUser();
            AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
            if (authHead == null && !StringUtils.isEmpty(sipConfig.getPassword())) {
            if (authHead == null && !ObjectUtils.isEmpty(sipConfig.getPassword())) {
                logger.info("[注册请求] 未携带授权头 回复401: {}", requestAddress);
                response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
                new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
@@ -90,7 +91,7 @@
            }
            // 校验密码是否正确
            passwordCorrect = StringUtils.isEmpty(sipConfig.getPassword()) ||
            passwordCorrect = ObjectUtils.isEmpty(sipConfig.getPassword()) ||
                    new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request, sipConfig.getPassword());
            if (!passwordCorrect) {
@@ -132,7 +133,7 @@
            String received = viaHeader.getReceived();
            int rPort = viaHeader.getRPort();
            // 解析本地地址替代
            if (StringUtils.isEmpty(received) || rPort == -1) {
            if (ObjectUtils.isEmpty(received) || rPort == -1) {
                received = viaHeader.getHost();
                rPort = viaHeader.getPort();
            }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
@@ -17,6 +17,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.*;
@@ -64,7 +65,7 @@
        String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
        String channelId = getText(rootElement, "DeviceID");
        // 远程启动功能
        if (!StringUtils.isEmpty(getText(rootElement, "TeleBoot"))) {
        if (!ObjectUtils.isEmpty(getText(rootElement, "TeleBoot"))) {
            if (parentPlatform.getServerGBId().equals(targetGBId)) {
                // 远程启动本平台:需要在重新启动程序后先对SipStack解绑
                logger.info("执行远程启动本平台命令");
@@ -101,7 +102,7 @@
            }
        }
        // 云台/前端控制命令
        if (!StringUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) {
        if (!ObjectUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) {
            String cmdString = getText(rootElement,"PTZCmd");
            Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
            if (deviceForPlatform == null) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
@@ -22,6 +22,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
@@ -114,7 +115,7 @@
            deviceAlarm.setLatitude(0.00);
        }
        if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
        if (!ObjectUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
            if ( deviceAlarm.getAlarmMethod().contains(DeviceAlarmMethod.GPS.getVal() + "")) {
                MobilePosition mobilePosition = new MobilePosition();
                mobilePosition.setCreateTime(DateUtil.getNow());
@@ -157,7 +158,7 @@
                redisCatchStorage.sendMobilePositionMsg(jsonObject);
            }
        }
        if (!StringUtils.isEmpty(deviceAlarm.getDeviceId())) {
        if (!ObjectUtils.isEmpty(deviceAlarm.getDeviceId())) {
            if (deviceAlarm.getAlarmMethod().contains(DeviceAlarmMethod.Video.getVal() + "")) {
                deviceAlarm.setAlarmType(getText(rootElement.element("Info"), "AlarmType"));
            }
@@ -231,7 +232,7 @@
            deviceAlarm.setLatitude(0.00);
        }
        if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
        if (!ObjectUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
            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
@@ -16,6 +16,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
@@ -58,7 +59,7 @@
            String received = viaHeader.getReceived();
            int rPort = viaHeader.getRPort();
            // 解析本地地址替代
            if (StringUtils.isEmpty(received) || rPort == -1) {
            if (ObjectUtils.isEmpty(received) || rPort == -1) {
                received = viaHeader.getHost();
                rPort = viaHeader.getPort();
            }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
@@ -18,6 +18,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
@@ -69,7 +70,7 @@
            }
            MobilePosition mobilePosition = new MobilePosition();
            mobilePosition.setCreateTime(DateUtil.getNow());
            if (!StringUtils.isEmpty(device.getName())) {
            if (!ObjectUtils.isEmpty(device.getName())) {
                mobilePosition.setDeviceName(device.getName());
            }
            mobilePosition.setDeviceId(device.getDeviceId());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
@@ -20,6 +20,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
@@ -88,7 +89,7 @@
            device.setManufacturer(getText(rootElement, "Manufacturer"));
            device.setModel(getText(rootElement, "Model"));
            device.setFirmware(getText(rootElement, "Firmware"));
            if (StringUtils.isEmpty(device.getStreamMode())) {
            if (ObjectUtils.isEmpty(device.getStreamMode())) {
                device.setStreamMode("UDP");
            }
            deviceService.updateDevice(device);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
@@ -20,6 +20,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
@@ -72,7 +73,7 @@
            }
            MobilePosition mobilePosition = new MobilePosition();
            mobilePosition.setCreateTime(DateUtil.getNow());
            if (!StringUtils.isEmpty(device.getName())) {
            if (!ObjectUtils.isEmpty(device.getName())) {
                mobilePosition.setDeviceName(device.getName());
            }
            mobilePosition.setDeviceId(device.getDeviceId());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
@@ -19,6 +19,7 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
@@ -93,7 +94,7 @@
                            recordInfo.setName(getText(rootElementForCharset, "Name"));
                            String sumNumStr = getText(rootElementForCharset, "SumNum");
                            int sumNum = 0;
                            if (!StringUtils.isEmpty(sumNumStr)) {
                            if (!ObjectUtils.isEmpty(sumNumStr)) {
                                sumNum = Integer.parseInt(sumNumStr);
                            }
                            recordInfo.setSumNum(sumNum);
@@ -172,16 +173,12 @@
    public void releaseRequest(String deviceId, String sn){
        String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn;
        WVPResult<RecordInfo> wvpResult = new WVPResult<>();
        wvpResult.setCode(0);
        wvpResult.setMsg("success");
        // 对数据进行排序
        Collections.sort(recordDataCatch.getRecordInfo(deviceId, sn).getRecordList());
        wvpResult.setData(recordDataCatch.getRecordInfo(deviceId, sn));
        RequestMessage msg = new RequestMessage();
        msg.setKey(key);
        msg.setData(wvpResult);
        msg.setData(recordDataCatch.getRecordInfo(deviceId, sn));
        deferredResultHolder.invokeAllResult(msg);
        recordDataCatch.remove(deviceId, sn);
    }
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -14,6 +14,7 @@
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sip.RequestEvent;
@@ -118,12 +119,12 @@
        // 如果是属性
        for (Object o : element.attributes()) {
            Attribute attr = (Attribute) o;
            if (!StringUtils.isEmpty(attr.getValue())) {
            if (!ObjectUtils.isEmpty(attr.getValue())) {
                json.put("@" + attr.getName(), attr.getValue());
            }
        }
        List<Element> chdEl = element.elements();
        if (chdEl.isEmpty() && !StringUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值
        if (chdEl.isEmpty() && !ObjectUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值
            json.put(element.getName(), element.getText());
        }
@@ -154,7 +155,7 @@
            } else { // 子元素没有子元素
                for (Object o : element.attributes()) {
                    Attribute attr = (Attribute) o;
                    if (!StringUtils.isEmpty(attr.getValue())) {
                    if (!ObjectUtils.isEmpty(attr.getValue())) {
                        json.put("@" + attr.getName(), attr.getValue());
                    }
                }
@@ -197,7 +198,7 @@
            return null;
        }
        String channelId = channdelIdElement.getTextTrim();
        if (StringUtils.isEmpty(channelId)) {
        if (ObjectUtils.isEmpty(channelId)) {
            logger.warn("解析Catalog消息时发现缺少 DeviceID");
            return null;
        }
@@ -316,7 +317,7 @@
        // 识别自带的目录标识
        String parental = XmlUtil.getText(itemDevice, "Parental");
        // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
        if (!StringUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
        if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
            deviceChannel.setParental(0);
        }else {
            deviceChannel.setParental(1);
@@ -332,14 +333,14 @@
        deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
        String safetyWay = XmlUtil.getText(itemDevice, "SafetyWay");
        if (StringUtils.isEmpty(safetyWay)) {
        if (ObjectUtils.isEmpty(safetyWay)) {
            deviceChannel.setSafetyWay(0);
        } else {
            deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
        }
        String registerWay = XmlUtil.getText(itemDevice, "RegisterWay");
        if (StringUtils.isEmpty(registerWay)) {
        if (ObjectUtils.isEmpty(registerWay)) {
            deviceChannel.setRegisterWay(1);
        } else {
            deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
@@ -9,6 +9,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.io.File;
@@ -49,7 +50,7 @@
        if (mediaServerItem == null) {
            return null;
        }
        if (StringUtils.isEmpty(mediaServerItem.getRecordAssistPort())) {
        if (ObjectUtils.isEmpty(mediaServerItem.getRecordAssistPort())) {
            logger.warn("未启用Assist服务");
            return null;
        }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -22,6 +22,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -633,7 +634,7 @@
    private Map<String, String> urlParamToMap(String params) {
        HashMap<String, String> map = new HashMap<>();
        if (StringUtils.isEmpty(params)) {
        if (ObjectUtils.isEmpty(params)) {
            return map;
        }
        String[] paramsArray = params.split("&");
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -9,6 +9,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.*;
@@ -187,7 +188,7 @@
        // 使用RTPServer 功能找一个可用的端口
        String sendRtpPortRange = serverItem.getSendRtpPortRange();
        if (StringUtils.isEmpty(sendRtpPortRange)) {
        if (ObjectUtils.isEmpty(sendRtpPortRange)) {
            return null;
        }
        String[] portRangeStrArray = serverItem.getSendRtpPortRange().split(",");
@@ -229,7 +230,7 @@
    public SendRtpItem createSendRtpItem(MediaServerItem serverItem, String ip, int port, String ssrc, String platformId, String app, String stream, String channelId, boolean tcp){
        // 使用RTPServer 功能找一个可用的端口
        String sendRtpPortRange = serverItem.getSendRtpPortRange();
        if (StringUtils.isEmpty(sendRtpPortRange)) {
        if (ObjectUtils.isEmpty(sendRtpPortRange)) {
            return null;
        }
        String[] portRangeStrArray = serverItem.getSendRtpPortRange().split(",");
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
@@ -4,6 +4,7 @@
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.HashMap;
@@ -106,9 +107,9 @@
    public MediaServerItem(ZLMServerConfig zlmServerConfig, String sipIp) {
        id = zlmServerConfig.getGeneralMediaServerId();
        ip = zlmServerConfig.getIp();
        hookIp = StringUtils.isEmpty(zlmServerConfig.getHookIp())? sipIp: zlmServerConfig.getHookIp();
        sdpIp = StringUtils.isEmpty(zlmServerConfig.getSdpIp())? zlmServerConfig.getIp(): zlmServerConfig.getSdpIp();
        streamIp = StringUtils.isEmpty(zlmServerConfig.getStreamIp())? zlmServerConfig.getIp(): zlmServerConfig.getStreamIp();
        hookIp = ObjectUtils.isEmpty(zlmServerConfig.getHookIp())? sipIp: zlmServerConfig.getHookIp();
        sdpIp = ObjectUtils.isEmpty(zlmServerConfig.getSdpIp())? zlmServerConfig.getIp(): zlmServerConfig.getSdpIp();
        streamIp = ObjectUtils.isEmpty(zlmServerConfig.getStreamIp())? zlmServerConfig.getIp(): zlmServerConfig.getStreamIp();
        httpPort = zlmServerConfig.getHttpPort();
        httpSSlPort = zlmServerConfig.getHttpSSLport();
        rtmpPort = zlmServerConfig.getRtmpPort();
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -64,7 +64,7 @@
    void clearMediaServerForOnline();
    WVPResult<String> add(MediaServerItem mediaSerItem);
    void add(MediaServerItem mediaSerItem);
    int addToDatabase(MediaServerItem mediaSerItem);
@@ -72,7 +72,7 @@
    void resetOnlineServerItem(MediaServerItem serverItem);
    WVPResult<MediaServerItem> checkMediaServer(String ip, int port, String secret);
    MediaServerItem checkMediaServer(String ip, int port, String secret);
    boolean checkMediaRecordServer(String ip, int port);
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
@@ -31,13 +31,13 @@
    void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String toString);
    DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
    DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
    DeferredResult<String> playBack(String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
    DeferredResult<String> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
    void zlmServerOffline(String mediaServerId);
    DeferredResult<ResponseEntity<String>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
    DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId,  String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
    DeferredResult<String> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
    DeferredResult<String> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId,  String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
    StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
@@ -2,12 +2,8 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.media.zlm.dto.MediaItem;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
public interface IStreamProxyService {
@@ -16,7 +12,7 @@
     * 保存视频代理
     * @param param
     */
    WVPResult<StreamInfo> save(StreamProxyItem param);
    StreamInfo save(StreamProxyItem param);
    /**
     * 添加视频代理到zlm
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -23,6 +23,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.incrementer.AbstractIdentityColumnMaxValueIncrementer;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.time.Instant;
@@ -282,13 +283,13 @@
            logger.warn("更新设备时未找到设备信息");
            return;
        }
        if (!StringUtils.isEmpty(device.getName())) {
        if (!ObjectUtils.isEmpty(device.getName())) {
            deviceInStore.setName(device.getName());
        }
        if (!StringUtils.isEmpty(device.getCharset())) {
        if (!ObjectUtils.isEmpty(device.getCharset())) {
            deviceInStore.setCharset(device.getCharset());
        }
        if (!StringUtils.isEmpty(device.getMediaServerId())) {
        if (!ObjectUtils.isEmpty(device.getMediaServerId())) {
            deviceInStore.setMediaServerId(device.getMediaServerId());
        }
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
@@ -18,6 +18,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
@@ -168,7 +169,7 @@
    public void sendCatalogMsgs(List<GbStream> gbStreams, String type) {
        if (gbStreams.size() > 0) {
            for (GbStream gs : gbStreams) {
                if (StringUtils.isEmpty(gs.getGbId())){
                if (ObjectUtils.isEmpty(gs.getGbId())){
                    continue;
                }
                List<ParentPlatform> parentPlatforms = platformGbStreamMapper.selectByAppAndStream(gs.getApp(), gs.getStream());
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -8,6 +8,8 @@
import java.util.Map;
import java.util.Set;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -16,6 +18,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSON;
@@ -91,7 +94,7 @@
    public void updateVmServer(List<MediaServerItem>  mediaServerItemList) {
        logger.info("[zlm] 缓存初始化 ");
        for (MediaServerItem mediaServerItem : mediaServerItemList) {
            if (StringUtils.isEmpty(mediaServerItem.getId())) {
            if (ObjectUtils.isEmpty(mediaServerItem.getId())) {
                continue;
            }
            // 更新
@@ -287,8 +290,7 @@
    }
    @Override
    public WVPResult<String> add(MediaServerItem mediaServerItem) {
        WVPResult<String> result = new WVPResult<>();
    public void add(MediaServerItem mediaServerItem) {
        mediaServerItem.setCreateTime(DateUtil.getNow());
        mediaServerItem.setUpdateTime(DateUtil.getNow());
        mediaServerItem.setHookAliveInterval(120);
@@ -298,26 +300,19 @@
            if (data != null && data.size() > 0) {
                ZLMServerConfig zlmServerConfig= JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
                if (mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()) != null) {
                    result.setCode(-1);
                    result.setMsg("保存失败,媒体服务ID [ " + zlmServerConfig.getGeneralMediaServerId() + " ] 已存在,请修改媒体服务器配置");
                    return result;
                    throw new ControllerException(ErrorCode.ERROR100.getCode(),"保存失败,媒体服务ID [ " + zlmServerConfig.getGeneralMediaServerId() + " ] 已存在,请修改媒体服务器配置");
                }
                mediaServerItem.setId(zlmServerConfig.getGeneralMediaServerId());
                zlmServerConfig.setIp(mediaServerItem.getIp());
                mediaServerMapper.add(mediaServerItem);
                zlmServerOnline(zlmServerConfig);
                result.setCode(0);
                result.setMsg("success");
            }else {
                result.setCode(-1);
                result.setMsg("连接失败");
                throw new ControllerException(ErrorCode.ERROR100.getCode(),"连接失败");
            }
        }else {
            result.setCode(-1);
            result.setMsg("连接失败");
            throw new ControllerException(ErrorCode.ERROR100.getCode(),"连接失败");
        }
       return result;
    }
    @Override
@@ -385,7 +380,7 @@
        }
        serverItem.setStatus(true);
        if (StringUtils.isEmpty(serverItem.getId())) {
        if (ObjectUtils.isEmpty(serverItem.getId())) {
            logger.warn("[未注册的zlm] serverItem缺少ID, 无法接入:{}:{}", zlmServerConfig.getIp(),zlmServerConfig.getHttpPort() );
            return;
        }
@@ -520,7 +515,7 @@
        // 最多等待未初始化的Track时间,单位毫秒,超时之后会忽略未初始化的Track, 设置此选项优化那些音频错误的不规范流,
        // 等zlm支持给每个rtpServer设置关闭音频的时候可以不设置此选项
        param.put("general.wait_track_ready_ms", "3000" );
        if (mediaServerItem.isRtpEnable() && !StringUtils.isEmpty(mediaServerItem.getRtpPortRange())) {
        if (mediaServerItem.isRtpEnable() && !ObjectUtils.isEmpty(mediaServerItem.getRtpPortRange())) {
            param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-"));
        }
@@ -547,12 +542,9 @@
    @Override
    public WVPResult<MediaServerItem> checkMediaServer(String ip, int port, String secret) {
        WVPResult<MediaServerItem> result = new WVPResult<>();
    public MediaServerItem checkMediaServer(String ip, int port, String secret) {
        if (mediaServerMapper.queryOneByHostAndPort(ip, port) != null) {
            result.setCode(-1);
            result.setMsg("此连接已存在");
            return result;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "此连接已存在");
        }
        MediaServerItem mediaServerItem = new MediaServerItem();
        mediaServerItem.setIp(ip);
@@ -560,21 +552,15 @@
        mediaServerItem.setSecret(secret);
        JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
        if (responseJSON == null) {
            result.setCode(-1);
            result.setMsg("连接失败");
            return result;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接失败");
        }
        JSONArray data = responseJSON.getJSONArray("data");
        ZLMServerConfig zlmServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), ZLMServerConfig.class);
        if (zlmServerConfig == null) {
            result.setCode(-1);
            result.setMsg("读取配置失败");
            return result;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "读取配置失败");
        }
        if (mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()) != null) {
            result.setCode(-1);
            result.setMsg("媒体服务ID [" + zlmServerConfig.getGeneralMediaServerId() + " ] 已存在,请修改媒体服务器配置");
            return result;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "媒体服务ID [" + zlmServerConfig.getGeneralMediaServerId() + " ] 已存在,请修改媒体服务器配置");
        }
        mediaServerItem.setHttpSSlPort(zlmServerConfig.getHttpPort());
        mediaServerItem.setRtmpPort(zlmServerConfig.getRtmpPort());
@@ -586,10 +572,7 @@
        mediaServerItem.setHookIp(sipConfig.getIp());
        mediaServerItem.setSdpIp(ip);
        mediaServerItem.setStreamNoneReaderDelayMS(zlmServerConfig.getGeneralStreamNoneReaderDelayMS());
        result.setCode(0);
        result.setMsg("成功");
        result.setData(mediaServerItem);
        return result;
        return mediaServerItem;
    }
    @Override
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -15,6 +15,7 @@
import com.genersoft.iot.vmp.service.IMediaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@Service
@@ -94,7 +95,7 @@
        }
        streamInfoResult.setIp(addr);
        streamInfoResult.setMediaServerId(mediaInfo.getId());
        String callIdParam = StringUtils.isEmpty(callId)?"":"?callId=" + callId;
        String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId;
        streamInfoResult.setRtmp(String.format("rtmp://%s:%s/%s/%s%s", addr, mediaInfo.getRtmpPort(), app,  stream, callIdParam));
        if (mediaInfo.getRtmpSSlPort() != 0) {
            streamInfoResult.setRtmps(String.format("rtmps://%s:%s/%s/%s%s", addr, mediaInfo.getRtmpSSlPort(), app,  stream, callIdParam));
@@ -121,7 +122,7 @@
            streamInfoResult.setHttps_ts(String.format("https://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setWss_ts(String.format("wss://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setWss_ts(String.format("wss://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setRtc(String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=play%s", mediaInfo.getStreamIp(), mediaInfo.getHttpSSlPort(), app,  stream, StringUtils.isEmpty(callId)?"":"&callId=" + callId));
            streamInfoResult.setRtc(String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=play%s", mediaInfo.getStreamIp(), mediaInfo.getHttpSSlPort(), app,  stream, ObjectUtils.isEmpty(callId)?"":"&callId=" + callId));
        }
        streamInfoResult.setTracks(tracks);
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -6,6 +6,8 @@
import javax.sip.ResponseEvent;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,7 +39,6 @@
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
import com.genersoft.iot.vmp.media.zlm.dto.HookType;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
@@ -52,7 +53,6 @@
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
@@ -114,6 +114,9 @@
    public PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId,
                           ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
                           Runnable timeoutCallback) {
        if (mediaServerItem == null) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
        }
        PlayResult playResult = new PlayResult();
        RequestMessage msg = new RequestMessage();
        String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
@@ -121,18 +124,11 @@
        String uuid = UUID.randomUUID().toString();
        msg.setId(uuid);
        playResult.setUuid(uuid);
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
        DeferredResult<WVPResult<String>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
        playResult.setResult(result);
        // 录像查询以channelId作为deviceId查询
        resultHolder.put(key, uuid, result);
        if (mediaServerItem == null) {
            WVPResult wvpResult = new WVPResult();
            wvpResult.setCode(-1);
            wvpResult.setMsg("未找到可用的zlm");
            msg.setData(wvpResult);
            resultHolder.invokeResult(msg);
            return playResult;
        }
        Device device = redisCatchStorage.getDevice(deviceId);
        StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
        playResult.setDevice(device);
@@ -143,17 +139,14 @@
                // TODO 应该在上流时调用更好,结束也可能是错误结束
                String path =  "snap";
                String fileName =  deviceId + "_" + channelId + ".jpg";
                ResponseEntity responseEntity =  (ResponseEntity)result.getResult();
                if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) {
                    WVPResult wvpResult = (WVPResult)responseEntity.getBody();
                    if (Objects.requireNonNull(wvpResult).getCode() == 0) {
                        StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData();
                        MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
                        String streamUrl = streamInfoForSuccess.getFmp4();
                        // 请求截图
                        logger.info("[请求截图]: " + fileName);
                        zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName);
                    }
                WVPResult wvpResult =  (WVPResult)result.getResult();
                if (Objects.requireNonNull(wvpResult).getCode() == 0) {
                    StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData();
                    MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
                    String streamUrl = streamInfoForSuccess.getFmp4();
                    // 请求截图
                    logger.info("[请求截图]: " + fileName);
                    zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName);
                }
            });
        });
@@ -161,7 +154,7 @@
            String streamId = streamInfo.getStream();
            if (streamId == null) {
                WVPResult wvpResult = new WVPResult();
                wvpResult.setCode(-1);
                wvpResult.setCode(ErrorCode.ERROR100.getCode());
                wvpResult.setMsg("点播失败, redis缓存streamId等于null");
                msg.setData(wvpResult);
                resultHolder.invokeAllResult(msg);
@@ -175,8 +168,8 @@
                if (rtpInfo.getBoolean("exist")) {
                    WVPResult wvpResult = new WVPResult();
                    wvpResult.setCode(0);
                    wvpResult.setMsg("success");
                    wvpResult.setCode(ErrorCode.SUCCESS.getCode());
                    wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
                    wvpResult.setData(streamInfo);
                    msg.setData(wvpResult);
@@ -211,7 +204,7 @@
            }, event -> {
                // sip error错误
                WVPResult wvpResult = new WVPResult();
                wvpResult.setCode(-1);
                wvpResult.setCode(ErrorCode.ERROR100.getCode());
                wvpResult.setMsg(String.format("点播失败, 错误码: %s, %s", event.statusCode, event.msg));
                msg.setData(wvpResult);
                resultHolder.invokeAllResult(msg);
@@ -221,7 +214,7 @@
            }, (code, msgStr)->{
                // invite点播超时
                WVPResult wvpResult = new WVPResult();
                wvpResult.setCode(-1);
                wvpResult.setCode(ErrorCode.ERROR100.getCode());
                if (code == 0) {
                    wvpResult.setMsg("点播超时,请稍候重试");
                }else if (code == 1) {
@@ -361,8 +354,8 @@
            redisCatchStorage.startPlay(streamInfo);
            WVPResult wvpResult = new WVPResult();
            wvpResult.setCode(0);
            wvpResult.setMsg("success");
            wvpResult.setCode(ErrorCode.SUCCESS.getCode());
            wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
            wvpResult.setData(streamInfo);
            msg.setData(wvpResult);
@@ -393,7 +386,7 @@
    }
    @Override
    public DeferredResult<ResponseEntity<String>> playBack(String deviceId, String channelId, String startTime,
    public DeferredResult<String> playBack(String deviceId, String channelId, String startTime,
                                                           String endTime,InviteStreamCallback inviteStreamCallback,
                                                           PlayBackCallback callback) {
        Device device = storager.queryVideoDevice(deviceId);
@@ -407,7 +400,7 @@
    }
    @Override
    public DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
    public DeferredResult<String> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
                                                           String deviceId, String channelId, String startTime,
                                                           String endTime, InviteStreamCallback infoCallBack,
                                                           PlayBackCallback playBackCallback) {
@@ -416,13 +409,11 @@
        }
        String uuid = UUID.randomUUID().toString();
        String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L);
        Device device = storager.queryVideoDevice(deviceId);
        if (device == null) {
            result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
            return result;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备: " + deviceId + "不存在");
        }
        DeferredResult<String> result = new DeferredResult<>(30000L);
        resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId, uuid, result);
        RequestMessage msg = new RequestMessage();
        msg.setId(uuid);
@@ -482,7 +473,7 @@
    }
    @Override
    public DeferredResult<ResponseEntity<String>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
    public DeferredResult<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;
@@ -494,17 +485,16 @@
    }
    @Override
    public DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
    public DeferredResult<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;
        }
        String uuid = UUID.randomUUID().toString();
        String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L);
        DeferredResult<String> result = new DeferredResult<>(30000L);
        Device device = storager.queryVideoDevice(deviceId);
        if (device == null) {
            result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
            return result;
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "不存在");
        }
        resultHolder.put(key, uuid, result);
@@ -519,7 +509,7 @@
        String downLoadTimeOutTaskKey = UUID.randomUUID().toString();
        dynamicTask.startDelay(downLoadTimeOutTaskKey, ()->{
            logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
            wvpResult.setCode(-1);
            wvpResult.setCode(ErrorCode.ERROR100.getCode());
            wvpResult.setMsg("录像下载请求超时");
            downloadResult.setCode(-1);
            hookCallBack.call(downloadResult);
@@ -545,8 +535,8 @@
                    streamInfo.setStartTime(startTime);
                    streamInfo.setEndTime(endTime);
                    redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());
                    wvpResult.setCode(0);
                    wvpResult.setMsg("success");
                    wvpResult.setCode(ErrorCode.SUCCESS.getCode());
                    wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
                    wvpResult.setData(streamInfo);
                    downloadResult.setCode(0);
                    downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
@@ -555,7 +545,7 @@
                }, event -> {
                    dynamicTask.stop(downLoadTimeOutTaskKey);
                    downloadResult.setCode(-1);
                    wvpResult.setCode(-1);
                    wvpResult.setCode(ErrorCode.ERROR100.getCode());
                    wvpResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg));
                    downloadResult.setEvent(event);
                    hookCallBack.call(downloadResult);
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -4,6 +4,7 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.TreeType;
@@ -24,6 +25,7 @@
import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper;
import com.genersoft.iot.vmp.service.IStreamProxyService;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
@@ -33,6 +35,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.net.InetAddress;
@@ -93,10 +96,8 @@
    @Override
    public WVPResult<StreamInfo> save(StreamProxyItem param) {
    public StreamInfo save(StreamProxyItem param) {
        MediaServerItem mediaInfo;
        WVPResult<StreamInfo> wvpResult = new WVPResult<>();
        wvpResult.setCode(0);
        if (param.getMediaServerId() == null || "auto".equals(param.getMediaServerId())){
            mediaInfo = mediaServerService.getMediaServerForMinimumLoad();
        }else {
@@ -104,14 +105,12 @@
        }
        if (mediaInfo == null) {
            logger.warn("保存代理未找到在线的ZLM...");
            wvpResult.setMsg("保存失败");
            return wvpResult;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "保存代理未找到在线的ZLM");
        }
        String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(),
                param.getStream() );
        param.setDst_url(dstUrl);
        StringBuffer result = new StringBuffer();
        StringBuffer resultMsg = new StringBuffer();
        boolean streamLive = false;
        param.setMediaServerId(mediaInfo.getId());
        boolean saveResult;
@@ -121,43 +120,47 @@
        }else { // 新增
            saveResult = addStreamProxy(param);
        }
        if (saveResult) {
            result.append("保存成功");
            if (param.isEnable()) {
                JSONObject jsonObject = addStreamProxyToZlm(param);
                if (jsonObject == null || jsonObject.getInteger("code") != 0) {
                    streamLive = false;
                    result.append(", 但是启用失败,请检查流地址是否可用");
                    param.setEnable(false);
                    // 直接移除
                    if (param.isEnable_remove_none_reader()) {
                        del(param.getApp(), param.getStream());
                    }else {
                        updateStreamProxy(param);
                    }
                }else {
                    streamLive = true;
                    StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
                            mediaInfo, param.getApp(), param.getStream(), null, null);
                    wvpResult.setData(streamInfo);
                }
            }
        }else {
            result.append("保存失败");
        if (!saveResult) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(),"保存失败");
        }
        if ( !StringUtils.isEmpty(param.getPlatformGbId()) && streamLive) {
        StreamInfo resultForStreamInfo = null;
        resultMsg.append("保存成功");
        if (param.isEnable()) {
            JSONObject jsonObject = addStreamProxyToZlm(param);
            if (jsonObject == null || jsonObject.getInteger("code") != 0) {
                streamLive = false;
                resultMsg.append(", 但是启用失败,请检查流地址是否可用");
                param.setEnable(false);
                // 直接移除
                if (param.isEnable_remove_none_reader()) {
                    del(param.getApp(), param.getStream());
                }else {
                    updateStreamProxy(param);
                }
            }else {
                streamLive = true;
                resultForStreamInfo = mediaService.getStreamInfoByAppAndStream(
                        mediaInfo, param.getApp(), param.getStream(), null, null);
            }
        }
        if ( !ObjectUtils.isEmpty(param.getPlatformGbId()) && streamLive) {
            List<GbStream> gbStreams = new ArrayList<>();
            gbStreams.add(param);
            if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId(), param.getCatalogId())){
                result.append(",  关联国标平台[ " + param.getPlatformGbId() + " ]成功");
                return resultForStreamInfo;
            }else {
                result.append(",  关联国标平台[ " + param.getPlatformGbId() + " ]失败");
                resultMsg.append(",  关联国标平台[ " + param.getPlatformGbId() + " ]失败");
                throw new ControllerException(ErrorCode.ERROR100.getCode(), resultMsg.toString());
            }
        }else {
            if (!streamLive) {
                throw new ControllerException(ErrorCode.ERROR100.getCode(), resultMsg.toString());
            }
        }
        wvpResult.setMsg(result.toString());
        return wvpResult;
        return resultForStreamInfo;
    }
    /**
@@ -174,7 +177,7 @@
        streamProxyItem.setCreateTime(now);
        try {
            if (streamProxyMapper.add(streamProxyItem) > 0) {
                if (!StringUtils.isEmpty(streamProxyItem.getGbId())) {
                if (!ObjectUtils.isEmpty(streamProxyItem.getGbId())) {
                    if (gbStreamMapper.add(streamProxyItem) < 0) {
                        //事务回滚
                        dataSourceTransactionManager.rollback(transactionStatus);
@@ -209,7 +212,7 @@
        streamProxyItem.setStreamType("proxy");
        try {
            if (streamProxyMapper.update(streamProxyItem) > 0) {
                if (!StringUtils.isEmpty(streamProxyItem.getGbId())) {
                if (!ObjectUtils.isEmpty(streamProxyItem.getGbId())) {
                    if (gbStreamMapper.updateByAppAndStream(streamProxyItem) == 0) {
                        //事务回滚
                        dataSourceTransactionManager.rollback(transactionStatus);
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
@@ -27,6 +27,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.*;
@@ -208,7 +209,7 @@
        Map<String, MediaItem> streamInfoPushItemMap = new HashMap<>();
        if (pushList.size() > 0) {
            for (StreamPushItem streamPushItem : pushList) {
                if (StringUtils.isEmpty(streamPushItem.getGbId())) {
                if (ObjectUtils.isEmpty(streamPushItem.getGbId())) {
                    pushItemMap.put(streamPushItem.getApp() + streamPushItem.getStream(), streamPushItem);
                }
            }
@@ -492,7 +493,7 @@
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            int addStreamResult = streamPushMapper.add(stream);
            if (!StringUtils.isEmpty(stream.getGbId())) {
            if (!ObjectUtils.isEmpty(stream.getGbId())) {
                stream.setStreamType("push");
                gbStreamMapper.add(stream);
            }
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
@@ -8,6 +8,7 @@
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.*;
@@ -82,9 +83,9 @@
    @Override
    public void invoke(StreamPushExcelDto streamPushExcelDto, AnalysisContext analysisContext) {
        if (StringUtils.isEmpty(streamPushExcelDto.getApp())
                || StringUtils.isEmpty(streamPushExcelDto.getStream())
                || StringUtils.isEmpty(streamPushExcelDto.getGbId())) {
        if (ObjectUtils.isEmpty(streamPushExcelDto.getApp())
                || ObjectUtils.isEmpty(streamPushExcelDto.getStream())
                || ObjectUtils.isEmpty(streamPushExcelDto.getGbId())) {
            return;
        }
@@ -130,7 +131,7 @@
        streamPushItems.add(streamPushItem);
        streamPushItemForSave.put(streamPushItem.getApp() + streamPushItem.getStream(), streamPushItem);
        if (!StringUtils.isEmpty(streamPushExcelDto.getPlatformId())) {
        if (!ObjectUtils.isEmpty(streamPushExcelDto.getPlatformId())) {
            List<String[]> platformList = streamPushItemsForPlatform.get(streamPushItem.getApp() + streamPushItem.getStream());
            if (platformList == null) {
                platformList = new ArrayList<>();
@@ -138,7 +139,7 @@
            }
            String platformId = streamPushExcelDto.getPlatformId();
            String catalogId = streamPushExcelDto.getCatalogId();
            if (StringUtils.isEmpty(streamPushExcelDto.getCatalogId())) {
            if (ObjectUtils.isEmpty(streamPushExcelDto.getCatalogId())) {
                catalogId = null;
            }
            String[] platFormInfoArray = new String[]{platformId, catalogId};
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
@@ -7,6 +7,7 @@
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.List;
@@ -60,7 +61,7 @@
    @Override
    public boolean checkPushAuthority(String callId, String sign) {
        if (StringUtils.isEmpty(callId)) {
        if (ObjectUtils.isEmpty(callId)) {
            return userMapper.checkPushAuthorityByCallId(sign).size() > 0;
        }else {
            return userMapper.checkPushAuthorityByCallIdAndSign(callId, sign).size() > 0;
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -26,6 +26,7 @@
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.util.*;
@@ -132,7 +133,7 @@
                        deviceChannel.setStreamId(allChannelMapInPlay.get(deviceChannel.getChannelId()).getStreamId());
                    }
                    channels.add(deviceChannel);
                    if (!StringUtils.isEmpty(deviceChannel.getParentId())) {
                    if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
                        if (subContMap.get(deviceChannel.getParentId()) == null) {
                            subContMap.put(deviceChannel.getParentId(), 1);
                        }else {
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java
New file
@@ -0,0 +1,31 @@
package com.genersoft.iot.vmp.vmanager.bean;
import io.swagger.v3.oas.annotations.media.Schema;
/**
 * 全局错误码
 */
public enum ErrorCode {
    SUCCESS(0, "成功"),
    ERROR100(100, "失败"),
    ERROR400(400, "参数不全或者错误"),
    ERROR403(403, "无权限操作"),
    ERROR401(401, "请登录后重新请求"),
    ERROR500(500, "系统异常");
    private final int code;
    private final String msg;
    ErrorCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public int getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/bean/PlayTypeEnum.java
File was renamed from src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/session/PlayTypeEnum.java
@@ -1,4 +1,4 @@
package com.genersoft.iot.vmp.vmanager.gb28181.session;
package com.genersoft.iot.vmp.vmanager.bean;
public enum PlayTypeEnum {
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
@@ -23,23 +23,21 @@
    @Schema(description = "数据")
    private T data;
    private static final Integer SUCCESS = 200;
    private static final Integer FAILED = 400;
    public static <T> WVPResult<T> Data(T t, String msg) {
        return new WVPResult<>(SUCCESS, msg, t);
    public static <T> WVPResult<T> success(T t, String msg) {
        return new WVPResult<>(ErrorCode.SUCCESS.getCode(), msg, t);
    }
    public static <T> WVPResult<T> Data(T t) {
        return Data(t, "成功");
    public static <T> WVPResult<T> success(T t) {
        return success(t, ErrorCode.SUCCESS.getMsg());
    }
    public static <T> WVPResult<T> fail(int code, String msg) {
        return new WVPResult<>(code, msg, null);
    }
    public static <T> WVPResult<T> fail(String msg) {
        return fail(FAILED, msg);
    public static <T> WVPResult<T> fail(ErrorCode errorCode) {
        return fail(errorCode.getCode(), errorCode.getMsg());
    }
    public int getCode() {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
@@ -65,7 +65,7 @@
    @Parameter(name = "start", description = "开始时间")
    @Parameter(name = "end", description = "结束时间")
    @GetMapping("/history/{deviceId}")
    public ResponseEntity<WVPResult<List<MobilePosition>>> positions(@PathVariable String deviceId,
    public List<MobilePosition> positions(@PathVariable String deviceId,
                                                                     @RequestParam(required = false) String channelId,
                                                                     @RequestParam(required = false) String start,
                                                                     @RequestParam(required = false) String end) {
@@ -76,11 +76,7 @@
        if (StringUtil.isEmpty(end)) {
            end = null;
        }
        WVPResult<List<MobilePosition>> wvpResult = new WVPResult<>();
        wvpResult.setCode(0);
        List<MobilePosition> result = storager.queryMobilePositions(deviceId, channelId, start, end);
        wvpResult.setData(result);
        return new ResponseEntity<>(wvpResult, HttpStatus.OK);
        return storager.queryMobilePositions(deviceId, channelId, start, end);
    }
    /**
@@ -91,9 +87,8 @@
    @Operation(summary = "查询设备最新位置")
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @GetMapping("/latest/{deviceId}")
    public ResponseEntity<MobilePosition> latestPosition(@PathVariable String deviceId) {
        MobilePosition result = storager.queryLatestPosition(deviceId);
        return new ResponseEntity<>(result, HttpStatus.OK);
    public MobilePosition latestPosition(@PathVariable String deviceId) {
        return storager.queryLatestPosition(deviceId);
    }
    /**
@@ -104,7 +99,7 @@
    @Operation(summary = "获取移动位置信息")
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @GetMapping("/realtime/{deviceId}")
    public DeferredResult<ResponseEntity<MobilePosition>> realTimePosition(@PathVariable String deviceId) {
    public DeferredResult<MobilePosition> realTimePosition(@PathVariable String deviceId) {
        Device device = storager.queryVideoDevice(deviceId);
        String uuid = UUID.randomUUID().toString();
        String key = DeferredResultHolder.CALLBACK_CMD_MOBILEPOSITION + deviceId;
@@ -115,7 +110,7 @@
            msg.setData(String.format("获取移动位置信息失败,错误码: %s, %s", event.statusCode, event.msg));
            resultHolder.invokeResult(msg);
        });
        DeferredResult<ResponseEntity<MobilePosition>> result = new DeferredResult<ResponseEntity<MobilePosition>>(5*1000L);
        DeferredResult<MobilePosition> result = new DeferredResult<MobilePosition>(5*1000L);
        result.onTimeout(()->{
            logger.warn(String.format("获取移动位置信息超时"));
            // 释放rtpserver
@@ -141,7 +136,7 @@
    @Parameter(name = "expires", description = "订阅超时时间", required = true)
    @Parameter(name = "interval", description = "上报时间间隔", required = true)
    @GetMapping("/subscribe/{deviceId}")
    public ResponseEntity<String> positionSubscribe(@PathVariable String deviceId,
    public String positionSubscribe(@PathVariable String deviceId,
                                                    @RequestParam String expires,
                                                    @RequestParam String interval) {
        String msg = ((expires.equals("0")) ? "取消" : "") + "订阅设备" + deviceId + "的移动位置";
@@ -163,6 +158,6 @@
            result += ",失败";
        }
        return new ResponseEntity<>(result, HttpStatus.OK);
        return result;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.vmanager.gb28181.alarm;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
@@ -8,14 +9,17 @@
import com.genersoft.iot.vmp.service.IDeviceAlarmService;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@@ -55,22 +59,22 @@
    @Parameter(name = "id", description = "ID")
    @Parameter(name = "deviceIds", description = "多个设备id,逗号分隔")
    @Parameter(name = "time", description = "结束时间")
    public ResponseEntity<WVPResult<String>> delete(
    public Integer delete(
            @RequestParam(required = false) Integer id,
            @RequestParam(required = false) String deviceIds,
            @RequestParam(required = false) String time
    ) {
        if (StringUtils.isEmpty(id)) {
        if (ObjectUtils.isEmpty(id)) {
            id = null;
        }
        if (StringUtils.isEmpty(deviceIds)) {
        if (ObjectUtils.isEmpty(deviceIds)) {
            deviceIds = null;
        }
        if (StringUtils.isEmpty(time)) {
        if (ObjectUtils.isEmpty(time)) {
            time = null;
        }
        if (!DateUtil.verification(time, DateUtil.formatter) ){
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
            return null;
        }
        List<String> deviceIdList = null;
        if (deviceIds != null) {
@@ -78,12 +82,7 @@
            deviceIdList = Arrays.asList(deviceIdArray);
        }
        int count = deviceAlarmService.clearAlarmBeforeTime(id, deviceIdList, time);
        WVPResult wvpResult = new WVPResult();
        wvpResult.setCode(0);
        wvpResult.setMsg("success");
        wvpResult.setData(count);
        return new ResponseEntity<WVPResult<String>>(wvpResult, HttpStatus.OK);
        return deviceAlarmService.clearAlarmBeforeTime(id, deviceIdList, time);
    }
    /**
@@ -95,12 +94,7 @@
    @GetMapping("/test/notify/alarm")
    @Operation(summary = "测试向上级/设备发送模拟报警通知")
    @Parameter(name = "deviceId", description = "设备国标编号")
    public ResponseEntity<WVPResult<String>> delete(
            @RequestParam(required = false) String deviceId
    ) {
        if (StringUtils.isEmpty(deviceId)) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    public void delete(@RequestParam String deviceId) {
        Device device = storage.queryVideoDevice(deviceId);
        ParentPlatform platform = storage.queryParentPlatByServerGBId(deviceId);
        DeviceAlarm deviceAlarm = new DeviceAlarm();
@@ -118,16 +112,9 @@
        }else if (device == null && platform != null){
            commanderForPlatform.sendAlarmMessage(platform, deviceAlarm);
        }else {
            WVPResult wvpResult = new WVPResult();
            wvpResult.setCode(0);
            wvpResult.setMsg("无法确定" + deviceId + "是平台还是设备");
            return new ResponseEntity<WVPResult<String>>(wvpResult, HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(),"无法确定" + deviceId + "是平台还是设备");
        }
        WVPResult wvpResult = new WVPResult();
        wvpResult.setCode(0);
        wvpResult.setMsg("success");
        return new ResponseEntity<WVPResult<String>>(wvpResult, HttpStatus.OK);
    }
    /**
@@ -153,7 +140,7 @@
    @Parameter(name = "startTime",description = "开始时间")
    @Parameter(name = "endTime",description = "结束时间")
    @GetMapping("/all")
    public ResponseEntity<PageInfo<DeviceAlarm>> getAll(
    public PageInfo<DeviceAlarm> getAll(
            @RequestParam int page,
            @RequestParam int count,
            @RequestParam(required = false)  String deviceId,
@@ -163,31 +150,28 @@
            @RequestParam(required = false) String startTime,
            @RequestParam(required = false) String endTime
    ) {
        if (StringUtils.isEmpty(alarmPriority)) {
        if (ObjectUtils.isEmpty(alarmPriority)) {
            alarmPriority = null;
        }
        if (StringUtils.isEmpty(alarmMethod)) {
        if (ObjectUtils.isEmpty(alarmMethod)) {
            alarmMethod = null;
        }
        if (StringUtils.isEmpty(alarmType)) {
        if (ObjectUtils.isEmpty(alarmType)) {
            alarmType = null;
        }
        if (StringUtils.isEmpty(startTime)) {
        if (ObjectUtils.isEmpty(startTime)) {
            startTime = null;
        }
        if (StringUtils.isEmpty(endTime)) {
        if (ObjectUtils.isEmpty(endTime)) {
            endTime = null;
        }
        if (!DateUtil.verification(startTime, DateUtil.formatter) || !DateUtil.verification(endTime, DateUtil.formatter)){
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间或结束时间格式有误");
        }
        PageInfo<DeviceAlarm> allAlarm = deviceAlarmService.getAllAlarm(page, count, deviceId, alarmPriority, alarmMethod,
        return deviceAlarmService.getAllAlarm(page, count, deviceId, alarmPriority, alarmMethod,
                alarmType, startTime, endTime);
        return new ResponseEntity<>(allAlarm, HttpStatus.OK);
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
@@ -21,6 +21,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
@@ -62,7 +63,7 @@
    @Parameter(name = "expiration", description = "到期时间")
    @Parameter(name = "heartBeatInterval", description = "心跳间隔")
    @Parameter(name = "heartBeatCount", description = "心跳计数")
    public DeferredResult<ResponseEntity<String>> homePositionApi(@PathVariable String deviceId,
    public DeferredResult<String> homePositionApi(@PathVariable String deviceId,
                                                                   String channelId,
                                                                @RequestParam(required = false) String name,
                                                                @RequestParam(required = false) String expiration,
@@ -81,7 +82,7 @@
            msg.setData(String.format("设备配置操作失败,错误码: %s, %s", event.statusCode, event.msg));
            resultHolder.invokeResult(msg);
        });
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L);
        DeferredResult<String> result = new DeferredResult<String>(3 * 1000L);
        result.onTimeout(() -> {
            logger.warn(String.format("设备配置操作超时, 设备未返回应答指令"));
            // 释放rtpserver
@@ -111,13 +112,13 @@
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @Parameter(name = "configType", description = "配置类型")
    @GetMapping("/query/{deviceId}/{configType}")
    public DeferredResult<ResponseEntity<String>> configDownloadApi(@PathVariable String deviceId,
    public DeferredResult<String> configDownloadApi(@PathVariable String deviceId,
                                                                @PathVariable String configType,
                                                                @RequestParam(required = false) String channelId) {
        if (logger.isDebugEnabled()) {
            logger.debug("设备状态查询API调用");
        }
        String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (StringUtils.isEmpty(channelId) ? deviceId : channelId);
        String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId);
        String uuid = UUID.randomUUID().toString();
        Device device = storager.queryVideoDevice(deviceId);
        cmder.deviceConfigQuery(device, channelId, configType, event -> {
@@ -127,7 +128,7 @@
            msg.setData(String.format("获取设备配置失败,错误码: %s, %s", event.statusCode, event.msg));
            resultHolder.invokeResult(msg);
        });
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (3 * 1000L);
        DeferredResult<String> result = new DeferredResult<String > (3 * 1000L);
        result.onTimeout(()->{
            logger.warn(String.format("获取设备配置超时"));
            // 释放rtpserver
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
@@ -8,12 +8,14 @@
package com.genersoft.iot.vmp.vmanager.gb28181.device;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.Device;
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.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -22,6 +24,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
@@ -50,14 +53,10 @@
     * 
     * @param deviceId 设备ID
     */
//     //@ApiOperation("远程启动控制命令")
//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "deviceId", value ="设备ID", required = true, dataTypeClass = String.class),
//    })
    @Operation(summary = "远程启动控制命令")
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @GetMapping("/teleboot/{deviceId}")
    public ResponseEntity<String> teleBootApi(@PathVariable String deviceId) {
    public String teleBootApi(@PathVariable String deviceId) {
        if (logger.isDebugEnabled()) {
            logger.debug("设备远程启动API调用");
        }
@@ -67,10 +66,10 @@
            JSONObject json = new JSONObject();
            json.put("DeviceID", deviceId);
            json.put("Result", "OK");
            return new ResponseEntity<>(json.toJSONString(), HttpStatus.OK);
            return json.toJSONString();
        } else {
            logger.warn("设备远程启动API调用失败!");
            return new ResponseEntity<String>("设备远程启动API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备远程启动API调用失败!");
        }
    }
@@ -255,7 +254,7 @@
        if (logger.isDebugEnabled()) {
            logger.debug("报警复位API调用");
        }
        String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (StringUtils.isEmpty(channelId) ? deviceId : channelId);
        String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId);
        String uuid = UUID.randomUUID().toString();
        Device device = storager.queryVideoDevice(deviceId);
        cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -2,6 +2,7 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
@@ -17,6 +18,7 @@
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
import io.swagger.v3.oas.annotations.Operation;
@@ -30,6 +32,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
@@ -81,10 +84,9 @@
    @Operation(summary = "查询国标设备")
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @GetMapping("/devices/{deviceId}")
    public ResponseEntity<Device> devices(@PathVariable String deviceId){
    public Device devices(@PathVariable String deviceId){
        
        Device device = storager.queryVideoDevice(deviceId);
        return new ResponseEntity<>(device,HttpStatus.OK);
        return storager.queryVideoDevice(deviceId);
    }
    /**
@@ -123,18 +125,17 @@
    @Parameter(name = "online", description = "是否在线")
    @Parameter(name = "channelType", description = "设备/子目录-> false/true")
    @Parameter(name = "catalogUnderDevice", description = "是否直属与设备的目录")
    public ResponseEntity<PageInfo> channels(@PathVariable String deviceId,
    public PageInfo channels(@PathVariable String deviceId,
                                               int page, int count,
                                               @RequestParam(required = false) String query,
                                               @RequestParam(required = false) Boolean online,
                                               @RequestParam(required = false) Boolean channelType,
                                               @RequestParam(required = false) Boolean catalogUnderDevice) {
        if (StringUtils.isEmpty(query)) {
        if (ObjectUtils.isEmpty(query)) {
            query = null;
        }
        PageInfo pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, catalogUnderDevice, page, count);
        return new ResponseEntity<>(pageResult,HttpStatus.OK);
        return storager.queryChannelsByDeviceId(deviceId, query, channelType, online, catalogUnderDevice, page, count);
    }
    /**
@@ -154,11 +155,8 @@
        boolean status = deviceService.isSyncRunning(deviceId);
        // 已存在则返回进度
        if (status) {
            WVPResult<SyncStatus> wvpResult = new WVPResult<>();
            wvpResult.setCode(0);
            SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId);
            wvpResult.setData(channelSyncStatus);
            return wvpResult;
            return WVPResult.success(channelSyncStatus);
        }
        deviceService.sync(device);
@@ -176,7 +174,7 @@
    @Operation(summary = "移除设备")
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @DeleteMapping("/devices/{deviceId}/delete")
    public ResponseEntity<String> delete(@PathVariable String deviceId){
    public String delete(@PathVariable String deviceId){
        
        if (logger.isDebugEnabled()) {
            logger.debug("设备信息删除API调用,deviceId:" + deviceId);
@@ -200,10 +198,10 @@
            }
            JSONObject json = new JSONObject();
            json.put("deviceId", deviceId);
            return new ResponseEntity<>(json.toString(),HttpStatus.OK);
            return json.toString();
        } else {
            logger.warn("设备信息删除API调用失败!");
            return new ResponseEntity<String>("设备信息删除API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备信息删除API调用失败!");
        }
    }
@@ -402,7 +400,8 @@
            wvpResult.setCode(-1);
            wvpResult.setMsg("同步尚未开始");
        }else {
            wvpResult.setCode(0);
            wvpResult.setCode(ErrorCode.SUCCESS.getCode());
            wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
            wvpResult.setData(channelSyncStatus);
            if (channelSyncStatus.getErrorMsg() != null) {
                wvpResult.setMsg(channelSyncStatus.getErrorMsg());
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
@@ -11,6 +11,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@@ -51,13 +52,13 @@
                                   @RequestParam(required = false)String catalogId,
                                   @RequestParam(required = false)String query,
                                   @RequestParam(required = false)String mediaServerId){
        if (StringUtils.isEmpty(catalogId)) {
        if (ObjectUtils.isEmpty(catalogId)) {
            catalogId = null;
        }
        if (StringUtils.isEmpty(query)) {
        if (ObjectUtils.isEmpty(query)) {
            query = null;
        }
        if (StringUtils.isEmpty(mediaServerId)) {
        if (ObjectUtils.isEmpty(mediaServerId)) {
            mediaServerId = null;
        }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
@@ -1,12 +1,14 @@
package com.genersoft.iot.vmp.vmanager.gb28181.media;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.IStreamProxyService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -51,7 +53,7 @@
    @Parameter(name = "useSourceIpAsStreamIp", description = "是否使用请求IP作为返回的地址IP")
    @GetMapping(value = "/stream_info_by_app_and_stream")
    @ResponseBody
    public WVPResult<StreamInfo> getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
    public StreamInfo getStreamInfoByAppAndStream(HttpServletRequest request, @RequestParam String app,
                                                             @RequestParam String stream,
                                                             @RequestParam(required = false) String mediaServerId,
                                                             @RequestParam(required = false) String callId,
@@ -63,10 +65,7 @@
            if (streamAuthorityInfo.getCallId().equals(callId)) {
                authority = true;
            }else {
                WVPResult<StreamInfo> result = new WVPResult<>();
                result.setCode(401);
                result.setMsg("fail");
                return result;
                throw new ControllerException(ErrorCode.ERROR400);
            }
        }else {
            // 是否登陆用户, 登陆用户返回完整信息
@@ -89,9 +88,7 @@
        WVPResult<StreamInfo> result = new WVPResult<>();
        if (streamInfo != null){
            result.setCode(0);
            result.setMsg("scccess");
            result.setData(streamInfo);
            return  streamInfo;
        }else {
            //获取流失败,重启拉流后重试一次
            streamProxyService.stop(app,stream);
@@ -110,14 +107,10 @@
                streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
            }
            if (streamInfo != null){
                result.setCode(0);
                result.setMsg("scccess");
                result.setData(streamInfo);
                return  streamInfo;
            }else {
                result.setCode(-1);
                result.setMsg("fail");
                throw new ControllerException(ErrorCode.ERROR100);
            }
        }
        return result;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
@@ -5,6 +5,7 @@
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
@@ -14,6 +15,7 @@
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.UpdateChannelParam;
@@ -26,6 +28,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import com.genersoft.iot.vmp.conf.SipConfig;
@@ -74,13 +77,13 @@
     */
    @Operation(summary = "获取国标服务的配置")
    @GetMapping("/server_config")
    public ResponseEntity<JSONObject> serverConfig() {
    public JSONObject serverConfig() {
        JSONObject result = new JSONObject();
        result.put("deviceIp", sipConfig.getIp());
        result.put("devicePort", sipConfig.getPort());
        result.put("username", sipConfig.getId());
        result.put("password", sipConfig.getPassword());
        return new ResponseEntity<>(result, HttpStatus.OK);
        return result;
    }
    /**
@@ -91,18 +94,14 @@
    @Operation(summary = "获取级联服务器信息")
    @Parameter(name = "id", description = "平台国标编号", required = true)
    @GetMapping("/info/{id}")
    public ResponseEntity<WVPResult<ParentPlatform>> getPlatform(@PathVariable String id) {
    public ParentPlatform getPlatform(@PathVariable String id) {
        ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(id);
        WVPResult<ParentPlatform> wvpResult = new WVPResult<>();
        if (parentPlatform != null) {
            wvpResult.setCode(0);
            wvpResult.setMsg("success");
            wvpResult.setData(parentPlatform);
            return  parentPlatform;
        } else {
            wvpResult.setCode(-1);
            wvpResult.setMsg("未查询到此平台");
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "未查询到此平台");
        }
        return new ResponseEntity<>(wvpResult, HttpStatus.OK);
    }
    /**
@@ -137,38 +136,31 @@
    @Operation(summary = "添加上级平台信息")
    @PostMapping("/add")
    @ResponseBody
    public ResponseEntity<WVPResult<String>> addPlatform(@RequestBody ParentPlatform parentPlatform) {
    public String addPlatform(@RequestBody ParentPlatform parentPlatform) {
        if (logger.isDebugEnabled()) {
            logger.debug("保存上级平台信息API调用");
        }
        WVPResult<String> wvpResult = new WVPResult<>();
        if (StringUtils.isEmpty(parentPlatform.getName())
                || StringUtils.isEmpty(parentPlatform.getServerGBId())
                || StringUtils.isEmpty(parentPlatform.getServerGBDomain())
                || StringUtils.isEmpty(parentPlatform.getServerIP())
                || StringUtils.isEmpty(parentPlatform.getServerPort())
                || StringUtils.isEmpty(parentPlatform.getDeviceGBId())
                || StringUtils.isEmpty(parentPlatform.getExpires())
                || StringUtils.isEmpty(parentPlatform.getKeepTimeout())
                || StringUtils.isEmpty(parentPlatform.getTransport())
                || StringUtils.isEmpty(parentPlatform.getCharacterSet())
        if (ObjectUtils.isEmpty(parentPlatform.getName())
                || ObjectUtils.isEmpty(parentPlatform.getServerGBId())
                || ObjectUtils.isEmpty(parentPlatform.getServerGBDomain())
                || ObjectUtils.isEmpty(parentPlatform.getServerIP())
                || ObjectUtils.isEmpty(parentPlatform.getServerPort())
                || ObjectUtils.isEmpty(parentPlatform.getDeviceGBId())
                || ObjectUtils.isEmpty(parentPlatform.getExpires())
                || ObjectUtils.isEmpty(parentPlatform.getKeepTimeout())
                || ObjectUtils.isEmpty(parentPlatform.getTransport())
                || ObjectUtils.isEmpty(parentPlatform.getCharacterSet())
        ) {
            wvpResult.setCode(-1);
            wvpResult.setMsg("missing parameters");
            return new ResponseEntity<>(wvpResult, HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400);
        }
        if (parentPlatform.getServerPort() < 0 || parentPlatform.getServerPort() > 65535) {
            wvpResult.setCode(-1);
            wvpResult.setMsg("error severPort");
            return new ResponseEntity<>(wvpResult, HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "error severPort");
        }
        ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());
        if (parentPlatformOld != null) {
            wvpResult.setCode(-1);
            wvpResult.setMsg("平台 " + parentPlatform.getServerGBId() + " 已存在");
            return new ResponseEntity<>(wvpResult, HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台 " + parentPlatform.getServerGBId() + " 已存在");
        }
        parentPlatform.setCreateTime(DateUtil.getNow());
        parentPlatform.setUpdateTime(DateUtil.getNow());
@@ -190,13 +182,9 @@
            } else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()) { // 关闭启用时注销
                commanderForPlatform.unregister(parentPlatform, null, null);
            }
            wvpResult.setCode(0);
            wvpResult.setMsg("success");
            return new ResponseEntity<>(wvpResult, HttpStatus.OK);
            return null;
        } else {
            wvpResult.setCode(-1);
            wvpResult.setMsg("写入数据库失败");
            return new ResponseEntity<>(wvpResult, HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(),"写入数据库失败");
        }
    }
@@ -209,26 +197,23 @@
    @Operation(summary = "保存上级平台信息")
    @PostMapping("/save")
    @ResponseBody
    public ResponseEntity<WVPResult<String>> savePlatform(@RequestBody ParentPlatform parentPlatform) {
    public String savePlatform(@RequestBody ParentPlatform parentPlatform) {
        if (logger.isDebugEnabled()) {
            logger.debug("保存上级平台信息API调用");
        }
        WVPResult<String> wvpResult = new WVPResult<>();
        if (StringUtils.isEmpty(parentPlatform.getName())
                || StringUtils.isEmpty(parentPlatform.getServerGBId())
                || StringUtils.isEmpty(parentPlatform.getServerGBDomain())
                || StringUtils.isEmpty(parentPlatform.getServerIP())
                || StringUtils.isEmpty(parentPlatform.getServerPort())
                || StringUtils.isEmpty(parentPlatform.getDeviceGBId())
                || StringUtils.isEmpty(parentPlatform.getExpires())
                || StringUtils.isEmpty(parentPlatform.getKeepTimeout())
                || StringUtils.isEmpty(parentPlatform.getTransport())
                || StringUtils.isEmpty(parentPlatform.getCharacterSet())
        if (ObjectUtils.isEmpty(parentPlatform.getName())
                || ObjectUtils.isEmpty(parentPlatform.getServerGBId())
                || ObjectUtils.isEmpty(parentPlatform.getServerGBDomain())
                || ObjectUtils.isEmpty(parentPlatform.getServerIP())
                || ObjectUtils.isEmpty(parentPlatform.getServerPort())
                || ObjectUtils.isEmpty(parentPlatform.getDeviceGBId())
                || ObjectUtils.isEmpty(parentPlatform.getExpires())
                || ObjectUtils.isEmpty(parentPlatform.getKeepTimeout())
                || ObjectUtils.isEmpty(parentPlatform.getTransport())
                || ObjectUtils.isEmpty(parentPlatform.getCharacterSet())
        ) {
            wvpResult.setCode(-1);
            wvpResult.setMsg("missing parameters");
            return new ResponseEntity<>(wvpResult, HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400);
        }
        parentPlatform.setCharacterSet(parentPlatform.getCharacterSet().toUpperCase());
        ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());
@@ -262,13 +247,9 @@
                // 停止订阅相关的定时任务
                subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
            }
            wvpResult.setCode(0);
            wvpResult.setMsg("success");
            return new ResponseEntity<>(wvpResult, HttpStatus.OK);
            return null;
        } else {
            wvpResult.setCode(0);
            wvpResult.setMsg("写入数据库失败");
            return new ResponseEntity<>(wvpResult, HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(),"写入数据库失败");
        }
    }
@@ -282,18 +263,18 @@
    @Parameter(name = "serverGBId", description = "上级平台的国标编号")
    @DeleteMapping("/delete/{serverGBId}")
    @ResponseBody
    public ResponseEntity<String> deletePlatform(@PathVariable String serverGBId) {
    public String deletePlatform(@PathVariable String serverGBId) {
        if (logger.isDebugEnabled()) {
            logger.debug("删除上级平台API调用");
        }
        if (StringUtils.isEmpty(serverGBId)
        if (ObjectUtils.isEmpty(serverGBId)
        ) {
            return new ResponseEntity<>("missing parameters", HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400);
        }
        ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(serverGBId);
        if (parentPlatform == null) {
            return new ResponseEntity<>("fail", HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台不存在");
        }
        // 发送离线消息,无论是否成功都删除缓存
        commanderForPlatform.unregister(parentPlatform, (event -> {
@@ -317,9 +298,9 @@
        // 删除缓存的订阅信息
        subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
        if (deleteResult) {
            return new ResponseEntity<>("success", HttpStatus.OK);
            return null;
        } else {
            return new ResponseEntity<>("fail", HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
@@ -333,10 +314,10 @@
    @Parameter(name = "serverGBId", description = "上级平台的国标编号")
    @GetMapping("/exit/{serverGBId}")
    @ResponseBody
    public ResponseEntity<String> exitPlatform(@PathVariable String serverGBId) {
    public Boolean exitPlatform(@PathVariable String serverGBId) {
        ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(serverGBId);
        return new ResponseEntity<>(String.valueOf(parentPlatform != null), HttpStatus.OK);
        return parentPlatform != null;
    }
    /**
@@ -367,13 +348,13 @@
                                               @RequestParam(required = false) Boolean online,
                                               @RequestParam(required = false) Boolean channelType) {
        if (StringUtils.isEmpty(platformId)) {
        if (ObjectUtils.isEmpty(platformId)) {
            platformId = null;
        }
        if (StringUtils.isEmpty(query)) {
        if (ObjectUtils.isEmpty(query)) {
            query = null;
        }
        if (StringUtils.isEmpty(platformId) || StringUtils.isEmpty(catalogId)) {
        if (ObjectUtils.isEmpty(platformId) || ObjectUtils.isEmpty(catalogId)) {
            catalogId = null;
        }
        PageInfo<ChannelReduce> channelReduces = storager.queryAllChannelList(page, count, query, online, channelType, platformId, catalogId);
@@ -390,14 +371,15 @@
    @Operation(summary = "向上级平台添加国标通道")
    @PostMapping("/update_channel_for_gb")
    @ResponseBody
    public ResponseEntity<String> updateChannelForGB(@RequestBody UpdateChannelParam param) {
    public void updateChannelForGB(@RequestBody UpdateChannelParam param) {
        if (logger.isDebugEnabled()) {
            logger.debug("给上级平台添加国标通道API调用");
        }
        int result = platformChannelService.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId());
        return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
        if (result <= 0) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    /**
@@ -409,14 +391,16 @@
    @Operation(summary = "从上级平台移除国标通道")
    @DeleteMapping("/del_channel_for_gb")
    @ResponseBody
    public ResponseEntity<String> delChannelForGB(@RequestBody UpdateChannelParam param) {
    public void delChannelForGB(@RequestBody UpdateChannelParam param) {
        if (logger.isDebugEnabled()) {
            logger.debug("给上级平台删除国标通道API调用");
        }
        int result = storager.delChannelForGB(param.getPlatformId(), param.getChannelReduces());
        return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK);
        if (result <= 0) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    /**
@@ -431,25 +415,20 @@
    @Parameter(name = "parentId", description = "父级目录的国标编号", required = true)
    @GetMapping("/catalog")
    @ResponseBody
    public ResponseEntity<WVPResult<List<PlatformCatalog>>> getCatalogByPlatform(String platformId, String parentId) {
    public List<PlatformCatalog> getCatalogByPlatform(String platformId, String parentId) {
        if (logger.isDebugEnabled()) {
            logger.debug("查询目录,platformId: {}, parentId: {}", platformId, parentId);
        }
        ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
        if (platform == null) {
            return new ResponseEntity<>(new WVPResult<>(400, "平台未找到", null), HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台未找到");
        }
        if (platformId.equals(parentId)) {
            parentId = platform.getDeviceGBId();
        }
        List<PlatformCatalog> platformCatalogList = storager.getChildrenCatalogByPlatform(platformId, parentId);
        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        result.setData(platformCatalogList);
        return new ResponseEntity<>(result, HttpStatus.OK);
        return storager.getChildrenCatalogByPlatform(platformId, parentId);
    }
    /**
@@ -461,28 +440,19 @@
    @Operation(summary = "添加目录")
    @PostMapping("/catalog/add")
    @ResponseBody
    public ResponseEntity<WVPResult<List<PlatformCatalog>>> addCatalog(@RequestBody PlatformCatalog platformCatalog) {
    public void addCatalog(@RequestBody PlatformCatalog platformCatalog) {
        if (logger.isDebugEnabled()) {
            logger.debug("添加目录,{}", JSON.toJSONString(platformCatalog));
        }
        PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId());
        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
        if (platformCatalogInStore != null) {
            result.setCode(-1);
            result.setMsg(platformCatalog.getId() + " already exists");
            return new ResponseEntity<>(result, HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), platformCatalog.getId() + " already exists");
        }
        int addResult = storager.addCatalog(platformCatalog);
        if (addResult > 0) {
            result.setCode(0);
            result.setMsg("success");
            return new ResponseEntity<>(result, HttpStatus.OK);
        } else {
            result.setCode(-500);
            result.setMsg("save error");
            return new ResponseEntity<>(result, HttpStatus.OK);
        if (addResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
@@ -495,26 +465,19 @@
    @Operation(summary = "编辑目录")
    @PostMapping("/catalog/edit")
    @ResponseBody
    public ResponseEntity<WVPResult<List<PlatformCatalog>>> editCatalog(@RequestBody PlatformCatalog platformCatalog) {
    public void editCatalog(@RequestBody PlatformCatalog platformCatalog) {
        if (logger.isDebugEnabled()) {
            logger.debug("编辑目录,{}", JSON.toJSONString(platformCatalog));
        }
        PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId());
        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
        result.setCode(0);
        if (platformCatalogInStore == null) {
            result.setMsg(platformCatalog.getId() + " not exists");
            return new ResponseEntity<>(result, HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), platformCatalog.getId() + " not exists");
        }
        int addResult = storager.updateCatalog(platformCatalog);
        if (addResult > 0) {
            result.setMsg("success");
            return new ResponseEntity<>(result, HttpStatus.OK);
        } else {
            result.setMsg("save error");
            return new ResponseEntity<>(result, HttpStatus.OK);
        if (addResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "写入数据库失败");
        }
    }
@@ -530,19 +493,15 @@
    @Parameter(name = "platformId", description = "平台Id", required = true)
    @DeleteMapping("/catalog/del")
    @ResponseBody
    public ResponseEntity<WVPResult<String>> delCatalog(String id, String platformId) {
    public void delCatalog(String id, String platformId) {
        if (logger.isDebugEnabled()) {
            logger.debug("删除目录,{}", id);
        }
        WVPResult<String> result = new WVPResult<>();
        if (StringUtils.isEmpty(id) || StringUtils.isEmpty(platformId)) {
            result.setCode(-1);
            result.setMsg("param error");
            return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
        if (ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(platformId)) {
            throw new ControllerException(ErrorCode.ERROR400);
        }
        result.setCode(0);
        int delResult = storager.delCatalog(id);
        // 如果删除的是默认目录则根目录设置为默认目录
@@ -551,16 +510,10 @@
        // 默认节点被移除
        if (parentPlatform == null) {
            storager.setDefaultCatalog(platformId, platformId);
            result.setData(platformId);
        }
        if (delResult > 0) {
            result.setMsg("success");
            return new ResponseEntity<>(result, HttpStatus.OK);
        } else {
            result.setMsg("save error");
            return new ResponseEntity<>(result, HttpStatus.OK);
        if (delResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "写入数据库失败");
        }
    }
@@ -573,21 +526,15 @@
    @Operation(summary = "删除关联")
    @DeleteMapping("/catalog/relation/del")
    @ResponseBody
    public ResponseEntity<WVPResult<List<PlatformCatalog>>> delRelation(@RequestBody PlatformCatalog platformCatalog) {
    public void delRelation(@RequestBody PlatformCatalog platformCatalog) {
        if (logger.isDebugEnabled()) {
            logger.debug("删除关联,{}", JSON.toJSONString(platformCatalog));
        }
        int delResult = storager.delRelation(platformCatalog);
        WVPResult<List<PlatformCatalog>> result = new WVPResult<>();
        result.setCode(0);
        if (delResult > 0) {
            result.setMsg("success");
            return new ResponseEntity<>(result, HttpStatus.OK);
        } else {
            result.setMsg("save error");
            return new ResponseEntity<>(result, HttpStatus.OK);
        if (delResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "写入数据库失败");
        }
    }
@@ -604,21 +551,15 @@
    @Parameter(name = "platformId", description = "平台Id", required = true)
    @PostMapping("/catalog/default/update")
    @ResponseBody
    public ResponseEntity<WVPResult<String>> setDefaultCatalog(String platformId, String catalogId) {
    public void setDefaultCatalog(String platformId, String catalogId) {
        if (logger.isDebugEnabled()) {
            logger.debug("修改默认目录,{},{}", platformId, catalogId);
        }
        int updateResult = storager.setDefaultCatalog(platformId, catalogId);
        WVPResult<String> result = new WVPResult<>();
        result.setCode(0);
        if (updateResult > 0) {
            result.setMsg("success");
            return new ResponseEntity<>(result, HttpStatus.OK);
        } else {
            result.setMsg("save error");
            return new ResponseEntity<>(result, HttpStatus.OK);
        if (updateResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "写入数据库失败");
        }
    }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -2,6 +2,7 @@
import com.alibaba.fastjson.JSONArray;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -11,6 +12,7 @@
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
import com.genersoft.iot.vmp.service.IMediaService;
@@ -78,7 +80,7 @@
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @GetMapping("/start/{deviceId}/{channelId}")
    public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId,
    public DeferredResult<String> play(@PathVariable String deviceId,
                                                       @PathVariable String channelId) {
        // 获取可用的zlm
@@ -94,12 +96,12 @@
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @GetMapping("/stop/{deviceId}/{channelId}")
    public DeferredResult<ResponseEntity<String>> playStop(@PathVariable String deviceId, @PathVariable String channelId) {
    public DeferredResult<String> playStop(@PathVariable String deviceId, @PathVariable String channelId) {
        logger.debug(String.format("设备预览/回放停止API调用,streamId:%s_%s", deviceId, channelId ));
        String uuid = UUID.randomUUID().toString();
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
        DeferredResult<String> result = new DeferredResult<>();
        // 录像查询以channelId作为deviceId查询
        String key = DeferredResultHolder.CALLBACK_CMD_STOP + deviceId + channelId;
@@ -164,40 +166,40 @@
    @Operation(summary = "将不是h264的视频通过ffmpeg 转码为h264 + aac")
    @Parameter(name = "streamId", description = "视频流ID", required = true)
    @PostMapping("/convert/{streamId}")
    public ResponseEntity<String> playConvert(@PathVariable String streamId) {
    public JSONObject playConvert(@PathVariable String streamId) {
        StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
        if (streamInfo == null) {
            streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
        }
        if (streamInfo == null) {
            logger.warn("视频转码API调用失败!, 视频流已经停止!");
            return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到视频流信息, 视频流可能已经停止");
        }
        MediaServerItem mediaInfo = mediaServerService.getOne(streamInfo.getMediaServerId());
        JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaInfo, streamId);
        if (!rtpInfo.getBoolean("exist")) {
            logger.warn("视频转码API调用失败!, 视频流已停止推流!");
            return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到视频流信息, 视频流可能已停止推流");
        } else {
            String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
                    streamId );
            String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId);
            JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(mediaInfo, srcUrl, dstUrl, "1000000", true, false, null);
            logger.info(jsonObject.toJSONString());
            JSONObject result = new JSONObject();
            if (jsonObject != null && jsonObject.getInteger("code") == 0) {
                   result.put("code", 0);
                JSONObject data = jsonObject.getJSONObject("data");
                if (data != null) {
                       result.put("key", data.getString("key"));
                    JSONObject result = new JSONObject();
                    result.put("key", data.getString("key"));
                    StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStreamWithCheck("convert", streamId, mediaInfo.getId(), false);
                    result.put("data", streamInfoResult);
                    result.put("StreamInfo", streamInfoResult);
                    return result;
                }else {
                    throw new ControllerException(ErrorCode.ERROR100.getCode(), "转码失败");
                }
            }else {
                result.put("code", 1);
                result.put("msg", "cover fail");
                throw new ControllerException(ErrorCode.ERROR100.getCode(), "转码失败");
            }
            return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
        }
    }
@@ -210,53 +212,40 @@
    @Parameter(name = "key", description = "视频流key", required = true)
    @Parameter(name = "mediaServerId", description = "流媒体服务ID", required = true)
    @PostMapping("/convertStop/{key}")
    public ResponseEntity<String> playConvertStop(@PathVariable String key, String mediaServerId) {
        JSONObject result = new JSONObject();
    public void playConvertStop(@PathVariable String key, String mediaServerId) {
        if (mediaServerId == null) {
            result.put("code", 400);
            result.put("msg", "mediaServerId is null");
            return new ResponseEntity<String>( result.toJSONString(), HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "流媒体:" + mediaServerId + "不存在" );
        }
        MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
        if (mediaInfo == null) {
            result.put("code", 0);
            result.put("msg", "使用的流媒体已经停止运行");
            return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "使用的流媒体已经停止运行" );
        }else {
            JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(mediaInfo, key);
            logger.info(jsonObject.toJSONString());
            if (jsonObject != null && jsonObject.getInteger("code") == 0) {
                result.put("code", 0);
                JSONObject data = jsonObject.getJSONObject("data");
                if (data != null && data.getBoolean("flag")) {
                    result.put("code", "0");
                    result.put("msg", "success");
                }else {
                if (data == null || data.getBoolean("flag") == null || !data.getBoolean("flag")) {
                    throw new ControllerException(ErrorCode.ERROR100 );
                }
            }else {
                result.put("code", 1);
                result.put("msg", "delFFmpegSource fail");
                throw new ControllerException(ErrorCode.ERROR100 );
            }
            return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
        }
    }
    @Operation(summary = "语音广播命令")
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @GetMapping("/broadcast/{deviceId}")
    @PostMapping("/broadcast/{deviceId}")
    public DeferredResult<ResponseEntity<String>> broadcastApi(@PathVariable String deviceId) {
    public DeferredResult<String> broadcastApi(@PathVariable String deviceId) {
        if (logger.isDebugEnabled()) {
            logger.debug("语音广播API调用");
        }
        Device device = storager.queryVideoDevice(deviceId);
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L);
        DeferredResult<String> result = new DeferredResult<>(3 * 1000L);
        String key  = DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId;
        if (resultHolder.exist(key, null)) {
            result.setResult(new ResponseEntity<>("设备使用中",HttpStatus.OK));
            result.setResult("设备使用中");
            return result;
        }
        String uuid  = UUID.randomUUID().toString();
@@ -307,7 +296,7 @@
    @Operation(summary = "获取所有的ssrc")
    @GetMapping("/ssrc")
    public WVPResult<JSONObject> getSSRC() {
    public JSONObject getSSRC() {
        if (logger.isDebugEnabled()) {
            logger.debug("获取所有的ssrc");
        }
@@ -322,14 +311,10 @@
            objects.add(jsonObject);
        }
        WVPResult<JSONObject> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("data", objects);
        jsonObject.put("count", objects.size());
        result.setData(jsonObject);
        return result;
        return jsonObject;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/PlayResult.java
@@ -1,21 +1,22 @@
package com.genersoft.iot.vmp.vmanager.gb28181.play.bean;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;
public class PlayResult {
    private DeferredResult<ResponseEntity<String>> result;
    private DeferredResult<WVPResult<String>> result;
    private String uuid;
    private Device device;
    public DeferredResult<ResponseEntity<String>> getResult() {
    public DeferredResult<WVPResult<String>> getResult() {
        return result;
    }
    public void setResult(DeferredResult<ResponseEntity<String>> result) {
    public void setResult(DeferredResult<WVPResult<String>> result) {
        this.result = result;
    }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
@@ -1,10 +1,12 @@
package com.genersoft.iot.vmp.vmanager.gb28181.playback;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -13,6 +15,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
@@ -55,14 +58,14 @@
    @Parameter(name = "startTime", description = "开始时间", required = true)
    @Parameter(name = "endTime", description = "结束时间", required = true)
    @GetMapping("/start/{deviceId}/{channelId}")
    public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId, @PathVariable String channelId,
    public DeferredResult<String> play(@PathVariable String deviceId, @PathVariable String channelId,
                                                       String startTime,String endTime) {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
        }
        DeferredResult<ResponseEntity<String>> result = playService.playBack(deviceId, channelId, startTime, endTime, null, wvpResult->{
        DeferredResult<String> result = playService.playBack(deviceId, channelId, startTime, endTime, null, wvpResult->{
            resultHolder.invokeResult(wvpResult.getData());
        });
@@ -75,67 +78,46 @@
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @Parameter(name = "stream", description = "流ID", required = true)
    @GetMapping("/stop/{deviceId}/{channelId}/{stream}")
    public ResponseEntity<String> playStop(
    public void playStop(
            @PathVariable String deviceId,
            @PathVariable String channelId,
            @PathVariable String stream) {
        if (ObjectUtils.isEmpty(deviceId) || ObjectUtils.isEmpty(channelId) || ObjectUtils.isEmpty(stream)) {
            throw new ControllerException(ErrorCode.ERROR400);
        }
        cmder.streamByeCmd(deviceId, channelId, stream, null);
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备录像回放停止 API调用,deviceId/channelId:%s/%s", deviceId, channelId));
        }
        if (StringUtils.isEmpty(deviceId) || StringUtils.isEmpty(channelId) || StringUtils.isEmpty(stream)) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        }
        if (deviceId != null && channelId != null) {
            JSONObject json = new JSONObject();
            json.put("deviceId", deviceId);
            json.put("channelId", channelId);
            return new ResponseEntity<>(json.toString(), HttpStatus.OK);
        } else {
            logger.warn("设备录像回放停止API调用失败!");
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
    @Operation(summary = "回放暂停")
    @Parameter(name = "streamId", description = "回放流ID", required = true)
    @GetMapping("/pause/{streamId}")
    public ResponseEntity<String> playPause(@PathVariable String streamId) {
    public void playPause(@PathVariable String streamId) {
        logger.info("playPause: "+streamId);
        JSONObject json = new JSONObject();
        StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
        if (null == streamInfo) {
            json.put("msg", "streamId不存在");
            logger.warn("streamId不存在!");
            return new ResponseEntity<String>(json.toString(), HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
        }
        Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
        cmder.playPauseCmd(device, streamInfo);
        json.put("msg", "ok");
        return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
    }
    @Operation(summary = "回放恢复")
    @Parameter(name = "streamId", description = "回放流ID", required = true)
    @GetMapping("/resume/{streamId}")
    public ResponseEntity<String> playResume(@PathVariable String streamId) {
    public void playResume(@PathVariable String streamId) {
        logger.info("playResume: "+streamId);
        JSONObject json = new JSONObject();
        StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
        if (null == streamInfo) {
            json.put("msg", "streamId不存在");
            logger.warn("streamId不存在!");
            return new ResponseEntity<String>(json.toString(), HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
        }
        Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
        cmder.playResumeCmd(device, streamInfo);
        json.put("msg", "ok");
        return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
    }
@@ -143,43 +125,33 @@
    @Parameter(name = "streamId", description = "回放流ID", required = true)
    @Parameter(name = "seekTime", description = "拖动偏移量,单位s", required = true)
    @GetMapping("/seek/{streamId}/{seekTime}")
    public ResponseEntity<String> playSeek(@PathVariable String streamId, @PathVariable long seekTime) {
    public void playSeek(@PathVariable String streamId, @PathVariable long seekTime) {
        logger.info("playSeek: "+streamId+", "+seekTime);
        JSONObject json = new JSONObject();
        StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
        if (null == streamInfo) {
            json.put("msg", "streamId不存在");
            logger.warn("streamId不存在!");
            return new ResponseEntity<String>(json.toString(), HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
        }
        Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
        cmder.playSeekCmd(device, streamInfo, seekTime);
        json.put("msg", "ok");
        return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
    }
    @Operation(summary = "回放倍速播放")
    @Parameter(name = "streamId", description = "回放流ID", required = true)
    @Parameter(name = "speed", description = "倍速0.25 0.5 1、2、4", required = true)
    @GetMapping("/speed/{streamId}/{speed}")
    public ResponseEntity<String> playSpeed(@PathVariable String streamId, @PathVariable Double speed) {
    public void playSpeed(@PathVariable String streamId, @PathVariable Double speed) {
        logger.info("playSpeed: "+streamId+", "+speed);
        JSONObject json = new JSONObject();
        StreamInfo streamInfo = redisCatchStorage.queryPlayback(null, null, streamId, null);
        if (null == streamInfo) {
            json.put("msg", "streamId不存在");
            logger.warn("streamId不存在!");
            return new ResponseEntity<String>(json.toString(), HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "streamId不存在");
        }
        if(speed != 0.25 && speed != 0.5 && speed != 1 && speed != 2.0 && speed != 4.0) {
            json.put("msg", "不支持的speed(0.25 0.5 1、2、4)");
            logger.warn("不支持的speed: " + speed);
            return new ResponseEntity<String>(json.toString(), HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持的speed(0.25 0.5 1、2、4)");
        }
        Device device = storager.queryVideoDevice(streamInfo.getDeviceID());
        cmder.playSpeedCmd(device, streamInfo, speed);
        json.put("msg", "ok");
        return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
@@ -7,8 +7,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
@@ -46,7 +45,6 @@
     * @param horizonSpeed    水平移动速度
     * @param verticalSpeed    垂直移动速度
     * @param zoomSpeed        缩放速度
     * @return String 控制结果
     */
    @Operation(summary = "云台控制")
@@ -57,7 +55,7 @@
    @Parameter(name = "verticalSpeed", description = "垂直速度", required = true)
    @Parameter(name = "zoomSpeed", description = "缩放速度", required = true)
    @PostMapping("/control/{deviceId}/{channelId}")
    public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId, String command, int horizonSpeed, int verticalSpeed, int zoomSpeed){
    public void ptz(@PathVariable String deviceId,@PathVariable String channelId, String command, int horizonSpeed, int verticalSpeed, int zoomSpeed){
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备云台控制 API调用,deviceId:%s ,channelId:%s ,command:%s ,horizonSpeed:%d ,verticalSpeed:%d ,zoomSpeed:%d",deviceId, channelId, command, horizonSpeed, verticalSpeed, zoomSpeed));
@@ -96,13 +94,11 @@
                cmdCode = 32;
                break;
            case "stop":
                cmdCode = 0;
                break;
            default:
                break;
        }
        cmder.frontEndCmd(device, channelId, cmdCode, horizonSpeed, verticalSpeed, zoomSpeed);
        return new ResponseEntity<String>("success",HttpStatus.OK);
    }
@@ -114,7 +110,7 @@
    @Parameter(name = "parameter2", description = "数据二", required = true)
    @Parameter(name = "combindCode2", description = "组合码二", required = true)
    @PostMapping("/front_end_command/{deviceId}/{channelId}")
    public ResponseEntity<String> frontEndCommand(@PathVariable String deviceId,@PathVariable String channelId,int cmdCode, int parameter1, int parameter2, int combindCode2){
    public void frontEndCommand(@PathVariable String deviceId,@PathVariable String channelId,int cmdCode, int parameter1, int parameter2, int combindCode2){
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备云台控制 API调用,deviceId:%s ,channelId:%s ,cmdCode:%d parameter1:%d parameter2:%d",deviceId, channelId, cmdCode, parameter1, parameter2));
@@ -122,7 +118,6 @@
        Device device = storager.queryVideoDevice(deviceId);
        cmder.frontEndCmd(device, channelId, cmdCode, parameter1, parameter2, combindCode2);
        return new ResponseEntity<String>("success",HttpStatus.OK);
    }
@@ -130,14 +125,14 @@
    @Parameter(name = "deviceId", description = "设备国标编号", required = true)
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @GetMapping("/preset/query/{deviceId}/{channelId}")
    public DeferredResult<ResponseEntity<String>> presetQueryApi(@PathVariable String deviceId, @PathVariable String channelId) {
    public DeferredResult<String> presetQueryApi(@PathVariable String deviceId, @PathVariable String channelId) {
        if (logger.isDebugEnabled()) {
            logger.debug("设备预置位查询API调用");
        }
        Device device = storager.queryVideoDevice(deviceId);
        String uuid =  UUID.randomUUID().toString();
        String key =  DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (StringUtils.isEmpty(channelId) ? deviceId : channelId);
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (3 * 1000L);
        String key =  DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId);
        DeferredResult<String> result = new DeferredResult<String> (3 * 1000L);
        result.onTimeout(()->{
            logger.warn(String.format("获取设备预置位超时"));
            // 释放rtpserver
@@ -158,7 +153,6 @@
            msg.setData(String.format("获取设备预置位失败,错误码: %s, %s", event.statusCode, event.msg));
            resultHolder.invokeResult(msg);
        });
        return result;
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
@@ -2,10 +2,12 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
@@ -58,28 +60,17 @@
    @Parameter(name = "startTime", description = "开始时间", required = true)
    @Parameter(name = "endTime", description = "结束时间", required = true)
    @GetMapping("/query/{deviceId}/{channelId}")
    public DeferredResult<ResponseEntity<WVPResult<RecordInfo>>> recordinfo(@PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime){
    public DeferredResult<WVPResult<RecordInfo>> recordinfo(@PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime){
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("录像信息查询 API调用,deviceId:%s ,startTime:%s, endTime:%s",deviceId, startTime, endTime));
        }
        DeferredResult<ResponseEntity<WVPResult<RecordInfo>>> result = new DeferredResult<>();
        DeferredResult<WVPResult<RecordInfo>> result = new DeferredResult<>();
        if (!DateUtil.verification(startTime, DateUtil.formatter)){
            WVPResult<RecordInfo> wvpResult = new WVPResult<>();
            wvpResult.setCode(-1);
            wvpResult.setMsg("startTime error, format is " + DateUtil.PATTERN);
            ResponseEntity<WVPResult<RecordInfo>> resultResponseEntity = new ResponseEntity<>(wvpResult, HttpStatus.OK);
            result.setResult(resultResponseEntity);
            return result;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime error, format is " + DateUtil.PATTERN);
        }
        if (!DateUtil.verification(endTime, DateUtil.formatter)){
            WVPResult<RecordInfo> wvpResult = new WVPResult<>();
            wvpResult.setCode(-1);
            wvpResult.setMsg("endTime error, format is " + DateUtil.PATTERN);
            ResponseEntity<WVPResult<RecordInfo>> resultResponseEntity = new ResponseEntity<>(wvpResult, HttpStatus.OK);
            result.setResult(resultResponseEntity);
            return result;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "endTime error, format is " + DateUtil.PATTERN);
        }
        Device device = storager.queryVideoDevice(deviceId);
@@ -92,7 +83,7 @@
        msg.setKey(key);
        cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> {
            WVPResult<RecordInfo> wvpResult = new WVPResult<>();
            wvpResult.setCode(-1);
            wvpResult.setCode(ErrorCode.ERROR100.getCode());
            wvpResult.setMsg("查询录像失败, status: " +  eventResult.statusCode + ", message: " + eventResult.msg);
            msg.setData(wvpResult);
            resultHolder.invokeResult(msg);
@@ -103,7 +94,7 @@
        result.onTimeout(()->{
            msg.setData("timeout");
            WVPResult<RecordInfo> wvpResult = new WVPResult<>();
            wvpResult.setCode(-1);
            wvpResult.setCode(ErrorCode.ERROR100.getCode());
            wvpResult.setMsg("timeout");
            msg.setData(wvpResult);
            resultHolder.invokeResult(msg);
@@ -119,59 +110,14 @@
    @Parameter(name = "endTime", description = "结束时间", required = true)
    @Parameter(name = "downloadSpeed", description = "下载倍速", required = true)
    @GetMapping("/download/start/{deviceId}/{channelId}")
    public DeferredResult<ResponseEntity<String>> download(@PathVariable String deviceId, @PathVariable String channelId,
    public DeferredResult<String> download(@PathVariable String deviceId, @PathVariable String channelId,
                                                       String startTime, String endTime, String downloadSpeed) {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed));
        }
//        String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
//        String uuid = UUID.randomUUID().toString();
//        DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L);
//        // 超时处理
//        result.onTimeout(()->{
//            logger.warn(String.format("设备下载响应超时,deviceId:%s ,channelId:%s", deviceId, channelId));
//            RequestMessage msg = new RequestMessage();
//            msg.setId(uuid);
//            msg.setKey(key);
//            msg.setData("Timeout");
//            resultHolder.invokeAllResult(msg);
//        });
//        if(resultHolder.exist(key, null)) {
//            return result;
//        }
//        resultHolder.put(key, uuid, result);
//        Device device = storager.queryVideoDevice(deviceId);
//
//        MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
//        if (newMediaServerItem == null) {
//            logger.warn(String.format("设备下载响应超时,deviceId:%s ,channelId:%s", deviceId, channelId));
//            RequestMessage msg = new RequestMessage();
//            msg.setId(uuid);
//            msg.setKey(key);
//            msg.setData("Timeout");
//            resultHolder.invokeAllResult(msg);
//            return result;
//        }
//
//        SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
//
//        cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (InviteStreamInfo inviteStreamInfo) -> {
//            logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
//            playService.onPublishHandlerForDownload(inviteStreamInfo, deviceId, channelId, uuid);
//        }, event -> {
//            RequestMessage msg = new RequestMessage();
//            msg.setId(uuid);
//            msg.setKey(key);
//            msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
//            resultHolder.invokeAllResult(msg);
//        });
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
        }
        DeferredResult<ResponseEntity<String>> result = playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, hookCallBack->{
        DeferredResult<String> result = playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, hookCallBack->{
            resultHolder.invokeResult(hookCallBack.getData());
        });
@@ -183,7 +129,7 @@
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @Parameter(name = "stream", description = "流ID", required = true)
    @GetMapping("/download/stop/{deviceId}/{channelId}/{stream}")
    public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
    public void playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
        cmder.streamByeCmd(deviceId, channelId, stream, null);
@@ -191,14 +137,8 @@
            logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId));
        }
        if (deviceId != null && channelId != null) {
            JSONObject json = new JSONObject();
            json.put("deviceId", deviceId);
            json.put("channelId", channelId);
            return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
        } else {
            logger.warn("设备历史媒体下载停止API调用失败!");
            return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
        if (deviceId == null || channelId == null) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
@@ -207,9 +147,7 @@
    @Parameter(name = "channelId", description = "通道国标编号", required = true)
    @Parameter(name = "stream", description = "流ID", required = true)
    @GetMapping("/download/progress/{deviceId}/{channelId}/{stream}")
    public ResponseEntity<StreamInfo> getProgress(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
        StreamInfo streamInfo = playService.getDownLoadInfo(deviceId, channelId, stream);
        return new ResponseEntity<>(streamInfo, HttpStatus.OK);
    public StreamInfo getProgress(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
        return playService.getDownLoadInfo(deviceId, channelId, stream);
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java
@@ -1,9 +1,11 @@
package com.genersoft.iot.vmp.vmanager.log;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.service.ILogService;
import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
@@ -15,6 +17,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@@ -53,7 +56,7 @@
    @Parameter(name = "type", description = "类型", required = true)
    @Parameter(name = "startTime", description = "开始时间", required = true)
    @Parameter(name = "endTime", description = "结束时间", required = true)
    public ResponseEntity<PageInfo<LogDto>> getAll(
    public PageInfo<LogDto> getAll(
            @RequestParam int page,
            @RequestParam int count,
            @RequestParam(required = false)  String query,
@@ -61,13 +64,13 @@
            @RequestParam(required = false) String startTime,
            @RequestParam(required = false) String endTime
    ) {
        if (StringUtils.isEmpty(query)) {
        if (ObjectUtils.isEmpty(query)) {
            query = null;
        }
        if (StringUtils.isEmpty(startTime)) {
        if (ObjectUtils.isEmpty(startTime)) {
            startTime = null;
        }
        if (StringUtils.isEmpty(endTime)) {
        if (ObjectUtils.isEmpty(endTime)) {
            endTime = null;
        }
        if (!userSetting.getLogInDatebase()) {
@@ -75,11 +78,10 @@
        }
        if (!DateUtil.verification(startTime, DateUtil.formatter) || !DateUtil.verification(endTime, DateUtil.formatter)){
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
            throw new ControllerException(ErrorCode.ERROR400);
        }
        PageInfo<LogDto> allLog = logService.getAll(page, count, query, type, startTime, endTime);
        return new ResponseEntity<>(allLog, HttpStatus.OK);
        return logService.getAll(page, count, query, type, startTime, endTime);
    }
    /**
@@ -88,14 +90,8 @@
     */
    @Operation(summary = "停止视频回放")
    @DeleteMapping("/clear")
    public ResponseEntity<WVPResult<String>> clear() {
        int count = logService.clear();
        WVPResult wvpResult = new WVPResult();
        wvpResult.setCode(0);
        wvpResult.setMsg("success");
        wvpResult.setData(count);
        return new ResponseEntity<WVPResult<String>>(wvpResult, HttpStatus.OK);
    public void clear() {
        logService.clear();
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
@@ -4,24 +4,27 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.VManageBootstrap;
import com.genersoft.iot.vmp.common.VersionPo;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.VersionInfo;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import gov.nist.javax.sip.SipStackImpl;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.ehcache.xml.model.ThreadPoolsType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@@ -30,7 +33,6 @@
import javax.sip.SipProvider;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@SuppressWarnings("rawtypes")
@Tag(name = "服务控制")
@@ -54,45 +56,34 @@
    @Autowired
    private UserSetting userSetting;
    @Autowired
    private DynamicTask dynamicTask;
    @Value("${server.port}")
    private int serverPort;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @GetMapping(value = "/media_server/list")
    @ResponseBody
    @Operation(summary = "流媒体服务列表")
    public WVPResult<List<MediaServerItem>> getMediaServerList() {
        WVPResult<List<MediaServerItem>> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        result.setData(mediaServerService.getAll());
        return result;
    public List<MediaServerItem> getMediaServerList() {
        return mediaServerService.getAll();
    }
    @GetMapping(value = "/media_server/online/list")
    @ResponseBody
    @Operation(summary = "在线流媒体服务列表")
    public WVPResult<List<MediaServerItem>> getOnlineMediaServerList() {
        WVPResult<List<MediaServerItem>> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        result.setData(mediaServerService.getAllOnline());
        return result;
    public List<MediaServerItem> getOnlineMediaServerList() {
        return mediaServerService.getAllOnline();
    }
    @GetMapping(value = "/media_server/one/{id}")
    @ResponseBody
    @Operation(summary = "停止视频回放")
    @Parameter(name = "id", description = "流媒体服务ID", required = true)
    public WVPResult<MediaServerItem> getMediaServer(@PathVariable String id) {
        WVPResult<MediaServerItem> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        result.setData(mediaServerService.getOne(id));
        return result;
    public MediaServerItem getMediaServer(@PathVariable String id) {
        return mediaServerService.getOne(id);
    }
    @Operation(summary = "测试流媒体服务")
@@ -101,7 +92,7 @@
    @Parameter(name = "secret", description = "流媒体服务secret", required = true)
    @GetMapping(value = "/media_server/check")
    @ResponseBody
    public WVPResult<MediaServerItem> checkMediaServer(@RequestParam String ip, @RequestParam int port, @RequestParam String secret) {
    public MediaServerItem checkMediaServer(@RequestParam String ip, @RequestParam int port, @RequestParam String secret) {
        return mediaServerService.checkMediaServer(ip, port, secret);
    }
@@ -110,122 +101,87 @@
    @Parameter(name = "port", description = "流媒体服务HTT端口", required = true)
    @GetMapping(value = "/media_server/record/check")
    @ResponseBody
    public WVPResult<String> checkMediaRecordServer(@RequestParam String ip, @RequestParam int port) {
    public void checkMediaRecordServer(@RequestParam String ip, @RequestParam int port) {
        boolean checkResult = mediaServerService.checkMediaRecordServer(ip, port);
        WVPResult<String> result = new WVPResult<>();
        if (checkResult) {
            result.setCode(0);
            result.setMsg("success");
        } else {
            result.setCode(-1);
            result.setMsg("连接失败");
        if (!checkResult) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接失败");
        }
        return result;
    }
    @Operation(summary = "保存流媒体服务")
    @Parameter(name = "mediaServerItem", description = "流媒体信息", required = true)
    @PostMapping(value = "/media_server/save")
    @ResponseBody
    public WVPResult<String> saveMediaServer(@RequestBody MediaServerItem mediaServerItem) {
    public void saveMediaServer(@RequestBody MediaServerItem mediaServerItem) {
        MediaServerItem mediaServerItemInDatabase = mediaServerService.getOne(mediaServerItem.getId());
        if (mediaServerItemInDatabase != null) {
            if (StringUtils.isEmpty(mediaServerItemInDatabase.getSendRtpPortRange()) && StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())) {
            if (ObjectUtils.isEmpty(mediaServerItemInDatabase.getSendRtpPortRange()) && ObjectUtils.isEmpty(mediaServerItem.getSendRtpPortRange())) {
                mediaServerItem.setSendRtpPortRange("30000,30500");
            }
            mediaServerService.update(mediaServerItem);
        } else {
            if (StringUtils.isEmpty(mediaServerItem.getSendRtpPortRange())) {
            if (ObjectUtils.isEmpty(mediaServerItem.getSendRtpPortRange())) {
                mediaServerItem.setSendRtpPortRange("30000,30500");
            }
            return mediaServerService.add(mediaServerItem);
            mediaServerService.add(mediaServerItem);
        }
        WVPResult<String> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        return result;
    }
    @Operation(summary = "移除流媒体服务")
    @Parameter(name = "id", description = "流媒体ID", required = true)
    @DeleteMapping(value = "/media_server/delete")
    @ResponseBody
    public WVPResult<String> deleteMediaServer(@RequestParam String id) {
        if (mediaServerService.getOne(id) != null) {
            mediaServerService.delete(id);
            mediaServerService.deleteDb(id);
        } else {
            WVPResult<String> result = new WVPResult<>();
            result.setCode(-1);
            result.setMsg("未找到此节点");
            return result;
    public void deleteMediaServer(@RequestParam String id) {
        if (mediaServerService.getOne(id) == null) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到此节点");
        }
        WVPResult<String> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        return result;
        mediaServerService.delete(id);
        mediaServerService.deleteDb(id);
    }
    @Operation(summary = "重启服务")
    @GetMapping(value = "/restart")
    @ResponseBody
    public Object restart() {
        Thread restartThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
                    SipStackImpl stack = (SipStackImpl) up.getSipStack();
                    stack.stop();
                    Iterator listener = stack.getListeningPoints();
                    while (listener.hasNext()) {
                        stack.deleteListeningPoint((ListeningPoint) listener.next());
                    }
                    Iterator providers = stack.getSipProviders();
                    while (providers.hasNext()) {
                        stack.deleteSipProvider((SipProvider) providers.next());
                    }
                    VManageBootstrap.restart();
                } catch (InterruptedException ignored) {
                } catch (ObjectInUseException e) {
                    e.printStackTrace();
    public void restart() {
        taskExecutor.execute(()-> {
            try {
                Thread.sleep(3000);
                SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
                SipStackImpl stack = (SipStackImpl) up.getSipStack();
                stack.stop();
                Iterator listener = stack.getListeningPoints();
                while (listener.hasNext()) {
                    stack.deleteListeningPoint((ListeningPoint) listener.next());
                }
                Iterator providers = stack.getSipProviders();
                while (providers.hasNext()) {
                    stack.deleteSipProvider((SipProvider) providers.next());
                }
                VManageBootstrap.restart();
            } catch (InterruptedException | ObjectInUseException e) {
                throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
            }
        });
        restartThread.setDaemon(false);
        restartThread.start();
        return "success";
    }
    };
    @Operation(summary = "获取版本信息")
    @GetMapping(value = "/version")
    @ResponseBody
    public WVPResult<VersionPo> getVersion() {
        WVPResult<VersionPo> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        result.setData(versionInfo.getVersion());
        return result;
    public VersionPo VersionPogetVersion() {
        return versionInfo.getVersion();
    }
    @GetMapping(value = "/config")
    @Operation(summary = "获取配置信息")
    @Parameter(name = "type", description = "配置类型(sip, base)", required = true)
    @ResponseBody
    public WVPResult<JSONObject> getVersion(String type) {
        WVPResult<JSONObject> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
    public JSONObject getVersion(String type) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("server.port", serverPort);
        if (StringUtils.isEmpty(type)) {
        if (ObjectUtils.isEmpty(type)) {
            jsonObject.put("sip", JSON.toJSON(sipConfig));
            jsonObject.put("base", JSON.toJSON(userSetting));
        } else {
@@ -240,50 +196,13 @@
                    break;
            }
        }
        result.setData(jsonObject);
        return result;
        return jsonObject;
    }
    @GetMapping(value = "/hooks")
    @ResponseBody
    @Operation(summary = "获取当前所有hook")
    public WVPResult<List<IHookSubscribe>> getHooks() {
        WVPResult<List<IHookSubscribe>> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        List<IHookSubscribe> all = zlmHttpHookSubscribe.getAll();
        result.setData(all);
        return result;
    public List<IHookSubscribe> getHooks() {
        return zlmHttpHookSubscribe.getAll();
    }
//     //@ApiOperation("当前进行中的动态任务")
//    @GetMapping(value = "/dynamicTask")
//    @ResponseBody
//    public WVPResult<JSONObject> getDynamicTask(){
//        WVPResult<JSONObject> result = new WVPResult<>();
//        result.setCode(0);
//        result.setMsg("success");
//
//        JSONObject jsonObject = new JSONObject();
//
//        Set<String> allKeys = dynamicTask.getAllKeys();
//        jsonObject.put("server.port", serverPort);
//        if (StringUtils.isEmpty(type)) {
//            jsonObject.put("sip", JSON.toJSON(sipConfig));
//            jsonObject.put("base", JSON.toJSON(userSetting));
//        }else {
//            switch (type){
//                case "sip":
//                    jsonObject.put("sip", sipConfig);
//                    break;
//                case "base":
//                    jsonObject.put("base", userSetting);
//                    break;
//                default:
//                    break;
//            }
//        }
//        result.setData(jsonObject);
//        return result;
//    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
@@ -2,12 +2,14 @@
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.service.IStreamProxyService;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
import io.swagger.v3.oas.annotations.Operation;
@@ -18,6 +20,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@@ -32,10 +35,6 @@
public class StreamProxyController {
    private final static Logger logger = LoggerFactory.getLogger(StreamProxyController.class);
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
    @Autowired
    private IMediaServerService mediaServerService;
@@ -64,35 +63,32 @@
    })
    @PostMapping(value = "/save")
    @ResponseBody
    public WVPResult save(@RequestBody StreamProxyItem param){
    public StreamInfo save(@RequestBody StreamProxyItem param){
        logger.info("添加代理: " + JSONObject.toJSONString(param));
        if (StringUtils.isEmpty(param.getMediaServerId())) {
        if (ObjectUtils.isEmpty(param.getMediaServerId())) {
            param.setMediaServerId("auto");
        }
        if (StringUtils.isEmpty(param.getType())) {
        if (ObjectUtils.isEmpty(param.getType())) {
            param.setType("default");
        }
        if (StringUtils.isEmpty(param.getGbId())) {
        if (ObjectUtils.isEmpty(param.getGbId())) {
            param.setGbId(null);
        }
        WVPResult<StreamInfo> result = streamProxyService.save(param);
        return result;
        return streamProxyService.save(param);
    }
    @GetMapping(value = "/ffmpeg_cmd/list")
    @ResponseBody
    @Operation(summary = "获取ffmpeg.cmd模板")
    @Parameter(name = "mediaServerId", description = "流媒体ID", required = true)
    public WVPResult getFFmpegCMDs(@RequestParam String mediaServerId){
    public JSONObject getFFmpegCMDs(@RequestParam String mediaServerId){
        logger.debug("获取节点[ {} ]ffmpeg.cmd模板", mediaServerId );
        MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
        JSONObject data = streamProxyService.getFFmpegCMDs(mediaServerItem);
        WVPResult<JSONObject> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        result.setData(data);
        return result;
        if (mediaServerItem == null) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "流媒体: " + mediaServerId + "未找到");
        }
        return streamProxyService.getFFmpegCMDs(mediaServerItem);
    }
    @DeleteMapping(value = "/del")
@@ -100,18 +96,13 @@
    @Operation(summary = "移除代理")
    @Parameter(name = "app", description = "应用名", required = true)
    @Parameter(name = "stream", description = "流id", required = true)
    public WVPResult del(@RequestParam String app, @RequestParam String stream){
    public void del(@RequestParam String app, @RequestParam String stream){
        logger.info("移除代理: " + app + "/" + stream);
        WVPResult<Object> result = new WVPResult<>();
        if (app == null || stream == null) {
            result.setCode(400);
            result.setMsg(app == null ?"app不能为null":"stream不能为null");
            throw new ControllerException(ErrorCode.ERROR400.getCode(), app == null ?"app不能为null":"stream不能为null");
        }else {
            streamProxyService.del(app, stream);
            result.setCode(0);
            result.setMsg("success");
        }
        return result;
    }
    @GetMapping(value = "/start")
@@ -119,13 +110,13 @@
    @Operation(summary = "启用代理")
    @Parameter(name = "app", description = "应用名", required = true)
    @Parameter(name = "stream", description = "流id", required = true)
    public Object start(String app, String stream){
    public void start(String app, String stream){
        logger.info("启用代理: " + app + "/" + stream);
        boolean result = streamProxyService.start(app, stream);
        if (!result) {
            logger.info("启用代理失败: " + app + "/" + stream);
            throw new ControllerException(ErrorCode.ERROR100);
        }
        return result?"success":"fail";
    }
    @GetMapping(value = "/stop")
@@ -133,9 +124,12 @@
    @Operation(summary = "停用代理")
    @Parameter(name = "app", description = "应用名", required = true)
    @Parameter(name = "stream", description = "流id", required = true)
    public Object stop(String app, String stream){
    public void stop(String app, String stream){
        logger.info("停用代理: " + app + "/" + stream);
        boolean result = streamProxyService.stop(app, stream);
        return result?"success":"fail";
        if (!result) {
            logger.info("停用代理失败: " + app + "/" + stream);
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
@@ -31,6 +31,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
@@ -81,10 +82,10 @@
                                         @RequestParam(required = false)Boolean pushing,
                                         @RequestParam(required = false)String mediaServerId ){
        if (StringUtils.isEmpty(query)) {
        if (ObjectUtils.isEmpty(query)) {
            query = null;
        }
        if (StringUtils.isEmpty(mediaServerId)) {
        if (ObjectUtils.isEmpty(mediaServerId)) {
            mediaServerId = null;
        }
        PageInfo<StreamPushItem> pushList = streamPushService.getPushList(page, count, query, pushing, mediaServerId);
@@ -285,11 +286,11 @@
    @ResponseBody
    @Operation(summary = "停止视频回放")
    public WVPResult<StreamInfo> add(@RequestBody StreamPushItem stream){
        if (StringUtils.isEmpty(stream.getGbId())) {
        if (ObjectUtils.isEmpty(stream.getGbId())) {
            return new WVPResult<>(400, "国标ID不可为空", null);
        }
        if (StringUtils.isEmpty(stream.getApp()) && StringUtils.isEmpty(stream.getStream())) {
        if (ObjectUtils.isEmpty(stream.getApp()) && ObjectUtils.isEmpty(stream.getStream())) {
            return new WVPResult<>(400, "app或stream不可为空", null);
        }
        stream.setStatus(false);
src/main/java/com/genersoft/iot/vmp/vmanager/user/RoleController.java
@@ -1,9 +1,11 @@
package com.genersoft.iot.vmp.vmanager.user;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.service.IRoleService;
import com.genersoft.iot.vmp.storager.dao.dto.Role;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
@@ -29,16 +31,13 @@
    @Operation(summary = "添加角色")
    @Parameter(name = "name", description = "角色名", required = true)
    @Parameter(name = "authority", description = "权限(自行定义内容,目前未使用)", required = true)
    public ResponseEntity<WVPResult<Integer>> add(@RequestParam String name,
    public void add(@RequestParam String name,
                                                  @RequestParam(required = false) String authority){
        WVPResult<Integer> result = new WVPResult<>();
        // 获取当前登录用户id
        int currenRoleId = SecurityUtils.getUserInfo().getRole().getId();
        if (currenRoleId != 1) {
            // 只用角色id为1才可以删除和添加用户
            result.setCode(-1);
            result.setMsg("用户无权限");
            return new ResponseEntity<>(result, HttpStatus.FORBIDDEN);
            throw new ControllerException(ErrorCode.ERROR403);
        }
        Role role = new Role();
@@ -48,42 +47,33 @@
        role.setUpdateTime(DateUtil.getNow());
        int addResult = roleService.add(role);
        result.setCode(addResult > 0 ? 0 : -1);
        result.setMsg(addResult > 0 ? "success" : "fail");
        result.setData(addResult);
        return new ResponseEntity<>(result, HttpStatus.OK);
        if (addResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除角色")
    @Parameter(name = "id", description = "用户Id", required = true)
    public ResponseEntity<WVPResult<String>> delete(@RequestParam Integer id){
    public void delete(@RequestParam Integer id){
        // 获取当前登录用户id
        int currenRoleId = SecurityUtils.getUserInfo().getRole().getId();
        WVPResult<String> result = new WVPResult<>();
        if (currenRoleId != 1) {
            // 只用角色id为0才可以删除和添加用户
            result.setCode(-1);
            result.setMsg("用户无权限");
            return new ResponseEntity<>(result, HttpStatus.FORBIDDEN);
            throw new ControllerException(ErrorCode.ERROR403);
        }
        int deleteResult = roleService.delete(id);
        result.setCode(deleteResult>0? 0 : -1);
        result.setMsg(deleteResult>0? "success" : "fail");
        return new ResponseEntity<>(result, HttpStatus.OK);
        if (deleteResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    @GetMapping("/all")
    @Operation(summary = "查询角色")
    public ResponseEntity<WVPResult<List<Role>>> all(){
    public List<Role> all(){
        // 获取当前登录用户id
        List<Role> allRoles = roleService.getAll();
        WVPResult<List<Role>> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        result.setData(allRoles);
        return new ResponseEntity<>(result, HttpStatus.OK);
        return roleService.getAll();
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
@@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.vmanager.user;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.service.IRoleService;
@@ -7,6 +8,7 @@
import com.genersoft.iot.vmp.storager.dao.dto.Role;
import com.genersoft.iot.vmp.storager.dao.dto.User;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
@@ -18,6 +20,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
@@ -43,25 +46,17 @@
    @Operation(summary = "登录")
    @Parameter(name = "username", description = "用户名", required = true)
    @Parameter(name = "password", description = "密码(32位md5加密)", required = true)
    public WVPResult<LoginUser> login(@RequestParam String username, @RequestParam String password){
    public LoginUser login(@RequestParam String username, @RequestParam String password){
        LoginUser user = null;
        WVPResult<LoginUser> result = new WVPResult<>();
        try {
            user = SecurityUtils.login(username, password, authenticationManager);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            result.setCode(-1);
            result.setMsg("fail");
            throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
        }
        if (user != null) {
            result.setCode(0);
            result.setMsg("success");
            result.setData(user);
        }else {
            result.setCode(-1);
            result.setMsg("fail");
        if (user == null) {
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误");
        }
        return result;
        return user;
    }
    @PostMapping("/changePassword")
@@ -69,27 +64,27 @@
    @Parameter(name = "username", description = "用户名", required = true)
    @Parameter(name = "oldpassword", description = "旧密码(已md5加密的密码)", required = true)
    @Parameter(name = "password", description = "新密码(未md5加密的密码)", required = true)
    public String changePassword(@RequestParam String oldPassword, @RequestParam String password){
    public void changePassword(@RequestParam String oldPassword, @RequestParam String password){
        // 获取当前登录用户id
        LoginUser userInfo = SecurityUtils.getUserInfo();
        if (userInfo== null) {
            return "fail";
            throw new ControllerException(ErrorCode.ERROR100);
        }
        String username = userInfo.getUsername();
        LoginUser user = null;
        try {
            user = SecurityUtils.login(username, oldPassword, authenticationManager);
            if (user != null) {
                int userId = SecurityUtils.getUserId();
                boolean result = userService.changePassword(userId, DigestUtils.md5DigestAsHex(password.getBytes()));
                if (result) {
                    return "success";
                }
            if (user == null) {
                throw new ControllerException(ErrorCode.ERROR100);
            }
            int userId = SecurityUtils.getUserId();
            boolean result = userService.changePassword(userId, DigestUtils.md5DigestAsHex(password.getBytes()));
            if (!result) {
                throw new ControllerException(ErrorCode.ERROR100);
            }
        } catch (AuthenticationException e) {
            e.printStackTrace();
            throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
        }
        return "fail";
    }
@@ -98,22 +93,17 @@
    @Parameter(name = "username", description = "用户名", required = true)
    @Parameter(name = "password", description = "密码(未md5加密的密码)", required = true)
    @Parameter(name = "roleId", description = "角色ID", required = true)
    public ResponseEntity<WVPResult<Integer>> add(@RequestParam String username,
    public void add(@RequestParam String username,
                                                 @RequestParam String password,
                                                 @RequestParam Integer roleId){
        WVPResult<Integer> result = new WVPResult<>();
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password) || roleId == null) {
            result.setCode(-1);
            result.setMsg("参数不可为空");
            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
        if (ObjectUtils.isEmpty(username) || ObjectUtils.isEmpty(password) || roleId == null) {
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "参数不可为空");
        }
        // 获取当前登录用户id
        int currenRoleId = SecurityUtils.getUserInfo().getRole().getId();
        if (currenRoleId != 1) {
            // 只用角色id为1才可以删除和添加用户
            result.setCode(-1);
            result.setMsg("用户无权限");
            return new ResponseEntity<>(result, HttpStatus.FORBIDDEN);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "用户无权限");
        }
        User user = new User();
        user.setUsername(username);
@@ -123,53 +113,38 @@
        Role role = roleService.getRoleById(roleId);
        if (role == null) {
            result.setCode(-1);
            result.setMsg("roleId is not found");
            // 角色不存在
            return new ResponseEntity<>(result, HttpStatus.OK);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "角色不存在");
        }
        user.setRole(role);
        user.setCreateTime(DateUtil.getNow());
        user.setUpdateTime(DateUtil.getNow());
        int addResult = userService.addUser(user);
        result.setCode(addResult > 0 ? 0 : -1);
        result.setMsg(addResult > 0 ? "success" : "fail");
        result.setData(addResult);
        return new ResponseEntity<>(result, HttpStatus.OK);
        if (addResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    @DeleteMapping("/删除用户")
    @Operation(summary = "停止视频回放")
    @Parameter(name = "id", description = "用户Id", required = true)
    public ResponseEntity<WVPResult<String>> delete(@RequestParam Integer id){
    public void delete(@RequestParam Integer id){
        // 获取当前登录用户id
        int currenRoleId = SecurityUtils.getUserInfo().getRole().getId();
        WVPResult<String> result = new WVPResult<>();
        if (currenRoleId != 1) {
            // 只用角色id为0才可以删除和添加用户
            result.setCode(-1);
            result.setMsg("用户无权限");
            return new ResponseEntity<>(result, HttpStatus.FORBIDDEN);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "用户无权限");
        }
        int deleteResult = userService.deleteUser(id);
        result.setCode(deleteResult>0? 0 : -1);
        result.setMsg(deleteResult>0? "success" : "fail");
        return new ResponseEntity<>(result, HttpStatus.OK);
        if (deleteResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    @GetMapping("/all")
    @Operation(summary = "查询用户")
    public ResponseEntity<WVPResult<List<User>>> all(){
    public List<User> all(){
        // 获取当前登录用户id
        List<User> allUsers = userService.getAllUsers();
        WVPResult<List<User>> result = new WVPResult<>();
        result.setCode(0);
        result.setMsg("success");
        result.setData(allUsers);
        return new ResponseEntity<>(result, HttpStatus.OK);
        return userService.getAllUsers();
    }
    /**
@@ -191,21 +166,18 @@
    @Operation(summary = "修改pushkey")
    @Parameter(name = "userId", description = "用户Id", required = true)
    @Parameter(name = "pushKey", description = "新的pushKey", required = true)
    public ResponseEntity<WVPResult<String>> changePushKey(@RequestParam Integer userId,@RequestParam String pushKey) {
    public void changePushKey(@RequestParam Integer userId,@RequestParam String pushKey) {
        // 获取当前登录用户id
        int currenRoleId = SecurityUtils.getUserInfo().getRole().getId();
        WVPResult<String> result = new WVPResult<>();
        if (currenRoleId != 1) {
            // 只用角色id为0才可以删除和添加用户
            result.setCode(-1);
            result.setMsg("用户无权限");
            return new ResponseEntity<>(result, HttpStatus.FORBIDDEN);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "用户无权限");
        }
        int resetPushKeyResult = userService.changePushKey(userId,pushKey);
        result.setCode(resetPushKeyResult > 0 ? 0 : -1);
        result.setMsg(resetPushKeyResult > 0 ? "success" : "fail");
        return new ResponseEntity<>(result, HttpStatus.OK);
        if (resetPushKeyResult <= 0) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    @PostMapping("/changePasswordForAdmin")
@@ -213,20 +185,18 @@
    @Parameter(name = "adminId", description = "管理员id", required = true)
    @Parameter(name = "userId", description = "用户id", required = true)
    @Parameter(name = "password", description = "新密码(未md5加密的密码)", required = true)
    public String changePasswordForAdmin(@RequestParam int userId, @RequestParam String password) {
    public void changePasswordForAdmin(@RequestParam int userId, @RequestParam String password) {
        // 获取当前登录用户id
        LoginUser userInfo = SecurityUtils.getUserInfo();
        if (userInfo == null) {
            return "fail";
            throw new ControllerException(ErrorCode.ERROR100);
        }
        Role role = userInfo.getRole();
        if (role != null && role.getId() == 1) {
            boolean result = userService.changePassword(userId, DigestUtils.md5DigestAsHex(password.getBytes()));
            if (result) {
                return "success";
            if (!result) {
                throw new ControllerException(ErrorCode.ERROR100);
            }
        }
        return "fail";
    }
}
web_src/package-lock.json
Diff too large
web_src/src/components/CloudRecord.vue
@@ -125,8 +125,10 @@
          }
        }).then(function (res) {
          console.log(res)
          that.total = res.data.data.total;
          that.recordList = res.data.data.list;
          if (res.data.code === 0) {
            that.total = res.data.data.total;
            that.recordList = res.data.data.list;
          }
          that.loading = false;
        }).catch(function (error) {
          console.log(error);
@@ -174,8 +176,10 @@
          }
        }).then(function (res) {
          console.log(res)
          that.total = res.data.data.total;
          that.recordList = res.data.data.list;
          if (res.data.code === 0) {
            that.total = res.data.data.total;
            that.recordList = res.data.data.list;
          }
        }).catch(function (error) {
          console.log(error);
        });
web_src/src/components/CloudRecordDetail.vue
@@ -250,8 +250,10 @@
            count: that.count
          }
        }).then(function (res) {
          that.total = res.data.data.total;
          that.detailFiles = that.detailFiles.concat(res.data.data.list);
          if (res.data.code === 0) {
            that.total = res.data.data.total;
            that.detailFiles = that.detailFiles.concat(res.data.data.list);
          }
          that.loading = false;
          if (callback) callback();
        }).catch(function (error) {
@@ -320,7 +322,7 @@
            count: that.count
          }
        }).then(function (res) {
          if (res.data.code == 0) {
          if (res.data.code === 0) {
            that.total = res.data.data.total;
            that.recordList = res.data.data.list;
          }
web_src/src/components/DeviceList.vue
@@ -146,22 +146,23 @@
      this.getDeviceList();
    },
    getDeviceList: function () {
      let that = this;
      this.getDeviceListLoading = true;
      this.$axios({
        method: 'get',
        url: `/api/device/query/devices`,
        params: {
          page: that.currentPage,
          count: that.count
          page: this.currentPage,
          count: this.count
        }
      }).then(function (res) {
        that.total = res.data.total;
        that.deviceList = res.data.list;
        that.getDeviceListLoading = false;
      }).catch(function (error) {
      }).then( (res)=> {
        if (res.data.code === 0) {
          this.total = res.data.data.total;
          this.deviceList = res.data.data.list;
        }
        this.getDeviceListLoading = false;
      }).catch( (error)=> {
        console.error(error);
        that.getDeviceListLoading = false;
        this.getDeviceListLoading = false;
      });
    },
web_src/src/components/Login.vue
@@ -85,7 +85,7 @@
        params: loginParam
      }).then(function (res) {
        console.log(JSON.stringify(res));
          if (res.data.code == 0 && res.data.msg == "success") {
          if (res.data.code === 0 ) {
            that.$cookies.set("session", {"username": that.username,"roleId":res.data.data.role.id}) ;
            //登录成功后
            that.cancelEnterkeyDefaultAction();
web_src/src/components/ParentPlatformList.vue
@@ -130,7 +130,7 @@
        method: 'delete',
        url:`/api/platform/delete/${platform.serverGBId}`
        }).then(function (res) {
            if (res.data == "success") {
            if (res.data.code === 0) {
                that.$message({
                    showClose: true,
                    message: '删除成功',
@@ -163,8 +163,11 @@
          method: 'get',
        url:`/api/platform/query/${that.count}/${that.currentPage}`
      }).then(function (res) {
        that.total = res.data.total;
        that.platformList = res.data.list;
        if (res.data.code === 0) {
          that.total = res.data.data.total;
          that.platformList = res.data.data.list;
        }
      }).catch(function (error) {
        console.log(error);
      });
web_src/src/components/PushVideoList.vue
@@ -180,8 +180,11 @@
          mediaServerId: that.mediaServerId,
        }
      }).then(function (res) {
        that.total = res.data.total;
        that.pushList = res.data.list;
          if (res.data.code === 0) {
            that.total = res.data.data.total;
            that.pushList = res.data.data.list;
          }
        that.getDeviceListLoading = false;
      }).catch(function (error) {
        console.error(error);
web_src/src/components/channelList.vue
@@ -215,12 +215,15 @@
          channelType: that.channelType
        }
      }).then(function (res) {
        that.total = res.data.total;
        that.deviceChannelList = res.data.list;
        // 防止出现表格错位
        that.$nextTick(() => {
          that.$refs.channelListTable.doLayout();
        })
        if (res.data.code === 0) {
          that.total = res.data.data.total;
          that.deviceChannelList = res.data.data.list;
          // 防止出现表格错位
          that.$nextTick(() => {
            that.$refs.channelListTable.doLayout();
          })
        }
      }).catch(function (error) {
        console.log(error);
      });
web_src/src/components/dialog/chooseChannelForGb.vue
@@ -243,15 +243,16 @@
                    }
                })
                .then(function (res) {
                    that.total = res.data.total;
                    that.gbChannels = res.data.list;
                  if (res.data.code === 0 ) {
                    that.total = res.data.data.total;
                    that.gbChannels = res.data.data.list;
                    that.gbChoosechannel = {};
                    // 防止出现表格错位
                    that.$nextTick(() => {
                        that.$refs.gbChannelsTable.doLayout();
                        that.eventEnable = true;
                    })
                    console.log(that.gbChoosechannel)
                  }
                  // 防止出现表格错位
                  that.$nextTick(() => {
                      that.$refs.gbChannelsTable.doLayout();
                      that.eventEnable = true;
                  })
                })
                .catch(function (error) {
                    console.log(error);
web_src/src/components/dialog/devicePlayer.vue
@@ -605,13 +605,15 @@
                    url: '/api/playback/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' +
                        row.endTime
                }).then(function (res) {
                    that.streamInfo = res.data;
                  if (res.data.code === 0) {
                    that.streamInfo = res.data.data;
                    that.app = that.streamInfo.app;
                    that.streamId = that.streamInfo.stream;
                    that.mediaServerId = that.streamInfo.mediaServerId;
                    that.ssrc = that.streamInfo.ssrc;
                    that.videoUrl = that.getUrlByStreamInfo();
                    that.recordPlay = true;
                  }
                  that.recordPlay = true;
                });
            }
        },
web_src/src/components/dialog/platformEdit.vue
@@ -194,13 +194,16 @@
          url:`/api/platform/server_config`
        }).then(function (res) {
          console.log(res);
          that.platform.deviceGBId = res.data.username;
          that.platform.deviceIp = res.data.deviceIp;
          that.platform.devicePort = res.data.devicePort;
          that.platform.username = res.data.username;
          that.platform.password = res.data.password;
          that.platform.treeType = "BusinessGroup";
          that.platform.administrativeDivision = res.data.username.substr(0, 6);
          if (res.data.code === 0) {
            that.platform.deviceGBId = res.data.data.username;
            that.platform.deviceIp = res.data.data.deviceIp;
            that.platform.devicePort = res.data.data.devicePort;
            that.platform.username = res.data.data.username;
            that.platform.password = res.data.data.password;
            that.platform.treeType = "BusinessGroup";
            that.platform.administrativeDivision = res.data.data.username.substr(0, 6);
          }
        }).catch(function (error) {
          console.log(error);
        });
@@ -328,7 +331,9 @@
                method: 'post',
                url:`/api/platform/exit/${deviceGbId}`})
        .then(function (res) {
          result = res.data;
            if (res.data.code === 0) {
              result = res.data.data;
            }
        })
        .catch(function (error) {
          console.log(error);
web_src/src/components/live.vue
@@ -140,7 +140,7 @@
        // that.isLoging = false;
        console.log('=====----=====')
        console.log(res)
        if (res.data.code == 0 && res.data.data) {
        if (res.data.code === 0 && res.data.data) {
          itemData.playUrl = res.data.data.httpsFlv
          that.setPlayUrl(res.data.data.ws_flv, idxTmp)
        } else {