648540858
2023-04-08 8c4922cbe14b126c5c04a23b0c1968676e597eb7
Merge branch '2.6.7' into wvp-28181-2.0

# Conflicts:
# src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java
# src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
# src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
7个文件已修改
2个文件已添加
2个文件已删除
458 ■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisTemplateConfig.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/utils/ConfigConst.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisConfig.java
@@ -9,6 +9,9 @@
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
/**
 * Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisTemplateConfig.java
New file
@@ -0,0 +1,28 @@
package com.genersoft.iot.vmp.conf.redis;
import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisTemplateConfig {
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        // 使用fastJson序列化
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
        // value值的序列化采用fastJsonRedisSerializer
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
        // key的序列化采用StringRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
}
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java
@@ -38,7 +38,6 @@
            return;
        }
        if (!userSetting.isInterfaceAuthentication()) {
            // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() );
            SecurityContextHolder.getContext().setAuthentication(token);
            chain.doFilter(request, response);
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java
New file
@@ -0,0 +1,132 @@
package com.genersoft.iot.vmp.gb28181.session;
import com.genersoft.iot.vmp.conf.SipConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
 * ssrc使用
 */
@Component
public class SSRCFactory {
    /**
     * 播流最大并发个数
     */
    private static final Integer MAX_STREAM_COUNT = 10000;
    /**
     * 播流最大并发个数
     */
    private static final String SSRC_INFO_KEY = "VMP_SSRC_INFO_";
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SipConfig sipConfig;
    public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) {
        String ssrcPrefix = sipConfig.getDomain().substring(3, 8);
        String redisKey = SSRC_INFO_KEY + mediaServerId;
        List<String> ssrcList = new ArrayList<>();
        for (int i = 1; i < MAX_STREAM_COUNT; i++) {
            String ssrc = String.format("%s%04d", ssrcPrefix, i);
            if (null == usedSet || !usedSet.contains(ssrc)) {
                ssrcList.add(ssrc);
            }
        }
        if (redisTemplate.opsForSet().size(redisKey) != null) {
            redisTemplate.delete(redisKey);
        }
        redisTemplate.opsForSet().add(redisKey, ssrcList.toArray(new String[0]));
    }
    /**
     * 获取视频预览的SSRC值,第一位固定为0
     *
     * @return ssrc
     */
    public String getPlaySsrc(String mediaServerId) {
        return "0" + getSN(mediaServerId);
    }
    /**
     * 获取录像回放的SSRC值,第一位固定为1
     */
    public String getPlayBackSsrc(String mediaServerId) {
        return "1" + getSN(mediaServerId);
    }
    /**
     * 释放ssrc,主要用完的ssrc一定要释放,否则会耗尽
     *
     * @param ssrc 需要重置的ssrc
     */
    public void releaseSsrc(String mediaServerId, String ssrc) {
        if (ssrc == null) {
            return;
        }
        String sn = ssrc.substring(1);
        String redisKey = SSRC_INFO_KEY + mediaServerId;
        redisTemplate.opsForSet().add(redisKey, sn);
    }
    /**
     * 获取后四位数SN,随机数
     */
    private String getSN(String mediaServerId) {
        String sn = null;
        String redisKey = SSRC_INFO_KEY + mediaServerId;
        Long size = redisTemplate.opsForSet().size(redisKey);
        if (size == null || size == 0) {
            throw new RuntimeException("ssrc已经用完");
        } else {
            // 在集合中移除并返回一个随机成员。
            sn = (String) redisTemplate.opsForSet().pop(redisKey);
            redisTemplate.opsForSet().remove(redisKey, sn);
        }
        return sn;
    }
    /**
     * 重置一个流媒体服务的所有ssrc
     *
     * @param mediaServerId 流媒体服务ID
     */
    public void reset(String mediaServerId) {
        this.initMediaServerSSRC(mediaServerId, null);
    }
    /**
     * 是否已经存在了某个MediaServer的SSRC信息
     *
     * @param mediaServerId 流媒体服务ID
     */
    public boolean hasMediaServerSSRC(String mediaServerId) {
        String redisKey = SSRC_INFO_KEY + mediaServerId;
        return redisTemplate.opsForSet().members(redisKey) != null;
    }
    /**
     * 查询ssrc是否可用
     *
     * @param mediaServerId
     * @param ssrc
     * @return
     */
    public boolean checkSsrc(String mediaServerId, String ssrc) {
        String sn = ssrc.substring(1);
        String redisKey = SSRC_INFO_KEY + mediaServerId;
        return redisTemplate.opsForSet().isMember(redisKey, sn) != null;
    }
}
src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java
File was deleted
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -5,7 +5,7 @@
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
@@ -73,6 +73,9 @@
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
    @Autowired
    private SSRCFactory ssrcFactory;
    @Autowired
    private DynamicTask dynamicTask;
