修复国标点播缓存启动未清理的BUG

pull/1669/head
648540858 2024-10-25 17:41:50 +08:00
parent ef66bd8781
commit 059635c2cc
29 changed files with 256 additions and 350 deletions

View File

@ -16,7 +16,7 @@ public class VideoManagerConstants {
public static final String ONLINE_MEDIA_SERVERS_PREFIX = "VMP_ONLINE_MEDIA_SERVERS:"; public static final String ONLINE_MEDIA_SERVERS_PREFIX = "VMP_ONLINE_MEDIA_SERVERS:";
public static final String DEVICE_PREFIX = "VMP_DEVICE:"; public static final String DEVICE_PREFIX = "VMP_DEVICE_INFO";
public static final String INVITE_PREFIX = "VMP_INVITE_INFO"; public static final String INVITE_PREFIX = "VMP_INVITE_INFO";
@ -24,7 +24,7 @@ public class VideoManagerConstants {
public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_"; public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_";
public static final String SEND_RTP_INFO = "VMP_SEND_RTP_INFO:"; public static final String SEND_RTP_PORT = "VM_SEND_RTP_PORT:";
public static final String SEND_RTP_INFO_CALLID = "VMP_SEND_RTP_INFO:CALL_ID:"; public static final String SEND_RTP_INFO_CALLID = "VMP_SEND_RTP_INFO:CALL_ID:";
public static final String SEND_RTP_INFO_STREAM = "VMP_SEND_RTP_INFO:STREAM:"; public static final String SEND_RTP_INFO_STREAM = "VMP_SEND_RTP_INFO:STREAM:";
public static final String SEND_RTP_INFO_CHANNEL = "VMP_SEND_RTP_INFO:CHANNEL:"; public static final String SEND_RTP_INFO_CHANNEL = "VMP_SEND_RTP_INFO:CHANNEL:";

View File

@ -151,9 +151,6 @@ public interface DeviceChannelMapper {
" </script>"}) " </script>"})
List<DeviceChannelExtend> queryChannelsWithDeviceInfo(@Param("deviceId") String deviceId, @Param("parentChannelId") String parentChannelId, @Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel, @Param("online") Boolean online, @Param("channelIds") List<String> channelIds); List<DeviceChannelExtend> queryChannelsWithDeviceInfo(@Param("deviceId") String deviceId, @Param("parentChannelId") String parentChannelId, @Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel, @Param("online") Boolean online, @Param("channelIds") List<String> channelIds);
@Update(value = {"UPDATE wvp_device_channel SET stream_id=null WHERE device_db_id=#{deviceId} AND device_id=#{channelId}"})
void stopPlay(@Param("deviceId") int deviceId, @Param("channelId") String channelId);
@Update(value = {"UPDATE wvp_device_channel SET stream_id=#{streamId} WHERE id=#{channelId}"}) @Update(value = {"UPDATE wvp_device_channel SET stream_id=#{streamId} WHERE id=#{channelId}"})
void startPlay(@Param("channelId") Integer channelId, @Param("streamId") String streamId); void startPlay(@Param("channelId") Integer channelId, @Param("streamId") String streamId);

View File

@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent; import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent; import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent; import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent;
import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent; import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -39,15 +40,15 @@ public class EventPublisher {
applicationEventPublisher.publishEvent(alarmEvent); applicationEventPublisher.publishEvent(alarmEvent);
} }
public void mediaServerOfflineEventPublish(String mediaServerId){ public void mediaServerOfflineEventPublish(MediaServer mediaServer){
MediaServerOfflineEvent outEvent = new MediaServerOfflineEvent(this); MediaServerOfflineEvent outEvent = new MediaServerOfflineEvent(this);
outEvent.setMediaServerId(mediaServerId); outEvent.setMediaServer(mediaServer);
applicationEventPublisher.publishEvent(outEvent); applicationEventPublisher.publishEvent(outEvent);
} }
public void mediaServerOnlineEventPublish(String mediaServerId) { public void mediaServerOnlineEventPublish(MediaServer mediaServer) {
MediaServerOnlineEvent outEvent = new MediaServerOnlineEvent(this); MediaServerOnlineEvent outEvent = new MediaServerOnlineEvent(this);
outEvent.setMediaServerId(mediaServerId); outEvent.setMediaServer(mediaServer);
applicationEventPublisher.publishEvent(outEvent); applicationEventPublisher.publishEvent(outEvent);
} }

View File

@ -30,13 +30,13 @@ public interface IPlayService {
MediaServer getNewMediaServerItem(Device device); MediaServer getNewMediaServerItem(Device device);
void playBack(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback<StreamInfo> callback); void playBack(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback<StreamInfo> callback);
void zlmServerOffline(String mediaServerId); void zlmServerOffline(MediaServer mediaServer);
void download(Device device, DeviceChannel channel, String startTime, String endTime, int downloadSpeed, ErrorCallback<StreamInfo> callback); void download(Device device, DeviceChannel channel, String startTime, String endTime, int downloadSpeed, ErrorCallback<StreamInfo> callback);
StreamInfo getDownLoadInfo(Device device, DeviceChannel channel, String stream); StreamInfo getDownLoadInfo(Device device, DeviceChannel channel, String stream);
void zlmServerOnline(String mediaServerId); void zlmServerOnline(MediaServer mediaServer);
AudioBroadcastResult audioBroadcast(Device device, DeviceChannel deviceChannel, Boolean broadcastMode); AudioBroadcastResult audioBroadcast(Device device, DeviceChannel deviceChannel, Boolean broadcastMode);

View File

@ -210,9 +210,6 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
":" + inviteInfo.getSsrcInfo().getSsrc(); ":" + inviteInfo.getSsrcInfo().getSsrc();
redisTemplate.opsForHash().delete(key, objectKey); redisTemplate.opsForHash().delete(key, objectKey);
} }
if (redisTemplate.opsForHash().size(key) == 0) {
redisTemplate.opsForHash().delete(key);
}
} }
@Override @Override

View File

