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
61个文件已修改
5个文件已添加
1 文件已重命名
9个文件已删除
| | |
| | | - [设备注册不上来的解决办法](_content/qa/regiser_error.md) |
| | | - [点播超时/报错的解决办法](_content/qa/play_error.md) |
| | | * [**免责声明**](_content/disclaimers.md) |
| | | * [**捐赠**](_content/donation.md) |
| | | * [**关于本文档**](_content/about_doc.md) |
| | |
| | | |
| | | <groupId>com.genersoft</groupId> |
| | | <artifactId>wvp-pro</artifactId> |
| | | <version>2.3.1</version> |
| | | <version>2.3.2</version> |
| | | <name>web video platform</name> |
| | | <description>国标28181视频平台</description> |
| | | |
| | |
| | | private String rtsp; |
| | | private String rtsps; |
| | | private String rtc; |
| | | |
| | | private String rtcs; |
| | | private String mediaServerId; |
| | | private Object tracks; |
| | | private String startTime; |
| | |
| | | public void setIp(String ip) { |
| | | this.ip = ip; |
| | | } |
| | | |
| | | public String getRtcs() { |
| | | return rtcs; |
| | | } |
| | | |
| | | public void setRtcs(String rtcs) { |
| | | this.rtcs = rtcs; |
| | | } |
| | | } |
| | |
| | |
|
| | | 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";
|
| | |
| | | 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; |
| | |
| | | |
| | | /** |
| | | * 系统启动时控制上级平台重新注册 |
| | | * @author lin |
| | | */ |
| | | @Component |
| | | @Order(value=3) |
| | |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Autowired |
| | | private EventPublisher publisher; |
| | | private IPlatformService platformService; |
| | | |
| | | @Autowired |
| | | private ISIPCommanderForPlatform sipCommanderForPlatform; |
| | |
| | | |
| | | @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()); |
| | | }); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | private Boolean logInDatebase = Boolean.TRUE; |
| | | |
| | | private Boolean redisConfig = Boolean.TRUE; |
| | | |
| | | private String serverId = "000000"; |
| | | |
| | | private String thirdPartyGBIdReg = "[\\s\\S]*"; |
| | |
| | | |
| | | public void setThirdPartyGBIdReg(String thirdPartyGBIdReg) { |
| | | this.thirdPartyGBIdReg = thirdPartyGBIdReg; |
| | | } |
| | | |
| | | public Boolean getRedisConfig() { |
| | | return redisConfig; |
| | | } |
| | | |
| | | public void setRedisConfig(Boolean redisConfig) { |
| | | this.redisConfig = redisConfig; |
| | | } |
| | | |
| | | public Boolean getRecordSip() { |
| | |
| | | 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; |
| | |
| | | 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()); |
New file |
| | |
| | | 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); |
| | | |
| | | } |
| | | } |
| | |
| | | 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{
|
| | |
| | | * 完整配置参考 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 _对话框传递_终止的_事件
|
| | |
| | | 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;
|
| | |
| | | * 注册周期 (秒) |
| | | */ |
| | | @Schema(description = "注册周期 (秒)") |
| | | private String expires; |
| | | private int expires; |
| | | |
| | | /** |
| | | * 心跳周期(秒) |
| | |
| | | this.password = password; |
| | | } |
| | | |
| | | public String getExpires() { |
| | | public int getExpires() { |
| | | return expires; |
| | | } |
| | | |
| | | public void setExpires(String expires) { |
| | | public void setExpires(int expires) { |
| | | this.expires = expires; |
| | | } |
| | | |
| | |
| | | |
| | | private String id; |
| | | |
| | | // 心跳未回复次数 |
| | | /** |
| | | * 心跳未回复次数 |
| | | */ |
| | | private int keepAliveReply; |
| | | |
| | | // 注册未回复次数 |
| | |
| | | import java.util.List; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | | /** |
| | | * @author lin |
| | | */ |
| | | @Component |
| | | public class SubscribeHolder { |
| | | |
| | |
| | |
|
| | | 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;
|
| | |
| | |
|
| | | @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);
|
| | | }
|
| | |
|
| | | /**
|
| | | * 设备报警事件
|
| | |
| | | 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; |
| | |
| | | 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(); |
| | |
| | | |
| | | }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(); |
| | |
| | | |
| | | @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; |
| | |
| | | // TODO 暂时只处理视频流的回复,后续增加对国标设备的支持 |
| | | List<DeviceChannel> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId()); |
| | | if (gbStreams.size() == 0) { |
| | | logger.info("发送订阅时发现平台已经没有关联的直播流:{}", platform.getServerGBId()); |
| | | return; |
| | | } |
| | | for (DeviceChannel deviceChannel : gbStreams) { |
| | |
| | | @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) { |
| | |
| | | @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! |
| | |
| | | } 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) { |
| | |
| | | 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;
|
| | |
| | | * @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);
|
| | |
|
| | | /**
|
| | | * 请求回放视频流
|
| | |
| | | * @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); |
| | | |
| | | /** |
| | | * 向上级平台注销 |
| | |
| | | * @param parentPlatform |
| | | * @return callId(作为接受回复的判定) |
| | | */ |
| | | String keepalive(ParentPlatform parentPlatform); |
| | | String keepalive(ParentPlatform parentPlatform,SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent); |
| | | |
| | | |
| | | /** |
| | |
| | | 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; |
| | |
| | | } |
| | | |
| | | |
| | | 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(); |
| | | //请求行 |
| | |
| | | .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"); |
| | |
| | |
|
| | | 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;
|
| | |
| | | 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",
|
| | |
| | | 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;
|
| | |
| | | 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:设备能力接口,用于定义设备的控制、查询能力
|
| | |
| | | private UserSetting userSetting;
|
| | |
|
| | | @Autowired
|
| | | private ZLMHttpHookSubscribe subscribe;
|
| | | private ZlmHttpHookSubscribe subscribe;
|
| | |
|
| | | @Autowired
|
| | | private SipSubscribe sipSubscribe;
|
| | |
| | | */
|
| | | @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) {
|
| | |
| | | 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)->{
|
| | |
| | | // 增加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)) {
|
| | |
| | | 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);
|
| | | }
|
| | |
| | | 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; |
| | |
| | | |
| | | @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(); |
| | |
| | | |
| | | 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) { |
| | |
| | | }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); |
| | |
| | | } |
| | | |
| | | @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(); |
| | |
| | | UUID.randomUUID().toString().replace("-", ""), |
| | | null, |
| | | callIdHeader); |
| | | transmitRequest(parentPlatform, request); |
| | | transmitRequest(parentPlatform, request, errorEvent, okEvent); |
| | | callId = callIdHeader.getCallId(); |
| | | } catch (ParseException | InvalidArgumentException | SipException e) { |
| | | e.printStackTrace(); |
| | |
| | | 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); |
| | |
| | | logger.error(e.getMessage()); |
| | | } catch (TransactionUnavailableException e) { |
| | | logger.error(e.getMessage()); |
| | | }finally { |
| | | |
| | | } |
| | | } |
| | | return serverTransaction; |
| | |
| | | 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); |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | private IMediaServerService mediaServerService; |
| | | |
| | | @Autowired |
| | | private ZLMHttpHookSubscribe subscribe; |
| | | private ZlmHttpHookSubscribe subscribe; |
| | | |
| | | @Autowired |
| | | private DynamicTask dynamicTask; |
| | |
| | | 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; |
| | |
| | | |
| | | 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; |
| | |
| | | |
| | | 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); |
| | |
| | | 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); |
| | |
| | | |
| | | 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); |
| | |
| | | } |
| | | } |
| | | |
| | | if (channelId.equals(sipConfig.getId())) { |
| | | if ("7".equals(deviceAlarm.getAlarmMethod()) ) { |
| | | // 发送给平台的报警信息。 发送redis通知 |
| | | AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage(); |
| | | alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod())); |
| | |
| | | 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; |
| | |
| | | } |
| | | 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)); |
| | |
| | | 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; |
| | |
| | | @Autowired |
| | | private SubscribeHolder subscribeHolder; |
| | | |
| | | @Autowired |
| | | private IPlatformService platformService; |
| | | |
| | | @Override |
| | | public void afterPropertiesSet() throws Exception { |
| | | // 添加消息处理的订阅 |
| | |
| | | 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); |
| | | } |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | if (mediaServerItem == null) { |
| | | return null; |
| | | } |
| | | if (ObjectUtils.isEmpty(mediaServerItem.getRecordAssistPort())) { |
| | | if (mediaServerItem.getRecordAssistPort() > 0) { |
| | | logger.warn("未启用Assist服务"); |
| | | return null; |
| | | } |
| | |
| | | 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;
|
| | |
| | | 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;
|
| | |
| | |
|
| | | @Autowired
|
| | | private SIPCommander cmder;
|
| | |
|
| | | @Autowired
|
| | | private SIPCommanderFroPlatform commanderFroPlatform;
|
| | |
|
| | | @Autowired
|
| | | private IPlayService playService;
|
| | |
| | | private ZLMMediaListManager zlmMediaListManager;
|
| | |
|
| | | @Autowired
|
| | | private ZLMHttpHookSubscribe subscribe;
|
| | | private ZlmHttpHookSubscribe subscribe;
|
| | |
|
| | | @Autowired
|
| | | private UserSetting userSetting;
|
| | |
| | | @Autowired
|
| | | private AssistRESTfulUtils assistRESTfulUtils;
|
| | |
|
| | | @Qualifier("taskExecutor")
|
| | | @Autowired
|
| | | private ThreadPoolTaskExecutor taskExecutor;
|
| | |
|
| | | /**
|
| | | * 服务器定时上报时间,上报间隔可配置,默认10s上报一次
|
| | | *
|
| | |
| | |
|
| | | 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);
|
| | | }
|
| | | }
|
| | |
| | | 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) {
|
| | |
| | | // 鉴权通过
|
| | | 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());
|
| | | }
|
| | |
| | | }
|
| | |
|
| | |
|
| | | 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);
|
| | |
| | | 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) {
|
| | |
| | | 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) {
|
| | |
| | | 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);
|
| | |
| | | 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) {
|
| | |
| | | }
|
| | | 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);
|
| | | }
|
| | | }
|
| | |
| | | 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 |
| | |
| | | private StreamPushMapper streamPushMapper; |
| | | |
| | | @Autowired |
| | | private ZLMHttpHookSubscribe subscribe; |
| | | private ZlmHttpHookSubscribe subscribe; |
| | | |
| | | @Autowired |
| | | private UserSetting userSetting; |
| | |
| | | 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"); |
| | |
| | | } |
| | | 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"); |
| | |
| | | * 查询待转推的流是否就绪 |
| | | */ |
| | | 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")); |
| | | } |
| | | |
| | |
| | | * @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; |
| | | } |
| | |
| | | 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; |
| | |
| | | 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) |
| | |
| | | private ZLMRESTfulUtils zlmresTfulUtils; |
| | | |
| | | @Autowired |
| | | private ZLMHttpHookSubscribe hookSubscribe; |
| | | private ZlmHttpHookSubscribe hookSubscribe; |
| | | |
| | | @Autowired |
| | | private EventPublisher publisher; |
| | |
| | | } |
| | | 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)->{ |
File was renamed from src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java |
| | |
| | | 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; |
| | | |
| | |
| | | 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)); |
| | |
| | | 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; |
| | |
| | | |
| | | 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); |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | * @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)); |
| | | } |
| | |
| | | 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); |
| | | } |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | | /** |
| | |
| | | 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); |
| | | |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | public class MediaServerServiceImpl implements IMediaServerService { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(MediaServerServiceImpl.class); |
| | | |
| | | private final String zlmKeepaliveKeyPrefix = "zlm-keepalive_"; |
| | | |
| | | @Autowired |
| | | private SipConfig sipConfig; |
| | |
| | | @Autowired |
| | | private ZLMRTPServerFactory zlmrtpServerFactory; |
| | | |
| | | |
| | | @Autowired |
| | | private EventPublisher publisher; |
| | | |
| | | @Autowired |
| | | private DynamicTask dynamicTask; |
| | | |
| | | /** |
| | | * 初始化 |
| | |
| | | logger.info("media server [ {} ] ssrcConfig is null", mediaServerItem.getId()); |
| | | return null; |
| | | }else { |
| | | String ssrc = null; |
| | | String ssrc; |
| | | if (presetSsrc != null) { |
| | | ssrc = presetSsrc; |
| | | }else { |
| | |
| | | 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 |
| | |
| | | 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"); |
| | |
| | | }else { |
| | | clearRTPServer(serverItem); |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | // 获取分数最低的,及并发最低的 |
| | | 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); |
| | |
| | | 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"); |
| | |
| | | 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)); |
| | |
| | | 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() ); |
| | | // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。 |
| | |
| | | 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) { |
| | |
| | | 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)); |
| | |
| | | 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); |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | private DynamicTask dynamicTask; |
| | | |
| | | @Autowired |
| | | private ZLMHttpHookSubscribe subscribe; |
| | | private ZlmHttpHookSubscribe subscribe; |
| | | |
| | | |
| | | @Qualifier("taskExecutor") |
| | |
| | | |
| | | @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"); |
| | |
| | | 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); |
| | |
| | | |
| | | @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()) { |
| | |
| | | // 单端口模式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)->{ |
| | |
| | | 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"); |
| | |
| | | // 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()); |
| | | // } |
| | | // } |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | return; |
| | | } |
| | | String gbId = alarmChannelMessage.getGbId(); |
| | | Device device = storage.queryVideoDevice(gbId); |
| | | ParentPlatform platform = storage.queryParentPlatByServerGBId(gbId); |
| | | |
| | | DeviceAlarm deviceAlarm = new DeviceAlarm(); |
| | | deviceAlarm.setCreateTime(DateUtil.getNow()); |
| | |
| | | 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 + "是平台还是设备"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | 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.*; |
| | |
| | | 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; |
| | |
| | | private ZLMMediaListManager mediaListManager; |
| | | |
| | | @Autowired |
| | | private ZLMHttpHookSubscribe subscribe; |
| | | private ZlmHttpHookSubscribe subscribe; |
| | | |
| | | |
| | | public interface PlayMsgCallback{ |
| | |
| | | }, 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); |
| | |
| | | if (jsonObject == null) { |
| | | return false; |
| | | } |
| | | System.out.println(jsonObject); |
| | | if (jsonObject.getInteger("code") == 0) { |
| | | result = true; |
| | | streamProxy.setEnable(true); |
| | |
| | | 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"); |
| | |
| | | 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; |
| | |
| | | |
| | | 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); |
| | | |
| | |
| | | * 发送redis消息 查询所有推流设备的状态 |
| | | */ |
| | | void sendStreamPushRequestedMsgForStatus(); |
| | | |
| | | List<SendRtpItem> querySendRTPServerByChnnelId(String channelId); |
| | | } |
| | |
| | | */ |
| | | boolean deleteParentPlatform(ParentPlatform parentPlatform); |
| | | |
| | | |
| | | /** |
| | | * 分页获取上级平台 |
| | | * @param page |
| | | * @param count |
| | | * @return |
| | | */ |
| | | PageInfo<ParentPlatform> queryParentPlatformList(int page, int count); |
| | | |
| | | /** |
| | | * 获取所有已启用的平台 |
| | | * @return |
New file |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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.*; |
| | |
| | | } |
| | | |
| | | @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); |
| | | } |
| | |
| | | |
| | | |
| | | @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 |
| | |
| | | } |
| | | |
| | | @Override |
| | | public List<SendRtpItem> querySendRTPServerByChnnelId(String channelId) { |
| | | if (channelId == null) { |
| | | return null; |
| | | } |
| | | String platformGbId = "*"; |
| | | String callId = "*"; |
| | | String streamId = "*"; |
| | | String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + userSetting.getServerId() + "_" + platformGbId |
| | | + "_" + channelId + "_" + streamId + "_" + callId; |
| | | List<Object> scan = RedisUtil.scan(key); |
| | | List<SendRtpItem> result = new ArrayList<>(); |
| | | for (Object o : scan) { |
| | | result.add((SendRtpItem) RedisUtil.get((String) o)); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<SendRtpItem> querySendRTPServer(String platformGbId) { |
| | | if (platformGbId == null) { |
| | | platformGbId = "*"; |
| | |
| | | } |
| | | |
| | | @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); |
| | | } |
| | |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | public static String getNowForISO8601() { |
| | | LocalDateTime nowDateTime = LocalDateTime.now(); |
| | | return formatterISO8601.format(nowDateTime); |
| | | } |
| | | } |
| | |
| | | /**
|
| | | * 获取对象 这里重写了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);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | |
|
| | | 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 {
|
| | |
| | | private static RedisTemplate redisTemplate;
|
| | |
|
| | | static {
|
| | | redisTemplate = (RedisTemplate)SpringBeanFactory.getBean("redisTemplate");
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | |
| | |
|
| | | /**
|
| | | * 指定缓存失效时间
|
| | | * @param key 键
|
| | |
| | | * @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);
|
| | |
| | | /**
|
| | | * 根据 key 获取过期时间
|
| | | * @param key 键
|
| | | * @return
|
| | | */
|
| | | public static long getExpire(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
| | | }
|
| | |
|
| | |
| | | * @return true / false
|
| | | */
|
| | | public static boolean hasKey(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | try {
|
| | | return redisTemplate.hasKey(key);
|
| | | } catch (Exception e) {
|
| | |
| | | * @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) {
|
| | |
| | | * @return 值
|
| | | */
|
| | | public static Object get(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return key == null ? null : redisTemplate.opsForValue().get(key);
|
| | | }
|
| | |
|
| | |
| | | * @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;
|
| | |
| | | * @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);
|
| | |
| | | * @return
|
| | | */
|
| | | public static long incr(String key, long delta) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | if (delta < 0) {
|
| | | throw new RuntimeException("递增因子必须大于 0");
|
| | | }
|
| | |
| | | * @return
|
| | | */
|
| | | public static long decr(String key, long delta) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | if (delta < 0) {
|
| | | throw new RuntimeException("递减因子必须大于 0");
|
| | | }
|
| | |
| | | * @return 值
|
| | | */
|
| | | public static Object hget(String key, String item) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.opsForHash().get(key, item);
|
| | | }
|
| | |
|
| | |
| | | * @return 对应的多个键值
|
| | | */
|
| | | public static Map<Object, Object> hmget(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.opsForHash().entries(key);
|
| | | }
|
| | |
|
| | |
| | | * @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;
|
| | |
| | | * @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) {
|
| | |
| | | * @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;
|
| | |
| | | * @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) {
|
| | |
| | | * @param item 项(可以多个,no null)
|
| | | */
|
| | | public static void hdel(String key, Object... item) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | redisTemplate.opsForHash().delete(key, item);
|
| | | }
|
| | |
|
| | |
| | | * @return true / false
|
| | | */
|
| | | public static boolean hHasKey(String key, String item) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.opsForHash().hasKey(key, item);
|
| | | }
|
| | |
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | |
| | | * @return 值
|
| | | */
|
| | | public static Set<Object> sGet(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | try {
|
| | | return redisTemplate.opsForSet().members(key);
|
| | | } catch (Exception e) {
|
| | |
| | | * @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) {
|
| | |
| | | * @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) {
|
| | |
| | | * @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) {
|
| | |
| | | * @return 长度
|
| | | */
|
| | | public static long sGetSetSize(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | try {
|
| | | return redisTemplate.opsForSet().size(key);
|
| | | } catch (Exception e) {
|
| | |
| | | * @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) {
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | |
| | | * @param value
|
| | | */
|
| | | public static void zRemove(Object key, Object value) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | redisTemplate.opsForZSet().remove(key, value);
|
| | | }
|
| | |
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | |
| | | * @return
|
| | | */
|
| | | public static Double zScore(Object key, Object value) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.opsForZSet().score(key, value);
|
| | | }
|
| | |
|
| | |
| | | * @return
|
| | | */
|
| | | public static Long zRank(Object key, Object value) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.opsForZSet().rank(key, value);
|
| | | }
|
| | |
|
| | |
| | | * @return
|
| | | */
|
| | | public static Long zSize(Object key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.opsForZSet().zCard(key);
|
| | | }
|
| | |
|
| | |
| | | * @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);
|
| | | }
|
| | | /**
|
| | |
| | | * @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);
|
| | | }
|
| | | /**
|
| | |
| | | * @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);
|
| | | }
|
| | | /**
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | |
| | | * @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) {
|
| | |
| | | * @return 长度
|
| | | */
|
| | | public static long lGetListSize(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | try {
|
| | | return redisTemplate.opsForList().size(key);
|
| | | } catch (Exception e) {
|
| | |
| | | * @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) {
|
| | |
| | | * @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;
|
| | |
| | | * @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) {
|
| | |
| | | * @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;
|
| | |
| | | * @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) {
|
| | |
| | | * @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;
|
| | |
| | | * @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) {
|
| | |
| | | * @return
|
| | | */
|
| | | public static Object lLeftPop(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.opsForList().leftPop(key);
|
| | | }
|
| | |
|
| | |
| | | * @return
|
| | | */
|
| | | public static Object lrightPop(String key) {
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | return redisTemplate.opsForList().rightPop(key);
|
| | | }
|
| | |
|
| | |
| | | * @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);
|
| | |
| | | * @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);
|
| | |
| | |
|
| | | // ============================== 消息发送与订阅 ==============================
|
| | | public static void convertAndSend(String channel, JSONObject msg) {
|
| | | // redisTemplate.convertAndSend(channel, msg);
|
| | | if (redisTemplate == null) {
|
| | | redisTemplate = SpringBeanFactory.getBean("redisTemplate");
|
| | | }
|
| | | redisTemplate.convertAndSend(channel, msg);
|
| | |
|
| | | }
|
| | |
|
| | | }
|
| | |
| | | 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; |
| | |
| | | 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; |
| | | |
| | |
| | | @Autowired |
| | | private DynamicTask dynamicTask; |
| | | |
| | | @Autowired |
| | | private IPlatformService platformService; |
| | | |
| | | /** |
| | | * 获取国标服务的配置 |
| | | * |
| | |
| | | @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 { |
| | |
| | | @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); |
| | |
| | | @Operation(summary = "添加上级平台信息") |
| | | @PostMapping("/add") |
| | | @ResponseBody |
| | | public String addPlatform(@RequestBody ParentPlatform parentPlatform) { |
| | | public void addPlatform(@RequestBody ParentPlatform parentPlatform) { |
| | | |
| | | if (logger.isDebugEnabled()) { |
| | | logger.debug("保存上级平台信息API调用"); |
| | |
| | | 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(),"写入数据库失败"); |
| | | } |
| | | } |
| | |
| | | @Operation(summary = "保存上级平台信息") |
| | | @PostMapping("/save") |
| | | @ResponseBody |
| | | public String savePlatform(@RequestBody ParentPlatform parentPlatform) { |
| | | public void savePlatform(@RequestBody ParentPlatform parentPlatform) { |
| | | |
| | | if (logger.isDebugEnabled()) { |
| | | logger.debug("保存上级平台信息API调用"); |
| | |
| | | // 停止订阅相关的定时任务 |
| | | subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId()); |
| | | } |
| | | return null; |
| | | } else { |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(),"写入数据库失败"); |
| | | } |
| | |
| | | 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; |
| | |
| | | public class ServerController { |
| | | |
| | | @Autowired |
| | | private ZLMHttpHookSubscribe zlmHttpHookSubscribe; |
| | | private ZlmHttpHookSubscribe zlmHttpHookSubscribe; |
| | | |
| | | @Autowired |
| | | private IMediaServerService mediaServerService; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | @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); |
| | | } |
| | | } |
| | | |
| | |
| | | @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); |
| | | } |
| | | } |
| | | |
| | |
| | | @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); |
| | | } |
| | | } |
| | | |
| | |
| | | @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; |
| | | // 是否登陆用户, 登陆用户返回完整信息 |
| | |
| | | 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); |
| | | } |
| | | } |
| | | } |
| | |
| | | platform-play-timeout: 60000 |
| | | # 是否开启接口鉴权 |
| | | interface-authentication: true |
| | | # 自动配置redis 可以过期事件 |
| | | redis-config: true |
| | | # 接口鉴权例外的接口, 即不进行接口鉴权的接口,尽量详细书写,尽量不用/**,至少两级目录 |
| | | interface-authentication-excludes: |
| | | - /api/v1/** |
| | |
| | | </encoder> |
| | | </appender> |
| | | |
| | | <!-- 生成 SIP日志追加 --> |
| | | <appender name="sipRollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> |
| | | <!--历史日志文件输出的文件名 --> |
| | | <FileNamePattern>${LOG_HOME}/sip-%d{yyyy-MM-dd}.%i.log</FileNamePattern> |
| | | <!--日志文件保留天数 --> |
| | | <MaxHistory>30</MaxHistory> |
| | | <maxFileSize>50MB</maxFileSize> |
| | | </rollingPolicy> |
| | | <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> |
| | | <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 --> |
| | | <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n</pattern> |
| | | </encoder> |
| | | </appender> |
| | | |
| | | |
| | | <!-- 日志输出级别 --> |
| | | <root level="INFO"> |
| | | <appender-ref ref="STDOUT" /> |
| | | <appender-ref ref="RollingFile" /> |
| | | <appender-ref ref="RollingFileError" /> |
| | | </root> |
| | | |
| | | <!-- <logger name="com.genersoft.iot.vmp.storager.dao" level="INFO">--> |
| | | <!-- <appender-ref ref="STDOUT"/>--> |
| | | <!-- </logger>--> |
| | | <!-- <logger name="com.genersoft.iot.vmp.gb28181" level="INFO">--> |
| | | <!-- <appender-ref ref="STDOUT"/>--> |
| | | <!-- </logger>--> |
| | | <logger name="GB28181_SIP" level="debug" additivity="true"> |
| | | <appender-ref ref="RollingFileError"/> |
| | | <appender-ref ref="sipRollingFile"/> |
| | | </logger> |
| | | |
| | | <!--记录druid-sql的记录--> |
| | | <logger name="druid.sql.Statement" level="debug" additivity="true"> |
| | | <logger name="com.genersoft.iot.vmp.storager.dao" level="info" additivity="true"> |
| | | <!--AppenderRef ref="Console"/--> |
| | | <!-- <appender-ref ref="RollingFile"/>--> |
| | | <appender-ref ref="RollingFileError"/> |
| | | <appender-ref ref="druidSqlRollingFile"/> |
| | | </logger> |
| | |
| | | <template> |
| | | <div id="app" style="width: 100%"> |
| | | <div class="page-header"> |
| | | <div class="page-title">云端录像</div> |
| | | <div class="page-title"> |
| | | <el-page-header v-if="recordDetail" @back="backToList" content="云端录像"></el-page-header> |
| | | <div v-if="!recordDetail">云端录像</div> |
| | | </div> |
| | | |
| | | <div class="page-header-btn"> |
| | | 节点选择: |
| | | <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerId" placeholder="请选择" :disabled="recordDetail"> |
| | |
| | | }).catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | |
| | | } |
| | |
| | | <template> |
| | | <div id="recordDetail"> |
| | | <el-container> |
| | | |
| | | <el-aside width="300px"> |
| | | |
| | | <div class="record-list-box-box"> |
| | | <el-date-picker size="mini" v-model="chooseDate" :picker-options="pickerOptions" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker> |
| | | <div class="record-list-box" :style="recordListStyle"> |
| | |
| | | }).catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | | }, |
| | | goBack(){ |
| | | this.$router.push('/cloudRecord'); |
| | | } |
| | | } |
| | | }; |
| | |
| | | |
| | | //登录请求 |
| | | toLogin(){ |
| | | |
| | | //一般要跟后端了解密码的加密规则 |
| | | //这里例子用的哈希算法来自./js/sha1.min.js |
| | | |
| | | //需要想后端发送的登录参数 |
| | | let loginParam = { |
| | | username: this.username, |
| | |
| | | var that = this; |
| | | //设置在登录状态 |
| | | this.isLoging = true; |
| | | let timeoutTask = setTimeout(()=>{ |
| | | that.$message.error("登录超时"); |
| | | that.isLoging = false; |
| | | }, 1000) |
| | | |
| | | this.$axios({ |
| | | method: 'get', |
| | | url:"/api/user/login", |
| | | params: loginParam |
| | | }).then(function (res) { |
| | | window.clearTimeout(timeoutTask) |
| | | console.log(JSON.stringify(res)); |
| | | if (res.data.code === 0 ) { |
| | | that.$cookies.set("session", {"username": that.username,"roleId":res.data.data.role.id}) ; |
| | |
| | | }); |
| | | } |
| | | }).catch(function (error) { |
| | | console.log(error) |
| | | window.clearTimeout(timeoutTask) |
| | | that.$message.error(error.response.data.msg); |
| | | that.isLoging = false; |
| | | }); |
| | |
| | | var result = false; |
| | | var that = this; |
| | | await that.$axios({ |
| | | method: 'post', |
| | | method: 'get', |
| | | url:`/api/platform/exit/${deviceGbId}` |
| | | }).then(function (res) { |
| | | result = res.data; |
| | |
| | | var result = false; |
| | | var that = this; |
| | | await that.$axios({ |
| | | method: 'post', |
| | | method: 'get', |
| | | url:`/api/platform/exit/${deviceGbId}` |
| | | }).then(function (res) { |
| | | result = res.data; |
| | |
| | | if (tab.name === "codec") { |
| | | this.$axios({ |
| | | method: 'get', |
| | | url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId |
| | | url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtsp&app='+ this.app +'&stream='+ this.streamId |
| | | }).then(function (res) { |
| | | that.tracksLoading = false; |
| | | if (res.data.code == 0 && res.data.tracks) { |
| | |
| | | } |
| | | }, |
| | | saveForm: function (){ |
| | | var that = this; |
| | | that.$axios({ |
| | | this.$axios({ |
| | | method: 'post', |
| | | url: this.saveUrl, |
| | | data: that.platform |
| | | }).then(function (res) { |
| | | data: this.platform |
| | | }).then((res) =>{ |
| | | if (res.data.code === 0) { |
| | | that.$message({ |
| | | this.$message({ |
| | | showClose: true, |
| | | message: "保存成功", |
| | | type: "success", |
| | | }); |
| | | that.showDialog = false; |
| | | if (that.listChangeCallback != null) { |
| | | that.listChangeCallback(); |
| | | this.showDialog = false; |
| | | if (this.listChangeCallback != null) { |
| | | this.listChangeCallback(); |
| | | } |
| | | }else { |
| | | that.$message({ |
| | | this.$message({ |
| | | showClose: true, |
| | | message: res.data.msg, |
| | | type: "error", |
| | | }); |
| | | } |
| | | }).catch(function (error) { |
| | | }).catch((error)=> { |
| | | console.log(error); |
| | | }); |
| | | }, |
| | |
| | | var result = false; |
| | | var that = this; |
| | | await that.$axios({ |
| | | method: 'post', |
| | | method: 'get', |
| | | url:`/api/platform/exit/${deviceGbId}`}) |
| | | .then(function (res) { |
| | | if (res.data.code === 0) { |
| | |
| | | var result = false; |
| | | var that = this; |
| | | await that.$axios({ |
| | | method:"post", |
| | | method:"get", |
| | | url:`/api/platform/exit/${deviceGbId}` |
| | | }).then(function (res) { |
| | | result = res.data; |