@@ -491,12 +494,8 @@
                } else if (gbStream != null) {
                    if(ssrc.equals(ssrcDefault))
                    {
                        SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();
                        if(ssrcConfig != null)
                        {
                            ssrc = ssrcConfig.getPlaySsrc();
                            ssrcConfig.releaseSsrc(ssrc);
                        }
                        ssrc = ssrcFactory.getPlaySsrc(mediaServerItem.getId());
                        ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrc);
                    }
                    if("push".equals(gbStream.getStreamType())) {
                        if (streamPushItem != null && streamPushItem.isPushIng()) {
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
@@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.media.zlm.dto;
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.util.ObjectUtils;
@@ -80,8 +80,8 @@
    @Schema(description = "是否是默认ZLM")
    private boolean defaultServer;
    @Schema(description = "SSRC信息")
    private SsrcConfig ssrcConfig;
//    @Schema(description = "SSRC信息")
//    private SsrcConfig ssrcConfig;
    @Schema(description = "当前使用到的端口")
    private int currentPort;
@@ -92,7 +92,7 @@
     * 在ApplicationCheckRunner里对mediaServerSsrcMap进行初始化
     */
    @Schema(description = "ID")
    private HashMap<String, SsrcConfig> mediaServerSsrcMap;
    private HashMap<String, SSRCFactory> mediaServerSsrcMap;
    public MediaServerItem() {
    }
@@ -279,20 +279,12 @@
        this.updateTime = updateTime;
    }
    public HashMap<String, SsrcConfig> getMediaServerSsrcMap() {
    public HashMap<String, SSRCFactory> getMediaServerSsrcMap() {
        return mediaServerSsrcMap;
    }
    public void setMediaServerSsrcMap(HashMap<String, SsrcConfig> mediaServerSsrcMap) {
    public void setMediaServerSsrcMap(HashMap<String, SSRCFactory> mediaServerSsrcMap) {
        this.mediaServerSsrcMap = mediaServerSsrcMap;
    }
    public SsrcConfig getSsrcConfig() {
        return ssrcConfig;
    }
    public void setSsrcConfig(SsrcConfig ssrcConfig) {
        this.ssrcConfig = ssrcConfig;
    }
    public int getCurrentPort() {
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
@@ -45,6 +45,8 @@
                device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId());
            }
            if ("WGS84".equals(device.getGeoCoordSys())) {
                deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
                deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -9,6 +9,8 @@
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
@@ -56,6 +58,9 @@
    @Autowired
    private SipConfig sipConfig;
    @Autowired
    private SSRCFactory ssrcFactory;
    @Value("${server.ssl.enabled:false}")
    private boolean sslEnabled;
@@ -96,6 +101,7 @@
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    /**
     * 初始化
     */
@@ -107,10 +113,8 @@
                continue;
            }
            // 更新
            if (mediaServerItem.getSsrcConfig() == null) {
                SsrcConfig ssrcConfig = new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getDomain());
                mediaServerItem.setSsrcConfig(ssrcConfig);
                redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId(), mediaServerItem);
            if (ssrcFactory.hasMediaServerSSRC(mediaServerItem.getId())) {
                ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null);
            }
            // 查询redis是否存在此mediaServer
            String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
@@ -134,36 +138,27 @@
            return null;
        }
        // 获取mediaServer可用的ssrc
        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
        SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();
        if (ssrcConfig == null) {
            logger.info("media server [ {} ] ssrcConfig is null", mediaServerItem.getId());
            return null;
        String ssrc;
        if (presetSsrc != null) {
            ssrc = presetSsrc;
        }else {
            String ssrc;
            if (presetSsrc != null) {
                ssrc = presetSsrc;
            if (isPlayback) {
                ssrc = ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
            }else {
                if (isPlayback) {
                    ssrc = ssrcConfig.getPlayBackSsrc();
                }else {
                    ssrc = ssrcConfig.getPlaySsrc();
                }
                ssrc = ssrcFactory.getPlaySsrc(mediaServerItem.getId());
            }
            if (streamId == null) {
                streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
            }
            int rtpServerPort;
            if (mediaServerItem.isRtpEnable()) {
                rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port);
            } else {
                rtpServerPort = mediaServerItem.getRtpProxyPort();
            }
            redisTemplate.opsForValue().set(key, mediaServerItem);
            return new SSRCInfo(rtpServerPort, ssrc, streamId);
        }
        if (streamId == null) {
            streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
        }
        int rtpServerPort;
        if (mediaServerItem.isRtpEnable()) {
            rtpServerPort = zlmrtpServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck?Integer.parseInt(ssrc):0, port);
        } else {
            rtpServerPort = mediaServerItem.getRtpProxyPort();
        }
        return new SSRCInfo(rtpServerPort, ssrc, streamId);
    }
    @Override