@ -246,32 +246,6 @@ public class PlatformServiceImpl implements IPlatformService {
return false; return false;
} }
private void unregister(Platform platform) {
// 停止心跳定时
final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + platform.getServerGBId();
dynamicTask.stop(keepaliveTaskKey);
// 停止注册定时
final String registerTaskKey = REGISTER_KEY_PREFIX + platform.getServerGBId();
dynamicTask.stop(registerTaskKey);
PlatformCatch platformCatchOld = redisCatchStorage.queryPlatformCatchInfo(platform.getServerGBId());
// 注销旧的
try {
if (platform.isStatus()) {
commanderForPlatform.unregister(platform, platformCatchOld.getSipTransactionInfo(), null, eventResult -> {
log.info("[国标级联] 注销命令发送成功,平台:{}", platform.getServerGBId());
});
}
} catch (InvalidArgumentException | ParseException | SipException e) {
log.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
}
}
private void register(Platform platform) {
}
@Override @Override
public void online(Platform platform, SipTransactionInfo sipTransactionInfo) { public void online(Platform platform, SipTransactionInfo sipTransactionInfo) {
log.info("[国标级联]{}, 平台上线", platform.getServerGBId()); log.info("[国标级联]{}, 平台上线", platform.getServerGBId());

View File

@ -1157,12 +1157,12 @@ public class PlayServiceImpl implements IPlayService {
@Override @Override
public void zlmServerOffline(String mediaServerId) { public void zlmServerOffline(MediaServer mediaServer) {
// 处理正在向上推流的上级平台 // 处理正在向上推流的上级平台
List<SendRtpInfo> sendRtpInfos = sendRtpServerService.queryAll(); List<SendRtpInfo> sendRtpInfos = sendRtpServerService.queryAll();
if (!sendRtpInfos.isEmpty()) { if (!sendRtpInfos.isEmpty()) {
for (SendRtpInfo sendRtpInfo : sendRtpInfos) { for (SendRtpInfo sendRtpInfo : sendRtpInfos) {
if (sendRtpInfo.getMediaServerId().equals(mediaServerId) && sendRtpInfo.isSendToPlatform()) { if (sendRtpInfo.getMediaServerId().equals(mediaServer.getId()) && sendRtpInfo.isSendToPlatform()) {
Platform platform = platformService.queryPlatformByServerGBId(sendRtpInfo.getTargetId()); Platform platform = platformService.queryPlatformByServerGBId(sendRtpInfo.getTargetId());
CommonGBChannel channel = channelService.getOne(sendRtpInfo.getChannelId()); CommonGBChannel channel = channelService.getOne(sendRtpInfo.getChannelId());
try { try {
@ -1177,7 +1177,7 @@ public class PlayServiceImpl implements IPlayService {
List<SsrcTransaction> allSsrc = sessionManager.getAll(); List<SsrcTransaction> allSsrc = sessionManager.getAll();
if (allSsrc.size() > 0) { if (allSsrc.size() > 0) {
for (SsrcTransaction ssrcTransaction : allSsrc) { for (SsrcTransaction ssrcTransaction : allSsrc) {
if (ssrcTransaction.getMediaServerId().equals(mediaServerId)) { if (ssrcTransaction.getMediaServerId().equals(mediaServer.getId())) {
Device device = deviceService.getDeviceByDeviceId(ssrcTransaction.getDeviceId()); Device device = deviceService.getDeviceByDeviceId(ssrcTransaction.getDeviceId());
if (device == null) { if (device == null) {
continue; continue;
@ -1314,7 +1314,22 @@ public class PlayServiceImpl implements IPlayService {
} }
@Override @Override
public void zlmServerOnline(String mediaServerId) { public void zlmServerOnline(MediaServer mediaServer) {
// 获取
List<InviteInfo> inviteInfoList = inviteStreamService.getAllInviteInfo();
if (inviteInfoList.isEmpty()) {
return;
}
List<String> rtpServerList = mediaServerService.listRtpServer(mediaServer);
if (rtpServerList.isEmpty()) {
return;
}
for (InviteInfo inviteInfo : inviteInfoList) {
if (!rtpServerList.contains(inviteInfo.getStream())){
inviteStreamService.removeInviteInfo(inviteInfo);
}
}
} }
@Override @Override
@ -1568,7 +1583,10 @@ public class PlayServiceImpl implements IPlayService {
public void stop(InviteSessionType type, Device device, DeviceChannel channel, String stream) { public void stop(InviteSessionType type, Device device, DeviceChannel channel, String stream) {
InviteInfo inviteInfo = inviteStreamService.getInviteInfo(type, channel.getId(), stream); InviteInfo inviteInfo = inviteStreamService.getInviteInfo(type, channel.getId(), stream);
if (inviteInfo == null) { if (inviteInfo == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "点播未找到"); if (type == InviteSessionType.PLAY) {
deviceChannelService.stopPlay(channel.getId());
}
return;
} }
inviteStreamService.removeInviteInfo(inviteInfo); inviteStreamService.removeInviteInfo(inviteInfo);
if (InviteSessionStatus.ok == inviteInfo.getStatus()) { if (InviteSessionStatus.ok == inviteInfo.getStatus()) {

View File

@ -41,7 +41,7 @@ public class MediaServerConfig implements CommandLineRunner {
mediaServerService.update(mediaSerItemInConfig); mediaServerService.update(mediaSerItemInConfig);
}else { }else {
if (defaultMediaServer != null) { if (defaultMediaServer != null) {
mediaServerService.delete(defaultMediaServer.getId()); mediaServerService.delete(defaultMediaServer);
} }
MediaServer mediaServerItem = mediaServerService.getOneFromDatabase(mediaSerItemInConfig.getId()); MediaServer mediaServerItem = mediaServerService.getOneFromDatabase(mediaSerItemInConfig.getId());
if (mediaServerItem == null) { if (mediaServerItem == null) {

View File

@ -1,24 +1,23 @@
package com.genersoft.iot.vmp.media.event.mediaServer; package com.genersoft.iot.vmp.media.event.mediaServer;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
public abstract class MediaServerEventAbstract extends ApplicationEvent { public abstract class MediaServerEventAbstract extends ApplicationEvent {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private String mediaServerId; @Getter
@Setter
private MediaServer mediaServer;
public MediaServerEventAbstract(Object source) { public MediaServerEventAbstract(Object source) {
super(source); super(source);
} }
public String getMediaServerId() {
return mediaServerId;
}
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
}
} }

View File

@ -25,16 +25,16 @@ public class MediaServerStatusEventListener {
@Async("taskExecutor") @Async("taskExecutor")
@EventListener @EventListener
public void onApplicationEvent(MediaServerOnlineEvent event) { public void onApplicationEvent(MediaServerOnlineEvent event) {
log.info("[媒体节点] 上线 ID" + event.getMediaServerId()); log.info("[媒体节点] 上线 ID" + event.getMediaServer().getId());
playService.zlmServerOnline(event.getMediaServerId()); playService.zlmServerOnline(event.getMediaServer());
} }
@Async("taskExecutor") @Async("taskExecutor")
@EventListener @EventListener
public void onApplicationEvent(MediaServerOfflineEvent event) { public void onApplicationEvent(MediaServerOfflineEvent event) {
log.info("[媒体节点] 离线ID" + event.getMediaServerId()); log.info("[媒体节点] 离线ID" + event.getMediaServer().getId());
// 处理ZLM离线 // 处理ZLM离线
playService.zlmServerOffline(event.getMediaServerId()); playService.zlmServerOffline(event.getMediaServer());
} }
} }

View File

@ -67,4 +67,7 @@ public interface IMediaNodeServerService {
StreamInfo startProxy(MediaServer mediaServer, StreamProxy streamProxy); StreamInfo startProxy(MediaServer mediaServer, StreamProxy streamProxy);
void stopProxy(MediaServer mediaServer, String streamKey); void stopProxy(MediaServer mediaServer, String streamKey);
List<String> listRtpServer(MediaServer mediaServer);
} }

View File

@ -65,7 +65,7 @@ public interface IMediaServerService {
boolean checkMediaRecordServer(String ip, int port); boolean checkMediaRecordServer(String ip, int port);
void delete(String id); void delete(MediaServer mediaServer);
MediaServer getDefaultMediaServer(); MediaServer getDefaultMediaServer();
@ -158,4 +158,5 @@ public interface IMediaServerService {
int createRTPServer(MediaServer mediaServerItem, String streamId, long ssrc, Integer port, boolean onlyAuto, boolean disableAudio, boolean reUsePort, Integer tcpMode); int createRTPServer(MediaServer mediaServerItem, String streamId, long ssrc, Integer port, boolean onlyAuto, boolean disableAudio, boolean reUsePort, Integer tcpMode);
List<String> listRtpServer(MediaServer mediaServer);
} }

View File

@ -81,6 +81,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
@Autowired @Autowired
private MediaConfig mediaConfig; private MediaConfig mediaConfig;
/** /**
* *
*/ */
@ -216,6 +217,16 @@ public class MediaServerServiceImpl implements IMediaServerService {
return rtpServerPort; return rtpServerPort;
} }
@Override
public List<String> listRtpServer(MediaServer mediaServer) {
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
if (mediaNodeServerService == null) {
log.info("[openRTPServer] 失败, mediaServer的类型 {},未找到对应的实现类", mediaServer.getType());
return new ArrayList<>();
}
return mediaNodeServerService.listRtpServer(mediaServer);
}
@Override @Override
public void closeRTPServer(MediaServer mediaServer, String streamId) { public void closeRTPServer(MediaServer mediaServer, String streamId) {
if (mediaServer == null) { if (mediaServer == null) {
@ -561,14 +572,14 @@ public class MediaServerServiceImpl implements IMediaServerService {
} }
@Override @Override
public void delete(String id) { public void delete(MediaServer mediaServer) {
mediaServerMapper.delOne(id); mediaServerMapper.delOne(mediaServer.getId());
redisTemplate.opsForZSet().remove(VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId(), id); redisTemplate.opsForZSet().remove(VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId(), mediaServer.getId());
String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + id; String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServer.getId();
redisTemplate.delete(key); redisTemplate.delete(key);
// 发送节点移除通知 // 发送节点移除通知
MediaServerDeleteEvent event = new MediaServerDeleteEvent(this); MediaServerDeleteEvent event = new MediaServerDeleteEvent(this);
event.setMediaServerId(id); event.setMediaServer(mediaServer);
applicationEventPublisher.publishEvent(event); applicationEventPublisher.publishEvent(event);
} }
@ -589,7 +600,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
for (MediaServer mediaServer : allInCatch) { for (MediaServer mediaServer : allInCatch) {
// 清除数据中不存在但redis缓存数据 // 清除数据中不存在但redis缓存数据
if (!mediaServerMap.containsKey(mediaServer.getId())) { if (!mediaServerMap.containsKey(mediaServer.getId())) {
delete(mediaServer.getId()); delete(mediaServer);
} }
} }
} }

View File

@ -1,133 +0,0 @@
package com.genersoft.iot.vmp.media.zlm;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
public class SendRtpPortManager {
@Autowired
private UserSetting userSetting;
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
private final String KEY = "VM_MEDIA_SEND_RTP_PORT_";
public synchronized int getNextPort(MediaServer mediaServer) {
if (mediaServer == null) {
log.warn("[发送端口管理] 参数错误mediaServer为NULL");
return -1;
}
String sendIndexKey = KEY + userSetting.getServerId() + "_" + mediaServer.getId();
String key = VideoManagerConstants.SEND_RTP_INFO
+ userSetting.getServerId() + "_*";
List<Object> queryResult = RedisUtil.scan(redisTemplate, key);
Map<Integer, SendRtpInfo> sendRtpItemMap = new HashMap<>();
for (Object o : queryResult) {
SendRtpInfo sendRtpItem = (SendRtpInfo) redisTemplate.opsForValue().get(o);
if (sendRtpItem != null) {
sendRtpItemMap.put(sendRtpItem.getLocalPort(), sendRtpItem);
}
}
String sendRtpPortRange = mediaServer.getSendRtpPortRange();
int startPort;
int endPort;
if (sendRtpPortRange != null) {
String[] portArray = sendRtpPortRange.split(",");
if (portArray.length != 2 || !NumberUtils.isParsable(portArray[0]) || !NumberUtils.isParsable(portArray[1])) {
log.warn("{}发送端口配置格式错误自动使用50000-60000作为端口范围", mediaServer.getId());
startPort = 50000;
endPort = 60000;
}else {
if ( Integer.parseInt(portArray[1]) - Integer.parseInt(portArray[0]) < 1) {
log.warn("{}发送端口配置错误,结束端口至少比开始端口大一自动使用50000-60000作为端口范围", mediaServer.getId());
startPort = 50000;
endPort = 60000;
}else {
startPort = Integer.parseInt(portArray[0]);
endPort = Integer.parseInt(portArray[1]);
}
}
}else {
log.warn("{}未设置发送端口默认值自动使用50000-60000作为端口范围", mediaServer.getId());
startPort = 50000;
endPort = 60000;
}
if (redisTemplate == null || redisTemplate.getConnectionFactory() == null) {
log.warn("{}获取redis连接信息失败", mediaServer.getId());
return -1;
}
// RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
// return redisAtomicInteger.getAndUpdate((current)->{
// return getPort(current, startPort, endPort, checkPort-> !sendRtpItemMap.containsKey(checkPort));
// });
return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap);
}
private synchronized int getSendPort(int startPort, int endPort, String sendIndexKey, Map<Integer, SendRtpInfo> sendRtpItemMap){
// TODO 这里改为只取偶数端口
RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
if (redisAtomicInteger.get() < startPort) {
redisAtomicInteger.set(startPort);
return startPort;
}else {
int port = redisAtomicInteger.getAndIncrement();
if (port > endPort) {
redisAtomicInteger.set(startPort);
if (sendRtpItemMap.containsKey(startPort)) {
return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap);
}else {
return startPort;
}
}
if (sendRtpItemMap.containsKey(port)) {
return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap);
}else {
return port;
}
}
}
interface CheckPortCallback{
boolean check(int port);
}
private int getPort(int current, int start, int end, CheckPortCallback checkPortCallback) {
if (current <= 0) {
if (start%2 == 0) {
current = start;
}else {
current = start + 1;
}
}else {
current += 2;
if (current > end) {
if (start%2 == 0) {
current = start;
}else {
current = start + 1;
}
}
}
if (!checkPortCallback.check(current)) {
return getPort(current + 2, start, end, checkPortCallback);
}
return current;
}
}

View File

@ -20,10 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j @Slf4j
@Service("zlm") @Service("zlm")
@ -136,9 +133,14 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
param.put("ssrc", ssrc); param.put("ssrc", ssrc);
} }
JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaInfo, param); JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaInfo, param);
log.info("停止发流结果: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSONString(param)); System.out.println(jsonObject);
return true; if (jsonObject.getInteger("code") != null && jsonObject.getInteger("code") == 0) {
log.info("[停止发流] 成功: 参数:{}", JSON.toJSONString(param));
return true;
}else {
log.info("停止发流结果: {}, 参数:{}", jsonObject.getString("msg"), JSON.toJSONString(param));
return false;
}
} }
@Override @Override
@ -496,4 +498,22 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg")); throw new ControllerException(jsonObject.getInteger("code"), jsonObject.getString("msg"));
} }
} }
@Override
public List<String> listRtpServer(MediaServer mediaServer) {
JSONObject jsonObject = zlmresTfulUtils.listRtpServer(mediaServer);
List<String> result = new ArrayList<>();
if (jsonObject == null || jsonObject.getInteger("code") != 0) {
return result;
}
JSONArray data = jsonObject.getJSONArray("data");
if (data == null || data.isEmpty()) {
return result;
}
for (int i = 0; i < data.size(); i++) {
JSONObject dataJSONObject = data.getJSONObject(i);
result.add(dataJSONObject.getString("stream_id"));
}
return result;
}
} }

View File

@ -112,13 +112,13 @@ public class ZLMMediaServerStatusManager {
@Async("taskExecutor") @Async("taskExecutor")
@EventListener @EventListener
public void onApplicationEvent(MediaServerDeleteEvent event) { public void onApplicationEvent(MediaServerDeleteEvent event) {
if (event.getMediaServerId() == null) { if (event.getMediaServer() == null) {
return; return;
} }
log.info("[ZLM-节点被移除] ID" + event.getMediaServerId()); log.info("[ZLM-节点被移除] ID" + event.getMediaServer().getId());
offlineZlmPrimaryMap.remove(event.getMediaServerId()); offlineZlmPrimaryMap.remove(event.getMediaServer().getId());
offlineZlmsecondaryMap.remove(event.getMediaServerId()); offlineZlmsecondaryMap.remove(event.getMediaServer().getId());
offlineZlmTimeMap.remove(event.getMediaServerId()); offlineZlmTimeMap.remove(event.getMediaServer().getId());
} }
@Scheduled(fixedDelay = 10*1000) //每隔10秒检查一次 @Scheduled(fixedDelay = 10*1000) //每隔10秒检查一次
@ -188,7 +188,7 @@ public class ZLMMediaServerStatusManager {
mediaServerItem.setHookAliveInterval(10F); mediaServerItem.setHookAliveInterval(10F);
mediaServerService.update(mediaServerItem); mediaServerService.update(mediaServerItem);
// 发送上线通知 // 发送上线通知
eventPublisher.mediaServerOnlineEventPublish(mediaServerItem.getId()); eventPublisher.mediaServerOnlineEventPublish(mediaServerItem);
if(mediaServerItem.isAutoConfig()) { if(mediaServerItem.isAutoConfig()) {
if (config == null) { if (config == null) {
JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem); JSONObject responseJSON = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
@ -213,7 +213,7 @@ public class ZLMMediaServerStatusManager {
offlineZlmPrimaryMap.put(mediaServerItem.getId(), mediaServerItem); offlineZlmPrimaryMap.put(mediaServerItem.getId(), mediaServerItem);
offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis()); offlineZlmTimeMap.put(mediaServerItem.getId(), System.currentTimeMillis());
// 发送离线通知 // 发送离线通知
eventPublisher.mediaServerOfflineEventPublish(mediaServerItem.getId()); eventPublisher.mediaServerOfflineEventPublish(mediaServerItem);
mediaServerService.update(mediaServerItem); mediaServerService.update(mediaServerItem);
}, (int)(mediaServerItem.getHookAliveInterval() * 2 * 1000)); }, (int)(mediaServerItem.getHookAliveInterval() * 2 * 1000));
} }

View File

@ -2,7 +2,6 @@ package com.genersoft.iot.vmp.media.zlm;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.common.CommonCallback;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -18,12 +17,6 @@ public class ZLMServerFactory {
@Autowired @Autowired
private ZLMRESTfulUtils zlmresTfulUtils; private ZLMRESTfulUtils zlmresTfulUtils;
@Autowired
private UserSetting userSetting;
@Autowired
private SendRtpPortManager sendRtpPortManager;
/** /**
* rtpServer * rtpServer

View File

@ -40,4 +40,6 @@ public interface ISendRtpServerService {
List<SendRtpInfo> queryByChannelId(int id); List<SendRtpInfo> queryByChannelId(int id);
void deleteByStream(String stream); void deleteByStream(String stream);
int getNextPort(MediaServer mediaServer);
} }

View File

@ -8,16 +8,13 @@ import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.gb28181.service.*; import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService;
import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager; import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.bean.ResultForOnPublish; import com.genersoft.iot.vmp.media.bean.ResultForOnPublish;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.IMediaService; import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.service.IUserService; import com.genersoft.iot.vmp.service.IUserService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
@ -56,33 +53,12 @@ public class MediaServiceImpl implements IMediaService {
@Autowired @Autowired
private IInviteStreamService inviteStreamService; private IInviteStreamService inviteStreamService;
@Autowired
private SSRCFactory ssrcFactory;
@Autowired @Autowired
private IDeviceChannelService deviceChannelService; private IDeviceChannelService deviceChannelService;
@Autowired @Autowired
private SipInviteSessionManager sessionManager; private SipInviteSessionManager sessionManager;
@Autowired
private IPlatformService platformService;
@Autowired
private IGbChannelService channelService;
@Autowired
private IDeviceService deviceService;
@Autowired
private ISIPCommanderForPlatform commanderForPlatform;
@Autowired
private ISIPCommander commander;
@Autowired
private ISendRtpServerService sendRtpServerService;
@Override @Override
public boolean authenticatePlay(String app, String stream, String callId) { public boolean authenticatePlay(String app, String stream, String callId) {
if (app == null || stream == null) { if (app == null || stream == null) {

View File

@ -4,19 +4,20 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.gb28181.bean.PlayException; import com.genersoft.iot.vmp.gb28181.bean.PlayException;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.gb28181.conf.StackLoggerImpl;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.utils.JsonUtil; import com.genersoft.iot.vmp.utils.JsonUtil;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
@Service @Service
@Slf4j @Slf4j
@ -25,18 +26,14 @@ public class SendRtpServerServiceImpl implements ISendRtpServerService {
@Autowired @Autowired
private UserSetting userSetting; private UserSetting userSetting;
@Autowired
private SendRtpPortManager sendRtpPortManager;
@Autowired @Autowired
private RedisTemplate<Object, Object> redisTemplate; private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private StackLoggerImpl stackLoggerImpl;
@Override @Override
public SendRtpInfo createSendRtpInfo(MediaServer mediaServer, String ip, Integer port, String ssrc, String requesterId, public SendRtpInfo createSendRtpInfo(MediaServer mediaServer, String ip, Integer port, String ssrc, String requesterId,
String deviceId, Integer channelId, Boolean isTcp, Boolean rtcp) { String deviceId, Integer channelId, Boolean isTcp, Boolean rtcp) {
int localPort = sendRtpPortManager.getNextPort(mediaServer); int localPort = getNextPort(mediaServer);
if (localPort == 0) { if (localPort == 0) {
return null; return null;
} }
@ -48,7 +45,7 @@ public class SendRtpServerServiceImpl implements ISendRtpServerService {
public SendRtpInfo createSendRtpInfo(MediaServer mediaServer, String ip, Integer port, String ssrc, String platformId, public SendRtpInfo createSendRtpInfo(MediaServer mediaServer, String ip, Integer port, String ssrc, String platformId,
String app, String stream, Integer channelId, Boolean tcp, Boolean rtcp){ String app, String stream, Integer channelId, Boolean tcp, Boolean rtcp){
int localPort = sendRtpPortManager.getNextPort(mediaServer); int localPort = getNextPort(mediaServer);
if (localPort <= 0) { if (localPort <= 0) {
throw new PlayException(javax.sip.message.Response.SERVER_INTERNAL_ERROR, "server internal error"); throw new PlayException(javax.sip.message.Response.SERVER_INTERNAL_ERROR, "server internal error");
} }
@ -64,7 +61,7 @@ public class SendRtpServerServiceImpl implements ISendRtpServerService {
@Override @Override
public void update(SendRtpInfo sendRtpItem) { public void update(SendRtpInfo sendRtpItem) {
redisTemplate.opsForValue().set(VideoManagerConstants.SEND_RTP_INFO_CALLID + sendRtpItem.getCallId(), sendRtpItem); redisTemplate.opsForHash().put(VideoManagerConstants.SEND_RTP_INFO_CALLID, sendRtpItem.getCallId(), sendRtpItem);
redisTemplate.opsForHash().put(VideoManagerConstants.SEND_RTP_INFO_STREAM + sendRtpItem.getStream(), sendRtpItem.getTargetId(), sendRtpItem); redisTemplate.opsForHash().put(VideoManagerConstants.SEND_RTP_INFO_STREAM + sendRtpItem.getStream(), sendRtpItem.getTargetId(), sendRtpItem);
redisTemplate.opsForHash().put(VideoManagerConstants.SEND_RTP_INFO_CHANNEL + sendRtpItem.getChannelId(), sendRtpItem.getTargetId(), sendRtpItem); redisTemplate.opsForHash().put(VideoManagerConstants.SEND_RTP_INFO_CHANNEL + sendRtpItem.getChannelId(), sendRtpItem.getTargetId(), sendRtpItem);
} }
@ -77,8 +74,8 @@ public class SendRtpServerServiceImpl implements ISendRtpServerService {
@Override @Override
public SendRtpInfo queryByCallId(String callId) { public SendRtpInfo queryByCallId(String callId) {
String key = VideoManagerConstants.SEND_RTP_INFO_CALLID + callId; String key = VideoManagerConstants.SEND_RTP_INFO_CALLID;
return JsonUtil.redisJsonToObject(redisTemplate, key, SendRtpInfo.class); return (SendRtpInfo)redisTemplate.opsForHash().get(key, callId);
} }
@Override @Override
@ -107,17 +104,9 @@ public class SendRtpServerServiceImpl implements ISendRtpServerService {
if (sendRtpInfo == null) { if (sendRtpInfo == null) {
return; return;
} }
redisTemplate.delete(VideoManagerConstants.SEND_RTP_INFO_CALLID + sendRtpInfo.getCallId()); redisTemplate.opsForHash().delete(VideoManagerConstants.SEND_RTP_INFO_CALLID, sendRtpInfo.getCallId());
if (redisTemplate.opsForHash().size(VideoManagerConstants.SEND_RTP_INFO_STREAM + sendRtpInfo.getStream()) == 0) { redisTemplate.opsForHash().delete(VideoManagerConstants.SEND_RTP_INFO_STREAM + sendRtpInfo.getStream(), sendRtpInfo.getTargetId());
redisTemplate.delete(VideoManagerConstants.SEND_RTP_INFO_STREAM + sendRtpInfo.getStream()); redisTemplate.opsForHash().delete(VideoManagerConstants.SEND_RTP_INFO_CHANNEL + sendRtpInfo.getChannelId(), sendRtpInfo.getTargetId());
}else {
redisTemplate.opsForHash().delete(VideoManagerConstants.SEND_RTP_INFO_STREAM + sendRtpInfo.getStream(), sendRtpInfo.getTargetId());
}
if (redisTemplate.opsForHash().size(VideoManagerConstants.SEND_RTP_INFO_CHANNEL + sendRtpInfo.getChannelId()) == 0) {
redisTemplate.delete(VideoManagerConstants.SEND_RTP_INFO_CHANNEL + sendRtpInfo.getChannelId());
}else {
redisTemplate.opsForHash().delete(VideoManagerConstants.SEND_RTP_INFO_CHANNEL + sendRtpInfo.getChannelId(), sendRtpInfo.getTargetId());
}
} }
@Override @Override
public void deleteByCallId(String callId) { public void deleteByCallId(String callId) {
@ -166,15 +155,12 @@ public class SendRtpServerServiceImpl implements ISendRtpServerService {
@Override @Override
public List<SendRtpInfo> queryAll() { public List<SendRtpInfo> queryAll() {
String key = VideoManagerConstants.SEND_RTP_INFO_CALLID + ":*"; String key = VideoManagerConstants.SEND_RTP_INFO_CALLID;
List<Object> queryResult = RedisUtil.scan(redisTemplate, key); List<Object> values = redisTemplate.opsForHash().values(key);
List<SendRtpInfo> result= new ArrayList<>(); List<SendRtpInfo> result= new ArrayList<>();
for (Object o : values) {
for (Object o : queryResult) { result.add((SendRtpInfo) o);
String keyItem = (String) o;
result.add((SendRtpInfo) redisTemplate.opsForValue().get(keyItem));
} }
return result; return result;
} }
@ -195,4 +181,80 @@ public class SendRtpServerServiceImpl implements ISendRtpServerService {
} }
return sendRtpInfos; return sendRtpInfos;
} }
private Set<Integer> getAllSendRtpPort() {
String key = VideoManagerConstants.SEND_RTP_INFO_CALLID;
List<Object> values = redisTemplate.opsForHash().values(key);
Set<Integer> result = new HashSet<>();
for (Object value : values) {
SendRtpInfo sendRtpInfo = (SendRtpInfo) value;
result.add(sendRtpInfo.getPort());
}
return result;
}
@Override
public synchronized int getNextPort(MediaServer mediaServer) {
if (mediaServer == null) {
log.warn("[发送端口管理] 参数错误mediaServer为NULL");
return -1;
}
String sendIndexKey = VideoManagerConstants.SEND_RTP_PORT + userSetting.getServerId() + ":" + mediaServer.getId();
Set<Integer> sendRtpSet = getAllSendRtpPort();
String sendRtpPortRange = mediaServer.getSendRtpPortRange();
int startPort;
int endPort;
if (sendRtpPortRange != null) {
String[] portArray = sendRtpPortRange.split(",");
if (portArray.length != 2 || !NumberUtils.isParsable(portArray[0]) || !NumberUtils.isParsable(portArray[1])) {
log.warn("{}发送端口配置格式错误自动使用50000-60000作为端口范围", mediaServer.getId());
startPort = 50000;
endPort = 60000;
}else {
if ( Integer.parseInt(portArray[1]) - Integer.parseInt(portArray[0]) < 1) {
log.warn("{}发送端口配置错误,结束端口至少比开始端口大一自动使用50000-60000作为端口范围", mediaServer.getId());
startPort = 50000;
endPort = 60000;
}else {
startPort = Integer.parseInt(portArray[0]);
endPort = Integer.parseInt(portArray[1]);
}
}
}else {
log.warn("{}未设置发送端口默认值自动使用50000-60000作为端口范围", mediaServer.getId());
startPort = 50000;
endPort = 60000;
}
if (redisTemplate == null || redisTemplate.getConnectionFactory() == null) {
log.warn("{}获取redis连接信息失败", mediaServer.getId());
return -1;
}
return getSendPort(startPort, endPort, sendIndexKey, sendRtpSet);
}
private synchronized int getSendPort(int startPort, int endPort, String sendIndexKey, Set<Integer> sendRtpPortSet){
// TODO 这里改为只取偶数端口
RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
if (redisAtomicInteger.get() < startPort) {
redisAtomicInteger.set(startPort);
return startPort;
}else {
int port = redisAtomicInteger.getAndIncrement();
if (port > endPort) {
redisAtomicInteger.set(startPort);
if (sendRtpPortSet.contains(startPort)) {
return getSendPort(startPort, endPort, sendIndexKey, sendRtpPortSet);
}else {
return startPort;
}
}
if (sendRtpPortSet.contains(port)) {
return getSendPort(startPort, endPort, sendIndexKey, sendRtpPortSet);
}else {
return port;
}
}
}
} }

View File

@ -10,16 +10,13 @@ import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest;
import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo;
import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaInfo;
import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.event.hook.Hook; import com.genersoft.iot.vmp.media.event.hook.Hook;
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.event.hook.HookType;
import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -41,10 +38,7 @@ public class RedisRpcController {
private IMediaServerService mediaServerService; private IMediaServerService mediaServerService;
@Autowired @Autowired
private SendRtpPortManager sendRtpPortManager; private ISendRtpServerService sendRtpServerService;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired @Autowired
private UserSetting userSetting; private UserSetting userSetting;
@ -56,13 +50,6 @@ public class RedisRpcController {
private RedisTemplate<Object, Object> redisTemplate; private RedisTemplate<Object, Object> redisTemplate;
@Autowired
private ISIPCommanderForPlatform commanderFroPlatform;
@Autowired
private ISendRtpServerService sendRtpServerService;
/** /**
* *
*/ */
@ -83,7 +70,7 @@ public class RedisRpcController {
response.setStatusCode(200); response.setStatusCode(200);
} }
// 自平台内容 // 自平台内容
int localPort = sendRtpPortManager.getNextPort(mediaServerItem); int localPort = sendRtpServerService.getNextPort(mediaServerItem);
if (localPort == 0) { if (localPort == 0) {
log.info("[redis-rpc] getSendRtpItem->服务器端口资源不足" ); log.info("[redis-rpc] getSendRtpItem->服务器端口资源不足" );
RedisRpcResponse response = request.getResponse(); RedisRpcResponse response = request.getResponse();

View File

@ -162,25 +162,25 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
@Override @Override
public void updateDevice(Device device) { public void updateDevice(Device device) {
String key = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId(); String key = VideoManagerConstants.DEVICE_PREFIX;
redisTemplate.opsForHash().put(key, device.getDeviceId(), device); redisTemplate.opsForHash().put(key, device.getDeviceId(), device);
} }
@Override @Override
public void removeDevice(String deviceId) { public void removeDevice(String deviceId) {
String key = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId(); String key = VideoManagerConstants.DEVICE_PREFIX;
redisTemplate.opsForHash().delete(key, deviceId); redisTemplate.opsForHash().delete(key, deviceId);
} }
@Override @Override
public void removeAllDevice() { public void removeAllDevice() {
String key = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId(); String key = VideoManagerConstants.DEVICE_PREFIX;
redisTemplate.delete(key); redisTemplate.delete(key);
} }
@Override @Override
public List<Device> getAllDevices() { public List<Device> getAllDevices() {
String key = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId(); String key = VideoManagerConstants.DEVICE_PREFIX;
List<Device> result = new ArrayList<>(); List<Device> result = new ArrayList<>();
List<Object> values = redisTemplate.opsForHash().values(key); List<Object> values = redisTemplate.opsForHash().values(key);
for (Object value : values) { for (Object value : values) {
@ -193,13 +193,16 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
@Override @Override
public Device getDevice(String deviceId) { public Device getDevice(String deviceId) {
String key = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId(); String key = VideoManagerConstants.DEVICE_PREFIX;
Device device = (Device)redisTemplate.opsForHash().get(key, deviceId); Device device;
if (device == null){ Object object = redisTemplate.opsForHash().get(key, deviceId);
if (object == null){
device = deviceMapper.getDeviceByDeviceId(deviceId); device = deviceMapper.getDeviceByDeviceId(deviceId);
if (device != null) { if (device != null) {
updateDevice(device); updateDevice(device);
} }
}else {
device = (Device)object;
} }
return device; return device;
} }
@ -418,9 +421,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
@Override @Override
public int getGbSendCount(String id) { public int getGbSendCount(String id) {
String key = VideoManagerConstants.SEND_RTP_INFO String key = VideoManagerConstants.SEND_RTP_INFO_CALLID;
+ userSetting.getServerId() + "_*_" + id + "_*"; return redisTemplate.opsForHash().size(key).intValue();
return RedisUtil.scan(redisTemplate, key).size();
} }
@Override @Override

View File

@ -64,17 +64,17 @@ public interface IStreamProxyService {
/** /**
* *
* @param mediaServerId * @param mediaServer
* @return * @return
*/ */
void zlmServerOnline(String mediaServerId); void zlmServerOnline(MediaServer mediaServer);
/** /**
* 线 * 线
* @param mediaServerId * @param mediaServer
* @return * @return
*/ */
void zlmServerOffline(String mediaServerId); void zlmServerOffline(MediaServer mediaServer);
/** /**
* *

View File

@ -121,7 +121,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
@EventListener @EventListener
@Transactional @Transactional
public void onApplicationEvent(MediaServerOnlineEvent event) { public void onApplicationEvent(MediaServerOnlineEvent event) {
zlmServerOnline(event.getMediaServerId()); zlmServerOnline(event.getMediaServer());
} }
/** /**
@ -131,7 +131,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
@EventListener @EventListener
@Transactional @Transactional
public void onApplicationEvent(MediaServerOfflineEvent event) { public void onApplicationEvent(MediaServerOfflineEvent event) {
zlmServerOffline(event.getMediaServerId()); zlmServerOffline(event.getMediaServer());
} }
@ -284,15 +284,14 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
@Override @Override
@Transactional @Transactional
public void zlmServerOnline(String mediaServerId) { public void zlmServerOnline(MediaServer mediaServer) {
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
if (mediaServer == null) { if (mediaServer == null) {
return; return;
} }
// 这里主要是控制数据库/redis缓存/以及zlm中存在的代理流 三者状态一致。以数据库中数据为根本 // 这里主要是控制数据库/redis缓存/以及zlm中存在的代理流 三者状态一致。以数据库中数据为根本
redisCatchStorage.removeStream(mediaServerId, "PULL"); redisCatchStorage.removeStream(mediaServer.getId(), "PULL");
List<StreamProxy> streamProxies = streamProxyMapper.selectForEnableInMediaServer(mediaServerId, true); List<StreamProxy> streamProxies = streamProxyMapper.selectForEnableInMediaServer(mediaServer.getId(), true);
if (streamProxies.isEmpty()) { if (streamProxies.isEmpty()) {
return; return;
} }
@ -359,11 +358,11 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
} }
@Override @Override
public void zlmServerOffline(String mediaServerId) { public void zlmServerOffline(MediaServer mediaServer) {
List<StreamProxy> streamProxies = streamProxyMapper.selectForEnableInMediaServer(mediaServerId, true); List<StreamProxy> streamProxies = streamProxyMapper.selectForEnableInMediaServer(mediaServer.getId(), true);
// 清理redis相关的缓存 // 清理redis相关的缓存
redisCatchStorage.removeStream(mediaServerId, "PULL"); redisCatchStorage.removeStream(mediaServer.getId(), "PULL");
if (streamProxies.isEmpty()) { if (streamProxies.isEmpty()) {
return; return;
@ -395,7 +394,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
jsonObject.put("app", streamProxy.getApp()); jsonObject.put("app", streamProxy.getApp());
jsonObject.put("stream", streamProxy.getStream()); jsonObject.put("stream", streamProxy.getStream());
jsonObject.put("register", false); jsonObject.put("register", false);
jsonObject.put("mediaServerId", mediaServerId); jsonObject.put("mediaServerId", mediaServer);
redisCatchStorage.sendStreamChangeMsg("pull", jsonObject); redisCatchStorage.sendStreamChangeMsg("pull", jsonObject);
} }
} }

View File

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.streamPush.service; package com.genersoft.iot.vmp.streamPush.service;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import com.genersoft.iot.vmp.streamPush.bean.StreamPush;
@ -36,12 +37,12 @@ public interface IStreamPushService {
/** /**
* *
*/ */
void zlmServerOnline(String mediaServerId); void zlmServerOnline(MediaServer mediaServer);
/** /**
* 线 * 线
*/ */
void zlmServerOffline(String mediaServerId); void zlmServerOffline(MediaServer mediaServer);
/** /**
* *

View File

@ -159,7 +159,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
@EventListener @EventListener
@Transactional @Transactional
public void onApplicationEvent(MediaServerOnlineEvent event) { public void onApplicationEvent(MediaServerOnlineEvent event) {
zlmServerOnline(event.getMediaServerId()); zlmServerOnline(event.getMediaServer());
} }
/** /**
@ -169,7 +169,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
@EventListener @EventListener
@Transactional @Transactional
public void onApplicationEvent(MediaServerOfflineEvent event) { public void onApplicationEvent(MediaServerOfflineEvent event) {
zlmServerOffline(event.getMediaServerId()); zlmServerOffline(event.getMediaServer());
} }
@Override @Override
@ -310,17 +310,16 @@ public class StreamPushServiceImpl implements IStreamPushService {
@Override @Override
@Transactional @Transactional
public void zlmServerOnline(String mediaServerId) { public void zlmServerOnline(MediaServer mediaServer) {
// 同步zlm推流信息 // 同步zlm推流信息
MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId); if (mediaServer == null) {
if (mediaServerItem == null) {
return; return;
} }
// 数据库记录 // 数据库记录
List<StreamPush> pushList = getPushList(mediaServerId); List<StreamPush> pushList = getPushList(mediaServer.getId());
Map<String, StreamPush> pushItemMap = new HashMap<>(); Map<String, StreamPush> pushItemMap = new HashMap<>();
// redis记录 // redis记录
List<MediaInfo> mediaInfoList = redisCatchStorage.getStreams(mediaServerId, "PUSH"); List<MediaInfo> mediaInfoList = redisCatchStorage.getStreams(mediaServer.getId(), "PUSH");
Map<String, MediaInfo> streamInfoPushItemMap = new HashMap<>(); Map<String, MediaInfo> streamInfoPushItemMap = new HashMap<>();
if (!pushList.isEmpty()) { if (!pushList.isEmpty()) {
for (StreamPush streamPushItem : pushList) { for (StreamPush streamPushItem : pushList) {
@ -340,7 +339,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
for (StreamAuthorityInfo streamAuthorityInfo : allStreamAuthorityInfo) { for (StreamAuthorityInfo streamAuthorityInfo : allStreamAuthorityInfo) {
streamAuthorityInfoInfoMap.put(streamAuthorityInfo.getApp() + streamAuthorityInfo.getStream(), streamAuthorityInfo); streamAuthorityInfoInfoMap.put(streamAuthorityInfo.getApp() + streamAuthorityInfo.getStream(), streamAuthorityInfo);
} }
List<StreamInfo> mediaList = mediaServerService.getMediaList(mediaServerItem, null, null, null); List<StreamInfo> mediaList = mediaServerService.getMediaList(mediaServer, null, null, null);
if (mediaList == null) { if (mediaList == null) {
return; return;
} }
@ -368,12 +367,12 @@ public class StreamPushServiceImpl implements IStreamPushService {
jsonObject.put("app", mediaInfo.getApp()); jsonObject.put("app", mediaInfo.getApp());
jsonObject.put("stream", mediaInfo.getStream()); jsonObject.put("stream", mediaInfo.getStream());
jsonObject.put("register", false); jsonObject.put("register", false);
jsonObject.put("mediaServerId", mediaServerId); jsonObject.put("mediaServerId", mediaServer.getId());
redisCatchStorage.sendStreamChangeMsg(type, jsonObject); redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
// 移除redis内流的信息 // 移除redis内流的信息
redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", mediaInfo.getApp(), mediaInfo.getStream()); redisCatchStorage.removeStream(mediaServer.getId(), "PUSH", mediaInfo.getApp(), mediaInfo.getStream());
// 冗余数据,自己系统中自用 // 冗余数据,自己系统中自用
redisCatchStorage.removePushListItem(mediaInfo.getApp(), mediaInfo.getStream(), mediaServerItem.getId()); redisCatchStorage.removePushListItem(mediaInfo.getApp(), mediaInfo.getStream(), mediaServer.getId());
} }
} }
@ -388,8 +387,8 @@ public class StreamPushServiceImpl implements IStreamPushService {
@Override @Override
@Transactional @Transactional
public void zlmServerOffline(String mediaServerId) { public void zlmServerOffline(MediaServer mediaServer) {
List<StreamPush> streamPushItems = streamPushMapper.selectAllByMediaServerId(mediaServerId); List<StreamPush> streamPushItems = streamPushMapper.selectAllByMediaServerId(mediaServer.getId());
if (!streamPushItems.isEmpty()) { if (!streamPushItems.isEmpty()) {
for (StreamPush streamPushItem : streamPushItems) { for (StreamPush streamPushItem : streamPushItems) {
stop(streamPushItem); stop(streamPushItem);
@ -403,21 +402,21 @@ public class StreamPushServiceImpl implements IStreamPushService {
// 发送流停止消息 // 发送流停止消息
String type = "PUSH"; String type = "PUSH";
// 发送redis消息 // 发送redis消息
List<MediaInfo> mediaInfoList = redisCatchStorage.getStreams(mediaServerId, type); List<MediaInfo> mediaInfoList = redisCatchStorage.getStreams(mediaServer.getId(), type);
if (!mediaInfoList.isEmpty()) { if (!mediaInfoList.isEmpty()) {
for (MediaInfo mediaInfo : mediaInfoList) { for (MediaInfo mediaInfo : mediaInfoList) {
// 移除redis内流的信息 // 移除redis内流的信息
redisCatchStorage.removeStream(mediaServerId, type, mediaInfo.getApp(), mediaInfo.getStream()); redisCatchStorage.removeStream(mediaServer.getId(), type, mediaInfo.getApp(), mediaInfo.getStream());
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("serverId", userSetting.getServerId()); jsonObject.put("serverId", userSetting.getServerId());
jsonObject.put("app", mediaInfo.getApp()); jsonObject.put("app", mediaInfo.getApp());
jsonObject.put("stream", mediaInfo.getStream()); jsonObject.put("stream", mediaInfo.getStream());
jsonObject.put("register", false); jsonObject.put("register", false);
jsonObject.put("mediaServerId", mediaServerId); jsonObject.put("mediaServerId", mediaServer.getId());
redisCatchStorage.sendStreamChangeMsg(type, jsonObject); redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
// 冗余数据,自己系统中自用 // 冗余数据,自己系统中自用
redisCatchStorage.removePushListItem(mediaInfo.getApp(), mediaInfo.getStream(), mediaServerId); redisCatchStorage.removePushListItem(mediaInfo.getApp(), mediaInfo.getStream(), mediaServer.getId());
} }
} }
} }

View File

@ -11,7 +11,7 @@ import com.genersoft.iot.vmp.media.event.hook.Hook;
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.event.hook.HookType;
import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
@ -28,9 +28,7 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -48,7 +46,7 @@ public class PsController {
private IMediaServerService mediaServerService; private IMediaServerService mediaServerService;
@Autowired @Autowired
private SendRtpPortManager sendRtpPortManager; private ISendRtpServerService sendRtpServerService;
@Autowired @Autowired
private UserSetting userSetting; private UserSetting userSetting;
@ -133,7 +131,7 @@ public class PsController {
if (isSend != null && isSend) { if (isSend != null && isSend) {
String key = VideoManagerConstants.WVP_OTHER_SEND_PS_INFO + userSetting.getServerId() + "_" + callId; String key = VideoManagerConstants.WVP_OTHER_SEND_PS_INFO + userSetting.getServerId() + "_" + callId;
// 预创建发流信息 // 预创建发流信息
int port = sendRtpPortManager.getNextPort(mediaServer); int port = sendRtpServerService.getNextPort(mediaServer);
otherPsSendInfo.setSendLocalIp(mediaServer.getSdpIp()); otherPsSendInfo.setSendLocalIp(mediaServer.getSdpIp());
otherPsSendInfo.setSendLocalPort(port); otherPsSendInfo.setSendLocalPort(port);
@ -249,11 +247,6 @@ public class PsController {
if (sendInfo == null){ if (sendInfo == null){
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未开启发流"); throw new ControllerException(ErrorCode.ERROR100.getCode(), "未开启发流");
} }
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app",sendInfo.getPushApp());
param.put("stream",sendInfo.getPushStream());
param.put("ssrc",sendInfo.getPushSSRC());
MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer(); MediaServer mediaServerItem = mediaServerService.getDefaultMediaServer();
boolean result = mediaServerService.stopSendRtp(mediaServerItem, sendInfo.getPushApp(), sendInfo.getStream(), sendInfo.getPushSSRC()); boolean result = mediaServerService.stopSendRtp(mediaServerItem, sendInfo.getPushApp(), sendInfo.getStream(), sendInfo.getPushSSRC());
if (!result) { if (!result) {
@ -283,6 +276,6 @@ public class PsController {
// }).start(); // }).start();
// } // }
return sendRtpPortManager.getNextPort(defaultMediaServer); return sendRtpServerService.getNextPort(defaultMediaServer);
} }
} }

View File

@ -11,7 +11,7 @@ import com.genersoft.iot.vmp.media.event.hook.Hook;
import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe;
import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.event.hook.HookType;
import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; import com.genersoft.iot.vmp.service.ISendRtpServerService;
import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.utils.redis.RedisUtil; import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit;
public class RtpController { public class RtpController {
@Autowired @Autowired
private SendRtpPortManager sendRtpPortManager; private ISendRtpServerService sendRtpServerService;
@Autowired @Autowired
private HookSubscribe hookSubscribe; private HookSubscribe hookSubscribe;
@ -130,8 +130,8 @@ public class RtpController {
redisTemplate.opsForValue().set(receiveKey, otherRtpSendInfo); redisTemplate.opsForValue().set(receiveKey, otherRtpSendInfo);
if (isSend != null && isSend) { if (isSend != null && isSend) {
// 预创建发流信息 // 预创建发流信息
int portForVideo = sendRtpPortManager.getNextPort(mediaServer); int portForVideo = sendRtpServerService.getNextPort(mediaServer);
int portForAudio = sendRtpPortManager.getNextPort(mediaServer); int portForAudio = sendRtpServerService.getNextPort(mediaServer);
otherRtpSendInfo.setSendLocalIp(mediaServer.getSdpIp()); otherRtpSendInfo.setSendLocalIp(mediaServer.getSdpIp());
otherRtpSendInfo.setSendLocalPortForVideo(portForVideo); otherRtpSendInfo.setSendLocalPortForVideo(portForVideo);

View File

@ -139,7 +139,11 @@ public class ServerController {
@DeleteMapping(value = "/media_server/delete") @DeleteMapping(value = "/media_server/delete")
@ResponseBody @ResponseBody
public void deleteMediaServer(@RequestParam String id) { public void deleteMediaServer(@RequestParam String id) {
mediaServerService.delete(id); MediaServer mediaServer = mediaServerService.getOne(id);
if(mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "流媒体不存在");
}
mediaServerService.delete(mediaServer);
} }