648540858
2022-08-26 9f680a2e9e8560cf5f38acdc30335e51d88b2001
修复bug以及日志按照,错误/sip/数据库 分割
24个文件已修改
1个文件已添加
300 ■■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/UrlTokenHandler.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/RedisAlarmMsgListener.java 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGbPlayMsgListener.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/logback-spring-local.xml 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/devicePlayer.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/platformEdit.vue 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -31,6 +31,8 @@
    private String rtsp;
    private String rtsps;
    private String rtc;
    private String rtcs;
    private String mediaServerId;
    private Object tracks;
    private String startTime;
@@ -302,4 +304,12 @@
    public void setIp(String ip) {
        this.ip = ip;
    }
    public String getRtcs() {
        return rtcs;
    }
    public void setRtcs(String rtcs) {
        this.rtcs = rtcs;
    }
}
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
@@ -1,6 +1,8 @@
package com.genersoft.iot.vmp.conf.security;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import org.apache.poi.hssf.eventmodel.ERFListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
@@ -28,8 +30,8 @@
        response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "-1");
        jsonObject.put("msg", "请登录后重新请求");
        jsonObject.put("code", ErrorCode.ERROR401.getCode());
        jsonObject.put("msg", ErrorCode.ERROR401.getMsg());
        String logUri = "api/user/login";
        if (request.getRequestURI().contains(logUri)){
            jsonObject.put("msg", e.getMessage());
src/main/java/com/genersoft/iot/vmp/conf/security/UrlTokenHandler.java
New file
@@ -0,0 +1,24 @@
package com.genersoft.iot.vmp.conf.security;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import java.util.Collections;
public class UrlTokenHandler extends SpringBootServletInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        servletContext.setSessionTrackingModes(
                Collections.singleton(SessionTrackingMode.COOKIE)
        );
        SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig();
        sessionCookieConfig.setHttpOnly(true);
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -2,8 +2,10 @@
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver;
import com.genersoft.iot.vmp.utils.DateUtil;
import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -13,6 +15,7 @@
import org.springframework.stereotype.Component;
import javax.sip.*;
import java.text.DateFormat;
import java.util.Properties;
import java.util.TooManyListenersException;
import java.util.concurrent.LinkedBlockingQueue;
@@ -52,7 +55,9 @@
         * 完整配置参考 gov.nist.javax.sip.SipStackImpl,需要下载源码
         * gov/nist/javax/sip/SipStackImpl.class
         */
        properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "true");
        if (logger.isDebugEnabled()) {
            properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "true");
        }
        // 接收所有notify请求,即使没有订阅
        properties.setProperty("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "true");
        // 为_NULL _对话框传递_终止的_事件
@@ -67,9 +72,10 @@
         * 0; public static final int TRACE_MESSAGES = 16; public static final int
         * TRACE_EXCEPTION = 17; public static final int TRACE_DEBUG = 32;
         */
        properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "0");
        properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sip_server_log");
        properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sip_debug_log");
        if (logger.isDebugEnabled()) {
            properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "DEBUG");
        }
        properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "INFO");
        sipStack = (SipStackImpl) sipFactory.createSipStack(properties);
        return sipStack;
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
@@ -71,7 +71,6 @@
    @Override
    @Async
    public void processRequest(RequestEvent requestEvent) {
        logger.debug("\n收到请求:\n{}", requestEvent.getRequest());
        String method = requestEvent.getRequest().getMethod();
        ISIPRequestProcessor sipRequestProcessor = requestProcessorMap.get(method);
        if (sipRequestProcessor == null) {
@@ -90,7 +89,6 @@
    @Async
    public void processResponse(ResponseEvent responseEvent) {
        Response response = responseEvent.getResponse();
        logger.debug("\n收到响应:\n{}", responseEvent.getResponse());
        int status = response.getStatusCode();
        if (((status >= 200) && (status < 300)) || status == Response.UNAUTHORIZED) { // Success!
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -640,7 +640,7 @@
                        hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
                        subscribe.removeSubscribe(hookSubscribe);
                        hookSubscribe.getContent().put("regist", false);
                        hookSubscribe.getContent().put("schema", "rtmp");
                        hookSubscribe.getContent().put("schema", "rtsp");
                        // 添加流注销的订阅,注销了后向设备发送bye
                        subscribe.addSubscribe(hookSubscribe,
                                (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -410,6 +410,7 @@
                                streamId = String.format("%s_%s", device.getDeviceId(), channelId);
                            }
                            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false);
                            logger.info(JSONObject.toJSONString(ssrcInfo));
                            sendRtpItem.setStreamId(ssrcInfo.getStream());
                            // 写入redis, 超时时回复
                            redisCatchStorage.updateSendRTPSever(sendRtpItem);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
@@ -180,7 +180,6 @@
    private void processNotifyCatalogList(RequestEvent evt, Element rootElement) throws SipException {
        System.out.println(evt.getRequest().toString());
        String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
        String deviceId = XmlUtil.getText(rootElement, "DeviceID");
        ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
@@ -164,7 +164,7 @@
            }
        }
        if (channelId.equals(sipConfig.getId())) {
        if ("7".equals(deviceAlarm.getAlarmMethod()) ) {
            // 发送给平台的报警信息。 发送redis通知
            AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage();
            alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod()));
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -7,12 +7,10 @@
import com.alibaba.fastjson.JSON;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.media.zlm.dto.*;
import com.genersoft.iot.vmp.service.*;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
@@ -48,6 +46,9 @@
    @Autowired
    private SIPCommander cmder;
    @Autowired
    private SIPCommanderFroPlatform commanderFroPlatform;
    @Autowired
    private IPlayService playService;
@@ -237,7 +238,7 @@
            // 鉴权通过
            redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
            // 通知assist新的callId
            if (mediaInfo != null) {
            if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) {
                assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null);
            }
        }else {
@@ -427,7 +428,7 @@
        }else {
            redisCatchStorage.removeStreamAuthorityInfo(app, stream);
        }
        if ("rtmp".equals(schema)){
        if ("rtsp".equals(schema)){
            logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", regist, app, stream);
            if (regist) {
                mediaServerService.addCount(mediaServerId);
@@ -523,17 +524,21 @@
        if ("rtp".equals(app)){
            ret.put("close", true);
            StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId);
            SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, null, streamId);
            if (streamInfoForPlayCatch != null) {
                // 如果在给上级推流,也不停止。
                // 收到无人观看说明流也没有在往上级推送
                if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {
                    ret.put("close", false);
                } else {
                    cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(),
                            streamInfoForPlayCatch.getStream(), null);
                    redisCatchStorage.stopPlay(streamInfoForPlayCatch);
                    storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
                    List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(streamInfoForPlayCatch.getChannelId());
                    if (sendRtpItems.size() > 0) {
                        for (SendRtpItem sendRtpItem : sendRtpItems) {
                            ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
                            commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
                        }
                    }
                }
                cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(),
                        streamInfoForPlayCatch.getStream(), null);
                redisCatchStorage.stopPlay(streamInfoForPlayCatch);
                storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
            }else{
                StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null);
                if (streamInfoForPlayBackCatch != null) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -92,6 +92,7 @@
        int result = -1;
        // 查询此rtp server 是否已经存在
        JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
        logger.info(JSONObject.toJSONString(rtpInfo));
        if(rtpInfo.getInteger("code") == 0){
            if (rtpInfo.getBoolean("exist")) {
                result = rtpInfo.getInteger("local_port");
@@ -113,7 +114,7 @@
        }
        param.put("ssrc", ssrc);
        JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
        logger.info(JSONObject.toJSONString(openRtpServerResultJson));
        if (openRtpServerResultJson != null) {
            if (openRtpServerResultJson.getInteger("code") == 0) {
                result= openRtpServerResultJson.getInteger("port");
@@ -270,7 +271,7 @@
     * 查询待转推的流是否就绪
     */
    public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtmp", streamId);
        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtsp", streamId);
        return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
    }
@@ -290,7 +291,7 @@
     * @return
     */
    public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) {
        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
        JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", streamId);
        if (mediaInfo == null) {
            return 0;
        }
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -417,7 +417,7 @@
        if (RedisUtil.zScore(key, serverItem.getId()) == null) {  // 不存在则设置默认值 已存在则重置
            RedisUtil.zAdd(key, serverItem.getId(), 0L);
            // 查询服务流数量
            zlmresTfulUtils.getMediaList(serverItem, null, null, "rtmp",(mediaList ->{
            zlmresTfulUtils.getMediaList(serverItem, null, null, "rtsp",(mediaList ->{
                Integer code = mediaList.getInteger("code");
                if (code == 0) {
                    JSONArray data = mediaList.getJSONArray("data");
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -112,6 +112,7 @@
        streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/%s/%s.live.mp4%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setTs(String.format("http://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setWs_ts(String.format("ws://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpPort(), app,  stream, callIdParam));
        streamInfoResult.setRtc(String.format("http://%s:%s/index/api/webrtc?app=%s&stream=%s&type=play%s", mediaInfo.getStreamIp(), mediaInfo.getHttpPort(), app,  stream, ObjectUtils.isEmpty(callId)?"":"&callId=" + callId));
        if (mediaInfo.getHttpSSlPort() != 0) {
            streamInfoResult.setHttps_flv(String.format("https://%s:%s/%s/%s.live.flv%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
            streamInfoResult.setWss_flv(String.format("wss://%s:%s/%s/%s.live.flv%s", addr, mediaInfo.getHttpSSlPort(), app,  stream, callIdParam));
@@ -122,7 +123,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, ObjectUtils.isEmpty(callId)?"":"&callId=" + callId));
            streamInfoResult.setRtcs(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
@@ -195,6 +195,7 @@
                streamId = String.format("%s_%s", device.getDeviceId(), channelId);
            }
            SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);
            logger.info(JSONObject.toJSONString(ssrcInfo));
            play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{
                if (hookEvent != null) {
                    hookEvent.response(mediaServerItem, response);
@@ -306,7 +307,7 @@
                    // 单端口模式streamId也有变化,需要重新设置监听
                    if (!mediaServerItem.isRtpEnable()) {
                        // 添加订阅
                        HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtmp", mediaServerItem.getId());
                        HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
                        subscribe.removeSubscribe(hookSubscribe);
                        hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
                        subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{
src/main/java/com/genersoft/iot/vmp/service/impl/RedisAlarmMsgListener.java
@@ -4,6 +4,8 @@
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.service.IPlatformChannelService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
import com.genersoft.iot.vmp.utils.DateUtil;
import org.slf4j.Logger;
@@ -12,6 +14,9 @@
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.util.List;
@Component
@@ -37,8 +42,6 @@
            return;
        }
        String gbId = alarmChannelMessage.getGbId();
        Device device = storage.queryVideoDevice(gbId);
        ParentPlatform platform = storage.queryParentPlatByServerGBId(gbId);
        DeviceAlarm deviceAlarm = new DeviceAlarm();
        deviceAlarm.setCreateTime(DateUtil.getNow());
@@ -46,18 +49,29 @@
        deviceAlarm.setAlarmDescription(alarmChannelMessage.getAlarmDescription());
        deviceAlarm.setAlarmMethod("" + alarmChannelMessage.getAlarmSn());
        deviceAlarm.setAlarmPriority("1");
        deviceAlarm.setAlarmTime(DateUtil.getNow());
        deviceAlarm.setAlarmTime(DateUtil.getNowForISO8601());
        deviceAlarm.setAlarmType("1");
        deviceAlarm.setLongitude(0);
        deviceAlarm.setLatitude(0);
        if (device != null && platform == null) {
            commander.sendAlarmMessage(device, deviceAlarm);
        }else if (device == null && platform != null){
            commanderForPlatform.sendAlarmMessage(platform, deviceAlarm);
        if (ObjectUtils.isEmpty(gbId)) {
            // 发送给所有的上级
            List<ParentPlatform> parentPlatforms = storage.queryEnableParentPlatformList(true);
            if (parentPlatforms.size() > 0) {
                for (ParentPlatform parentPlatform : parentPlatforms) {
                    commanderForPlatform.sendAlarmMessage(parentPlatform, deviceAlarm);
                }
            }
        }else {
           logger.warn("无法确定" + gbId + "是平台还是设备");
            Device device = storage.queryVideoDevice(gbId);
            ParentPlatform platform = storage.queryParentPlatByServerGBId(gbId);
            if (device != null && platform == null) {
                commander.sendAlarmMessage(device, deviceAlarm);
            }else if (device == null && platform != null){
                commanderForPlatform.sendAlarmMessage(platform, deviceAlarm);
            }else {
                logger.warn("无法确定" + gbId + "是平台还是设备");
            }
        }
    }
}
src/main/java/com/genersoft/iot/vmp/service/impl/RedisGbPlayMsgListener.java
@@ -271,7 +271,7 @@
            }, userSetting.getPlatformPlayTimeout());
            // 添加订阅
            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtmp", mediaServerItem.getId());
            HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtsp", mediaServerItem.getId());
            subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
                        dynamicTask.stop(taskKey);
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -301,7 +301,6 @@
            if (jsonObject == null) {
                return false;
            }
            System.out.println(jsonObject);
            if (jsonObject.getInteger("code") == 0) {
                result = true;
                streamProxy.setEnable(true);
@@ -427,7 +426,7 @@
                        if(data != null && data.size() > 0) {
                            for (int i = 0; i < data.size(); i++) {
                                JSONObject streamJSONObj = data.getJSONObject(i);
                                if ("rtmp".equals(streamJSONObj.getString("schema"))) {
                                if ("rtsp".equals(streamJSONObj.getString("schema"))) {
                                    StreamInfo streamInfo = new StreamInfo();
                                    String app = streamJSONObj.getString("app");
                                    String stream = streamJSONObj.getString("stream");
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -237,4 +237,6 @@
     * 发送redis消息 查询所有推流设备的状态
     */
    void sendStreamPushRequestedMsgForStatus();
    List<SendRtpItem> querySendRTPServerByChnnelId(String channelId);
}
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -380,6 +380,24 @@
    }
    @Override
    public List<SendRtpItem> querySendRTPServerByChnnelId(String channelId) {
        if (channelId == null) {
            return null;
        }
        String platformGbId = "*";
        String callId = "*";
        String streamId = "*";
        String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + userSetting.getServerId() + "_" + platformGbId
                + "_" + channelId + "_" + streamId + "_" + callId;
        List<Object> scan = RedisUtil.scan(key);
        List<SendRtpItem> result = new ArrayList<>();
        for (Object o : scan) {
            result.add((SendRtpItem) RedisUtil.get((String) o));
        }
        return result;
    }
    @Override
    public List<SendRtpItem> querySendRTPServer(String platformGbId) {
        if (platformGbId == null) {
            platformGbId = "*";
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
@@ -82,4 +82,9 @@
            return false;
        }
    }
    public static String getNowForISO8601() {
        LocalDateTime nowDateTime = LocalDateTime.now();
        return formatterISO8601.format(nowDateTime);
    }
}
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
@@ -197,7 +197,7 @@
    @Operation(summary = "保存上级平台信息")
    @PostMapping("/save")
    @ResponseBody
    public String savePlatform(@RequestBody ParentPlatform parentPlatform) {
    public void savePlatform(@RequestBody ParentPlatform parentPlatform) {
        if (logger.isDebugEnabled()) {
            logger.debug("保存上级平台信息API调用");
@@ -247,7 +247,6 @@
                // 停止订阅相关的定时任务
                subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
            }
            return null;
        } else {
            throw new ControllerException(ErrorCode.ERROR100.getCode(),"写入数据库失败");
        }
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java
@@ -5,6 +5,7 @@
import com.alibaba.excel.read.metadata.ReadSheet;
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.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
@@ -17,6 +18,7 @@
import com.genersoft.iot.vmp.service.IStreamPushService;
import com.genersoft.iot.vmp.service.impl.StreamPushUploadFileHandler;
import com.genersoft.iot.vmp.vmanager.bean.BatchGBStreamParam;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.github.pagehelper.PageInfo;
@@ -95,11 +97,9 @@
    @PostMapping(value = "/save_to_gb")
    @ResponseBody
    @Operation(summary = "将推流添加到国标")
    public Object saveToGB(@RequestBody GbStream stream){
        if (streamPushService.saveToGB(stream)){
            return "success";
        }else {
            return "fail";
    public void saveToGB(@RequestBody GbStream stream){
        if (!streamPushService.saveToGB(stream)){
           throw new ControllerException(ErrorCode.ERROR100);
        }
    }
@@ -107,11 +107,9 @@
    @DeleteMapping(value = "/remove_form_gb")
    @ResponseBody
    @Operation(summary = "将推流移出到国标")
    public Object removeFormGB(@RequestBody GbStream stream){
        if (streamPushService.removeFromGB(stream)){
            return "success";
        }else {
            return "fail";
    public void removeFormGB(@RequestBody GbStream stream){
        if (!streamPushService.removeFromGB(stream)){
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
@@ -121,25 +119,21 @@
    @Operation(summary = "中止一个推流")
    @Parameter(name = "app", description = "应用名", required = true)
    @Parameter(name = "stream", description = "流id", required = true)
    public Object stop(String app, String streamId){
        if (streamPushService.stop(app, streamId)){
            return "success";
        }else {
            return "fail";
    public void stop(String app, String streamId){
        if (!streamPushService.stop(app, streamId)){
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
    @DeleteMapping(value = "/batchStop")
    @ResponseBody
    @Operation(summary = "中止多个推流")
    public Object batchStop(@RequestBody BatchGBStreamParam batchGBStreamParam){
    public void batchStop(@RequestBody BatchGBStreamParam batchGBStreamParam){
        if (batchGBStreamParam.getGbStreams().size() == 0) {
            return "fail";
            throw new ControllerException(ErrorCode.ERROR100);
        }
        if (streamPushService.batchStop(batchGBStreamParam.getGbStreams())){
            return "success";
        }else {
            return "fail";
        if (!streamPushService.batchStop(batchGBStreamParam.getGbStreams())){
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
@@ -249,7 +243,7 @@
    @Parameter(name = "app", description = "应用名", required = true)
    @Parameter(name = "stream", description = "流id", required = true)
    @Parameter(name = "mediaServerId", description = "媒体服务器id")
    public WVPResult<StreamInfo> getPlayUrl(@RequestParam String app,@RequestParam String stream,
    public StreamInfo getPlayUrl(@RequestParam String app,@RequestParam String stream,
                                            @RequestParam(required = false) String mediaServerId){
        boolean authority = false;
        // 是否登陆用户, 登陆用户返回完整信息
@@ -257,52 +251,38 @@
        if (userInfo!= null) {
            authority = true;
        }
        WVPResult<StreamInfo> result = new WVPResult<>();
        StreamPushItem push = streamPushService.getPush(app, stream);
        if (push != null && !push.isSelf()) {
            result.setCode(-1);
            result.setMsg("来自其他平台的推流信息");
            return result;
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "来自其他平台的推流信息");
        }
        StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
        if (streamInfo != null){
            result.setCode(0);
            result.setMsg("success");
            result.setData(streamInfo);
        }else {
            result.setCode(-1);
            result.setMsg("获取播放地址失败");
        if (streamInfo == null){
            throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取播放地址失败");
        }
        return result;
        return streamInfo;
    }
    /**
     * 获取推流播放地址
     * 添加推流信息
     * @param stream 推流信息
     * @return
     */
    @PostMapping(value = "/add")
    @ResponseBody
    @Operation(summary = "停止视频回放")
    public WVPResult<StreamInfo> add(@RequestBody StreamPushItem stream){
    @Operation(summary = "添加推流信息")
    public void add(@RequestBody StreamPushItem stream){
        if (ObjectUtils.isEmpty(stream.getGbId())) {
            return new WVPResult<>(400, "国标ID不可为空", null);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "国标ID不可为空");
        }
        if (ObjectUtils.isEmpty(stream.getApp()) && ObjectUtils.isEmpty(stream.getStream())) {
            return new WVPResult<>(400, "app或stream不可为空", null);
            throw new ControllerException(ErrorCode.ERROR400.getCode(), "app或stream不可为空");
        }
        stream.setStatus(false);
        stream.setPushIng(false);
        stream.setAliveSecond(0L);
        stream.setTotalReaderCount("0");
        boolean result = streamPushService.add(stream);
        if (result) {
            return new WVPResult<>(0, "success", null);
        }else {
            return new WVPResult<>(-1, "fail", null);
        if (!streamPushService.add(stream)) {
            throw new ControllerException(ErrorCode.ERROR100);
        }
    }
}
src/main/resources/logback-spring-local.xml
@@ -77,25 +77,35 @@
        </encoder>
    </appender>
    <!-- 生成 SIP日志追加 -->
    <appender name="sipRollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--历史日志文件输出的文件名 -->
            <FileNamePattern>${LOG_HOME}/sip-%d{yyyy-MM-dd}.%i.log</FileNamePattern>
            <!--日志文件保留天数 -->
            <MaxHistory>30</MaxHistory>
            <maxFileSize>50MB</maxFileSize>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="RollingFile" />
        <appender-ref ref="RollingFileError" />
    </root>
<!--    <logger name="com.genersoft.iot.vmp.storager.dao" level="INFO">-->
<!--        <appender-ref ref="STDOUT"/>-->
<!--    </logger>-->
<!--    <logger name="com.genersoft.iot.vmp.gb28181" level="INFO">-->
<!--        <appender-ref ref="STDOUT"/>-->
<!--    </logger>-->
    <logger name="GB28181_SIP" level="debug" additivity="true">
        <appender-ref ref="RollingFileError"/>
        <appender-ref ref="sipRollingFile"/>
    </logger>
    <!--记录druid-sql的记录-->
    <logger name="druid.sql.Statement" level="debug" additivity="true">
    <logger name="com.genersoft.iot.vmp.storager.dao" level="info" additivity="true">
        <!--AppenderRef ref="Console"/-->
        <!--        <appender-ref ref="RollingFile"/>-->
        <appender-ref ref="RollingFileError"/>
        <appender-ref ref="druidSqlRollingFile"/>
    </logger>
web_src/src/components/dialog/devicePlayer.vue
@@ -371,7 +371,7 @@
            if (tab.name === "codec") {
                this.$axios({
                    method: 'get',
                    url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
                    url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtsp&app='+ this.app +'&stream='+ this.streamId
                }).then(function (res) {
                    that.tracksLoading = false;
                    if (res.data.code == 0 && res.data.tracks) {
web_src/src/components/dialog/platformEdit.vue
@@ -268,30 +268,29 @@
      }
    },
    saveForm: function (){
      var that = this;
      that.$axios({
      this.$axios({
        method: 'post',
        url: this.saveUrl,
        data: that.platform
      }).then(function (res) {
        data: this.platform
      }).then((res) =>{
        if (res.data.code === 0) {
          that.$message({
          this.$message({
            showClose: true,
            message: "保存成功",
            type: "success",
          });
          that.showDialog = false;
          if (that.listChangeCallback != null) {
            that.listChangeCallback();
          this.showDialog = false;
          if (this.listChangeCallback != null) {
            this.listChangeCallback();
          }
        }else {
          that.$message({
          this.$message({
            showClose: true,
            message: res.data.msg,
            type: "error",
          });
        }
      }).catch(function (error) {
      }).catch((error)=> {
        console.log(error);
      });
    },