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