@@ -191,11 +186,7 @@
        if (mediaServerItem == null || ssrc == null) {
            return;
        }
        SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();
        ssrcConfig.releaseSsrc(ssrc);
        mediaServerItem.setSsrcConfig(ssrcConfig);
        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
        redisTemplate.opsForValue().set(key, mediaServerItem);
        ssrcFactory.releaseSsrc(mediaServerItemId, ssrc);
    }
    /**
@@ -203,8 +194,7 @@
     */
    @Override
    public void clearRTPServer(MediaServerItem mediaServerItem) {
        mediaServerItem.setSsrcConfig(new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getDomain()));
        redisTemplate.opsForZSet().add(VideoManagerConstants.MEDIA_SERVERS_ONLINE_PREFIX + userSetting.getServerId(), mediaServerItem.getId(), 0);
        ssrcFactory.reset(mediaServerItem.getId());
    }
@@ -214,16 +204,8 @@
        mediaServerMapper.update(mediaSerItem);
        MediaServerItem mediaServerItemInRedis = getOne(mediaSerItem.getId());
        MediaServerItem mediaServerItemInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId());
        if (mediaServerItemInRedis != null && mediaServerItemInRedis.getSsrcConfig() != null) {
            mediaServerItemInDataBase.setSsrcConfig(mediaServerItemInRedis.getSsrcConfig());
        }else {
            mediaServerItemInDataBase.setSsrcConfig(
                    new SsrcConfig(
                            mediaServerItemInDataBase.getId(),
                            null,
                            sipConfig.getDomain()
                    )
            );
        if (mediaServerItemInRedis == null || ssrcFactory.hasMediaServerSSRC(mediaSerItem.getId())) {
            ssrcFactory.initMediaServerSSRC(mediaServerItemInDataBase.getId(),null);
        }
        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItemInDataBase.getId();
        redisTemplate.opsForValue().set(key, mediaServerItemInDataBase);
@@ -404,14 +386,8 @@
        }
        mediaServerMapper.update(serverItem);
        String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + zlmServerConfig.getGeneralMediaServerId();
        if (redisTemplate.opsForValue().get(key) == null) {
            SsrcConfig ssrcConfig = new SsrcConfig(zlmServerConfig.getGeneralMediaServerId(), null, sipConfig.getDomain());
            serverItem.setSsrcConfig(ssrcConfig);
        }else {
            MediaServerItem mediaServerItemInRedis = JsonUtil.redisJsonToObject(redisTemplate, key, MediaServerItem.class);
            if (Objects.nonNull(mediaServerItemInRedis)) {
                serverItem.setSsrcConfig(mediaServerItemInRedis.getSsrcConfig());
            }
        if (ssrcFactory.hasMediaServerSSRC(serverItem.getId())) {
            ssrcFactory.initMediaServerSSRC(zlmServerConfig.getGeneralMediaServerId(), null);
        }
        redisTemplate.opsForValue().set(key, serverItem);
        resetOnlineServerItem(serverItem);
@@ -709,8 +685,7 @@
            }
            // zlm连接重试
            logger.warn("[更新ZLM 保活信息]尝试链接zml id {}", mediaServerId);
            SsrcConfig ssrcConfig = new SsrcConfig(mediaServerItem.getId(), null, sipConfig.getDomain());
            mediaServerItem.setSsrcConfig(ssrcConfig);
            ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null);
            String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId();
            redisTemplate.opsForValue().set(key, mediaServerItem);
            clearRTPServer(mediaServerItem);
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -11,6 +11,7 @@
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
@@ -99,6 +100,9 @@
    @Autowired
    private ZlmHttpHookSubscribe subscribe;
    @Autowired
    private SSRCFactory ssrcFactory;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
@@ -298,10 +302,10 @@
                    if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
                        logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
                        if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
                        if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
                            // ssrc 不可用
                            // 释放ssrc
                            mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
                            ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
                            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
                            event.msg = "下级自定义了ssrc,但是此ssrc不可用";
                            event.statusCode = 400;
@@ -539,7 +543,7 @@
                                if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
                                    logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
                                    if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
                                    if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
                                        // ssrc 不可用
                                        // 释放ssrc
                                        mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
@@ -678,7 +682,7 @@
                                if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
                                    logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
                                    if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
                                    if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
                                        // ssrc 不可用
                                        // 释放ssrc
                                        mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
src/main/java/com/genersoft/iot/vmp/utils/ConfigConst.java
File was deleted