Merge branch 'wvp-28181-2.0'
# Conflicts: # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
This commit is contained in:
@@ -31,6 +31,8 @@ public class StreamInfo {
|
||||
private String rtsp;
|
||||
private String rtsps;
|
||||
private String rtc;
|
||||
|
||||
private String rtcs;
|
||||
private String mediaServerId;
|
||||
private Object tracks;
|
||||
private String startTime;
|
||||
@@ -302,4 +304,12 @@ public class StreamInfo {
|
||||
public void setIp(String ip) {
|
||||
this.ip = ip;
|
||||
}
|
||||
|
||||
public String getRtcs() {
|
||||
return rtcs;
|
||||
}
|
||||
|
||||
public void setRtcs(String rtcs) {
|
||||
this.rtcs = rtcs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ public class VideoManagerConstants {
|
||||
|
||||
public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
|
||||
|
||||
public static final String MEDIA_SERVER_KEEPALIVE_PREFIX = "VMP_MEDIA_SERVER_KEEPALIVE_";
|
||||
|
||||
public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_";
|
||||
|
||||
public static final String MEDIA_STREAM_PREFIX = "VMP_MEDIA_STREAM";
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class RedisKeyExpirationEventMessageListener extends KeyExpirationEventMessageListener {
|
||||
|
||||
private UserSetting userSetting;
|
||||
private RedisMessageListenerContainer listenerContainer;
|
||||
private String keyspaceNotificationsConfigParameter = "EA";
|
||||
|
||||
public RedisKeyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer, UserSetting userSetting) {
|
||||
super(listenerContainer);
|
||||
this.listenerContainer = listenerContainer;
|
||||
this.userSetting = userSetting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
if (!userSetting.getRedisConfig()) {
|
||||
// 配置springboot默认Config为空,即不让应用去修改redis的默认配置,因为Redis服务出于安全会禁用CONFIG命令给远程用户使用
|
||||
setKeyspaceNotificationsConfigParameter("");
|
||||
}else {
|
||||
|
||||
RedisConnection connection = this.listenerContainer.getConnectionFactory().getConnection();
|
||||
Properties config = connection.getConfig("notify-keyspace-events");
|
||||
try {
|
||||
if (!keyspaceNotificationsConfigParameter.equals(config.getProperty("notify-keyspace-events"))) {
|
||||
connection.setConfig("notify-keyspace-events", keyspaceNotificationsConfigParameter);
|
||||
}
|
||||
} finally {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
super.init();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.service.IPlatformService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -15,6 +16,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统启动时控制上级平台重新注册
|
||||
* @author lin
|
||||
*/
|
||||
@Component
|
||||
@Order(value=3)
|
||||
@@ -27,7 +29,7 @@ public class SipPlatformRunner implements CommandLineRunner {
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private EventPublisher publisher;
|
||||
private IPlatformService platformService;
|
||||
|
||||
@Autowired
|
||||
private ISIPCommanderForPlatform sipCommanderForPlatform;
|
||||
@@ -35,33 +37,26 @@ public class SipPlatformRunner implements CommandLineRunner {
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
// 设置所有平台离线
|
||||
storager.outlineForAllParentPlatform();
|
||||
|
||||
// 清理所有平台注册缓存
|
||||
redisCatchStorage.cleanPlatformRegisterInfos();
|
||||
|
||||
// 停止所有推流
|
||||
// zlmrtpServerFactory.closeAllSendRtpStream();
|
||||
|
||||
// 获取所有启用的平台
|
||||
List<ParentPlatform> parentPlatforms = storager.queryEnableParentPlatformList(true);
|
||||
|
||||
for (ParentPlatform parentPlatform : parentPlatforms) {
|
||||
redisCatchStorage.updatePlatformRegister(parentPlatform);
|
||||
|
||||
redisCatchStorage.updatePlatformKeepalive(parentPlatform);
|
||||
|
||||
// 更新缓存
|
||||
ParentPlatformCatch parentPlatformCatch = new ParentPlatformCatch();
|
||||
|
||||
parentPlatformCatch.setParentPlatform(parentPlatform);
|
||||
parentPlatformCatch.setId(parentPlatform.getServerGBId());
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
if (parentPlatform.isStatus()) {
|
||||
// 设置所有平台离线
|
||||
platformService.offline(parentPlatform);
|
||||
// 取消订阅
|
||||
sipCommanderForPlatform.unregister(parentPlatform, null, (eventResult)->{
|
||||
platformService.login(parentPlatform);
|
||||
});
|
||||
}else {
|
||||
platformService.login(parentPlatform);
|
||||
}
|
||||
|
||||
// 取消订阅
|
||||
sipCommanderForPlatform.unregister(parentPlatform, null, (eventResult)->{
|
||||
// 发送平台未注册消息
|
||||
publisher.platformNotRegisterEventPublish(parentPlatform.getServerGBId());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@ public class UserSetting {
|
||||
|
||||
private Boolean logInDatebase = Boolean.TRUE;
|
||||
|
||||
private Boolean redisConfig = Boolean.TRUE;
|
||||
|
||||
private String serverId = "000000";
|
||||
|
||||
private String thirdPartyGBIdReg = "[\\s\\S]*";
|
||||
@@ -123,14 +121,6 @@ public class UserSetting {
|
||||
this.thirdPartyGBIdReg = thirdPartyGBIdReg;
|
||||
}
|
||||
|
||||
public Boolean getRedisConfig() {
|
||||
return redisConfig;
|
||||
}
|
||||
|
||||
public void setRedisConfig(Boolean redisConfig) {
|
||||
this.redisConfig = redisConfig;
|
||||
}
|
||||
|
||||
public Boolean getRecordSip() {
|
||||
return recordSip;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.genersoft.iot.vmp.conf.security;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import org.apache.poi.hssf.eventmodel.ERFListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@@ -28,8 +30,8 @@ public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoi
|
||||
response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
|
||||
response.setHeader("Content-type", "application/json;charset=UTF-8");
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("code", "-1");
|
||||
jsonObject.put("msg", "请登录后重新请求");
|
||||
jsonObject.put("code", ErrorCode.ERROR401.getCode());
|
||||
jsonObject.put("msg", ErrorCode.ERROR401.getMsg());
|
||||
String logUri = "api/user/login";
|
||||
if (request.getRequestURI().contains(logUri)){
|
||||
jsonObject.put("msg", e.getMessage());
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.genersoft.iot.vmp.conf.security;
|
||||
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.SessionCookieConfig;
|
||||
import javax.servlet.SessionTrackingMode;
|
||||
import java.util.Collections;
|
||||
|
||||
public class UrlTokenHandler extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
super.onStartup(servletContext);
|
||||
|
||||
servletContext.setSessionTrackingModes(
|
||||
Collections.singleton(SessionTrackingMode.COOKIE)
|
||||
);
|
||||
SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig();
|
||||
sessionCookieConfig.setHttpOnly(true);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,10 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.*;
|
||||
import java.util.Properties;
|
||||
import java.util.TooManyListenersException;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Configuration
|
||||
public class SipLayer{
|
||||
@@ -52,7 +48,9 @@ public class SipLayer{
|
||||
* 完整配置参考 gov.nist.javax.sip.SipStackImpl,需要下载源码
|
||||
* gov/nist/javax/sip/SipStackImpl.class
|
||||
*/
|
||||
properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "true");
|
||||
if (logger.isDebugEnabled()) {
|
||||
properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "false");
|
||||
}
|
||||
// 接收所有notify请求,即使没有订阅
|
||||
properties.setProperty("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "true");
|
||||
// 为_NULL _对话框传递_终止的_事件
|
||||
@@ -63,13 +61,13 @@ public class SipLayer{
|
||||
properties.setProperty("gov.nist.javax.sip.RELIABLE_CONNECTION_KEEP_ALIVE_TIMEOUT", "60");
|
||||
|
||||
/**
|
||||
* sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE =
|
||||
* 0; public static final int TRACE_MESSAGES = 16; public static final int
|
||||
* TRACE_EXCEPTION = 17; public static final int TRACE_DEBUG = 32;
|
||||
* sip_server_log.log 和 sip_debug_log.log ERROR, INFO, WARNING, OFF, DEBUG, TRACE
|
||||
*/
|
||||
properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "0");
|
||||
properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sip_server_log");
|
||||
properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sip_debug_log");
|
||||
properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "ERROR");
|
||||
// if (logger.isDebugEnabled()) {
|
||||
// properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "DEBUG");
|
||||
// }
|
||||
|
||||
sipStack = (SipStackImpl) sipFactory.createSipStack(properties);
|
||||
|
||||
return sipStack;
|
||||
|
||||
@@ -84,7 +84,7 @@ public class ParentPlatform {
|
||||
* 注册周期 (秒)
|
||||
*/
|
||||
@Schema(description = "注册周期 (秒)")
|
||||
private String expires;
|
||||
private int expires;
|
||||
|
||||
/**
|
||||
* 心跳周期(秒)
|
||||
@@ -286,11 +286,11 @@ public class ParentPlatform {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getExpires() {
|
||||
public int getExpires() {
|
||||
return expires;
|
||||
}
|
||||
|
||||
public void setExpires(String expires) {
|
||||
public void setExpires(int expires) {
|
||||
this.expires = expires;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ public class ParentPlatformCatch {
|
||||
|
||||
private String id;
|
||||
|
||||
// 心跳未回复次数
|
||||
/**
|
||||
* 心跳未回复次数
|
||||
*/
|
||||
private int keepAliveReply;
|
||||
|
||||
// 注册未回复次数
|
||||
|
||||
@@ -14,6 +14,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author lin
|
||||
*/
|
||||
@Component
|
||||
public class SubscribeHolder {
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@ package com.genersoft.iot.vmp.gb28181.event;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
|
||||
import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent;
|
||||
import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformCycleRegisterEvent;
|
||||
import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent;
|
||||
import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
|
||||
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
|
||||
import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
|
||||
@@ -31,36 +28,6 @@ public class EventPublisher {
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
/**
|
||||
* 平台心跳到期事件
|
||||
* @param platformGbId
|
||||
*/
|
||||
public void platformKeepaliveExpireEventPublish(String platformGbId){
|
||||
PlatformKeepaliveExpireEvent platformKeepaliveExpireEvent = new PlatformKeepaliveExpireEvent(this);
|
||||
platformKeepaliveExpireEvent.setPlatformGbID(platformGbId);
|
||||
applicationEventPublisher.publishEvent(platformKeepaliveExpireEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台未注册事件
|
||||
* @param platformGbId
|
||||
*/
|
||||
public void platformNotRegisterEventPublish(String platformGbId){
|
||||
PlatformNotRegisterEvent platformNotRegisterEvent = new PlatformNotRegisterEvent(this);
|
||||
platformNotRegisterEvent.setPlatformGbID(platformGbId);
|
||||
applicationEventPublisher.publishEvent(platformNotRegisterEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台周期注册事件
|
||||
* @param paltformGbId
|
||||
*/
|
||||
public void platformRegisterCycleEventPublish(String paltformGbId) {
|
||||
PlatformCycleRegisterEvent platformCycleRegisterEvent = new PlatformCycleRegisterEvent(this);
|
||||
platformCycleRegisterEvent.setPlatformGbID(paltformGbId);
|
||||
applicationEventPublisher.publishEvent(platformCycleRegisterEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备报警事件
|
||||
|
||||
@@ -59,9 +59,25 @@ public class SipSubscribe {
|
||||
void response(EventResult eventResult);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public enum EventResultType{
|
||||
// 超时
|
||||
timeout,
|
||||
// 回复
|
||||
response,
|
||||
// 事务已结束
|
||||
transactionTerminated,
|
||||
// 会话已结束
|
||||
dialogTerminated,
|
||||
// 设备未找到
|
||||
deviceNotFoundEvent
|
||||
}
|
||||
|
||||
public static class EventResult<EventObject>{
|
||||
public int statusCode;
|
||||
public String type;
|
||||
public EventResultType type;
|
||||
public String msg;
|
||||
public String callId;
|
||||
public Dialog dialog;
|
||||
@@ -76,7 +92,7 @@ public class SipSubscribe {
|
||||
ResponseEvent responseEvent = (ResponseEvent)event;
|
||||
Response response = responseEvent.getResponse();
|
||||
this.dialog = responseEvent.getDialog();
|
||||
this.type = "response";
|
||||
this.type = EventResultType.response;
|
||||
if (response != null) {
|
||||
this.msg = response.getReasonPhrase();
|
||||
this.statusCode = response.getStatusCode();
|
||||
@@ -85,28 +101,28 @@ public class SipSubscribe {
|
||||
|
||||
}else if (event instanceof TimeoutEvent) {
|
||||
TimeoutEvent timeoutEvent = (TimeoutEvent)event;
|
||||
this.type = "timeout";
|
||||
this.type = EventResultType.timeout;
|
||||
this.msg = "消息超时未回复";
|
||||
this.statusCode = -1024;
|
||||
this.dialog = timeoutEvent.getClientTransaction().getDialog();
|
||||
this.callId = this.dialog != null?timeoutEvent.getClientTransaction().getDialog().getCallId().getCallId(): null;
|
||||
}else if (event instanceof TransactionTerminatedEvent) {
|
||||
TransactionTerminatedEvent transactionTerminatedEvent = (TransactionTerminatedEvent)event;
|
||||
this.type = "transactionTerminated";
|
||||
this.type = EventResultType.transactionTerminated;
|
||||
this.msg = "事务已结束";
|
||||
this.statusCode = -1024;
|
||||
this.callId = transactionTerminatedEvent.getClientTransaction().getDialog().getCallId().getCallId();
|
||||
this.dialog = transactionTerminatedEvent.getClientTransaction().getDialog();
|
||||
}else if (event instanceof DialogTerminatedEvent) {
|
||||
DialogTerminatedEvent dialogTerminatedEvent = (DialogTerminatedEvent)event;
|
||||
this.type = "dialogTerminated";
|
||||
this.type = EventResultType.dialogTerminated;
|
||||
this.msg = "会话已结束";
|
||||
this.statusCode = -1024;
|
||||
this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId();
|
||||
this.dialog = dialogTerminatedEvent.getDialog();
|
||||
}else if (event instanceof DeviceNotFoundEvent) {
|
||||
DeviceNotFoundEvent deviceNotFoundEvent = (DeviceNotFoundEvent)event;
|
||||
this.type = "deviceNotFoundEvent";
|
||||
this.type = EventResultType.deviceNotFoundEvent;
|
||||
this.msg = "设备未找到";
|
||||
this.statusCode = -1024;
|
||||
this.dialog = deviceNotFoundEvent.getDialog();
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* 平台心跳超时事件
|
||||
*/
|
||||
public class PlatformKeepaliveExpireEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* Add default serial version ID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String platformGbID;
|
||||
|
||||
public PlatformKeepaliveExpireEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public String getPlatformGbID() {
|
||||
return platformGbID;
|
||||
}
|
||||
|
||||
public void setPlatformGbID(String platformGbID) {
|
||||
this.platformGbID = platformGbID;
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.message.Response;
|
||||
|
||||
/**
|
||||
* @description: 平台心跳超时事件
|
||||
* @author: panll
|
||||
* @date: 2020年11月5日 10:00
|
||||
*/
|
||||
@Component
|
||||
public class PlatformKeepaliveExpireEventLister implements ApplicationListener<PlatformKeepaliveExpireEvent> {
|
||||
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(PlatformKeepaliveExpireEventLister.class);
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorage storager;
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private ISIPCommanderForPlatform sipCommanderForPlatform;
|
||||
|
||||
@Autowired
|
||||
private SipSubscribe sipSubscribe;
|
||||
|
||||
@Autowired
|
||||
private EventPublisher publisher;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(@NotNull PlatformKeepaliveExpireEvent event) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("平台心跳到期事件事件触发,平台国标ID:" + event.getPlatformGbID());
|
||||
}
|
||||
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformGbID());
|
||||
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(event.getPlatformGbID());
|
||||
if (parentPlatformCatch == null) {
|
||||
return;
|
||||
}
|
||||
if (parentPlatform == null) {
|
||||
logger.debug("平台心跳到期事件事件触发,但平台已经删除!!! 平台国标ID:" + event.getPlatformGbID());
|
||||
return;
|
||||
}
|
||||
parentPlatformCatch.setParentPlatform(parentPlatform);
|
||||
// 发送心跳
|
||||
if (parentPlatformCatch.getKeepAliveReply() >= 3) {
|
||||
// 有3次未收到心跳回复, 设置平台状态为离线, 开始重新注册
|
||||
logger.warn("有3次未收到心跳回复,标记设置平台状态为离线, 并重新注册 平台国标ID:" + event.getPlatformGbID());
|
||||
storager.updateParentPlatformStatus(event.getPlatformGbID(), false);
|
||||
publisher.platformNotRegisterEventPublish(event.getPlatformGbID());
|
||||
parentPlatformCatch.setKeepAliveReply(0);
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
}else {
|
||||
// 再次发送心跳
|
||||
String callId = sipCommanderForPlatform.keepalive(parentPlatform);
|
||||
|
||||
parentPlatformCatch.setKeepAliveReply( parentPlatformCatch.getKeepAliveReply() + 1);
|
||||
// 存储心跳信息, 并设置状态为未回复, 如果多次过期仍未收到回复,则认为上级平台已经离线
|
||||
redisCatchStorage.updatePlatformKeepalive(parentPlatform);
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
|
||||
sipSubscribe.addOkSubscribe(callId, (SipSubscribe.EventResult eventResult) ->{
|
||||
if (eventResult.statusCode == Response.OK) {
|
||||
// 收到心跳响应信息,
|
||||
parentPlatformCatch.setKeepAliveReply(0);
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
public class PlatformCycleRegisterEvent extends ApplicationEvent {
|
||||
/**
|
||||
* Add default serial version ID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String platformGbID;
|
||||
|
||||
public String getPlatformGbID() {
|
||||
return platformGbID;
|
||||
}
|
||||
|
||||
public void setPlatformGbID(String platformGbID) {
|
||||
this.platformGbID = platformGbID;
|
||||
}
|
||||
|
||||
public PlatformCycleRegisterEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@Component
|
||||
public class PlatformCycleRegisterEventLister implements ApplicationListener<PlatformCycleRegisterEvent> {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(PlatformCycleRegisterEventLister.class);
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorage storager;
|
||||
@Autowired
|
||||
private ISIPCommanderForPlatform sipCommanderFroPlatform;
|
||||
@Autowired
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(PlatformCycleRegisterEvent event) {
|
||||
logger.info("上级平台周期注册事件");
|
||||
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformGbID());
|
||||
if (parentPlatform == null) {
|
||||
logger.info("[ 平台未注册事件 ] 平台已经删除!!! 平台国标ID:" + event.getPlatformGbID());
|
||||
return;
|
||||
}
|
||||
String taskKey = "platform-cycle-register" + parentPlatform.getServerGBId();;
|
||||
SipSubscribe.Event okEvent = (responseEvent)->{
|
||||
dynamicTask.stop(taskKey);
|
||||
};
|
||||
dynamicTask.startCron(taskKey, ()->{
|
||||
logger.info("[平台注册]再次向平台注册,平台国标ID:" + event.getPlatformGbID());
|
||||
sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
|
||||
}, Integer.parseInt(parentPlatform.getExpires())* 1000);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
public class PlatformNotRegisterEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* Add default serial version ID
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String platformGbID;
|
||||
|
||||
public PlatformNotRegisterEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public String getPlatformGbID() {
|
||||
return platformGbID;
|
||||
}
|
||||
|
||||
public void setPlatformGbID(String platformGbID) {
|
||||
this.platformGbID = platformGbID;
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @description: 平台未注册事件,来源有二:
|
||||
* 1、平台新添加
|
||||
* 2、平台心跳超时
|
||||
* @author: panll
|
||||
* @date: 2020年11月24日 10:00
|
||||
*/
|
||||
@Component
|
||||
public class PlatformNotRegisterEventLister implements ApplicationListener<PlatformNotRegisterEvent> {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(PlatformNotRegisterEventLister.class);
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorage storager;
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private SIPCommanderFroPlatform sipCommanderFroPlatform;
|
||||
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
@Autowired
|
||||
private SipConfig config;
|
||||
|
||||
@Autowired
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
// @Autowired
|
||||
// private RedisUtil redis;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(PlatformNotRegisterEvent event) {
|
||||
|
||||
logger.info("[ 平台未注册事件 ]平台国标ID:" + event.getPlatformGbID());
|
||||
|
||||
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformGbID());
|
||||
if (parentPlatform == null) {
|
||||
logger.info("[ 平台未注册事件 ] 平台已经删除!!! 平台国标ID:" + event.getPlatformGbID());
|
||||
return;
|
||||
}
|
||||
// 查询是否有推流, 如果有则都停止
|
||||
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServer(event.getPlatformGbID());
|
||||
if (sendRtpItems != null && sendRtpItems.size() > 0) {
|
||||
logger.info("[ 平台未注册事件 ] 停止[ {} ]的所有推流", event.getPlatformGbID());
|
||||
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
||||
redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItem.getChannelId(), null, null);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", sendRtpItem.getApp());
|
||||
param.put("stream", sendRtpItem.getStreamId());
|
||||
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
|
||||
}
|
||||
|
||||
}
|
||||
String taskKey = "platform-not-register-" + parentPlatform.getServerGBId();
|
||||
SipSubscribe.Event okEvent = (responseEvent)->{
|
||||
dynamicTask.stop(taskKey);
|
||||
};
|
||||
dynamicTask.startCron(taskKey, ()->{
|
||||
logger.info("[平台注册]再次向平台注册,平台国标ID:" + event.getPlatformGbID());
|
||||
sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
|
||||
}, config.getRegisterTimeInterval()* 1000);
|
||||
}
|
||||
}
|
||||
@@ -30,23 +30,10 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
|
||||
|
||||
@Autowired
|
||||
private IVideoManagerStorage storager;
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private SIPCommanderFroPlatform sipCommanderFroPlatform;
|
||||
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
@Autowired
|
||||
private SipConfig config;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
@Autowired
|
||||
private IGbStreamService gbStreamService;
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
|
||||
// TODO 暂时只处理视频流的回复,后续增加对国标设备的支持
|
||||
List<DeviceChannel> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId());
|
||||
if (gbStreams.size() == 0) {
|
||||
logger.info("发送订阅时发现平台已经没有关联的直播流:{}", platform.getServerGBId());
|
||||
return;
|
||||
}
|
||||
for (DeviceChannel deviceChannel : gbStreams) {
|
||||
|
||||
@@ -71,7 +71,6 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
|
||||
@Override
|
||||
@Async
|
||||
public void processRequest(RequestEvent requestEvent) {
|
||||
logger.debug("\n收到请求:\n{}", requestEvent.getRequest());
|
||||
String method = requestEvent.getRequest().getMethod();
|
||||
ISIPRequestProcessor sipRequestProcessor = requestProcessorMap.get(method);
|
||||
if (sipRequestProcessor == null) {
|
||||
@@ -90,7 +89,6 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
|
||||
@Async
|
||||
public void processResponse(ResponseEvent responseEvent) {
|
||||
Response response = responseEvent.getResponse();
|
||||
logger.debug("\n收到响应:\n{}", responseEvent.getResponse());
|
||||
int status = response.getStatusCode();
|
||||
|
||||
if (((status >= 200) && (status < 300)) || status == Response.UNAUTHORIZED) { // Success!
|
||||
@@ -114,7 +112,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
|
||||
} else if ((status >= 100) && (status < 200)) {
|
||||
// 增加其它无需回复的响应,如101、180等
|
||||
} else {
|
||||
logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
|
||||
logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase());
|
||||
if (responseEvent.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) {
|
||||
CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME);
|
||||
if (callIdHeader != null) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import gov.nist.javax.sip.message.SIPRequest;
|
||||
@@ -98,7 +98,7 @@ public interface ISIPCommander {
|
||||
* @param device 视频设备
|
||||
* @param channelId 预览通道
|
||||
*/
|
||||
void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
|
||||
void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
|
||||
|
||||
/**
|
||||
* 请求回放视频流
|
||||
|
||||
@@ -15,7 +15,7 @@ public interface ISIPCommanderForPlatform {
|
||||
* @return
|
||||
*/
|
||||
boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent);
|
||||
boolean register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain);
|
||||
boolean register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister);
|
||||
|
||||
/**
|
||||
* 向上级平台注销
|
||||
@@ -30,7 +30,7 @@ public interface ISIPCommanderForPlatform {
|
||||
* @param parentPlatform
|
||||
* @return callId(作为接受回复的判定)
|
||||
*/
|
||||
String keepalive(ParentPlatform parentPlatform);
|
||||
String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.HeaderUtils;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import gov.nist.javax.sip.message.MessageFactoryImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -75,7 +76,7 @@ public class SIPRequestHeaderPlarformProvider {
|
||||
}
|
||||
|
||||
|
||||
public Request createRegisterRequest(@NotNull ParentPlatform platform, long CSeq, String fromTag, String viaTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
|
||||
public Request createRegisterRequest(@NotNull ParentPlatform platform, long CSeq, String fromTag, String viaTag, CallIdHeader callIdHeader, boolean isRegister) throws ParseException, InvalidArgumentException, PeerUnavailableException {
|
||||
Request request = null;
|
||||
String sipAddress = sipConfig.getIp() + ":" + sipConfig.getPort();
|
||||
//请求行
|
||||
@@ -109,18 +110,20 @@ public class SIPRequestHeaderPlarformProvider {
|
||||
.createSipURI(platform.getDeviceGBId(), sipAddress));
|
||||
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
|
||||
ExpiresHeader expires = sipFactory.createHeaderFactory().createExpiresHeader(Integer.parseInt(platform.getExpires()));
|
||||
ExpiresHeader expires = sipFactory.createHeaderFactory().createExpiresHeader(isRegister ? platform.getExpires() : 0);
|
||||
request.addHeader(expires);
|
||||
|
||||
UserAgentHeader userAgentHeader = HeaderUtils.createUserAgentHeader(sipFactory);
|
||||
request.addHeader(userAgentHeader);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, String fromTag, String viaTag,
|
||||
String callId, WWWAuthenticateHeader www , CallIdHeader callIdHeader) throws ParseException, PeerUnavailableException, InvalidArgumentException {
|
||||
String callId, WWWAuthenticateHeader www , CallIdHeader callIdHeader, boolean isRegister) throws ParseException, PeerUnavailableException, InvalidArgumentException {
|
||||
|
||||
|
||||
Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, viaTag, callIdHeader);
|
||||
Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, viaTag, callIdHeader, isRegister);
|
||||
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
|
||||
if (www == null) {
|
||||
AuthorizationHeader authorizationHeader = sipFactory.createHeaderFactory().createAuthorizationHeader("Digest");
|
||||
|
||||
@@ -12,6 +12,7 @@ import javax.sip.message.Request;
|
||||
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.HeaderUtils;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import gov.nist.javax.sip.SipProviderImpl;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
@@ -266,15 +267,7 @@ public class SIPRequestHeaderProvider {
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
|
||||
.createSipURI(sipConfig.getId(), sipConfig.getIp() + ":" + sipConfig.getPort()));
|
||||
infoRequest.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
List<String> agentParam = new ArrayList<>();
|
||||
agentParam.add("wvp-pro");
|
||||
// TODO 添加版本信息以及日期
|
||||
UserAgentHeader userAgentHeader = null;
|
||||
try {
|
||||
userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
UserAgentHeader userAgentHeader = HeaderUtils.createUserAgentHeader(sipFactory);
|
||||
infoRequest.addHeader(userAgentHeader);
|
||||
|
||||
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application",
|
||||
|
||||
@@ -10,12 +10,12 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.HeaderUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookType;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
@@ -33,19 +33,15 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sip.*;
|
||||
import javax.sip.address.Address;
|
||||
import javax.sip.address.SipURI;
|
||||
import javax.sip.address.URI;
|
||||
import javax.sip.header.*;
|
||||
import javax.sip.message.Request;
|
||||
import java.lang.reflect.Field;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description:设备能力接口,用于定义设备的控制、查询能力
|
||||
@@ -88,7 +84,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
private UserSetting userSetting;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
private ZlmHttpHookSubscribe subscribe;
|
||||
|
||||
@Autowired
|
||||
private SipSubscribe sipSubscribe;
|
||||
@@ -351,7 +347,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
*/
|
||||
@Override
|
||||
public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
||||
ZLMHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
|
||||
ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
|
||||
String stream = ssrcInfo.getStream();
|
||||
try {
|
||||
if (device == null) {
|
||||
@@ -640,7 +636,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
|
||||
subscribe.removeSubscribe(hookSubscribe);
|
||||
hookSubscribe.getContent().put("regist", false);
|
||||
hookSubscribe.getContent().put("schema", "rtmp");
|
||||
hookSubscribe.getContent().put("schema", "rtsp");
|
||||
// 添加流注销的订阅,注销了后向设备发送bye
|
||||
subscribe.addSubscribe(hookSubscribe,
|
||||
(MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{
|
||||
@@ -780,15 +776,7 @@ public class SIPCommander implements ISIPCommander {
|
||||
// 增加Contact header
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
|
||||
byeRequest.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
List<String> agentParam = new ArrayList<>();
|
||||
agentParam.add("wvp-pro");
|
||||
// TODO 添加版本信息以及日期
|
||||
UserAgentHeader userAgentHeader = null;
|
||||
try {
|
||||
userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
UserAgentHeader userAgentHeader = HeaderUtils.createUserAgentHeader(sipFactory);
|
||||
byeRequest.addHeader(userAgentHeader);
|
||||
ClientTransaction clientTransaction = null;
|
||||
if("TCP".equals(protocol)) {
|
||||
@@ -1680,14 +1668,11 @@ public class SIPCommander implements ISIPCommander {
|
||||
clientTransaction = udpSipProvider.getNewClientTransaction(request);
|
||||
}
|
||||
if (request.getHeader(UserAgentHeader.NAME) == null) {
|
||||
List<String> agentParam = new ArrayList<>();
|
||||
agentParam.add("wvp-pro");
|
||||
// TODO 添加版本信息以及日期
|
||||
UserAgentHeader userAgentHeader = null;
|
||||
try {
|
||||
userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
|
||||
userAgentHeader = HeaderUtils.createUserAgentHeader(sipFactory);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
logger.error("添加UserAgentHeader失败", e);
|
||||
}
|
||||
request.addHeader(userAgentHeader);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
@@ -75,28 +77,21 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
||||
|
||||
@Override
|
||||
public boolean register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) {
|
||||
return register(parentPlatform, null, null, errorEvent, okEvent, false);
|
||||
return register(parentPlatform, null, null, errorEvent, okEvent, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) {
|
||||
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
|
||||
parentPlatform.setExpires("0");
|
||||
if (parentPlatformCatch != null) {
|
||||
parentPlatformCatch.setParentPlatform(parentPlatform);
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
}
|
||||
return register(parentPlatform, null, null, errorEvent, okEvent, false);
|
||||
return register(parentPlatform, null, null, errorEvent, okEvent, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www,
|
||||
SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain) {
|
||||
SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) {
|
||||
try {
|
||||
Request request;
|
||||
String tm = Long.toString(System.currentTimeMillis());
|
||||
if (!registerAgain ) {
|
||||
// //callid
|
||||
CallIdHeader callIdHeader = null;
|
||||
if(parentPlatform.getTransport().equals("TCP")) {
|
||||
callIdHeader = tcpSipProvider.getNewCallId();
|
||||
@@ -107,10 +102,10 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
||||
|
||||
request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform,
|
||||
redisCatchStorage.getCSEQ(), "FromRegister" + tm,
|
||||
"z9hG4bK-" + UUID.randomUUID().toString().replace("-", ""), callIdHeader);
|
||||
"z9hG4bK-" + UUID.randomUUID().toString().replace("-", ""), callIdHeader, isRegister);
|
||||
// 将 callid 写入缓存, 等注册成功可以更新状态
|
||||
String callIdFromHeader = callIdHeader.getCallId();
|
||||
redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, parentPlatform.getServerGBId());
|
||||
redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, PlatformRegisterInfo.getInstance(parentPlatform.getServerGBId(), isRegister));
|
||||
|
||||
sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (event)->{
|
||||
if (event != null) {
|
||||
@@ -127,7 +122,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
||||
}else {
|
||||
CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
|
||||
: udpSipProvider.getNewCallId();
|
||||
request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, "FromRegister" + tm, null, callId, www, callIdHeader);
|
||||
request = headerProviderPlarformProvider.createRegisterRequest(parentPlatform, "FromRegister" + tm, null, callId, www, callIdHeader, isRegister);
|
||||
}
|
||||
|
||||
transmitRequest(parentPlatform, request, null, okEvent);
|
||||
@@ -145,7 +140,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String keepalive(ParentPlatform parentPlatform) {
|
||||
public String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) {
|
||||
String callId = null;
|
||||
try {
|
||||
String characterSet = parentPlatform.getCharacterSet();
|
||||
@@ -168,7 +163,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
|
||||
UUID.randomUUID().toString().replace("-", ""),
|
||||
null,
|
||||
callIdHeader);
|
||||
transmitRequest(parentPlatform, request);
|
||||
transmitRequest(parentPlatform, request, errorEvent, okEvent);
|
||||
callId = callIdHeader.getCallId();
|
||||
} catch (ParseException | InvalidArgumentException | SipException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -59,6 +59,9 @@ public abstract class SIPRequestProcessorParent {
|
||||
public ServerTransaction getServerTransaction(RequestEvent evt) {
|
||||
Request request = evt.getRequest();
|
||||
ServerTransaction serverTransaction = evt.getServerTransaction();
|
||||
if (serverTransaction != null) {
|
||||
System.out.println(serverTransaction.getState().toString());
|
||||
}
|
||||
// 判断TCP还是UDP
|
||||
boolean isTcp = false;
|
||||
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
|
||||
@@ -86,6 +89,8 @@ public abstract class SIPRequestProcessorParent {
|
||||
logger.error(e.getMessage());
|
||||
} catch (TransactionUnavailableException e) {
|
||||
logger.error(e.getMessage());
|
||||
}finally {
|
||||
|
||||
}
|
||||
}
|
||||
return serverTransaction;
|
||||
@@ -182,6 +187,10 @@ public abstract class SIPRequestProcessorParent {
|
||||
sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort()
|
||||
));
|
||||
response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
ServerTransaction serverTransaction = getServerTransaction(evt);
|
||||
if (serverTransaction == null) {
|
||||
|
||||
}
|
||||
getServerTransaction(evt).sendResponse(response);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,14 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
@@ -66,7 +68,7 @@ public class AckRequestProcessor extends SIPRequestProcessorParent implements In
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
private ZlmHttpHookSubscribe subscribe;
|
||||
|
||||
@Autowired
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
@@ -19,7 +19,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
@@ -50,7 +50,6 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sdp.*;
|
||||
import javax.sip.*;
|
||||
import javax.sip.address.SipURI;
|
||||
import javax.sip.header.CallIdHeader;
|
||||
import javax.sip.message.Request;
|
||||
import javax.sip.message.Response;
|
||||
@@ -337,7 +336,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
||||
|
||||
Long finalStartTime = startTime;
|
||||
Long finalStopTime = stopTime;
|
||||
ZLMHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON) -> {
|
||||
ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInUSe, responseJSON) -> {
|
||||
String app = responseJSON.getString("app");
|
||||
String stream = responseJSON.getString("stream");
|
||||
logger.info("[上级点播]下级已经开始推流。 回复200OK(SDP), {}/{}", app, stream);
|
||||
@@ -440,6 +439,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
||||
streamId = String.format("%s_%s", device.getDeviceId(), channelId);
|
||||
}
|
||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, null, device.isSsrcCheck(), false);
|
||||
logger.info(JSONObject.toJSONString(ssrcInfo));
|
||||
sendRtpItem.setStreamId(ssrcInfo.getStream());
|
||||
// 写入redis, 超时时回复
|
||||
redisCatchStorage.updateSendRTPSever(sendRtpItem);
|
||||
|
||||
@@ -180,7 +180,6 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
|
||||
|
||||
private void processNotifyCatalogList(RequestEvent evt, Element rootElement) throws SipException {
|
||||
|
||||
System.out.println(evt.getRequest().toString());
|
||||
String platformId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
|
||||
String deviceId = XmlUtil.getText(rootElement, "DeviceID");
|
||||
ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
|
||||
|
||||
@@ -164,7 +164,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
|
||||
}
|
||||
}
|
||||
|
||||
if (channelId.equals(sipConfig.getId())) {
|
||||
if ("7".equals(deviceAlarm.getAlarmMethod()) ) {
|
||||
// 发送给平台的报警信息。 发送redis通知
|
||||
AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage();
|
||||
alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod()));
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.HeaderUtils;
|
||||
import gov.nist.javax.sip.ResponseEventExt;
|
||||
import gov.nist.javax.sip.message.SIPResponse;
|
||||
import gov.nist.javax.sip.stack.SIPDialog;
|
||||
@@ -103,15 +104,7 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract {
|
||||
}
|
||||
requestURI.setPort(event.getRemotePort());
|
||||
reqAck.setRequestURI(requestURI);
|
||||
List<String> agentParam = new ArrayList<>();
|
||||
agentParam.add("wvp-pro");
|
||||
// TODO 添加版本信息以及日期
|
||||
UserAgentHeader userAgentHeader = null;
|
||||
try {
|
||||
userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
UserAgentHeader userAgentHeader = HeaderUtils.createUserAgentHeader(sipFactory);
|
||||
reqAck.addHeader(userAgentHeader);
|
||||
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
|
||||
reqAck.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
|
||||
|
||||
@@ -6,8 +6,10 @@ import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
|
||||
import com.genersoft.iot.vmp.service.IPlatformService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -44,6 +46,9 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
|
||||
@Autowired
|
||||
private SubscribeHolder subscribeHolder;
|
||||
|
||||
@Autowired
|
||||
private IPlatformService platformService;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// 添加消息处理的订阅
|
||||
@@ -60,48 +65,39 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
|
||||
Response response = evt.getResponse();
|
||||
CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME);
|
||||
String callId = callIdHeader.getCallId();
|
||||
|
||||
String platformGBId = redisCatchStorage.queryPlatformRegisterInfo(callId);
|
||||
if (platformGBId == null) {
|
||||
logger.info(String.format("未找到callId: %s 的注册/注销平台id", callId ));
|
||||
PlatformRegisterInfo platformRegisterInfo = redisCatchStorage.queryPlatformRegisterInfo(callId);
|
||||
if (platformRegisterInfo == null) {
|
||||
logger.info(String.format("[国标级联]未找到callId: %s 的注册/注销平台id", callId ));
|
||||
return;
|
||||
}
|
||||
|
||||
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(platformGBId);
|
||||
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(platformRegisterInfo.getPlatformId());
|
||||
if (parentPlatformCatch == null) {
|
||||
logger.warn(String.format("[收到注册/注销%S请求]平台:%s,但是平台缓存信息未查询到!!!", response.getStatusCode(),platformGBId));
|
||||
logger.warn(String.format("[国标级联]收到注册/注销%S请求,平台:%s,但是平台缓存信息未查询到!!!", response.getStatusCode(),platformRegisterInfo.getPlatformId()));
|
||||
return;
|
||||
}
|
||||
String action = parentPlatformCatch.getParentPlatform().getExpires().equals("0") ? "注销" : "注册";
|
||||
logger.info(String.format("[%s %S响应]%s ", action, response.getStatusCode(), platformGBId ));
|
||||
|
||||
String action = platformRegisterInfo.isRegister() ? "注册" : "注销";
|
||||
logger.info(String.format("[国标级联]%s %S响应,%s ", action, response.getStatusCode(), platformRegisterInfo.getPlatformId() ));
|
||||
ParentPlatform parentPlatform = parentPlatformCatch.getParentPlatform();
|
||||
if (parentPlatform == null) {
|
||||
logger.warn(String.format("收到 %s %s的%S请求, 但是平台信息未查询到!!!", platformGBId, action, response.getStatusCode()));
|
||||
logger.warn(String.format("[国标级联]收到 %s %s的%S请求, 但是平台信息未查询到!!!", platformRegisterInfo.getPlatformId(), action, response.getStatusCode()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.getStatusCode() == 401) {
|
||||
if (response.getStatusCode() == Response.UNAUTHORIZED) {
|
||||
WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME);
|
||||
sipCommanderForPlatform.register(parentPlatform, callId, www, null, null, true);
|
||||
}else if (response.getStatusCode() == 200){
|
||||
// 注册/注销成功
|
||||
logger.info(String.format("%s %s成功", platformGBId, action));
|
||||
sipCommanderForPlatform.register(parentPlatform, callId, www, null, null, true, platformRegisterInfo.isRegister());
|
||||
}else if (response.getStatusCode() == Response.OK){
|
||||
|
||||
if (platformRegisterInfo.isRegister()) {
|
||||
platformService.online(parentPlatform);
|
||||
}else {
|
||||
platformService.offline(parentPlatform);
|
||||
}
|
||||
|
||||
// 注册/注销成功移除缓存的信息
|
||||
redisCatchStorage.delPlatformRegisterInfo(callId);
|
||||
redisCatchStorage.delPlatformCatchInfo(platformGBId);
|
||||
// 取回Expires设置,避免注销过程中被置为0
|
||||
ParentPlatform parentPlatformTmp = storager.queryParentPlatByServerGBId(platformGBId);
|
||||
if (parentPlatformTmp != null) {
|
||||
parentPlatformTmp.setStatus("注册".equals(action));
|
||||
redisCatchStorage.updatePlatformRegister(parentPlatformTmp);
|
||||
redisCatchStorage.updatePlatformKeepalive(parentPlatformTmp);
|
||||
parentPlatformCatch.setParentPlatform(parentPlatformTmp);
|
||||
}
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
storager.updateParentPlatformStatus(platformGBId, "注册".equals(action));
|
||||
if ("注销".equals(action)) {
|
||||
subscribeHolder.removeCatalogSubscribe(platformGBId);
|
||||
subscribeHolder.removeMobilePositionSubscribe(platformGBId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.genersoft.iot.vmp.gb28181.utils;
|
||||
|
||||
import javax.sip.PeerUnavailableException;
|
||||
import javax.sip.SipFactory;
|
||||
import javax.sip.header.UserAgentHeader;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 生成header的工具类
|
||||
* @author lin
|
||||
*/
|
||||
public class HeaderUtils {
|
||||
|
||||
public static UserAgentHeader createUserAgentHeader(SipFactory sipFactory) throws PeerUnavailableException, ParseException {
|
||||
List<String> agentParam = new ArrayList<>();
|
||||
agentParam.add("WVP PRO");
|
||||
// TODO 添加版本信息以及日期
|
||||
return sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public class AssistRESTfulUtils {
|
||||
if (mediaServerItem == null) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectUtils.isEmpty(mediaServerItem.getRecordAssistPort())) {
|
||||
if (mediaServerItem.getRecordAssistPort() > 0) {
|
||||
logger.warn("未启用Assist服务");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -7,12 +7,10 @@ import java.util.Map;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.*;
|
||||
import com.genersoft.iot.vmp.service.*;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
@@ -20,10 +18,11 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -49,6 +48,9 @@ public class ZLMHttpHookListener {
|
||||
@Autowired
|
||||
private SIPCommander cmder;
|
||||
|
||||
@Autowired
|
||||
private SIPCommanderFroPlatform commanderFroPlatform;
|
||||
|
||||
@Autowired
|
||||
private IPlayService playService;
|
||||
|
||||
@@ -77,7 +79,7 @@ public class ZLMHttpHookListener {
|
||||
private ZLMMediaListManager zlmMediaListManager;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
private ZlmHttpHookSubscribe subscribe;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
@@ -91,6 +93,10 @@ public class ZLMHttpHookListener {
|
||||
@Autowired
|
||||
private AssistRESTfulUtils assistRESTfulUtils;
|
||||
|
||||
@Qualifier("taskExecutor")
|
||||
@Autowired
|
||||
private ThreadPoolTaskExecutor taskExecutor;
|
||||
|
||||
/**
|
||||
* 服务器定时上报时间,上报间隔可配置,默认10s上报一次
|
||||
*
|
||||
@@ -101,9 +107,9 @@ public class ZLMHttpHookListener {
|
||||
|
||||
logger.info("[ ZLM HOOK ] on_server_keepalive API调用,参数:" + json.toString());
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
|
||||
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
|
||||
if (subscribes != null && subscribes.size() > 0) {
|
||||
for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
|
||||
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
||||
subscribe.response(null, json);
|
||||
}
|
||||
}
|
||||
@@ -167,7 +173,7 @@ public class ZLMHttpHookListener {
|
||||
logger.debug("[ ZLM HOOK ]on_play API调用,参数:" + JSON.toJSONString(param));
|
||||
}
|
||||
String mediaServerId = param.getMediaServerId();
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json);
|
||||
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json);
|
||||
if (subscribe != null ) {
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
@@ -237,9 +243,11 @@ public class ZLMHttpHookListener {
|
||||
// 鉴权通过
|
||||
redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
|
||||
// 通知assist新的callId
|
||||
if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) {
|
||||
assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null);
|
||||
}
|
||||
taskExecutor.execute(()->{
|
||||
if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) {
|
||||
assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null);
|
||||
}
|
||||
});
|
||||
}else {
|
||||
zlmMediaListManager.sendStreamEvent(param.getApp(),param.getStream(), param.getMediaServerId());
|
||||
}
|
||||
@@ -252,7 +260,7 @@ public class ZLMHttpHookListener {
|
||||
}
|
||||
|
||||
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
|
||||
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
|
||||
if (subscribe != null) {
|
||||
if (mediaInfo != null) {
|
||||
subscribe.response(mediaInfo, json);
|
||||
@@ -376,7 +384,7 @@ public class ZLMHttpHookListener {
|
||||
logger.debug("[ ZLM HOOK ]on_shell_login API调用,参数:" + json.toString());
|
||||
}
|
||||
String mediaServerId = json.getString("mediaServerId");
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_shell_login, json);
|
||||
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_shell_login, json);
|
||||
if (subscribe != null ) {
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
@@ -402,7 +410,7 @@ public class ZLMHttpHookListener {
|
||||
logger.info("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item));
|
||||
String mediaServerId = item.getMediaServerId();
|
||||
JSONObject json = (JSONObject) JSON.toJSON(item);
|
||||
ZLMHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
|
||||
ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
|
||||
if (subscribe != null ) {
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaInfo != null) {
|
||||
@@ -415,19 +423,24 @@ public class ZLMHttpHookListener {
|
||||
String schema = item.getSchema();
|
||||
List<MediaItem.MediaTrack> tracks = item.getTracks();
|
||||
boolean regist = item.isRegist();
|
||||
if (regist) {
|
||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
|
||||
if (streamAuthorityInfo == null) {
|
||||
streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(item);
|
||||
if (item.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|
||||
|| item.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|
||||
|| item.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
|
||||
if (regist) {
|
||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(app, stream);
|
||||
if (streamAuthorityInfo == null) {
|
||||
streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(item);
|
||||
}else {
|
||||
streamAuthorityInfo.setOriginType(item.getOriginType());
|
||||
streamAuthorityInfo.setOriginTypeStr(item.getOriginTypeStr());
|
||||
}
|
||||
redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo);
|
||||
}else {
|
||||
streamAuthorityInfo.setOriginType(item.getOriginType());
|
||||
streamAuthorityInfo.setOriginTypeStr(item.getOriginTypeStr());
|
||||
redisCatchStorage.removeStreamAuthorityInfo(app, stream);
|
||||
}
|
||||
redisCatchStorage.updateStreamAuthorityInfo(app, stream, streamAuthorityInfo);
|
||||
}else {
|
||||
redisCatchStorage.removeStreamAuthorityInfo(app, stream);
|
||||
}
|
||||
if ("rtmp".equals(schema)){
|
||||
|
||||
if ("rtsp".equals(schema)){
|
||||
logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", regist, app, stream);
|
||||
if (regist) {
|
||||
mediaServerService.addCount(mediaServerId);
|
||||
@@ -523,17 +536,21 @@ public class ZLMHttpHookListener {
|
||||
if ("rtp".equals(app)){
|
||||
ret.put("close", true);
|
||||
StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId);
|
||||
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, null, streamId);
|
||||
if (streamInfoForPlayCatch != null) {
|
||||
// 如果在给上级推流,也不停止。
|
||||
// 收到无人观看说明流也没有在往上级推送
|
||||
if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {
|
||||
ret.put("close", false);
|
||||
} else {
|
||||
cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(),
|
||||
streamInfoForPlayCatch.getStream(), null);
|
||||
redisCatchStorage.stopPlay(streamInfoForPlayCatch);
|
||||
storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
|
||||
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(streamInfoForPlayCatch.getChannelId());
|
||||
if (sendRtpItems.size() > 0) {
|
||||
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
||||
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
|
||||
commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
|
||||
}
|
||||
}
|
||||
}
|
||||
cmder.streamByeCmd(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId(),
|
||||
streamInfoForPlayCatch.getStream(), null);
|
||||
redisCatchStorage.stopPlay(streamInfoForPlayCatch);
|
||||
storager.stopPlay(streamInfoForPlayCatch.getDeviceID(), streamInfoForPlayCatch.getChannelId());
|
||||
}else{
|
||||
StreamInfo streamInfoForPlayBackCatch = redisCatchStorage.queryPlayback(null, null, streamId, null);
|
||||
if (streamInfoForPlayBackCatch != null) {
|
||||
@@ -615,9 +632,9 @@ public class ZLMHttpHookListener {
|
||||
}
|
||||
String remoteAddr = request.getRemoteAddr();
|
||||
jsonObject.put("ip", remoteAddr);
|
||||
List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
|
||||
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
|
||||
if (subscribes != null && subscribes.size() > 0) {
|
||||
for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
|
||||
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
||||
subscribe.response(null, jsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,24 @@
|
||||
package com.genersoft.iot.vmp.media.zlm;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.*;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||
import com.genersoft.iot.vmp.service.IStreamPushService;
|
||||
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;
|
||||
import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
|
||||
import com.genersoft.iot.vmp.storager.dao.StreamPushMapper;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import org.checkerframework.checker.units.qual.C;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author lin
|
||||
@@ -59,7 +53,7 @@ public class ZLMMediaListManager {
|
||||
private StreamPushMapper streamPushMapper;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
private ZlmHttpHookSubscribe subscribe;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
@@ -92,6 +92,7 @@ public class ZLMRTPServerFactory {
|
||||
int result = -1;
|
||||
// 查询此rtp server 是否已经存在
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
|
||||
logger.info(JSONObject.toJSONString(rtpInfo));
|
||||
if(rtpInfo.getInteger("code") == 0){
|
||||
if (rtpInfo.getBoolean("exist")) {
|
||||
result = rtpInfo.getInteger("local_port");
|
||||
@@ -113,7 +114,7 @@ public class ZLMRTPServerFactory {
|
||||
}
|
||||
param.put("ssrc", ssrc);
|
||||
JSONObject openRtpServerResultJson = zlmresTfulUtils.openRtpServer(mediaServerItem, param);
|
||||
|
||||
logger.info(JSONObject.toJSONString(openRtpServerResultJson));
|
||||
if (openRtpServerResultJson != null) {
|
||||
if (openRtpServerResultJson.getInteger("code") == 0) {
|
||||
result= openRtpServerResultJson.getInteger("port");
|
||||
@@ -277,7 +278,7 @@ public class ZLMRTPServerFactory {
|
||||
* 查询待转推的流是否就绪
|
||||
*/
|
||||
public Boolean isRtpReady(MediaServerItem mediaServerItem, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtmp", streamId);
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem,"rtp", "rtsp", streamId);
|
||||
return (mediaInfo.getInteger("code") == 0 && mediaInfo.getBoolean("online"));
|
||||
}
|
||||
|
||||
@@ -297,7 +298,7 @@ public class ZLMRTPServerFactory {
|
||||
* @return
|
||||
*/
|
||||
public int totalReaderCount(MediaServerItem mediaServerItem, String app, String streamId) {
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtmp", streamId);
|
||||
JSONObject mediaInfo = zlmresTfulUtils.getMediaInfo(mediaServerItem, app, "rtsp", streamId);
|
||||
if (mediaInfo == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import com.genersoft.iot.vmp.conf.MediaConfig;
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForServerStarted;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import org.slf4j.Logger;
|
||||
@@ -19,9 +18,7 @@ import org.springframework.core.annotation.Order;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
@Order(value=1)
|
||||
@@ -35,7 +32,7 @@ public class ZLMRunner implements CommandLineRunner {
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe hookSubscribe;
|
||||
private ZlmHttpHookSubscribe hookSubscribe;
|
||||
|
||||
@Autowired
|
||||
private EventPublisher publisher;
|
||||
@@ -62,8 +59,6 @@ public class ZLMRunner implements CommandLineRunner {
|
||||
}
|
||||
mediaServerService.syncCatchFromDatabase();
|
||||
HookSubscribeForServerStarted hookSubscribeForServerStarted = HookSubscribeFactory.on_server_started();
|
||||
// Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.SECONDS.toSeconds(60));
|
||||
// hookSubscribeForStreamChange.setExpires(expiresInstant);
|
||||
// 订阅 zlm启动事件, 新的zlm也会从这里进入系统
|
||||
hookSubscribe.addSubscribe(hookSubscribeForServerStarted,
|
||||
(MediaServerItem mediaServerItem, JSONObject response)->{
|
||||
|
||||
@@ -4,6 +4,9 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookType;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -13,21 +16,22 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @description:针对 ZLMediaServer的hook事件订阅
|
||||
* @author: pan
|
||||
* @date: 2020年12月2日 21:17:32
|
||||
* ZLMediaServer的hook事件订阅
|
||||
* @author lin
|
||||
*/
|
||||
@Component
|
||||
public class ZLMHttpHookSubscribe {
|
||||
public class ZlmHttpHookSubscribe {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ZlmHttpHookSubscribe.class);
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Event{
|
||||
void response(MediaServerItem mediaServerItem, JSONObject response);
|
||||
}
|
||||
|
||||
private Map<HookType, Map<IHookSubscribe, ZLMHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
|
||||
private Map<HookType, Map<IHookSubscribe, ZlmHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
|
||||
|
||||
public void addSubscribe(IHookSubscribe hookSubscribe, ZLMHttpHookSubscribe.Event event) {
|
||||
public void addSubscribe(IHookSubscribe hookSubscribe, ZlmHttpHookSubscribe.Event event) {
|
||||
if (hookSubscribe.getExpires() == null) {
|
||||
// 默认5分钟过期
|
||||
Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(5));
|
||||
@@ -36,8 +40,8 @@ public class ZLMHttpHookSubscribe {
|
||||
allSubscribes.computeIfAbsent(hookSubscribe.getHookType(), k -> new ConcurrentHashMap<>()).put(hookSubscribe, event);
|
||||
}
|
||||
|
||||
public ZLMHttpHookSubscribe.Event sendNotify(HookType type, JSONObject hookResponse) {
|
||||
ZLMHttpHookSubscribe.Event event= null;
|
||||
public ZlmHttpHookSubscribe.Event sendNotify(HookType type, JSONObject hookResponse) {
|
||||
ZlmHttpHookSubscribe.Event event= null;
|
||||
Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type);
|
||||
if (eventMap == null) {
|
||||
return null;
|
||||
@@ -69,8 +73,8 @@ public class ZLMHttpHookSubscribe {
|
||||
|
||||
Set<Map.Entry<IHookSubscribe, Event>> entries = eventMap.entrySet();
|
||||
if (entries.size() > 0) {
|
||||
List<Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event>> entriesToRemove = new ArrayList<>();
|
||||
for (Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event> entry : entries) {
|
||||
List<Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event>> entriesToRemove = new ArrayList<>();
|
||||
for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entries) {
|
||||
JSONObject content = entry.getKey().getContent();
|
||||
if (content == null || content.size() == 0) {
|
||||
entriesToRemove.add(entry);
|
||||
@@ -87,13 +91,13 @@ public class ZLMHttpHookSubscribe {
|
||||
result = result && content.getString(s).equals(hookSubscribe.getContent().getString(s));
|
||||
}
|
||||
}
|
||||
if (null != result && result){
|
||||
if (result){
|
||||
entriesToRemove.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(entriesToRemove)) {
|
||||
for (Map.Entry<IHookSubscribe, ZLMHttpHookSubscribe.Event> entry : entriesToRemove) {
|
||||
for (Map.Entry<IHookSubscribe, ZlmHttpHookSubscribe.Event> entry : entriesToRemove) {
|
||||
entries.remove(entry);
|
||||
}
|
||||
}
|
||||
@@ -106,12 +110,12 @@ public class ZLMHttpHookSubscribe {
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public List<ZLMHttpHookSubscribe.Event> getSubscribes(HookType type) {
|
||||
public List<ZlmHttpHookSubscribe.Event> getSubscribes(HookType type) {
|
||||
Map<IHookSubscribe, Event> eventMap = allSubscribes.get(type);
|
||||
if (eventMap == null) {
|
||||
return null;
|
||||
}
|
||||
List<ZLMHttpHookSubscribe.Event> result = new ArrayList<>();
|
||||
List<ZlmHttpHookSubscribe.Event> result = new ArrayList<>();
|
||||
for (IHookSubscribe key : eventMap.keySet()) {
|
||||
result.add(eventMap.get(key));
|
||||
}
|
||||
@@ -127,5 +131,28 @@ public class ZLMHttpHookSubscribe {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对订阅数据进行过期清理
|
||||
*/
|
||||
@Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次
|
||||
public void execute(){
|
||||
|
||||
logger.info("[hook订阅] 清理");
|
||||
|
||||
Instant instant = Instant.now().minusMillis(TimeUnit.MINUTES.toMillis(5));
|
||||
int total = 0;
|
||||
for (HookType hookType : allSubscribes.keySet()) {
|
||||
Map<IHookSubscribe, Event> hookSubscribeEventMap = allSubscribes.get(hookType);
|
||||
if (hookSubscribeEventMap.size() > 0) {
|
||||
for (IHookSubscribe hookSubscribe : hookSubscribeEventMap.keySet()) {
|
||||
if (hookSubscribe.getExpires().isBefore(instant)) {
|
||||
// 过期的
|
||||
hookSubscribeEventMap.remove(hookSubscribe);
|
||||
total ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.info("[hook订阅] 清理结束,共清理{}条过期数据", total);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.event;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.VideoManagerConstants;
|
||||
import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.connection.Message;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件
|
||||
* @author: swwheihei
|
||||
* @date: 2020年5月6日 上午11:35:46
|
||||
*/
|
||||
@Component
|
||||
public class ZLMKeepliveTimeoutListener extends RedisKeyExpirationEventMessageListener {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(ZLMKeepliveTimeoutListener.class);
|
||||
|
||||
@Autowired
|
||||
private EventPublisher publisher;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
public ZLMKeepliveTimeoutListener(RedisMessageListenerContainer listenerContainer, UserSetting userSetting) {
|
||||
super(listenerContainer, userSetting);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 监听失效的key,key格式为keeplive_deviceId
|
||||
* @param message
|
||||
* @param pattern
|
||||
*/
|
||||
@Override
|
||||
public void onMessage(Message message, byte[] pattern) {
|
||||
// 获取失效的key
|
||||
String expiredKey = message.toString();
|
||||
String KEEPLIVEKEY_PREFIX = VideoManagerConstants.MEDIA_SERVER_KEEPALIVE_PREFIX + userSetting.getServerId() + "_";
|
||||
if(!expiredKey.startsWith(KEEPLIVEKEY_PREFIX)){
|
||||
return;
|
||||
}
|
||||
|
||||
String mediaServerId = expiredKey.substring(KEEPLIVEKEY_PREFIX.length(),expiredKey.length());
|
||||
logger.info("[zlm心跳到期]:" + mediaServerId);
|
||||
// 发起http请求验证zlm是否确实无法连接,如果确实无法连接则发送离线事件,否则不作处理
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
JSONObject mediaServerConfig = zlmresTfulUtils.getMediaServerConfig(mediaServerItem);
|
||||
if (mediaServerConfig != null && mediaServerConfig.getInteger("code") == 0) {
|
||||
logger.info("[zlm心跳到期]:{}验证后zlm仍在线,恢复心跳信息", mediaServerId);
|
||||
// 添加zlm信息
|
||||
mediaServerService.updateMediaServerKeepalive(mediaServerId, mediaServerConfig);
|
||||
}else {
|
||||
publisher.zlmOfflineEventPublish(mediaServerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
|
||||
/**
|
||||
* 国标平台的业务类
|
||||
* @author lin
|
||||
*/
|
||||
public interface IPlatformService {
|
||||
|
||||
ParentPlatform queryPlatformByServerGBId(String platformGbId);
|
||||
|
||||
/**
|
||||
* 分页获取上级平台
|
||||
* @param page
|
||||
* @param count
|
||||
* @return
|
||||
*/
|
||||
PageInfo<ParentPlatform> queryParentPlatformList(int page, int count);
|
||||
|
||||
/**
|
||||
* 添加级联平台
|
||||
* @param parentPlatform 级联平台
|
||||
*/
|
||||
boolean add(ParentPlatform parentPlatform);
|
||||
|
||||
/**
|
||||
* 平台上线
|
||||
* @param parentPlatform 平台信息
|
||||
*/
|
||||
void online(ParentPlatform parentPlatform);
|
||||
|
||||
/**
|
||||
* 平台离线
|
||||
* @param parentPlatform 平台信息
|
||||
*/
|
||||
void offline(ParentPlatform parentPlatform);
|
||||
|
||||
/**
|
||||
* 向上级平台发起注册
|
||||
* @param parentPlatform
|
||||
*/
|
||||
void login(ParentPlatform parentPlatform);
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
|
||||
import com.genersoft.iot.vmp.service.bean.PlayBackCallback;
|
||||
@@ -14,7 +14,6 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
/**
|
||||
@@ -25,9 +24,9 @@ public interface IPlayService {
|
||||
void onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId, String uuid);
|
||||
|
||||
void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
||||
ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
|
||||
ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
|
||||
InviteTimeOutCallback timeoutCallback, String uuid);
|
||||
PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent, Runnable timeoutCallback);
|
||||
PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent, Runnable timeoutCallback);
|
||||
|
||||
MediaServerItem getNewMediaServerItem(Device device);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.Set;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRunner;
|
||||
import com.genersoft.iot.vmp.service.IStreamProxyService;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import org.slf4j.Logger;
|
||||
@@ -22,7 +23,6 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
@@ -42,7 +42,6 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.storager.dao.MediaServerMapper;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
@@ -58,6 +57,8 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class);
|
||||
|
||||
private final String zlmKeepaliveKeyPrefix = "zlm-keepalive_";
|
||||
|
||||
@Autowired
|
||||
private SipConfig sipConfig;
|
||||
|
||||
@@ -88,10 +89,12 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
|
||||
@Autowired
|
||||
private EventPublisher publisher;
|
||||
|
||||
@Autowired
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
@@ -135,7 +138,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
logger.info("media server [ {} ] ssrcConfig is null", mediaServerItem.getId());
|
||||
return null;
|
||||
}else {
|
||||
String ssrc = null;
|
||||
String ssrc;
|
||||
if (presetSsrc != null) {
|
||||
ssrc = presetSsrc;
|
||||
}else {
|
||||
@@ -404,15 +407,43 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
if (serverItem.isAutoConfig()) {
|
||||
setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable()));
|
||||
}
|
||||
final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId();
|
||||
dynamicTask.stop(zlmKeepaliveKey);
|
||||
dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (serverItem.getHookAliveInterval() + 5) * 1000);
|
||||
publisher.zlmOnlineEventPublish(serverItem.getId());
|
||||
logger.info("[ZLM] 连接成功 {} - {}:{} ",
|
||||
zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
|
||||
}
|
||||
|
||||
class KeepAliveTimeoutRunnable implements Runnable{
|
||||
|
||||
private MediaServerItem serverItem;
|
||||
|
||||
public KeepAliveTimeoutRunnable(MediaServerItem serverItem) {
|
||||
this.serverItem = serverItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
logger.info("[zlm心跳到期]:" + serverItem.getId());
|
||||
// 发起http请求验证zlm是否确实无法连接,如果确实无法连接则发送离线事件,否则不作处理
|
||||
JSONObject mediaServerConfig = zlmresTfulUtils.getMediaServerConfig(serverItem);
|
||||
if (mediaServerConfig != null && mediaServerConfig.getInteger("code") == 0) {
|
||||
logger.info("[zlm心跳到期]:{}验证后zlm仍在线,恢复心跳信息,请检查zlm是否可以正常向wvp发送心跳", serverItem.getId());
|
||||
// 添加zlm信息
|
||||
updateMediaServerKeepalive(serverItem.getId(), mediaServerConfig);
|
||||
}else {
|
||||
publisher.zlmOfflineEventPublish(serverItem.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void zlmServerOffline(String mediaServerId) {
|
||||
delete(mediaServerId);
|
||||
final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + mediaServerId;
|
||||
dynamicTask.stop(zlmKeepaliveKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -423,7 +454,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
if (RedisUtil.zScore(key, serverItem.getId()) == null) { // 不存在则设置默认值 已存在则重置
|
||||
RedisUtil.zAdd(key, serverItem.getId(), 0L);
|
||||
// 查询服务流数量
|
||||
zlmresTfulUtils.getMediaList(serverItem, null, null, "rtmp",(mediaList ->{
|
||||
zlmresTfulUtils.getMediaList(serverItem, null, null, "rtsp",(mediaList ->{
|
||||
Integer code = mediaList.getInteger("code");
|
||||
if (code == 0) {
|
||||
JSONArray data = mediaList.getJSONArray("data");
|
||||
@@ -435,7 +466,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
}else {
|
||||
clearRTPServer(serverItem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -471,7 +501,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
}
|
||||
|
||||
// 获取分数最低的,及并发最低的
|
||||
Set<Object> objects = RedisUtil.ZRange(key, 0, -1);
|
||||
Set<Object> objects = RedisUtil.zRange(key, 0, -1);
|
||||
ArrayList<Object> mediaServerObjectS = new ArrayList<>(objects);
|
||||
|
||||
String mediaServerId = (String)mediaServerObjectS.get(0);
|
||||
@@ -489,10 +519,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
String protocol = sslEnabled ? "https" : "http";
|
||||
String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort);
|
||||
String recordHookPrex = null;
|
||||
if (mediaServerItem.getRecordAssistPort() != 0) {
|
||||
recordHookPrex = String.format("http://127.0.0.1:%s/api/record", mediaServerItem.getRecordAssistPort());
|
||||
}
|
||||
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
|
||||
param.put("ffmpeg.cmd","%s -fflags nobuffer -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s");
|
||||
@@ -501,7 +528,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
param.put("hook.on_play",String.format("%s/on_play", hookPrex));
|
||||
param.put("hook.on_http_access",String.format("%s/on_http_access", hookPrex));
|
||||
param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
|
||||
param.put("hook.on_record_mp4",recordHookPrex != null? String.format("%s/on_record_mp4", recordHookPrex): "");
|
||||
param.put("hook.on_record_ts",String.format("%s/on_record_ts", hookPrex));
|
||||
param.put("hook.on_rtsp_auth",String.format("%s/on_rtsp_auth", hookPrex));
|
||||
param.put("hook.on_rtsp_realm",String.format("%s/on_rtsp_realm", hookPrex));
|
||||
@@ -511,6 +537,11 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
|
||||
param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
|
||||
param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrex));
|
||||
if (mediaServerItem.getRecordAssistPort() > 0) {
|
||||
param.put("hook.on_record_mp4",String.format("http://127.0.0.1:%s/api/record/on_record_mp4", mediaServerItem.getRecordAssistPort()));
|
||||
}else {
|
||||
param.put("hook.on_record_mp4","");
|
||||
}
|
||||
param.put("hook.timeoutSec","20");
|
||||
param.put("general.streamNoneReaderDelayMS",mediaServerItem.getStreamNoneReaderDelayMS()==-1?"3600000":mediaServerItem.getStreamNoneReaderDelayMS() );
|
||||
// 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
|
||||
@@ -631,9 +662,9 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
return;
|
||||
}
|
||||
}
|
||||
String key = VideoManagerConstants.MEDIA_SERVER_KEEPALIVE_PREFIX + userSetting.getServerId() + "_" + mediaServerId;
|
||||
int hookAliveInterval = mediaServerItem.getHookAliveInterval() + 2;
|
||||
RedisUtil.set(key, data, hookAliveInterval);
|
||||
final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + mediaServerItem.getId();
|
||||
dynamicTask.stop(zlmKeepaliveKey);
|
||||
dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(mediaServerItem), (mediaServerItem.getHookAliveInterval() + 5) * 1000);
|
||||
}
|
||||
|
||||
private MediaServerItem getOneFromDatabase(String mediaServerId) {
|
||||
|
||||
@@ -108,6 +108,7 @@ public class MediaServiceImpl implements IMediaService {
|
||||
streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/%s/%s.live.mp4%s", addr, mediaInfo.getHttpPort(), app, stream, callIdParam));
|
||||
streamInfoResult.setTs(String.format("http://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpPort(), app, stream, callIdParam));
|
||||
streamInfoResult.setWs_ts(String.format("ws://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpPort(), app, stream, callIdParam));
|
||||
streamInfoResult.setRtc(String.format("http://%s:%s/index/api/webrtc?app=%s&stream=%s&type=play%s", mediaInfo.getStreamIp(), mediaInfo.getHttpPort(), app, stream, ObjectUtils.isEmpty(callId)?"":"&callId=" + callId));
|
||||
if (mediaInfo.getHttpSSlPort() != 0) {
|
||||
streamInfoResult.setHttps_flv(String.format("https://%s:%s/%s/%s.live.flv%s", addr, mediaInfo.getHttpSSlPort(), app, stream, callIdParam));
|
||||
streamInfoResult.setWss_flv(String.format("wss://%s:%s/%s/%s.live.flv%s", addr, mediaInfo.getHttpSSlPort(), app, stream, callIdParam));
|
||||
@@ -118,7 +119,7 @@ public class MediaServiceImpl implements IMediaService {
|
||||
streamInfoResult.setHttps_ts(String.format("https://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app, stream, callIdParam));
|
||||
streamInfoResult.setWss_ts(String.format("wss://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app, stream, callIdParam));
|
||||
streamInfoResult.setWss_ts(String.format("wss://%s:%s/%s/%s.live.ts%s", addr, mediaInfo.getHttpSSlPort(), app, stream, callIdParam));
|
||||
streamInfoResult.setRtc(String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=%s%s", mediaInfo.getStreamIp(), mediaInfo.getHttpSSlPort(), app, stream, isPlay?"play":"push", ObjectUtils.isEmpty(callId)?"":"&callId=" + callId));
|
||||
streamInfoResult.setRtcs(String.format("https://%s:%s/index/api/webrtc?app=%s&stream=%s&type=play%s", mediaInfo.getStreamIp(), mediaInfo.getHttpSSlPort(), app, stream, ObjectUtils.isEmpty(callId)?"":"&callId=" + callId));
|
||||
}
|
||||
|
||||
streamInfoResult.setTracks(tracks);
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.IPlatformService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.sip.TimeoutEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author lin
|
||||
*/
|
||||
@Service
|
||||
public class PlatformServiceImpl implements IPlatformService {
|
||||
|
||||
private final static String REGISTER_KEY_PREFIX = "platform_register_";
|
||||
private final static String KEEPALIVE_KEY_PREFIX = "platform_keepalive_";
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private ParentPlatformMapper platformMapper;
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private SIPCommanderFroPlatform commanderForPlatform;
|
||||
|
||||
@Autowired
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
@Autowired
|
||||
private ZLMRTPServerFactory zlmrtpServerFactory;
|
||||
|
||||
@Autowired
|
||||
private SubscribeHolder subscribeHolder;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ParentPlatform queryPlatformByServerGBId(String platformGbId) {
|
||||
return platformMapper.getParentPlatByServerGBId(platformGbId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageInfo<ParentPlatform> queryParentPlatformList(int page, int count) {
|
||||
PageHelper.startPage(page, count);
|
||||
List<ParentPlatform> all = platformMapper.getParentPlatformList();
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(ParentPlatform parentPlatform) {
|
||||
|
||||
if (parentPlatform.getCatalogGroup() == 0) {
|
||||
// 每次发送目录的数量默认为1
|
||||
parentPlatform.setCatalogGroup(1);
|
||||
}
|
||||
if (parentPlatform.getAdministrativeDivision() == null) {
|
||||
// 行政区划默认去编号的前6位
|
||||
parentPlatform.setAdministrativeDivision(parentPlatform.getServerGBId().substring(0,6));
|
||||
}
|
||||
parentPlatform.setCatalogId(parentPlatform.getDeviceGBId());
|
||||
int result = platformMapper.addParentPlatform(parentPlatform);
|
||||
// 添加缓存
|
||||
ParentPlatformCatch parentPlatformCatch = new ParentPlatformCatch();
|
||||
parentPlatformCatch.setParentPlatform(parentPlatform);
|
||||
parentPlatformCatch.setId(parentPlatform.getServerGBId());
|
||||
parentPlatformCatch.setParentPlatform(parentPlatform);
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
if (parentPlatform.isEnable()) {
|
||||
// 保存时启用就发送注册
|
||||
// 注册成功时由程序直接调用了online方法
|
||||
commanderForPlatform.register(parentPlatform, eventResult -> {
|
||||
logger.info("[国标级联] {},添加向上级注册失败,请确定上级平台可用时重新保存", parentPlatform.getServerGBId());
|
||||
}, null);
|
||||
}
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void online(ParentPlatform parentPlatform) {
|
||||
logger.info("[国标级联]:{}, 平台上线/更新注册", parentPlatform.getServerGBId());
|
||||
platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), true);
|
||||
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
|
||||
if (parentPlatformCatch != null) {
|
||||
parentPlatformCatch.getParentPlatform().setStatus(true);
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
}else {
|
||||
parentPlatformCatch = new ParentPlatformCatch();
|
||||
parentPlatformCatch.setParentPlatform(parentPlatform);
|
||||
parentPlatformCatch.setId(parentPlatform.getServerGBId());
|
||||
parentPlatform.setStatus(true);
|
||||
parentPlatformCatch.setParentPlatform(parentPlatform);
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
}
|
||||
|
||||
final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
|
||||
if (dynamicTask.contains(registerTaskKey)) {
|
||||
dynamicTask.stop(registerTaskKey);
|
||||
}
|
||||
// 添加注册任务
|
||||
dynamicTask.startDelay(registerTaskKey,
|
||||
// 注册失败(注册成功时由程序直接调用了online方法)
|
||||
()->commanderForPlatform.register(parentPlatform, eventResult -> offline(parentPlatform),null),
|
||||
parentPlatform.getExpires()*1000);
|
||||
|
||||
final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId();
|
||||
if (!dynamicTask.contains(keepaliveTaskKey)) {
|
||||
// 添加心跳任务
|
||||
dynamicTask.startCron(keepaliveTaskKey,
|
||||
()-> commanderForPlatform.keepalive(parentPlatform, eventResult -> {
|
||||
// 心跳失败
|
||||
if (eventResult.type == SipSubscribe.EventResultType.timeout) {
|
||||
// 心跳超时
|
||||
ParentPlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
|
||||
// 此时是第三次心跳超时, 平台离线
|
||||
if (platformCatch.getKeepAliveReply() == 2) {
|
||||
// 设置平台离线,并重新注册
|
||||
offline(parentPlatform);
|
||||
logger.info("[国标级联] {},三次心跳超时后再次发起注册", parentPlatform.getServerGBId());
|
||||
commanderForPlatform.register(parentPlatform, eventResult1 -> {
|
||||
logger.info("[国标级联] {},三次心跳超时后再次发起注册仍然失败,开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId());
|
||||
// 添加注册任务
|
||||
dynamicTask.startCron(registerTaskKey,
|
||||
// 注册失败(注册成功时由程序直接调用了online方法)
|
||||
()->logger.info("[国标级联] {},平台离线后持续发起注册,失败", parentPlatform.getServerGBId()),
|
||||
60*1000);
|
||||
}, null);
|
||||
}
|
||||
|
||||
}else {
|
||||
logger.warn("[国标级联]发送心跳收到错误,code: {}, msg: {}", eventResult.statusCode, eventResult.msg);
|
||||
}
|
||||
|
||||
}, eventResult -> {
|
||||
// 心跳成功
|
||||
// 清空之前的心跳超时计数
|
||||
ParentPlatformCatch platformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
|
||||
if (platformCatch.getKeepAliveReply() > 0) {
|
||||
platformCatch.setKeepAliveReply(0);
|
||||
redisCatchStorage.updatePlatformCatchInfo(platformCatch);
|
||||
}
|
||||
}),
|
||||
parentPlatform.getExpires()*1000);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offline(ParentPlatform parentPlatform) {
|
||||
logger.info("[平台离线]:{}", parentPlatform.getServerGBId());
|
||||
ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
|
||||
parentPlatformCatch.setKeepAliveReply(0);
|
||||
parentPlatformCatch.setRegisterAliveReply(0);
|
||||
ParentPlatform parentPlatformInCatch = parentPlatformCatch.getParentPlatform();
|
||||
parentPlatformInCatch.setStatus(false);
|
||||
parentPlatformCatch.setParentPlatform(parentPlatformInCatch);
|
||||
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
|
||||
platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), false);
|
||||
|
||||
// 停止所有推流
|
||||
logger.info("[平台离线] {}, 停止所有推流", parentPlatform.getServerGBId());
|
||||
stopAllPush(parentPlatform.getServerGBId());
|
||||
// 清除注册定时
|
||||
logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId());
|
||||
final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
|
||||
if (dynamicTask.contains(registerTaskKey)) {
|
||||
dynamicTask.stop(registerTaskKey);
|
||||
}
|
||||
// 清除心跳定时
|
||||
logger.info("[平台离线] {}, 停止定时发送心跳任务", parentPlatform.getServerGBId());
|
||||
final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId();
|
||||
if (dynamicTask.contains(keepaliveTaskKey)) {
|
||||
// 添加心跳任务
|
||||
dynamicTask.stop(keepaliveTaskKey);
|
||||
}
|
||||
// 停止目录订阅回复
|
||||
logger.info("[平台离线] {}, 停止订阅回复", parentPlatform.getServerGBId());
|
||||
subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
|
||||
}
|
||||
|
||||
private void stopAllPush(String platformId) {
|
||||
List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServer(platformId);
|
||||
if (sendRtpItems != null && sendRtpItems.size() > 0) {
|
||||
for (SendRtpItem sendRtpItem : sendRtpItems) {
|
||||
redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(), null, null);
|
||||
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
|
||||
Map<String, Object> param = new HashMap<>(3);
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", sendRtpItem.getApp());
|
||||
param.put("stream", sendRtpItem.getStreamId());
|
||||
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login(ParentPlatform parentPlatform) {
|
||||
final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
|
||||
commanderForPlatform.register(parentPlatform, eventResult1 -> {
|
||||
logger.info("[国标级联] {},开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId());
|
||||
// 添加注册任务
|
||||
dynamicTask.startCron(registerTaskKey,
|
||||
// 注册失败(注册成功时由程序直接调用了online方法)
|
||||
()->logger.info("[国标级联] {},平台离线后持续发起注册,失败", parentPlatform.getServerGBId()),
|
||||
60*1000);
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
@@ -128,7 +128,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
private ZlmHttpHookSubscribe subscribe;
|
||||
|
||||
|
||||
@Qualifier("taskExecutor")
|
||||
@@ -139,7 +139,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
|
||||
@Override
|
||||
public PlayResult play(MediaServerItem mediaServerItem, String deviceId, String channelId,
|
||||
ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
|
||||
ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
|
||||
Runnable timeoutCallback) {
|
||||
if (mediaServerItem == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
|
||||
@@ -222,6 +222,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
streamId = String.format("%s_%s", device.getDeviceId(), channelId);
|
||||
}
|
||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);
|
||||
logger.info(JSONObject.toJSONString(ssrcInfo));
|
||||
play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{
|
||||
if (hookEvent != null) {
|
||||
hookEvent.response(mediaServerItem, response);
|
||||
@@ -257,8 +258,8 @@ public class PlayServiceImpl implements IPlayService {
|
||||
|
||||
@Override
|
||||
public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
||||
ZLMHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
|
||||
InviteTimeOutCallback timeoutCallback, String uuid) {
|
||||
ZlmHttpHookSubscribe.Event hookEvent, SipSubscribe.Event errorEvent,
|
||||
InviteTimeOutCallback timeoutCallback, String uuid) {
|
||||
|
||||
String streamId = null;
|
||||
if (mediaServerItem.isRtpEnable()) {
|
||||
@@ -333,7 +334,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
// 单端口模式streamId也有变化,需要重新设置监听
|
||||
if (!mediaServerItem.isRtpEnable()) {
|
||||
// 添加订阅
|
||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtmp", mediaServerItem.getId());
|
||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
|
||||
subscribe.removeSubscribe(hookSubscribe);
|
||||
hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
|
||||
subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{
|
||||
@@ -609,7 +610,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
logger.warn("查询录像信息时发现节点已离线");
|
||||
return null;
|
||||
}
|
||||
if (mediaServerItem.getRecordAssistPort() != 0) {
|
||||
if (mediaServerItem.getRecordAssistPort() > 0) {
|
||||
JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, streamInfo.getApp(), streamInfo.getStream(), null);
|
||||
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
|
||||
long duration = jsonObject.getLong("data");
|
||||
@@ -802,7 +803,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
// for (SendRtpItem sendRtpItem : sendRtpItems) {
|
||||
// if (sendRtpItem.getMediaServerId().equals(mediaServerId)) {
|
||||
// if (mediaListMap.get(sendRtpItem.getStreamId()) == null) {
|
||||
// ParentPlatform platform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
|
||||
// ParentPlatform platform = storager.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
|
||||
// sipCommanderFroPlatform.streamByeCmd(platform, sendRtpItem.getCallId());
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.service.IPlatformChannelService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import org.slf4j.Logger;
|
||||
@@ -12,6 +14,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.connection.Message;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Component
|
||||
@@ -37,8 +42,6 @@ public class RedisAlarmMsgListener implements MessageListener {
|
||||
return;
|
||||
}
|
||||
String gbId = alarmChannelMessage.getGbId();
|
||||
Device device = storage.queryVideoDevice(gbId);
|
||||
ParentPlatform platform = storage.queryParentPlatByServerGBId(gbId);
|
||||
|
||||
DeviceAlarm deviceAlarm = new DeviceAlarm();
|
||||
deviceAlarm.setCreateTime(DateUtil.getNow());
|
||||
@@ -46,18 +49,29 @@ public class RedisAlarmMsgListener implements MessageListener {
|
||||
deviceAlarm.setAlarmDescription(alarmChannelMessage.getAlarmDescription());
|
||||
deviceAlarm.setAlarmMethod("" + alarmChannelMessage.getAlarmSn());
|
||||
deviceAlarm.setAlarmPriority("1");
|
||||
deviceAlarm.setAlarmTime(DateUtil.getNow());
|
||||
deviceAlarm.setAlarmTime(DateUtil.getNowForISO8601());
|
||||
deviceAlarm.setAlarmType("1");
|
||||
deviceAlarm.setLongitude(0);
|
||||
deviceAlarm.setLatitude(0);
|
||||
|
||||
|
||||
if (device != null && platform == null) {
|
||||
commander.sendAlarmMessage(device, deviceAlarm);
|
||||
}else if (device == null && platform != null){
|
||||
commanderForPlatform.sendAlarmMessage(platform, deviceAlarm);
|
||||
if (ObjectUtils.isEmpty(gbId)) {
|
||||
// 发送给所有的上级
|
||||
List<ParentPlatform> parentPlatforms = storage.queryEnableParentPlatformList(true);
|
||||
if (parentPlatforms.size() > 0) {
|
||||
for (ParentPlatform parentPlatform : parentPlatforms) {
|
||||
commanderForPlatform.sendAlarmMessage(parentPlatform, deviceAlarm);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
logger.warn("无法确定" + gbId + "是平台还是设备");
|
||||
Device device = storage.queryVideoDevice(gbId);
|
||||
ParentPlatform platform = storage.queryParentPlatByServerGBId(gbId);
|
||||
if (device != null && platform == null) {
|
||||
commander.sendAlarmMessage(device, deviceAlarm);
|
||||
}else if (device == null && platform != null){
|
||||
commanderForPlatform.sendAlarmMessage(platform, deviceAlarm);
|
||||
}else {
|
||||
logger.warn("无法确定" + gbId + "是平台还是设备");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,11 @@ import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMMediaListManager;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookType;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.*;
|
||||
@@ -24,9 +23,6 @@ import org.springframework.data.redis.connection.Message;
|
||||
import org.springframework.data.redis.connection.MessageListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sip.InvalidArgumentException;
|
||||
import javax.sip.SipException;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@@ -86,7 +82,7 @@ public class RedisGbPlayMsgListener implements MessageListener {
|
||||
private ZLMMediaListManager mediaListManager;
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe subscribe;
|
||||
private ZlmHttpHookSubscribe subscribe;
|
||||
|
||||
|
||||
public interface PlayMsgCallback{
|
||||
@@ -271,7 +267,7 @@ public class RedisGbPlayMsgListener implements MessageListener {
|
||||
}, userSetting.getPlatformPlayTimeout());
|
||||
|
||||
// 添加订阅
|
||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtmp", mediaServerItem.getId());
|
||||
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtsp", mediaServerItem.getId());
|
||||
|
||||
subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||
dynamicTask.stop(taskKey);
|
||||
|
||||
@@ -295,7 +295,6 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
if (jsonObject == null) {
|
||||
return false;
|
||||
}
|
||||
System.out.println(jsonObject);
|
||||
if (jsonObject.getInteger("code") == 0) {
|
||||
result = true;
|
||||
streamProxy.setEnable(true);
|
||||
@@ -421,7 +420,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
if(data != null && data.size() > 0) {
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
JSONObject streamJSONObj = data.getJSONObject(i);
|
||||
if ("rtmp".equals(streamJSONObj.getString("schema"))) {
|
||||
if ("rtsp".equals(streamJSONObj.getString("schema"))) {
|
||||
StreamInfo streamInfo = new StreamInfo();
|
||||
String app = streamJSONObj.getString("app");
|
||||
String stream = streamJSONObj.getString("stream");
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
|
||||
import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -61,17 +62,13 @@ public interface IRedisCatchStorage {
|
||||
|
||||
void delPlatformCatchInfo(String platformGbId);
|
||||
|
||||
void updatePlatformKeepalive(ParentPlatform parentPlatform);
|
||||
|
||||
void delPlatformKeepalive(String platformGbId);
|
||||
|
||||
void updatePlatformRegister(ParentPlatform parentPlatform);
|
||||
|
||||
void delPlatformRegister(String platformGbId);
|
||||
|
||||
void updatePlatformRegisterInfo(String callId, String platformGbId);
|
||||
void updatePlatformRegisterInfo(String callId, PlatformRegisterInfo platformRegisterInfo);
|
||||
|
||||
String queryPlatformRegisterInfo(String callId);
|
||||
PlatformRegisterInfo queryPlatformRegisterInfo(String callId);
|
||||
|
||||
void delPlatformRegisterInfo(String callId);
|
||||
|
||||
@@ -237,4 +234,6 @@ public interface IRedisCatchStorage {
|
||||
* 发送redis消息 查询所有推流设备的状态
|
||||
*/
|
||||
void sendStreamPushRequestedMsgForStatus();
|
||||
|
||||
List<SendRtpItem> querySendRTPServerByChnnelId(String channelId);
|
||||
}
|
||||
|
||||
@@ -170,15 +170,6 @@ public interface IVideoManagerStorage {
|
||||
*/
|
||||
boolean deleteParentPlatform(ParentPlatform parentPlatform);
|
||||
|
||||
|
||||
/**
|
||||
* 分页获取上级平台
|
||||
* @param page
|
||||
* @param count
|
||||
* @return
|
||||
*/
|
||||
PageInfo<ParentPlatform> queryParentPlatformList(int page, int count);
|
||||
|
||||
/**
|
||||
* 获取所有已启用的平台
|
||||
* @return
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.genersoft.iot.vmp.storager.dao.dto;
|
||||
|
||||
/**
|
||||
* 平台发送注册/注销消息时缓存此消息
|
||||
* @author lin
|
||||
*/
|
||||
public class PlatformRegisterInfo {
|
||||
|
||||
/**
|
||||
* 平台Id
|
||||
*/
|
||||
private String platformId;
|
||||
|
||||
/**
|
||||
* 是否时注册,false为注销
|
||||
*/
|
||||
private boolean register;
|
||||
|
||||
public static PlatformRegisterInfo getInstance(String platformId, boolean register) {
|
||||
PlatformRegisterInfo platformRegisterInfo = new PlatformRegisterInfo();
|
||||
platformRegisterInfo.setPlatformId(platformId);
|
||||
platformRegisterInfo.setRegister(register);
|
||||
return platformRegisterInfo;
|
||||
}
|
||||
|
||||
public String getPlatformId() {
|
||||
return platformId;
|
||||
}
|
||||
|
||||
public void setPlatformId(String platformId) {
|
||||
this.platformId = platformId;
|
||||
}
|
||||
|
||||
public boolean isRegister() {
|
||||
return register;
|
||||
}
|
||||
|
||||
public void setRegister(boolean register) {
|
||||
this.register = register;
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,13 @@ import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
|
||||
import com.genersoft.iot.vmp.service.bean.ThirdPartyGB;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
|
||||
import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
@@ -289,18 +291,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||
RedisUtil.set(key, parentPlatformCatch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlatformKeepalive(ParentPlatform parentPlatform) {
|
||||
String key = VideoManagerConstants.PLATFORM_KEEPALIVE_PREFIX + userSetting.getServerId() + "_" + parentPlatform.getServerGBId();
|
||||
RedisUtil.set(key, "", Integer.parseInt(parentPlatform.getKeepTimeout()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlatformRegister(ParentPlatform parentPlatform) {
|
||||
String key = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + userSetting.getServerId() + "_" + parentPlatform.getServerGBId();
|
||||
RedisUtil.set(key, "", Integer.parseInt(parentPlatform.getExpires()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParentPlatformCatch queryPlatformCatchInfo(String platformGbId) {
|
||||
return (ParentPlatformCatch)RedisUtil.get(VideoManagerConstants.PLATFORM_CATCH_PREFIX + userSetting.getServerId() + "_" + platformGbId);
|
||||
@@ -323,15 +313,15 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||
|
||||
|
||||
@Override
|
||||
public void updatePlatformRegisterInfo(String callId, String platformGbId) {
|
||||
public void updatePlatformRegisterInfo(String callId, PlatformRegisterInfo platformRegisterInfo) {
|
||||
String key = VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_" + callId;
|
||||
RedisUtil.set(key, platformGbId, 30);
|
||||
RedisUtil.set(key, platformRegisterInfo, 30);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String queryPlatformRegisterInfo(String callId) {
|
||||
return (String)RedisUtil.get(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_" + callId);
|
||||
public PlatformRegisterInfo queryPlatformRegisterInfo(String callId) {
|
||||
return (PlatformRegisterInfo)RedisUtil.get(VideoManagerConstants.PLATFORM_REGISTER_INFO_PREFIX + userSetting.getServerId() + "_" + callId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -379,6 +369,24 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SendRtpItem> querySendRTPServerByChnnelId(String channelId) {
|
||||
if (channelId == null) {
|
||||
return null;
|
||||
}
|
||||
String platformGbId = "*";
|
||||
String callId = "*";
|
||||
String streamId = "*";
|
||||
String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + userSetting.getServerId() + "_" + platformGbId
|
||||
+ "_" + channelId + "_" + streamId + "_" + callId;
|
||||
List<Object> scan = RedisUtil.scan(key);
|
||||
List<SendRtpItem> result = new ArrayList<>();
|
||||
for (Object o : scan) {
|
||||
result.add((SendRtpItem) RedisUtil.get((String) o));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SendRtpItem> querySendRTPServer(String platformGbId) {
|
||||
if (platformGbId == null) {
|
||||
|
||||
@@ -457,13 +457,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageInfo<ParentPlatform> queryParentPlatformList(int page, int count) {
|
||||
PageHelper.startPage(page, count);
|
||||
List<ParentPlatform> all = platformMapper.getParentPlatformList();
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParentPlatform queryParentPlatByServerGBId(String platformGbId) {
|
||||
return platformMapper.getParentPlatByServerGBId(platformGbId);
|
||||
|
||||
@@ -82,4 +82,9 @@ public class DateUtil {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getNowForISO8601() {
|
||||
LocalDateTime nowDateTime = LocalDateTime.now();
|
||||
return formatterISO8601.format(nowDateTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ public class SpringBeanFactory implements ApplicationContextAware {
|
||||
/**
|
||||
* 获取对象 这里重写了bean方法,起主要作用
|
||||
*/
|
||||
public static Object getBean(String beanId) throws BeansException {
|
||||
public static <T> T getBean(String beanId) throws BeansException {
|
||||
if (applicationContext == null) {
|
||||
return null;
|
||||
}
|
||||
return applicationContext.getBean(beanId);
|
||||
return (T) applicationContext.getBean(beanId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,15 +5,14 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import gov.nist.javax.sip.stack.UDPMessageChannel;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @description:Redis工具类
|
||||
* @author: swwheihei
|
||||
* @date: 2020年5月6日 下午8:27:29
|
||||
* Redis工具类
|
||||
* @author swwheihei
|
||||
* @date 2020年5月6日 下午8:27:29
|
||||
*/
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
public class RedisUtil {
|
||||
@@ -21,9 +20,9 @@ public class RedisUtil {
|
||||
private static RedisTemplate redisTemplate;
|
||||
|
||||
static {
|
||||
redisTemplate = (RedisTemplate)SpringBeanFactory.getBean("redisTemplate");
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 指定缓存失效时间
|
||||
* @param key 键
|
||||
@@ -31,6 +30,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean expire(String key, long time) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
||||
@@ -45,9 +47,11 @@ public class RedisUtil {
|
||||
/**
|
||||
* 根据 key 获取过期时间
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public static long getExpire(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@@ -57,6 +61,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean hasKey(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.hasKey(key);
|
||||
} catch (Exception e) {
|
||||
@@ -71,6 +78,9 @@ public class RedisUtil {
|
||||
* @param key 键(一个或者多个)
|
||||
*/
|
||||
public static boolean del(String... key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
if (key != null && key.length > 0) {
|
||||
if (key.length == 1) {
|
||||
@@ -95,6 +105,9 @@ public class RedisUtil {
|
||||
* @return 值
|
||||
*/
|
||||
public static Object get(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return key == null ? null : redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
@@ -105,6 +118,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean set(String key, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
return true;
|
||||
@@ -122,6 +138,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean set(String key, Object value, long time) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||
@@ -142,6 +161,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static long incr(String key, long delta) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
if (delta < 0) {
|
||||
throw new RuntimeException("递增因子必须大于 0");
|
||||
}
|
||||
@@ -155,6 +177,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static long decr(String key, long delta) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
if (delta < 0) {
|
||||
throw new RuntimeException("递减因子必须大于 0");
|
||||
}
|
||||
@@ -170,6 +195,9 @@ public class RedisUtil {
|
||||
* @return 值
|
||||
*/
|
||||
public static Object hget(String key, String item) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForHash().get(key, item);
|
||||
}
|
||||
|
||||
@@ -179,6 +207,9 @@ public class RedisUtil {
|
||||
* @return 对应的多个键值
|
||||
*/
|
||||
public static Map<Object, Object> hmget(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
@@ -189,6 +220,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean hmset(String key, Map<Object, Object> map) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
return true;
|
||||
@@ -206,6 +240,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean hmset(String key, Map<Object, Object> map, long time) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
if (time > 0) {
|
||||
@@ -226,6 +263,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean hset(String key, String item, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
return true;
|
||||
@@ -244,6 +284,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean hset(String key, String item, Object value, long time) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
if (time > 0) {
|
||||
@@ -262,6 +305,9 @@ public class RedisUtil {
|
||||
* @param item 项(可以多个,no null)
|
||||
*/
|
||||
public static void hdel(String key, Object... item) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
redisTemplate.opsForHash().delete(key, item);
|
||||
}
|
||||
|
||||
@@ -272,6 +318,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean hHasKey(String key, String item) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForHash().hasKey(key, item);
|
||||
}
|
||||
|
||||
@@ -283,6 +332,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Double hincr(String key, String item, Double by) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForHash().increment(key, item, by);
|
||||
}
|
||||
|
||||
@@ -294,6 +346,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Double hdecr(String key, String item, Double by) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForHash().increment(key, item, -by);
|
||||
}
|
||||
|
||||
@@ -305,6 +360,9 @@ public class RedisUtil {
|
||||
* @return 值
|
||||
*/
|
||||
public static Set<Object> sGet(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
} catch (Exception e) {
|
||||
@@ -320,6 +378,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean sHasKey(String key, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForSet().isMember(key, value);
|
||||
} catch (Exception e) {
|
||||
@@ -335,6 +396,9 @@ public class RedisUtil {
|
||||
* @return 成功个数
|
||||
*/
|
||||
public static long sSet(String key, Object... values) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForSet().add(key, values);
|
||||
} catch (Exception e) {
|
||||
@@ -351,6 +415,9 @@ public class RedisUtil {
|
||||
* @return 成功放入个数
|
||||
*/
|
||||
public static long sSet(String key, long time, Object... values) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
long count = redisTemplate.opsForSet().add(key, values);
|
||||
if (time > 0) {
|
||||
@@ -369,6 +436,9 @@ public class RedisUtil {
|
||||
* @return 长度
|
||||
*/
|
||||
public static long sGetSetSize(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForSet().size(key);
|
||||
} catch (Exception e) {
|
||||
@@ -384,6 +454,9 @@ public class RedisUtil {
|
||||
* @return 成功移除个数
|
||||
*/
|
||||
public static long setRemove(String key, Object... values) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForSet().remove(key, values);
|
||||
} catch (Exception e) {
|
||||
@@ -401,6 +474,9 @@ public class RedisUtil {
|
||||
* @param score
|
||||
*/
|
||||
public static void zAdd(Object key, Object value, double score) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
redisTemplate.opsForZSet().add(key, value, score);
|
||||
}
|
||||
|
||||
@@ -411,6 +487,9 @@ public class RedisUtil {
|
||||
* @param value
|
||||
*/
|
||||
public static void zRemove(Object key, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
redisTemplate.opsForZSet().remove(key, value);
|
||||
}
|
||||
|
||||
@@ -422,6 +501,9 @@ public class RedisUtil {
|
||||
* @param delta -1 表示减 1 表示加1
|
||||
*/
|
||||
public static Double zIncrScore(Object key, Object value, double delta) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForZSet().incrementScore(key, value, delta);
|
||||
}
|
||||
|
||||
@@ -433,6 +515,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Double zScore(Object key, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForZSet().score(key, value);
|
||||
}
|
||||
|
||||
@@ -444,6 +529,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Long zRank(Object key, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForZSet().rank(key, value);
|
||||
}
|
||||
|
||||
@@ -454,6 +542,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Long zSize(Object key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForZSet().zCard(key);
|
||||
}
|
||||
|
||||
@@ -467,7 +558,10 @@ public class RedisUtil {
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public static Set<Object> ZRange(Object key, int start, int end) {
|
||||
public static Set<Object> zRange(Object key, int start, int end) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForZSet().range(key, start, end);
|
||||
}
|
||||
/**
|
||||
@@ -479,6 +573,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Set<ZSetOperations.TypedTuple<String>> zRangeWithScore(Object key, int start, int end) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
|
||||
}
|
||||
/**
|
||||
@@ -492,6 +589,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Set<String> zRevRange(Object key, int start, int end) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForZSet().reverseRange(key, start, end);
|
||||
}
|
||||
/**
|
||||
@@ -503,6 +603,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Set<String> zSortRange(Object key, int min, int max) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
|
||||
}
|
||||
|
||||
@@ -517,6 +620,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static List<Object> lGet(String key, long start, long end) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForList().range(key, start, end);
|
||||
} catch (Exception e) {
|
||||
@@ -531,6 +637,9 @@ public class RedisUtil {
|
||||
* @return 长度
|
||||
*/
|
||||
public static long lGetListSize(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForList().size(key);
|
||||
} catch (Exception e) {
|
||||
@@ -548,6 +657,9 @@ public class RedisUtil {
|
||||
* @return 值
|
||||
*/
|
||||
public static Object lGetIndex(String key, long index) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForList().index(key, index);
|
||||
} catch (Exception e) {
|
||||
@@ -563,6 +675,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean lSet(String key, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
return true;
|
||||
@@ -580,6 +695,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean lSet(String key, Object value, long time) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
if (time > 0) {
|
||||
@@ -599,6 +717,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean lSetList(String key, List<Object> values) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, values);
|
||||
return true;
|
||||
@@ -616,6 +737,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean lSetList(String key, List<Object> values, long time) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, values);
|
||||
if (time > 0) {
|
||||
@@ -636,6 +760,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static boolean lUpdateIndex(String key, long index, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
redisTemplate.opsForList().set(key, index, value);
|
||||
return true;
|
||||
@@ -655,6 +782,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static long lRemove(String key, long count, Object value) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
return redisTemplate.opsForList().remove(key, count, value);
|
||||
} catch (Exception e) {
|
||||
@@ -669,6 +799,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Object lLeftPop(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForList().leftPop(key);
|
||||
}
|
||||
|
||||
@@ -678,6 +811,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static Object lrightPop(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
return redisTemplate.opsForList().rightPop(key);
|
||||
}
|
||||
|
||||
@@ -687,6 +823,9 @@ public class RedisUtil {
|
||||
* @return true / false
|
||||
*/
|
||||
public static List<Object> keys(String key) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
try {
|
||||
Set<String> set = redisTemplate.keys(key);
|
||||
return new ArrayList<>(set);
|
||||
@@ -727,6 +866,9 @@ public class RedisUtil {
|
||||
* @return
|
||||
*/
|
||||
public static List<Object> scan(String query) {
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
Set<String> resultKeys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
|
||||
ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build();
|
||||
Cursor<byte[]> scan = connection.scan(scanOptions);
|
||||
@@ -743,9 +885,10 @@ public class RedisUtil {
|
||||
|
||||
// ============================== 消息发送与订阅 ==============================
|
||||
public static void convertAndSend(String channel, JSONObject msg) {
|
||||
// redisTemplate.convertAndSend(channel, msg);
|
||||
if (redisTemplate == null) {
|
||||
redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
||||
}
|
||||
redisTemplate.convertAndSend(channel, msg);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,14 +9,13 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.TreeType;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
|
||||
import com.genersoft.iot.vmp.service.IPlatformChannelService;
|
||||
import com.genersoft.iot.vmp.service.IPlatformService;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
|
||||
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.UpdateChannelParam;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
@@ -26,10 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
|
||||
@@ -70,6 +66,9 @@ public class PlatformController {
|
||||
@Autowired
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
@Autowired
|
||||
private IPlatformService platformService;
|
||||
|
||||
/**
|
||||
* 获取国标服务的配置
|
||||
*
|
||||
@@ -95,8 +94,7 @@ public class PlatformController {
|
||||
@Parameter(name = "id", description = "平台国标编号", required = true)
|
||||
@GetMapping("/info/{id}")
|
||||
public ParentPlatform getPlatform(@PathVariable String id) {
|
||||
ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(id);
|
||||
WVPResult<ParentPlatform> wvpResult = new WVPResult<>();
|
||||
ParentPlatform parentPlatform = platformService.queryPlatformByServerGBId(id);
|
||||
if (parentPlatform != null) {
|
||||
return parentPlatform;
|
||||
} else {
|
||||
@@ -117,7 +115,7 @@ public class PlatformController {
|
||||
@Parameter(name = "count", description = "每页条数", required = true)
|
||||
public PageInfo<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count) {
|
||||
|
||||
PageInfo<ParentPlatform> parentPlatformPageInfo = storager.queryParentPlatformList(page, count);
|
||||
PageInfo<ParentPlatform> parentPlatformPageInfo = platformService.queryParentPlatformList(page, count);
|
||||
if (parentPlatformPageInfo.getList().size() > 0) {
|
||||
for (ParentPlatform platform : parentPlatformPageInfo.getList()) {
|
||||
platform.setMobilePositionSubscribe(subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId()) != null);
|
||||
@@ -136,7 +134,7 @@ public class PlatformController {
|
||||
@Operation(summary = "添加上级平台信息")
|
||||
@PostMapping("/add")
|
||||
@ResponseBody
|
||||
public String addPlatform(@RequestBody ParentPlatform parentPlatform) {
|
||||
public void addPlatform(@RequestBody ParentPlatform parentPlatform) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("保存上级平台信息API调用");
|
||||
@@ -158,32 +156,16 @@ public class PlatformController {
|
||||
throw new ControllerException(ErrorCode.ERROR400.getCode(), "error severPort");
|
||||
}
|
||||
|
||||
|
||||
ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());
|
||||
if (parentPlatformOld != null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台 " + parentPlatform.getServerGBId() + " 已存在");
|
||||
}
|
||||
parentPlatform.setCreateTime(DateUtil.getNow());
|
||||
parentPlatform.setUpdateTime(DateUtil.getNow());
|
||||
boolean updateResult = storager.updateParentPlatform(parentPlatform);
|
||||
boolean updateResult = platformService.add(parentPlatform);
|
||||
|
||||
if (updateResult) {
|
||||
// 保存时启用就发送注册
|
||||
if (parentPlatform.isEnable()) {
|
||||
if (parentPlatformOld != null && parentPlatformOld.isStatus()) {
|
||||
commanderForPlatform.unregister(parentPlatformOld, null, eventResult -> {
|
||||
// 只要保存就发送注册
|
||||
commanderForPlatform.register(parentPlatform, null, null);
|
||||
});
|
||||
} else {
|
||||
// 只要保存就发送注册
|
||||
commanderForPlatform.register(parentPlatform, null, null);
|
||||
}
|
||||
|
||||
} else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()) { // 关闭启用时注销
|
||||
commanderForPlatform.unregister(parentPlatform, null, null);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
if (!updateResult) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(),"写入数据库失败");
|
||||
}
|
||||
}
|
||||
@@ -197,7 +179,7 @@ public class PlatformController {
|
||||
@Operation(summary = "保存上级平台信息")
|
||||
@PostMapping("/save")
|
||||
@ResponseBody
|
||||
public String savePlatform(@RequestBody ParentPlatform parentPlatform) {
|
||||
public void savePlatform(@RequestBody ParentPlatform parentPlatform) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("保存上级平台信息API调用");
|
||||
@@ -247,7 +229,6 @@ public class PlatformController {
|
||||
// 停止订阅相关的定时任务
|
||||
subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(),"写入数据库失败");
|
||||
}
|
||||
|
||||
@@ -8,24 +8,21 @@ import com.genersoft.iot.vmp.conf.SipConfig;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.VersionInfo;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import gov.nist.javax.sip.SipStackImpl;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.ehcache.xml.model.ThreadPoolsType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.sip.ListeningPoint;
|
||||
@@ -42,7 +39,7 @@ import java.util.List;
|
||||
public class ServerController {
|
||||
|
||||
@Autowired
|
||||
private ZLMHttpHookSubscribe zlmHttpHookSubscribe;
|
||||
private ZlmHttpHookSubscribe zlmHttpHookSubscribe;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.alibaba.excel.ExcelReader;
|
||||
import com.alibaba.excel.read.metadata.ReadSheet;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.conf.security.SecurityUtils;
|
||||
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
|
||||
@@ -17,6 +18,7 @@ import com.genersoft.iot.vmp.service.IMediaService;
|
||||
import com.genersoft.iot.vmp.service.IStreamPushService;
|
||||
import com.genersoft.iot.vmp.service.impl.StreamPushUploadFileHandler;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.BatchGBStreamParam;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
@@ -95,11 +97,9 @@ public class StreamPushController {
|
||||
@PostMapping(value = "/save_to_gb")
|
||||
@ResponseBody
|
||||
@Operation(summary = "将推流添加到国标")
|
||||
public Object saveToGB(@RequestBody GbStream stream){
|
||||
if (streamPushService.saveToGB(stream)){
|
||||
return "success";
|
||||
}else {
|
||||
return "fail";
|
||||
public void saveToGB(@RequestBody GbStream stream){
|
||||
if (!streamPushService.saveToGB(stream)){
|
||||
throw new ControllerException(ErrorCode.ERROR100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,11 +107,9 @@ public class StreamPushController {
|
||||
@DeleteMapping(value = "/remove_form_gb")
|
||||
@ResponseBody
|
||||
@Operation(summary = "将推流移出到国标")
|
||||
public Object removeFormGB(@RequestBody GbStream stream){
|
||||
if (streamPushService.removeFromGB(stream)){
|
||||
return "success";
|
||||
}else {
|
||||
return "fail";
|
||||
public void removeFormGB(@RequestBody GbStream stream){
|
||||
if (!streamPushService.removeFromGB(stream)){
|
||||
throw new ControllerException(ErrorCode.ERROR100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,25 +119,21 @@ public class StreamPushController {
|
||||
@Operation(summary = "中止一个推流")
|
||||
@Parameter(name = "app", description = "应用名", required = true)
|
||||
@Parameter(name = "stream", description = "流id", required = true)
|
||||
public Object stop(String app, String streamId){
|
||||
if (streamPushService.stop(app, streamId)){
|
||||
return "success";
|
||||
}else {
|
||||
return "fail";
|
||||
public void stop(String app, String streamId){
|
||||
if (!streamPushService.stop(app, streamId)){
|
||||
throw new ControllerException(ErrorCode.ERROR100);
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping(value = "/batchStop")
|
||||
@ResponseBody
|
||||
@Operation(summary = "中止多个推流")
|
||||
public Object batchStop(@RequestBody BatchGBStreamParam batchGBStreamParam){
|
||||
public void batchStop(@RequestBody BatchGBStreamParam batchGBStreamParam){
|
||||
if (batchGBStreamParam.getGbStreams().size() == 0) {
|
||||
return "fail";
|
||||
throw new ControllerException(ErrorCode.ERROR100);
|
||||
}
|
||||
if (streamPushService.batchStop(batchGBStreamParam.getGbStreams())){
|
||||
return "success";
|
||||
}else {
|
||||
return "fail";
|
||||
if (!streamPushService.batchStop(batchGBStreamParam.getGbStreams())){
|
||||
throw new ControllerException(ErrorCode.ERROR100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +243,7 @@ public class StreamPushController {
|
||||
@Parameter(name = "app", description = "应用名", required = true)
|
||||
@Parameter(name = "stream", description = "流id", required = true)
|
||||
@Parameter(name = "mediaServerId", description = "媒体服务器id")
|
||||
public WVPResult<StreamInfo> getPlayUrl(@RequestParam String app,@RequestParam String stream,
|
||||
public StreamInfo getPlayUrl(@RequestParam String app,@RequestParam String stream,
|
||||
@RequestParam(required = false) String mediaServerId){
|
||||
boolean authority = false;
|
||||
// 是否登陆用户, 登陆用户返回完整信息
|
||||
@@ -257,52 +251,38 @@ public class StreamPushController {
|
||||
if (userInfo!= null) {
|
||||
authority = true;
|
||||
}
|
||||
WVPResult<StreamInfo> result = new WVPResult<>();
|
||||
StreamPushItem push = streamPushService.getPush(app, stream);
|
||||
if (push != null && !push.isSelf()) {
|
||||
result.setCode(-1);
|
||||
result.setMsg("来自其他平台的推流信息");
|
||||
return result;
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "来自其他平台的推流信息");
|
||||
}
|
||||
StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, mediaServerId, authority);
|
||||
if (streamInfo != null){
|
||||
result.setCode(0);
|
||||
result.setMsg("success");
|
||||
result.setData(streamInfo);
|
||||
}else {
|
||||
result.setCode(-1);
|
||||
result.setMsg("获取播放地址失败");
|
||||
if (streamInfo == null){
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取播放地址失败");
|
||||
}
|
||||
|
||||
return result;
|
||||
return streamInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推流播放地址
|
||||
* 添加推流信息
|
||||
* @param stream 推流信息
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/add")
|
||||
@ResponseBody
|
||||
@Operation(summary = "停止视频回放")
|
||||
public WVPResult<StreamInfo> add(@RequestBody StreamPushItem stream){
|
||||
@Operation(summary = "添加推流信息")
|
||||
public void add(@RequestBody StreamPushItem stream){
|
||||
if (ObjectUtils.isEmpty(stream.getGbId())) {
|
||||
|
||||
return new WVPResult<>(400, "国标ID不可为空", null);
|
||||
throw new ControllerException(ErrorCode.ERROR400.getCode(), "国标ID不可为空");
|
||||
}
|
||||
if (ObjectUtils.isEmpty(stream.getApp()) && ObjectUtils.isEmpty(stream.getStream())) {
|
||||
return new WVPResult<>(400, "app或stream不可为空", null);
|
||||
throw new ControllerException(ErrorCode.ERROR400.getCode(), "app或stream不可为空");
|
||||
}
|
||||
stream.setStatus(false);
|
||||
stream.setPushIng(false);
|
||||
stream.setAliveSecond(0L);
|
||||
stream.setTotalReaderCount("0");
|
||||
boolean result = streamPushService.add(stream);
|
||||
|
||||
if (result) {
|
||||
return new WVPResult<>(0, "success", null);
|
||||
}else {
|
||||
return new WVPResult<>(-1, "fail", null);
|
||||
if (!streamPushService.add(stream)) {
|
||||
throw new ControllerException(ErrorCode.ERROR100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user