src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
@@ -1,7 +1,7 @@ package com.genersoft.iot.vmp.common; /** * @Description: 定义常量 * @description: 定义常量 * @author: swwheihei * @date: 2019年5月30日 下午3:04:04 * src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java
@@ -16,7 +16,7 @@ import redis.clients.jedis.JedisPoolConfig; /** * @Description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置 * @description:Redis中间件配置类,使用spring-data-redis集成,自动从application.yml中加载redis配置 * @author: swwheihei * @date: 2019年5月30日 上午10:58:25 * src/main/java/com/genersoft/iot/vmp/conf/SipDeviceRunner.java
@@ -32,5 +32,7 @@ for (String deviceId : onlineForAll) { storager.online(deviceId); } // TODO 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 } } src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java
@@ -4,7 +4,7 @@ import org.springframework.context.annotation.Configuration; /** * @Description: 获取数据库配置 * @description: 获取数据库配置 * @author: swwheihei * @date: 2020年5月6日 下午2:46:00 */ src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -1,19 +1,10 @@ package com.genersoft.iot.vmp.gb28181; import java.text.ParseException; import java.util.Properties; import java.util.TooManyListenersException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.sip.*; import javax.sip.header.CallIdHeader; import javax.sip.header.Header; import javax.sip.message.Response; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import gov.nist.javax.sip.SipProviderImpl; import gov.nist.javax.sip.SipStackImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -21,14 +12,15 @@ import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Component; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory; import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; import gov.nist.javax.sip.SipStackImpl; 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; @Component public class SipLayer implements SipListener { public class SipLayer{ private final static Logger logger = LoggerFactory.getLogger(SipLayer.class); @@ -36,7 +28,7 @@ private SipConfig sipConfig; @Autowired private SIPProcessorFactory processorFactory; private SIPProcessorObserver sipProcessorObserver; @Autowired private SipSubscribe sipSubscribe; @@ -50,19 +42,16 @@ */ private ThreadPoolExecutor processThreadPool; @Bean("initSipServer") private ThreadPoolExecutor initSipServer() { public SipLayer() { int processThreadNum = Runtime.getRuntime().availableProcessors() * 10; LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<>(10000); processThreadPool = new ThreadPoolExecutor(processThreadNum,processThreadNum, 0L,TimeUnit.MILLISECONDS,processQueue, new ThreadPoolExecutor.CallerRunsPolicy()); return processThreadPool; } @Bean("sipFactory") @DependsOn("initSipServer") private SipFactory createSipFactory() { sipFactory = SipFactory.getInstance(); sipFactory.setPathName("gov.nist"); @@ -70,7 +59,7 @@ } @Bean("sipStack") @DependsOn({"initSipServer", "sipFactory"}) @DependsOn({"sipFactory"}) private SipStack createSipStack() throws PeerUnavailableException { Properties properties = new Properties(); properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); @@ -96,7 +85,7 @@ try { tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "TCP"); tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint); tcpSipProvider.addSipListener(this); tcpSipProvider.addSipListener(sipProcessorObserver); logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "}"); } catch (TransportNotSupportedException e) { e.printStackTrace(); @@ -119,8 +108,7 @@ try { udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP"); udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint); udpSipProvider.addSipListener(this); // udpSipProvider.setAutomaticDialogSupportEnabled(false); udpSipProvider.addSipListener(sipProcessorObserver); } catch (TransportNotSupportedException e) { e.printStackTrace(); } catch (InvalidArgumentException e) { @@ -133,142 +121,6 @@ } logger.info("Sip Server UDP 启动成功 port [" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "]"); return udpSipProvider; } /** * SIP服务端接收消息的方法 Content 里面是GBK编码 This method is called by the SIP stack when a * new request arrives. */ @Override public void processRequest(RequestEvent evt) { logger.debug(evt.getRequest().toString()); // 由于jainsip是单线程程序,为提高性能并发处理 processThreadPool.execute(() -> { if (processorFactory != null) { processorFactory.createRequestProcessor(evt).process(); } }); } @Override public void processResponse(ResponseEvent evt) { Response response = evt.getResponse(); logger.debug(evt.getResponse().toString()); int status = response.getStatusCode(); if (((status >= 200) && (status < 300)) || status == 401) { // Success! ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt); try { processor.process(evt, this, sipConfig); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) { CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME); if (callIdHeader != null) { SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId()); if (subscribe != null) { SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(evt); subscribe.response(eventResult); } } } } else if ((status >= 100) && (status < 200)) { // 增加其它无需回复的响应,如101、180等 } else { logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) { CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME); if (callIdHeader != null) { SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()); if (subscribe != null) { SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(evt); subscribe.response(eventResult); } } } } } /** * <p> * Title: processTimeout * </p> * <p> * Description: * </p> * * @param timeoutEvent */ @Override public void processTimeout(TimeoutEvent timeoutEvent) { // TODO Auto-generated method stub CallIdHeader callIdHeader = timeoutEvent.getClientTransaction().getDialog().getCallId(); String callId = callIdHeader.getCallId(); SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId); SipSubscribe.EventResult<TimeoutEvent> timeoutEventEventResult = new SipSubscribe.EventResult<>(timeoutEvent); errorSubscribe.response(timeoutEventEventResult); } /** * <p> * Title: processIOException * </p> * <p> * Description: * </p> * * @param exceptionEvent */ @Override public void processIOException(IOExceptionEvent exceptionEvent) { // TODO Auto-generated method stub } /** * <p> * Title: processTransactionTerminated * </p> * <p> * Description: * </p> * * @param transactionTerminatedEvent */ @Override public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) { // TODO Auto-generated method stub // CallIdHeader callIdHeader = transactionTerminatedEvent.getClientTransaction().getDialog().getCallId(); // String callId = callIdHeader.getCallId(); // SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId); // SipSubscribe.EventResult<TransactionTerminatedEvent> eventResult = new SipSubscribe.EventResult<>(transactionTerminatedEvent); // errorSubscribe.response(eventResult); } /** * <p> * Title: processDialogTerminated * </p> * <p> * Description: * </p> * * @param dialogTerminatedEvent */ @Override public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { // TODO Auto-generated method stub // CallIdHeader callIdHeader = dialogTerminatedEvent.getDialog().getCallId(); // String callId = callIdHeader.getCallId(); // SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId); // SipSubscribe.EventResult<DialogTerminatedEvent> eventResult = new SipSubscribe.EventResult<>(dialogTerminatedEvent); // errorSubscribe.response(eventResult); } } src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java
@@ -9,7 +9,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; /** * @Description:注册逻辑处理,当设备注册后触发逻辑。 * @description:注册逻辑处理,当设备注册后触发逻辑。 * @author: swwheihei * @date: 2020年5月8日 下午9:41:46 */ src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -109,6 +109,11 @@ */ private String charset ; /** * 目录订阅周期,0为不订阅 */ private int subscribeCycleForCatalog ; public String getDeviceId() { @@ -270,4 +275,12 @@ public void setCharset(String charset) { this.charset = charset; } public int getSubscribeCycleForCatalog() { return subscribeCycleForCatalog; } public void setSubscribeCycleForCatalog(int subscribeCycleForCatalog) { this.subscribeCycleForCatalog = subscribeCycleForCatalog; } } src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java
@@ -1,7 +1,7 @@ package com.genersoft.iot.vmp.gb28181.bean; /** * @Description: 移动位置bean * @description: 移动位置bean * @author: lawrencehj * @date: 2021年1月23日 */ src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
@@ -6,7 +6,7 @@ import java.util.List; /** * @Description:设备录像信息bean * @description:设备录像信息bean * @author: swwheihei * @date: 2020年5月8日 下午2:05:56 */ src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
@@ -8,7 +8,7 @@ import java.util.Date; /** * @Description:设备录像bean * @description:设备录像bean * @author: swwheihei * @date: 2020年5月8日 下午2:06:54 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java
@@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.utils.redis.RedisUtil; /** * @Description:设备离在线状态检测器,用于检测设备状态 * @description:设备离在线状态检测器,用于检测设备状态 * @author: swwheihei * @date: 2020年5月13日 下午2:40:29 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
@@ -13,7 +13,7 @@ import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent; /** * @Description:Event事件通知推送器,支持推送在线事件、离线事件 * @description:Event事件通知推送器,支持推送在线事件、离线事件 * @author: swwheihei * @date: 2020年5月6日 上午11:30:50 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java
@@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher; /** * @Description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 * @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 * @author: swwheihei * @date: 2020年5月6日 上午11:35:46 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java
@@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.gb28181.event.EventPublisher; /** * @Description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 * @description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件 * @author: swwheihei * @date: 2020年5月6日 上午11:35:46 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEvent.java
@@ -3,7 +3,7 @@ import org.springframework.context.ApplicationEvent; /** * @Description: 离线事件类 * @description: 离线事件类 * @author: swwheihei * @date: 2020年5月6日 上午11:33:13 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java
@@ -11,8 +11,8 @@ import com.genersoft.iot.vmp.utils.redis.RedisUtil; /** * @Description: 离线事件监听器,监听到离线后,修改设备离在线状态。 设备离线有两个来源: * 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor} * @description: 离线事件监听器,监听到离线后,修改设备离在线状态。 设备离线有两个来源: * 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor} * 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.offline.OfflineEventListener} * @author: swwheihei * @date: 2020年5月6日 下午1:51:23 @@ -54,5 +54,8 @@ // 处理离线监听 storager.outline(event.getDeviceId()); // TODO 离线取消订阅 } } src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java
@@ -4,7 +4,7 @@ import org.springframework.context.ApplicationEvent; /** * @Description: 在线事件类 * @description: 在线事件类 * @author: swwheihei * @date: 2020年5月6日 上午11:32:56 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
@@ -13,12 +13,11 @@ import com.genersoft.iot.vmp.utils.redis.RedisUtil; import java.text.SimpleDateFormat; import java.util.Date; /** * @Description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源: * 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor} * 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor} * @description: 在线事件监听器,监听到离线后,修改设备离在线状态。 设备在线有两个来源: * 1、设备主动注销,发送注销指令,{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor} * 2、设备未知原因离线,心跳超时,{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.MessageRequestProcessor} * @author: swwheihei * @date: 2020年5月6日 下午1:51:23 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java
@@ -18,7 +18,7 @@ import javax.sip.message.Response; /** * @Description: 平台心跳超时事件 * @description: 平台心跳超时事件 * @author: panll * @date: 2020年11月5日 10:00 */ src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
@@ -19,7 +19,7 @@ import java.util.*; /** * @Description: 平台未注册事件,来源有二: * @description: 平台未注册事件,来源有二: * 1、平台新添加 * 2、平台心跳超时 * @author: panll src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
@@ -15,7 +15,7 @@ import org.springframework.stereotype.Component; /** * @Description:视频流session管理器,管理视频预览、预览回放的通信句柄 * @description:视频流session管理器,管理视频预览、预览回放的通信句柄 * @author: swwheihei * @date: 2020年5月13日 下午4:03:02 */ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
New file @@ -0,0 +1,113 @@ package com.genersoft.iot.vmp.gb28181.transmit; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.response.ISIPResponseProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.sip.*; import javax.sip.header.CSeqHeader; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @description: SIP信令处理类观察者 * @author: panlinlin * @date: 2021年11月5日 下午15:32 */ @Component public class SIPProcessorObserver implements SipListener { private final static Logger logger = LoggerFactory.getLogger(SIPProcessorObserver.class); private static Map<String, ISIPRequestProcessor> requestProcessorMap = new ConcurrentHashMap<>(); private static Map<String, ISIPResponseProcessor> responseProcessorMap = new ConcurrentHashMap<>(); private static ITimeoutProcessor timeoutProcessor; /** * 添加 request订阅 * @param method 方法名 * @param processor 处理程序 */ public void addRequestProcessor(String method, ISIPRequestProcessor processor) { requestProcessorMap.put(method, processor); } /** * 添加 response订阅 * @param method 方法名 * @param processor 处理程序 */ public void addResponseProcessor(String method, ISIPResponseProcessor processor) { responseProcessorMap.put(method, processor); } /** * 添加 超时事件订阅 * @param processor 处理程序 */ public void addTimeoutProcessor(ITimeoutProcessor processor) { this.timeoutProcessor = processor; } /** * 分发RequestEvent事件 * @param requestEvent RequestEvent事件 */ @Override public void processRequest(RequestEvent requestEvent) { String method = requestEvent.getRequest().getMethod(); ISIPRequestProcessor sipRequestProcessor = requestProcessorMap.get(method); if (sipRequestProcessor == null) { logger.warn("不支持方法{}的request", method); return; } requestProcessorMap.get(requestEvent.getRequest().getMethod()).process(requestEvent); } /** * 分发ResponseEvent事件 * @param responseEvent responseEvent事件 */ @Override public void processResponse(ResponseEvent responseEvent) { CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME); String method = cseqHeader.getMethod(); ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method); if (sipRequestProcessor == null) { logger.warn("不支持方法{}的response", method); return; } sipRequestProcessor.process(responseEvent); } /** * 向超时订阅发送消息 * @param timeoutEvent timeoutEvent事件 */ @Override public void processTimeout(TimeoutEvent timeoutEvent) { if(timeoutProcessor != null) { timeoutProcessor.process(timeoutEvent); } } @Override public void processIOException(IOExceptionEvent exceptionEvent) { } @Override public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) { } @Override public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) { } } src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java
@@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; import com.genersoft.iot.vmp.gb28181.bean.RecordItem; import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.MessageRequestProcessor; import com.genersoft.iot.vmp.utils.redis.RedisUtil; import org.slf4j.Logger; src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
@@ -11,7 +11,7 @@ import org.springframework.web.context.request.async.DeferredResult; /** * @Description: 异步请求处理 * @description: 异步请求处理 * @author: swwheihei * @date: 2020年5月8日 下午7:59:05 */ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java
@@ -1,7 +1,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.callback; /** * @Description: 请求信息定义 * @description: 请求信息定义 * @author: swwheihei * @date: 2020年5月8日 下午1:09:18 */ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; /** * @Description:设备能力接口,用于定义设备的控制、查询能力 * @description:设备能力接口,用于定义设备的控制、查询能力 * @author: swwheihei * @date: 2020年5月3日 下午9:16:34 */ @@ -299,4 +299,11 @@ * @return true = 命令发送成功 */ boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime); /** * 订阅、取消订阅目录信息 * @param device 视频设备 * @return true = 命令发送成功 */ boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent); } src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
@@ -19,7 +19,7 @@ import java.util.UUID; /** * @Description: 平台命令request创造器 TODO 冗余代码太多待优化 * @description: 平台命令request创造器 TODO 冗余代码太多待优化 * @author: panll * @date: 2020年5月6日 上午9:29:02 */ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
@@ -18,7 +18,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; /** * @Description:摄像头命令request创造器 TODO 冗余代码太多待优化 * @description:摄像头命令request创造器 TODO 冗余代码太多待优化 * @author: swwheihei * @date: 2020年5月6日 上午9:29:02 */ src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -1,20 +1,17 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; import java.lang.reflect.Field; import java.text.ParseException; import java.util.HashSet; import javax.sip.*; import javax.sip.address.SipURI; import javax.sip.header.CallIdHeader; import javax.sip.header.ViaHeader; import javax.sip.message.Request; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetup; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; import com.genersoft.iot.vmp.media.zlm.*; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider; import com.genersoft.iot.vmp.gb28181.utils.DateUtil; import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; 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; @@ -29,20 +26,20 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.gb28181.bean.Device; 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.DateUtil; import com.genersoft.iot.vmp.gb28181.utils.NumericUtil; import org.springframework.util.StringUtils; import javax.sip.*; import javax.sip.address.SipURI; import javax.sip.header.CallIdHeader; import javax.sip.header.ViaHeader; import javax.sip.message.Request; import java.lang.reflect.Field; import java.text.ParseException; import java.util.HashSet; /** * @Description:设备能力接口,用于定义设备的控制、查询能力 * @description:设备能力接口,用于定义设备的控制、查询能力 * @author: swwheihei * @date: 2020年5月3日 下午9:22:48 */ @@ -55,12 +52,10 @@ @Autowired private SipConfig sipConfig; @Lazy @Autowired @Qualifier(value="tcpSipProvider") private SipProviderImpl tcpSipProvider; @Lazy @Autowired @Qualifier(value="udpSipProvider") private SipProviderImpl udpSipProvider; @@ -89,11 +84,6 @@ @Autowired private IMediaServerService mediaServerService; private SIPDialog dialog; public SipConfig getSipConfig() { return sipConfig; } /** * 云台方向放控制,使用配置文件中的默认镜头移动速度 @@ -1490,6 +1480,33 @@ } } @Override public boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) { try { StringBuffer cmdXml = new StringBuffer(200); cmdXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n"); cmdXml.append("<Query>\r\n"); cmdXml.append("<CmdType>CataLog</CmdType>\r\n"); cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); cmdXml.append("</Query>\r\n"); String tm = Long.toString(System.currentTimeMillis()); CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() : udpSipProvider.getNewCallId(); Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "presence" , callIdHeader); transmitRequest(device, request, errorEvent, okEvent); return true; } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) { e.printStackTrace(); return false; } } private ClientTransaction transmitRequest(Device device, Request request) throws SipException { return transmitRequest(device, request, null, null); src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/SIPResponseProcessorAbstract.java
New file @@ -0,0 +1,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response; import org.springframework.beans.factory.InitializingBean; public abstract class SIPResponseProcessorAbstract implements InitializingBean, ISIPResponseProcessor { } src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java
New file @@ -0,0 +1,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.timeout; import javax.sip.TimeoutEvent; public interface ITimeoutProcessor { void process(TimeoutEvent event); } src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java
New file @@ -0,0 +1,36 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.timeout.impl; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.sip.TimeoutEvent; import javax.sip.header.CallIdHeader; @Component public class TimeoutProcessorImpl implements InitializingBean, ITimeoutProcessor { @Autowired private SIPProcessorObserver processorObserver; @Autowired private SipSubscribe sipSubscribe; @Override public void afterPropertiesSet() throws Exception { processorObserver.addTimeoutProcessor(this); } @Override public void process(TimeoutEvent event) { // TODO Auto-generated method stub CallIdHeader callIdHeader = event.getClientTransaction().getDialog().getCallId(); String callId = callIdHeader.getCallId(); SipSubscribe.Event errorSubscribe = sipSubscribe.getErrorSubscribe(callId); SipSubscribe.EventResult<TimeoutEvent> timeoutEventEventResult = new SipSubscribe.EventResult<>(event); errorSubscribe.response(timeoutEventEventResult); } } src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/ISIPRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/SIPRequestAbstractProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/ByeRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/CancelRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/NotifyRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/OtherRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/ISIPResponseProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/ByeResponseProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/CancelResponseProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/OtherResponseProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java
File was deleted src/main/java/com/genersoft/iot/vmp/gb28181/utils/DateUtil.java
@@ -6,7 +6,7 @@ import java.util.Locale; /** * @Description:时间工具类,主要处理ISO 8601格式转换 * @description:时间工具类,主要处理ISO 8601格式转换 * @author: swwheihei * @date: 2020年5月8日 下午3:24:42 */ src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
File was renamed from src/main/java/com/genersoft/iot/vmp/utils/SipUtils.java @@ -1,4 +1,4 @@ package com.genersoft.iot.vmp.utils; package com.genersoft.iot.vmp.gb28181.utils; import gov.nist.javax.sip.address.AddressImpl; import gov.nist.javax.sip.address.SipUri; @@ -9,15 +9,20 @@ /** * @author panlinlin * @version 1.0.0 * @Description JAIN SIP的工具类 * @description JAIN SIP的工具类 * @createTime 2021年09月27日 15:12:00 */ public class SipUtils { public static String getUserIdFromFromHeader(Request request) { FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME); return getUserIdFromFromHeader(fromHeader); } public static String getUserIdFromFromHeader(FromHeader fromHeader) { AddressImpl address = (AddressImpl)fromHeader.getAddress(); SipUri uri = (SipUri) address.getURI(); return uri.getUser(); } } src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
@@ -1,15 +1,7 @@ package com.genersoft.iot.vmp.gb28181.utils; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; @@ -18,6 +10,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import javax.sip.RequestEvent; import javax.sip.message.Request; import java.io.ByteArrayInputStream; import java.io.StringReader; import java.util.*; /** * 基于dom4j的工具包 @@ -161,4 +159,23 @@ } } } public static Element getRootElement(RequestEvent evt) throws DocumentException { return getRootElement(evt, "gb2312"); } public static Element getRootElement(RequestEvent evt, String charset) throws DocumentException { Request request = evt.getRequest(); return getRootElement(request.getRawContent(), charset); } public static Element getRootElement(byte[] content, String charset) throws DocumentException { if (charset == null) { charset = "gb2312"; } SAXReader reader = new SAXReader(); reader.setEncoding(charset); Document xml = reader.read(new ByteArrayInputStream(content)); return xml.getRootElement(); } } src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -31,7 +31,7 @@ import javax.servlet.http.HttpServletRequest; /** * @Description:针对 ZLMediaServer的hook事件监听 * @description:针对 ZLMediaServer的hook事件监听 * @author: swwheihei * @date: 2020年5月8日 上午10:46:48 */ src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookSubscribe.java
@@ -8,7 +8,7 @@ import java.util.concurrent.ConcurrentHashMap; /** * @Description:针对 ZLMediaServer的hook事件订阅 * @description:针对 ZLMediaServer的hook事件订阅 * @author: pan * @date: 2020年12月2日 21:17:32 */ src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
@@ -10,7 +10,7 @@ import com.github.pagehelper.PageInfo; /** * @Description:视频设备数据存储接口 * @description:视频设备数据存储接口 * @author: swwheihei * @date: 2020年5月6日 下午2:14:31 */ src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
@@ -25,7 +25,7 @@ import org.springframework.transaction.annotation.Transactional; /** * @Description:视频设备数据存储-jdbc实现 * @description:视频设备数据存储-jdbc实现 * @author: swwheihei * @date: 2020年5月6日 下午2:31:42 */ src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java
@@ -6,7 +6,7 @@ import org.springframework.stereotype.Component; /** * @Description:spring bean获取工厂,获取spring中的已初始化的bean * @description:spring bean获取工厂,获取spring中的已初始化的bean * @author: swwheihei * @date: 2019年6月25日 下午4:51:52 * src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java
@@ -9,7 +9,7 @@ import com.alibaba.fastjson.serializer.SerializerFeature; /** * @Description:使用fastjson实现redis的序列化 * @description:使用fastjson实现redis的序列化 * @author: swwheihei * @date: 2020年5月6日 下午8:40:11 */ src/main/java/com/genersoft/iot/vmp/utils/redis/JedisUtil.java
@@ -8,7 +8,7 @@ import java.util.Set; /** * @Description:Jedis工具类 * @description:Jedis工具类 * @author: wangshaopeng@sunnybs.com * @date: 2021年03月22日 下午8:27:29 */ src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
@@ -9,7 +9,7 @@ import org.springframework.util.CollectionUtils; /** * @Description:Redis工具类 * @description:Redis工具类 * @author: swwheihei * @date: 2020年5月6日 下午8:27:29 */ src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -1,11 +1,21 @@ package com.genersoft.iot.vmp.vmanager.gb28181.device; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.service.IDeviceService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.github.pagehelper.PageInfo; import io.swagger.annotations.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -15,15 +25,6 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; import com.alibaba.fastjson.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; import javax.sip.message.Response; import java.io.UnsupportedEncodingException; import java.util.UUID; @Api(tags = "国标设备查询", value = "国标设备查询") @@ -49,6 +50,9 @@ @Autowired private DeviceOffLineDetector offLineDetector; @Autowired private IDeviceService deviceService; /** * 使用ID查询国标设备 @@ -301,6 +305,18 @@ if (!StringUtils.isEmpty(device.getName())) deviceInStore.setName(device.getName()); if (!StringUtils.isEmpty(device.getCharset())) deviceInStore.setCharset(device.getCharset()); if (!StringUtils.isEmpty(device.getMediaServerId())) deviceInStore.setMediaServerId(device.getMediaServerId()); if (deviceInStore.getSubscribeCycleForCatalog() <=0 && device.getSubscribeCycleForCatalog() > 0) { deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); // 开启订阅 deviceService.addCatalogSubscribe(deviceInStore); } if (deviceInStore.getSubscribeCycleForCatalog() > 0 && device.getSubscribeCycleForCatalog() <= 0) { deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); // 取消订阅 deviceService.removeCatalogSubscribe(deviceInStore); } storager.updateDevice(deviceInStore); cmder.deviceInfoQuery(deviceInStore); }